65.9K
CodeProject 正在变化。 阅读更多。
Home

Galileo+Windows & IoT 第 2 部分:一个 IoT 应用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (8投票s)

2014年12月7日

CPOL

4分钟阅读

viewsIcon

29377

downloadIcon

322

继关于在 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 上做了一个简化的版本。

Electonics

在代码方面,更改了一些常量

 

// 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. 运行所有 :)

根据传感器温度(通过触摸传感器就足以改变它),风扇将启动

Start

 或停止

Stop

温度报告设置为每秒自动刷新。

Report

4. 安全考虑

我承认,我们多年来一直在我们的解决方案中使用这种通过 GET 参数的通信方式,在物联网这个词出现之前,我们的公司就在物联网领域了。 但是由于我们的客户都在制造业,我们与我们的应用程序和传感器一起使用的网络是私有的。
我的观点是,GET 方法不安全,请记住这一点,这是一种在数据不敏感或网络是私有的情况下的解决方案。 此外,流量很容易调试。
因此,如果安全是关注点,那么 POST、https、Azure 以及其他您应该考虑的事情。
并且有一些有趣的 Azure 产品可以用于此物联网场景(当然,您可以从 Windows Galileo 连接,因为 C++ 方法的表面几乎都是一个“大型” Windows)

我只是列举了一些适合物联网解决方案的 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 任务等等。

接下来 也许会有更多? 这取决于反馈 :)

© . All rights reserved.