Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Galileo+Windows & IoT Part 2: A IoT application

4.61/5 (8 votes)
6 Dec 2014CPOL4 min read 29K   299  
The second part (concerning a new Galileo Windows connected (at last) application) to a series of articles about Galileo running Windows and IoT.

Introduction

We talk about Internet of Things but up to now we just fiddled with a board and the programs that run on it. So let’s do something that use some internet (or at least some network :)), send some data and receives some commands from some server.

1. Premise

We would use as a starting point the Smart Fan sample http://ms-iot.github.io/content/SmartFan.htm .
The target is to modify the application to:

  • Read the temperature

  • Send it to a server

  • Execute the server commands to start or stop the fan

We would remove the light sensor part.
How do we communicate with the server, and what server it is?
We open a web page (web server then) and through GET parameters we send the data

http://WebSite/SiteName/Temperatures.aspx?id=2&temp=30&fan=false

The parameters are:

  • id – the id of the device

  • temp – the temperature

  • fan – true if the fan is on otherwise false

The page responds with an invalid html page with 3 commands:

  • listen - do nothing
  • start - start the fan
  • stop - stop the fan

The page is invalid because contains no html markings, just the command text to reduce the bandwidth used. Somethimes you pay for data transfer, and the "dead", no util information, as the markups are in our case, add up.

2. Developing the Galileo application

The hardware pin wise need to be the same. My colleagues (I do software :D) did a simplified version on a Arduino Proto Shield.

Electonics

Code wise some constants were changed:

 

C++
// Convert the voltage
double voltage_to_celsius(double voltage) {
 //+1 for our schema
 return 100 * voltage + 1;
}
C++
void toggle_motor(bool motor_is_on) {
 if (motor_is_on) {
  // Turn off motor
  motor_is_on = false;
  analogWrite(MOTOR_PIN, 0);
 }
 else {
  // Turn on motor
  motor_is_on = true;
  //for our schema
  analogWrite(MOTOR_PIN, 250);
  //The old code
  //delay(1);
  //analogWrite(MOTOR_PIN, 50);
 }
}

                               

The code to open a web site is a pretty trivial Windows C++ open a page

C++
int SendTempAndGetCommand(int deviceId, double temperature, bool fanRunning)
{
	char hostname[] = "169.254.178.34";

	WSADATA                WsaData;
	size_t                 socketResult;
	WSAStartup(0x0101, &WsaData);
	socketResult = socket(AF_INET, SOCK_STREAM, 0);
	if (socketResult == -1)
	{
		return -100;
	}

	struct addrinfo addrinfoHints;
	struct addrinfo *pAddrinfo = NULL;
	struct addrinfo *pAddrinfoResult = NULL;
	int result = -7;

	// Setup the addrinfoHints address info structure
	// which is passed to the getaddrinfo() function
	ZeroMemory(&addrinfoHints, sizeof(addrinfoHints));
	addrinfoHints.ai_family = AF_INET;

	DWORD  dwReturnValue = getaddrinfo(hostname, PORT, &addrinfoHints, &pAddrinfoResult);
	if (dwReturnValue != 0)
	{
		return -101;
	}

	// loop through all the results and connect to the first we can
	for (pAddrinfo = pAddrinfoResult; pAddrinfo != NULL; pAddrinfo = pAddrinfo->ai_next)
	{
		if ((socketResult = socket(pAddrinfo->ai_family, pAddrinfo->ai_socktype,
			pAddrinfo->ai_protocol)) == -1)
		{
			perror("client: socket");
			continue;
		}

		if (connect(socketResult, pAddrinfo->ai_addr, pAddrinfo->ai_addrlen) == -1) {
			perror("client: connect");
			DWORD lasterr = WSAGetLastError();
			continue;
		}

		break;
	}

	if (pAddrinfo == NULL)
	{
		return -102;
	}

	freeaddrinfo(pAddrinfoResult);

	char msg[500];
	sprintf_s(msg, "GET http://WebSite/SiteName/Temperatures.aspx?id=%d&temp=%f&fan=false \r\n\r\n ", deviceId, temperature);
	if (fanRunning)
		sprintf_s(msg, "GET http://WebSite/SiteName/Temperatures.aspx?id=%d&temp=%f&fan=true \r\n\r\n ", deviceId, temperature);

	send(socketResult, msg, (int)strlen(msg), 0);
	char buffer[10000];
	recv(socketResult, buffer, 10000, 0);

	char listen[] = "Listen";
	char start[] = "Start";
	char stop[] = "Stop";

	if (strstr(buffer, listen) != NULL)
	{
		result = -1;
	}
	else
		if (strstr(buffer, start) != NULL)
		{
			result = 1;
		}
		else
			if (strstr(buffer, stop) != NULL)
			{
				result = 0;
			}

	closesocket(socketResult);

	WSACleanup();

	return result;
}

And the motor is commanded using the result of this method

C++
int result = SendTempAndGetCommand(3, temp_in_c, motor_is_on);

if (result==1) {
    if (!motor_is_on) //super sure
    {
        toggle_motor(motor_is_on);
        motor_is_on = true;
        Log(L"Motor On\r\n");
    }
}
else if (result==0) {
    if (motor_is_on) //super sure
    {
        toggle_motor(motor_is_on);
        motor_is_on = false;
        Log(L"Motor Off\r\n");
    }
}

The code is attached to the article, bear in mind that you need to adapt it to your specific hardware.

3. Developing the server applications

The server app is an ASP.Net web site but could be anything (this is why I do not put the full code for it in the article :)).

The aspx is “empty”:

ASP.NET
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Temperatures.aspx.cs" Inherits="FanTemperature.Temperatures" %>

And on .cs on the Page_Load is all the code.
This is how the paramethers are read.

C#
int deviceId = 0;
double curentTemperature = 0;
bool fanRunning = false;
int commandFanToRun = -1;

if (this.Request["ID"] != null)
{
    deviceId = Convert.ToInt32(this.Request["ID"], CultureInfo.InvariantCulture);

    if (this.Request["temp"] != null)
    {
        curentTemperature = Convert.ToDouble(this.Request["temp"], CultureInfo.InvariantCulture);
    }
    if (this.Request["fan"] != null)
    {
        fanRunning = Convert.ToBoolean(this.Request["fan"], CultureInfo.InvariantCulture);
    }
}

 

  And to suppress the headers the adding of the markups, this is the code used, the result string is the command.

C#
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Write(result);
Response.ClearHeaders();

About the rest of the code could be a simple if,  switch or a decision workflow etc. Also the data could be written into the database, and get a report from it using Reporting Services for example.

3. Run all :)

Depending on the sensor temperature (by touching the sensor is enough to change it) the fan will start

Start

 or stop

Stop

The temperature report is set to auto refresh each second.

Report

4. Security consideration

I would admit that we use this communication through GET parameters in our solutions for years, our company was in IoT before the term was coined. But because our clients are in manufacturing the networks we use with our apps and sensors are private.
My point, the GET method is not secure, bear this in mind, is a solution in the cases when data is not sensitive or the network is private. As a plus the traffic is very easy to debug.
So if security is a concern POST, https, Azure and so is something that you should think of.
And there are some interesting Azure offerings that could be used in this IoT scenarios (for sure you can connect from Windows Galileo since the C++ method surface is almost all of a “big” Windows)

And I’m naming just a few Azure offerings that could fit in an IoT solution.

5. Conclusions

I hope that I was able to fill the gaps of the Windows Developer Program for IoT (http://dev.windows.com/en-us/featured/windows-developer-program-for-iot) documentation and tutorials and show you that running Windows on Galileo is an option.

Also there (https://ms-iot.github.io/content/AdvancedUsage.htm) are answers to some advanced questions, how to do not use the USB network card, how to ensure that my application runs on the device without using Visual Studio debug, how to kill a Galileo task and so on.

Next Maybe more of this? Depends on the feedback :)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)