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:
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:
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.
Code wise some constants were changed:
double voltage_to_celsius(double voltage) {
return 100 * voltage + 1;
}
void toggle_motor(bool motor_is_on) {
if (motor_is_on) {
motor_is_on = false;
analogWrite(MOTOR_PIN, 0);
}
else {
motor_is_on = true;
analogWrite(MOTOR_PIN, 250);
}
}
The code to open a web site is a pretty trivial Windows C++ open a page
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;
ZeroMemory(&addrinfoHints, sizeof(addrinfoHints));
addrinfoHints.ai_family = AF_INET;
DWORD dwReturnValue = getaddrinfo(hostname, PORT, &addrinfoHints, &pAddrinfoResult);
if (dwReturnValue != 0)
{
return -101;
}
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
int result = SendTempAndGetCommand(3, temp_in_c, motor_is_on);
if (result==1) {
if (!motor_is_on) {
toggle_motor(motor_is_on);
motor_is_on = true;
Log(L"Motor On\r\n");
}
}
else if (result==0) {
if (motor_is_on) {
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”:
<%@ 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.
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.
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
or stop
The temperature report is set to auto refresh each second.
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 :)