转载

使用 Arduino Uno 和 IBM IoT Foundation 构建云就绪的温度传感器,第 2 部分: 编写 sketch...

注册使用 IBM Bluemix

这个云平台提供了许多免费的服务、运行时和基础架构,可以帮助您快速构建和部署下一个移动或 Web 应用程序。

在这个由 4 部分组成的教程系列的第 1 部分 中,我讨论了一个监视我的配线箱中的温度的项目的设计,该项目是使用 Arduino Uno 和 Virtuabotix DHT11 温度传感器来构建的。我展示了该项目的电路构造,演示了 Arduino IDE 的安装和如何使用不同的 Arduino 示例 sketch 测试项目的各个组件。您现在已准备好了解将 IoT 项目部署到云中的 sketch 设计,以及实现远程实时监视温度和湿度数据的步骤。但是,首先我需要讨论一下用来与 IBM IoT Foundation 进行通信的协议:MQTT。

什么是 MQTT?

MQTT(以前称为 Message Queueing Telemetry Transport)是一个轻量型、快速的通信协议,专为物联网而设计。它起源于 IBM(最初由 Andy Stanford-Clark 在这里开发),自那时起就提交给了 Organization for the Advancement of Structured Information Standards (OASIS) 来进行标准化,该协议标准的最新版本为 3.1 版。MQTT V3.1 协议规范 规定,它的用途是用作一个 “轻量型、基于代理的发布/订阅消息协议,它的设计开放、简单、轻量且容易实现。”自它引入后,“容易实现” 部分已经过实践检验,因为已经开发了多个实现 MQTT 客户端的不同库。您可以在 Eclipse Paho 项目页面 上找到几乎所有这些库的链接。

MQTT 非常适合用在嵌入式设备中,因为它:

  • 是异步的,具有多种不同的服务质量水平,这在 Internet 连接不可靠时很重要。
  • 发送较短、紧凑的消息,这使得它很适合用于低带宽情形。
  • 不需要太多软件来实现客户端,这使它非常适合像 Arduino 这样具有有限的内存的设备。

MQTT 是 IBM IoT Foundation QuickStart 设计获取输入时所依据的协议。

回页首

下载并安装 Arduino MQTT 库

在本教程中,您将使用 IBM Internet of Things Foundation Quickstart 的内置特性描绘来自 Arduino 传感器的实时数据的图表。

为 Arduino 安装针对 MQTT 的客户端库很简单,就像查找和安装您已在第 1 部分 中看到的针对特定硬件设备的库一样。用于您的项目的特定的库可以在 Arduino Client for MQTT 网站上找到,该网站介绍了该库,链接到相关文档,并提供了一个额外的 GitHub 链接,从该链接也可以下载它。

在我的示例中,我使用了来自 GitHub 链接的 V1.9.1 客户端。下载 ZIP 或 TAR 文件,然后将该归档文件中的 PubSubClient 目录解压到您的 Arduino IDE 目录的 libraries 子目录。然后重新启动 Arduino IDE。 PubSubClient>mqtt_authPubSubClient>mqtt_basicPubSubClient>mqtt_publish_in_callback 菜单项现在应该可供使用,如图 1 所示。

图 1. PubSubClient 菜单

使用 Arduino Uno 和 IBM IoT Foundation 构建云就绪的温度传感器,第 2      部分: 编写 sketch...

回页首

在本地测试 MQTT

目前位置在本教程系列中采用的流程是,向解决方案中引入一个新组件或技术,然后独立地测试它,以确保它能正常运行。在下载并安装 MQTT 客户端软件后,我们将对它执行同样的操作。但是,仍然需要一个额外的软件来测试您的客户端。

MQTT 是一个基于代理的协议:客户端连接到一个协调它们之间的通信的代理。事实上,这个流程非常简单。一组客户端向该代理注册它们感兴趣的一个主题。另一个客户端向该主题发布一条消息,该代理将该消息转发到订阅客户端。

您将用于本地测试的代理是另一个叫做 Mosquitto 的开源产品。可将它安装在您用于编写 Arduino 程序的本地 PC,然后测试 Arduino 能否与代理进行通信。

Mosquitto

您可以从 Mosquitto 网站 下载 Mosquitto。它可用于 Windows®、Mac 和大多数 Linux® 变体。安装它很简单:对于 Linux,只需要安装一个新包;对于 Windows,可采用 Windows 服务或一个单独的可执行文件的形式来安装该系统。如果使用 Windows,一定要清除安装为服务的复选框。从命令行运行它更容易,因为可更轻松地查看它记录的调试信息。

安装 Mosquitto 后,运行以下命令来从(任何平台上的)命令行启动它:

mosquitto -v

-v 标志表示 “详细” 日志,它表示可以查看所建立的连接的信息以及接收或发送的消息。开始将消息发送到本地代理后,在一分钟内就可以看到结果。

下载示例 sketch

下一步是下载将所有部分衔接在一起的示例 sketch(参见下载)。您将通过 MQTT 将一条消息发布到一个 MQTT 代理(首先发送到本地代理,然后将它发送到 IoT Foundation QuickStart 中包含的代理)。要让 IoT Foundation QuickStart 最终解析和显示传感器数据,必须将它发布到一个名为 iot-2/evt/status/fmt/json 的主题。类似地,还必须以某种特定的方式格式化该数据。如果在 IoT Foundation QuickStart 文档中查找 “ 将我的设备连接到 QuickStart ” 秘诀,就会看到数据必须具有以下 JavaScript 对象表示法 (JSON) 格式:

{     "d": {          "name1": "stringvalue",          "name2": intvalue,          ...     } }

示例 sketch 是一个简单的程序。从我在第 1 部分 中指出了其他 Arduino 示例,可以看到所有 Arduino 程序都具有相同的结构。它们包含一个标准的函数集(名为 setup()loop() ),以及一些可选的变量声明和您在 setup()loop() 函数中使用的任何实用程序函数的声明。首先,需要在代码的开头对其中一些变量声明执行一些更改,以便可以在本地测试该程序。

对示例 sketch 的更改

与所有其他 Arduino sketch 一样,最顶部的程序包含对您在 sketch 中使用的库的引用:

#include <SPI.h> #include <Ethernet.h> #include <PubSubClient.h> #include <dht11.h>

您可以看到,该 sketch 使用了以太网库来驱动以太网扩展卡,使用 DHT11 库来实现对来自 DHT11 的读数的访问,就像在第 1 部分 中看到的示例那样。但是,第一次还要使用 PubSubClient 库。要利用这些特性,需要对代码执行两处更改,以便针对本地服务器测试它:

// Update this to either the MAC address found on the sticker on your Ethernet shield (newer shields) // or a different random hexadecimal value (change at least the last four bytes) byte mac[]    = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; char macstr[] = "deedbafefeed"; // Note this next value is only used if you intend to test against a local MQTT server byte localserver[] = {192, 168, 1, 98 }; // Update this value to an appropriate open IP on your local network byte ip[]     = {192, 168, 1, 20 };

从第一条注释中可以看出,需要执行的第一处更改是更新 macmacstr 变量,使之与以太网扩展卡的 MAC 地址相匹配。较新的以太网扩展卡已将此信息打印在该卡的标签上。如果使用较旧的卡,可以将最后 4 位十六进制字符更改为其他任何有效的十六进制值。接下来,将 ip 变量更改为本地网络上一个开放的 IP 地址。以太网库能够使用 DHCP,如果感兴趣的话,您可以了解一下如何做,但尽可能地使用固定 IP 地址会更简单。接下来,将 localserver 变量更新为您在其上使用 Mosquitto 服务器的计算机的 IP 地址。最后,更新 sketch 以连接到您的本地 MQTT 服务器,而不是 IBM IoT Foundation QuickStart 服务器。

在代码中找到下面这一节:

// Uncomment this next line and comment out the line after it to test against a local MQTT server //PubSubClient client(localserver, 1883, 0, ethClient); PubSubClient client(servername, 1883, callback, ethClient);

取消注释包含以 client(localserver 开头的构造函数的一行,并注释掉它之下的以 client(servername 开头的一行。然后保存 sketch。

执行必要的更改后,可以快速查看这个简单程序的剩余部分。在两个代码段之间,我们已看到一组变量声明:

char servername[]="messaging.quickstart.internetofthings.ibmcloud.com"; String clientName = String("d:quickstart:arduino:") + macstr; String topicName = String("iot-2/evt/status/fmt/json"); dht11 DHT11; float tempF = 0.0; float tempC = 0.0; float humidity = 0.0; EthernetClient ethClient;

可以看到,拥有针对华氏和摄氏度的温度的变量,以及针对湿度的变量。还有一个变量将包含将由 PubSub 客户端使用的以太网客户端的实例。

接下来是 setup() 函数的定义:

void setup()  {   // Start the Ethernet client, open up serial port for debugging, and attach the DHT11 sensor   Ethernet.begin(mac, ip);   Serial.begin(9600);   DHT11.attach(3); }

此函数非常简单;它使用提供的 MAC 地址和以太网客户端运行时使用的静态 IP 地址来启动该客户端。它然后启动串行端口(用于出于调试用途而与串行监视器通信),最后在引脚 3 上打开与 DHT11 的通信。

下一个要检查的函数是 loop() ,只要 Arduino 在运行,就会持续调用该函数:

void loop() {   char clientStr[34];   clientName.toCharArray(clientStr,34);   char topicStr[26];   topicName.toCharArray(topicStr,26);   getData();   if (!client.connected()) {     Serial.print("Trying to connect to: ");     Serial.println(clientStr);     client.connect(clientStr);   }   if (client.connected() ) {     String json = buildJson();     char jsonStr[200];     json.toCharArray(jsonStr,200);     boolean pubresult = client.publish(topicStr,jsonStr);     Serial.print("attempt to send ");     Serial.println(jsonStr);     Serial.print("to ");     Serial.println(topicStr);     if (pubresult)       Serial.println("successfully sent");     else       Serial.println("unsuccessfully sent");   }   delay(5000); }

可以看到,此函数的大部分内容专门用于生成调试输出。但是,还有一些重要元素需要注意。靠近该函数顶部是对 getData() 函数(接下来将解释)的调用,用于获取来自 DHT11 的传感器数据。然后, loop() 函数会检查 PubSubClient 客户端是否已连接。如果未连接,那么 loop() 函数会尝试连接到 MQTT 代理。如果已经连接,那么 loop() 函数会使用 buildJson() 格式化一个 JSON 字符串,然后使用 PubSubClientpublish() 方法将该字符串发布到 MQTT 代理。最后, loop() 在函数底部等待 5,000 毫秒,之后 Arduino 运行时周期返回并再次调用该函数。

接下来看看 getData() 函数:

void getData() {   int chk = DHT11.read();   switch (chk)   {   case 0:     Serial.println("Read OK");     humidity = (float)DHT11.humidity;     tempF = DHT11.fahrenheit();     tempC = DHT11.temperature;     break;   case -1:     Serial.println("Checksum error");     break;   case -2:     Serial.println("Time out error");     break;   default:     Serial.println("Unknown error");     break;   } }

此函数检查来自 DHT11 库的数据的状态,然后读取已准备好的传感器数据值;否则,它在控制台上打印一条提供信息的消息。

最后看看格式化 JSON 输出的函数:

String buildJson() {   String data = "{";   data+="/n";   data+= "/"d/": {";   data+="/n";   data+="/"myName/": /"Arduino DHT11/",";   data+="/n";   data+="/"temperature (F)/": ";   data+=(int)tempF;   data+= ",";   data+="/n";   data+="/"temperature (C)/": ";   data+=(int)tempC;   data+= ",";   data+="/n";   data+="/"humidity/": ";   data+=(int)humidity;   data+="/n";   data+="}";   data+="/n";   data+="}";   return data; }

在 Arduino 中实现的 Processing 的一个缺陷是,它缺乏用来处理字符串的良好工具。您可能已注意到,需要在 String 类实例与字符类型之间制定一些古怪的约定,以便调用需要一种或另一种实例的函数。类似地,由于缺乏很好的字符串格式化库,格式化一个像这样的简单 JSON 字符串都可能很难 — 即使存在这样的函数来格式化控制台输出。

对一个本地 Mosquitto 代理执行测试

现在,您基本上完成第一部分了。接下来按照第 1 部分 中讨论的上传过程,将修改的 sketch 上传到 Arduino。在 Arduino IDE 的状态栏中看到状态 “Done uploading.” 后,立即按下 Ctrl-Shift-M 打开串行监视器。

验证您的输出

现在,假设一切正常,您应该在启动 Mosquitto 的终端窗口中看到以下类型的输出:

1405807697: mosquitto version 1.2.3 (build date 22/12/2013 13:36:32.54) starting 1405807697: Using default config. 1405807697: Opening ipv6 listen socket on port 1883. 1405807697: Opening ipv4 listen socket on port 1883. 1405807718: New connection from 192.168.1.20 on port 1883. 1405807718: New client connected from 192.168.1.20 as d:quickstart:arduino:deedb afefeed (c2, k15). 1405807718: Sending CONNACK to d:quickstart:arduino:deedbafefeed (0) 1405807718: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,  m0, 'iot-2/evt/status/fmt/json', ... (100 bytes)) 1405807723: Socket error on client d:quickstart:arduino:deedbafefeed, disconnect ing. 1405807723: New connection from 192.168.1.20 on port 1883. 1405807723: New client connected from 192.168.1.20 as d:quickstart:arduino:deedb afefeed (c2, k15). 1405807723: Sending CONNACK to d:quickstart:arduino:deedbafefeed (0) 1405807723: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,  m0, 'iot-2/evt/status/fmt/json', ... (100 bytes)) 1405807729: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,  m0, 'iot-2/evt/status/fmt/json', ... (100 bytes)) 1405807734: Received PUBLISH from d:quickstart:arduino:deedbafefeed (d0, q0, r0,  m0, 'iot-2/evt/status/fmt/json', ... (100 bytes))

了解您正确完成了操作的关键是,您将在最后几行中看到 Received PUBLISH from... 。这意味着 Arduino sketch 已成功连接到 Mosquitto 代理。现在查看您的串行监视器;它应该包含类似以下信息的消息:

Read OK Trying to connect to d:quickstart:arduino:deedbafefeed attempt to send { "d": { "myName": "Arduino DHT11", "temperature (F)": 71, "temperature (C)": 22, "humidity": 43 } } to iot-2/evt/status/fmt/json successfully sent

回页首

将 Arduino 连接到 IoT Foundation Quickstart

所有功能都能在本地运行后,可以尝试对 IoT Foundation QuickStart 运行这些功能了。在浏览器中访问 IBM Internet of Things Foundation 网站,如图 2 所示。

图 2. IBM IoT Foundation 主页

使用 Arduino Uno 和 IBM IoT Foundation 构建云就绪的温度传感器,第 2      部分: 编写 sketch...

单击显示 Try it out with our Quickstart 的按钮。您将看到图 3 中所示的页面。

图 3. IBM IoT Foundation Quickstart 欢迎页面

使用 Arduino Uno 和 IBM IoT Foundation 构建云就绪的温度传感器,第 2      部分: 编写 sketch...

在本教程中,您将使用 IBM IoT Foundation Quickstart 的内置特性描绘来自 Arduino 传感器的实时数据的图表。在第 3 部分 和第 4 部分 中,将编写一个应用程序来对您收到的数据执行一些更有趣的操作。

IoT Foundation 有一些针对其他设备的令人兴奋的方案。如果您有一个更加复杂的设备,比如 Intel Galileo 或 Raspberry Pi,您可能希望尝试这些方案。对于目前,只需键入您的 Arduino 的 MAC 地址。但在单击 Go 之前,还需要在 sketch 中执行一项更改。

更改 sketch

您是否还记得之前您将 sketch 更改为指向本地 MQTT 服务器,而不是 IoT Foundation 上的 MQTT 服务器?现在是时候更改回来了。注释和取消注释您在原始代码中更改的行:

// Uncomment this next line and comment out the line after it to test against a local MQTT server //PubSubClient client(localserver, 1883, 0, ethClient); PubSubClient client(servername, 1883, callback, ethClient);

执行此更改后,保存 sketch 并将它上传到 Arduino。如果想要重新启动串行监视器,可以这么做,但在您查看 IoT Foundation 时才会看到结果如何。返回到浏览器中,单击 Mac 地址页面上的 Go 按钮,然后等待几分钟。

描绘数据的图表

如果各项功能运行正常,您会看到一个页面显示了您的温度读数的图表,如图 4 中所示。

图 4. 数据曲线图

使用 Arduino Uno 和 IBM IoT Foundation 构建云就绪的温度传感器,第 2      部分: 编写 sketch...

大功告成!您现在已经构建了一个可作为全球 IoT 的一部分的设备。对于我的这个具体的简单情形,这是我需要的全部功能:一个曲线图,我可以观察其中的几小时数据,以检查配线箱内部的温度。坏消息是,甚至在热天的中午,预计的温度也绝不会高于 73 华氏度,所以我又不得不返回到制图板上来查找我的问题。而您学习如何利用 IoT 的旅程才刚刚开始。

回页首

结束语

在本系列的接下来两部教程中,您将编写自己的应用程序(在 IBM® Bluemix 上运行™),它可保留从 Arduino 发送的数据,支持显示和对比当前数据与历史数据。

回页首

下载

描述 名字 大小
示例 sketch MQTT_IOT_SENSORS.ino 4KB
正文到此结束
Loading...