Galileo+Windows & IoT 第 2 部分:一个 IoT 应用
继关于在 Galileo 上运行 Windows 和物联网的一系列文章之后,这是第二部分(关于一个新的 Galileo Windows 连接(最终)的应用)。
引言
我们谈论物联网,但到目前为止,我们只是摆弄了一个电路板和在其上运行的程序。 让我们做一些使用互联网(或者至少是网络 :)),发送一些数据并从某个服务器接收一些命令的事情。
1. 前提
我们将使用 Smart Fan 示例作为起点 http://ms-iot.github.io/content/SmartFan.htm 。
目标是修改应用程序以
-
读取温度
-
将其发送到服务器
-
执行服务器命令以启动或停止风扇
我们将移除光线传感器部分。
我们如何与服务器通信,它是什么服务器?
我们打开一个网页(然后是 Web 服务器),并通过 GET 参数发送数据
http://WebSite/SiteName/Temperatures.aspx?id=2&temp=30&fan=false
参数如下:
-
id – 设备的 id
-
temp – 温度
-
fan – 如果风扇开启则为 true,否则为 false
该页面使用 3 个命令响应一个无效的 html 页面
- listen - 什么都不做
- start - 启动风扇
- stop - 停止风扇
页面无效是因为不包含 html 标记,只是命令文本以减少使用的带宽。 有时候您需要为数据传输付费,而“死掉的”,没有用的信息,就像在我们的例子中一样,标记会累积起来。
2. 开发 Galileo 应用程序
硬件引脚方面需要相同。 我的同事(我做软件 :D)在 Arduino Proto Shield 上做了一个简化的版本。
在代码方面,更改了一些常量
// Convert the voltage
double voltage_to_celsius(double voltage) {
//+1 for our schema
return 100 * voltage + 1;
}
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);
}
}
打开一个网站的代码是一个非常简单的 Windows 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;
}
并且电机的控制使用此方法的结果
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");
}
}
代码附在文章中,请记住您需要根据您的特定硬件进行调整。
3. 开发服务器应用程序
服务器应用程序是一个 ASP.Net 网站,但可以是任何东西(这就是为什么我没有在文章中放入它的完整代码 :))。
aspx 是“空的”
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Temperatures.aspx.cs" Inherits="FanTemperature.Temperatures" %>
并且在 .cs 的 Page_Load 中是所有的代码。
这就是参数的读取方式。
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);
}
}
为了抑制标头添加标记,使用了这段代码,结果字符串就是命令。
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Write(result);
Response.ClearHeaders();
关于其余的代码可能是一个简单的 if、switch 或决策工作流程等。 也可以将数据写入数据库,并例如使用 Reporting Services 从中获取报告。
3. 运行所有 :)
根据传感器温度(通过触摸传感器就足以改变它),风扇将启动
或停止
温度报告设置为每秒自动刷新。
4. 安全考虑
我承认,我们多年来一直在我们的解决方案中使用这种通过 GET 参数的通信方式,在物联网这个词出现之前,我们的公司就在物联网领域了。 但是由于我们的客户都在制造业,我们与我们的应用程序和传感器一起使用的网络是私有的。
我的观点是,GET 方法不安全,请记住这一点,这是一种在数据不敏感或网络是私有的情况下的解决方案。 此外,流量很容易调试。
因此,如果安全是关注点,那么 POST、https、Azure 以及其他您应该考虑的事情。
并且有一些有趣的 Azure 产品可以用于此物联网场景(当然,您可以从 Windows Galileo 连接,因为 C++ 方法的表面几乎都是一个“大型” Windows)
-
智能系统服务 http://www.microsoft.com/windowsembedded/en-us/intelligent-systems-service.aspx
-
Azure 服务总线 http://azure.microsoft.com/en-us/services/service-bus/
-
Azure 通知中心 http://azure.microsoft.com/en-us/documentation/services/notification-hubs/
我只是列举了一些适合物联网解决方案的 Azure 产品。
5. 结论
我希望我能够填补 Windows Developer Program for IoT (http://dev.windows.com/en-us/featured/windows-developer-program-for-iot) 文档和教程的空白,并向您展示在 Galileo 上运行 Windows 是一种选择。
此外 (https://ms-iot.github.io/content/AdvancedUsage.htm) 也有一些高级问题的答案,如何不使用 USB 网卡,如何确保我的应用程序在设备上运行而不使用 Visual Studio 调试,如何终止 Galileo 任务等等。
接下来 也许会有更多? 这取决于反馈 :)