NodeMCU具有较为丰富的对外接口和多个IO,可驱动多种传感器使用,本次例程将使用NodeMCU实现温湿度传感器DHT11的数据采集,以及数据的阿里云物联网平台上报。
NodeMCU环境传感器 - 图1

DHT11温湿度传感器使用

学习过TinyEngine的同学可能看过DeveloperKit shtc1传感器的驱动脚本:
image.png
发现全是16进制的数据以及+-x/各类数据变化,看到这里别见怪,传感器就是能够将真实世界的物理量映射成为电信号,再通过数字电路(甚至模拟电路)进行编码或映射得到的数据,部分售价较高的传感器传输的数据为已经编码好的(即在传感器内部再加变送器模块,实现数据的误差消除、格式封装、传输协议适配等等),而一些性价比高的传感器往往没有复杂的电路,类似shtc1,只是将温度和湿度使用数字电路封装成字节码就给送出来了,需要开发者在外置程序中对数据进行处理和变换。

类似于在线TinyEngine和在线JavaScript开发工作台提供的转换驱动程序脚本,在Arduino环境一些主流的传感器都有驱动库支持,免去了开发者再查找各类datasheet对数据进行转换的痛苦。

接线图

请参照以下接线方式进行:
NodeMCU环境传感器 - 图3

安装DHT11驱动库

在这里我们使用Adafruit提供的DHT系列传感器库,在库管理器搜索DHT11,选择安装即可(示例安装1.3.4版本)
image.png
这个库部分程序依赖Adafruit_seneor包(本人在github找到,但是觉得麻烦,这里直接在库文件中将相关依赖部分删除—并不用到)。
image.png

在Arduino IDE中找到DHT_Sensor库提供的例程。
image.png

修改传感器引脚、传感器型号、通信波特率后下载代码至NodeMCU,观察串口输出。

image.png

程序输出

程序正常输出后,在串口监视器将自动打印传感器采集到的温湿度数据,传感器调试完成。
image.png

程序粗略分析

在setup()函数中,进行串口初始化以及传感器对象的初始化设置,在loop()函数中进行温湿度数据的读取和打印,其中:

  • 温度:float t = dht.readTemperature();
  • 相对湿度:float h = dht.readHumidity();

温湿度数据上云

通过DHT11传感器数据以及前面设备上云的例程之后,相信你可以很快地将两个程序整合在一起,按照阿里云物联网平台的设备模型,封装成Alink JSON格式的数据进行上报,阿里云物联网平台依据设备模型进行解析。

设备模型定义

我们在物联网平台上定义一款空气盒子产品,包含“当前温度”、“相对湿度”两个属性。
image.png

设备端开发

设备端程序开发,在NodeMCU上云例程的基础上进行代码修改。

  • 修改设备三元组信息以及MQTT连接信息(略)
  • 在程序最上方引入DHT11库 #include "DHT.h"
  • 在程序开始加入传感器定义

    1. #define DHTPIN 13 // Digital pin connected to the DHT sensor
    2. #define DHTTYPE DHT11 // DHT 11
    3. DHT dht(DHTPIN, DHTTYPE);
  • 在初始化添加dht初始化:dht.begin();

  • 在mqttIntervalPost()函数中封装温湿度Alink JSON格式数据:
  1. //mqtt循环发送内容
  2. void mqttIntervalPost()
  3. {
  4. //读取传感器数据
  5. float h = dht.readHumidity();
  6. // Read temperature as Celsius (the default)
  7. float t = dht.readTemperature();
  8. // Read temperature as Fahrenheit (isFahrenheit = true)
  9. float f = dht.readTemperature(true);
  10. // Check if any reads failed and exit early (to try again).
  11. if (isnan(h) || isnan(t) || isnan(f)) {
  12. Serial.println(F("Failed to read from DHT sensor!"));
  13. return;
  14. }
  15. char param[32];
  16. char jsonBuf[128];
  17. //注意设备模型定义的属性小数点位数需要符合才可以被平台解析
  18. sprintf(param, "{\"CurrentHumidity\":%.0f,\"CurrentTemperature\":%.1f }",h,t);
  19. sprintf(jsonBuf, ALINK_BODY_FORMAT, ALINK_METHOD_PROP_POST, param);
  20. Serial.println(jsonBuf);
  21. client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
  22. }

待设备持续上报时,在阿里云物联网平台即可看到设备实时运行属性:
image.png

完整参考代码

  1. #include <ArduinoJson.h>
  2. #include <ESP8266WiFi.h>
  3. #include <PubSubClient.h>
  4. #include "DHT.h"
  5. #define DHTPIN 13 // Digital pin connected to the DHT sensor
  6. #define DHTTYPE DHT11 // DHT 11
  7. /* 连接您的WIFI SSID和密码,这个9个设备可以一致 */
  8. #define WIFI_SSID "mimi8"
  9. #define WIFI_PASSWD "123456788"
  10. /* 产品的三元组信息,根据9个测试设备的三元组,每个设备都烧录不同的*/
  11. #define PRODUCT_KEY "换"
  12. #define DEVICE_NAME "换"
  13. #define DEVICE_SECRET "换"
  14. /* LD线上环境域名和端口号,不需要改 */
  15. #define MQTT_SERVER PRODUCT_KEY".iot-as-mqtt.cn-shanghai.aliyuncs.com"
  16. #define MQTT_PORT 1883
  17. #define MQTT_USRNAME DEVICE_NAME "&" PRODUCT_KEY
  18. // TODO: MQTT连接的签名信息,哈希加密请以"clientIdtestdeviceName"+设备名称+"productKey"+设备模型标识+“timestamp123456789”前往http://tool.oschina.net/encrypt?type=2进行加密
  19. //clientId可以随意命名,以下为test,加密生成MQTT_PASSWD的秘钥为设备的deviceSecret
  20. // HMACSHA1_SRC clientIdtestdeviceNamehuman04productKeya1rezUVs103timestamp123456789
  21. #define CLIENT_ID "hello|securemode=3,timestamp=123456789,signmethod=hmacsha1|"
  22. #define MQTT_PASSWD "换"
  23. #define ALINK_BODY_FORMAT "{\"id\":\"123\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":%s}"
  24. #define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
  25. #define ALINK_TOPIC_PROP_POSTRSP "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post_reply"
  26. #define ALINK_TOPIC_PROP_SET "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/service/property/set"
  27. #define ALINK_METHOD_PROP_POST "thing.event.property.post"
  28. unsigned long lastMs = 0;
  29. DHT dht(DHTPIN, DHTTYPE);
  30. WiFiClient espClient;
  31. PubSubClient client(espClient);
  32. //下行消息的回调函数
  33. void callback(char *topic, byte *payload, unsigned int length)
  34. {
  35. Serial.print("Message arrived [");
  36. Serial.print(topic);
  37. Serial.print("] ");
  38. payload[length] = '\0';
  39. Serial.println((char *)payload);
  40. if (strstr(topic, ALINK_TOPIC_PROP_SET))
  41. {
  42. StaticJsonBuffer<100> jsonBuffer;
  43. JsonObject& root = jsonBuffer.parseObject(payload);
  44. if (!root.success())
  45. {
  46. Serial.println("parseObject() failed");
  47. return ;
  48. }
  49. }
  50. }
  51. //wifi初始化连接函数
  52. void wifiInit()
  53. {
  54. WiFi.mode(WIFI_STA);
  55. WiFi.begin(WIFI_SSID, WIFI_PASSWD);
  56. while (WiFi.status() != WL_CONNECTED)
  57. {
  58. delay(1000);
  59. Serial.println("WiFi not Connect");
  60. }
  61. Serial.println("Connected to AP");
  62. Serial.println("IP address: ");
  63. Serial.println(WiFi.localIP());
  64. client.setServer(MQTT_SERVER, MQTT_PORT); /* 连接WiFi之后,连接MQTT服务器 */
  65. client.setCallback(callback);
  66. }
  67. //mqtt连接检查函数
  68. void mqttCheckConnect()
  69. {
  70. while (!client.connected())
  71. {
  72. Serial.println("Connecting to MQTT Server ...");
  73. if (client.connect(CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD))
  74. {
  75. Serial.println("MQTT Connected!");
  76. // client.subscribe(ALINK_TOPIC_PROP_POSTRSP);
  77. client.subscribe(ALINK_TOPIC_PROP_SET);
  78. Serial.println("subscribe done");
  79. }
  80. else
  81. {
  82. Serial.print("MQTT Connect err:");
  83. Serial.println(client.state());
  84. delay(5000);
  85. }
  86. }
  87. }
  88. //mqtt循环发送内容
  89. void mqttIntervalPost()
  90. {
  91. //读取传感器数据
  92. float h = dht.readHumidity();
  93. // Read temperature as Celsius (the default)
  94. float t = dht.readTemperature();
  95. // Read temperature as Fahrenheit (isFahrenheit = true)
  96. float f = dht.readTemperature(true);
  97. // Check if any reads failed and exit early (to try again).
  98. if (isnan(h) || isnan(t) || isnan(f)) {
  99. Serial.println(F("Failed to read from DHT sensor!"));
  100. return;
  101. }
  102. char param[32];
  103. char jsonBuf[128];
  104. sprintf(param, "{\"CurrentHumidity\":%.0f,\"CurrentTemperature\":%.1f }",h,t);
  105. sprintf(jsonBuf, ALINK_BODY_FORMAT, ALINK_METHOD_PROP_POST, param);
  106. Serial.println(jsonBuf);
  107. client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
  108. }
  109. //初始化函数
  110. void setup()
  111. {
  112. /* initialize serial for debugging */
  113. Serial.begin(115200);
  114. Serial.println("Demo Start");
  115. wifiInit();
  116. dht.begin();
  117. }
  118. //主函数
  119. // the loop function runs over and over again forever
  120. void loop()
  121. {
  122. if (millis() - lastMs >= 5000)
  123. {
  124. lastMs = millis();
  125. mqttCheckConnect();
  126. Serial.println("start once!");
  127. /* 上报 */
  128. mqttIntervalPost();
  129. }
  130. client.loop();
  131. }