我是靠谱客的博主 热情皮皮虾,最近开发中收集的这篇文章主要介绍NodeMCU-ESP8266连接阿里云Iot平台进行数据监测,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

简介

本教程中主要讲解使用阿里云Iot监测控制NodeMCU的方法。

设备从MQTT数据上传、监测、控制的全流程如下图所示,本教程仅仅讲解从设备与Aliyun平台之间的交互,业务服务器部分(App开发)会在后面的教程中进行讲解,敬请期待。

欢迎关注笔者关于NodeMCU-ESP8266的学习教程,里面整理了很多快速上手的实例案例和一些特别好的学习教程,可以减少很多走弯路的机会!

image-20211201185328155

友情提醒:多看官方文档,官方文档什么都有。

开发环境

  • Arduino IDE
    • NodeMCU1.0芯片包
    • ArduinoJson库
    • PubSubClient库

PubSubClient

作者名:Nick O’Leary
官网地址:https://pubsubclient.knolleary.net/
GitHub:https://github.com/knolleary/pubsubclient/
百度网盘下载: https://pan.baidu.com/s/12MHGbdfiOdwOGip5RMSSEQ 提取码: sizy

如果不知道怎么安装芯片包和导入第三方库,自行research

上一节讲述了NoduMCU通过软串口控制Arduino的例程,这一次笔者将NodeMCU接入AliyunIot平台,通过MQTT来远程监测控制NodeMCU,再通过NodeMCU来控制Arduino。

前述知识

MQTT协议

这里不做过多介绍,笔者默认您已经掌握了该知识,如果对MQTT不够了解,可以参考零基础入门学用物联网 – MQTT基础篇

物模型

物模型是产品数字化的描述,定义了产品的功能,物模型将不同品牌不同品类的产品功能抽象归纳,形成“标准物模型”,便于各方用统一的语言描述、控制、理解产品功能。

物模型由若干条“参数”组成,参数按描述的功能类型不同,又分为属性、方法和事件。

image-20211201211023911

更为详细的物模型解析

为什么要有物模型?当下的云平台为了兼容不同的通信协议,在通信层之间构建了一个物模型,这才是最重要的事,为了让不同通信协议的设备都可以整合在一个平台内进行运行,因此需要一个云平台们非常需要一个中间层做整合,物模型由此诞生。本例程中采用MQTT模型,其订阅发布的逻辑也因为加了物模型层而有所不同。

虽然在本例程中的原理还是基于订阅发布的物模型,但是订阅发布的主题和要处理的数据已经与传统MQTT意义上的数据有所不同,下面将做简单的讲解。

image-20211201211254921

基于物模型的MQTT协议

MQTT协议的使用方式在物模型的产生后所迭代,下面我举两个例子就可以看出传统MQTT和基于MQTT的物模型之间的差别了。

传统MQTT

image-20211202171220466

在以上图示中一共有三个MQTT客户端。它们分别是汽车,手机和电脑。MQTT服务端在管理MQTT通讯时使用了“主题”来对信息进行管理的。比如上图所示,假设我们需要利用手机和电脑获取汽车的速度,那么我们首先要利用电脑和手机向MQTT服务器订阅主题“汽车速度”。接下来,当汽车客户端向服务端的“汽车速度”主题发布信息后,服务端就会首先检查以下都有哪些客户端订阅了“汽车速度”这一主题的信息。当它发现订阅了该主题的客户端有一个手机和一个电脑,于是服务端就会将刚刚收到的“汽车速度”信息转发给订阅了该主题的手机和电脑客户端。

我们现在做一个假设,汽车发布了多少数据手机端就像看到多少数据。而现在汽车只发布了一个速度的属性,如果这个时候汽车还想把自己车内温度上传上去,那么就要向一个名为“CarTemperture”的主题发布数据,这样一来,一个循环内,小车就要向两个主题发布两次消息,而手机也因此需要多订阅一个主题。在小车向n个主题发布数据的状态下,如果手机端想要全部接收到,难道就要一次一次把所有的主题都订阅了吗?这样来看就有些臃肿了。

而云平台的定位就和我们刚才所述的手机端一样,云平台想要看到设备发布的所有数据,因此不可能让云平台一个一个主题的去订阅,能不能把所有数据全部发送给云平台让云平台自己去解析呢?由此就产生了物模型。

基于物模型的MQTT

物模型的作用就相当于定义了主题名叫“post”,汽车只要把所有的数据放在一起发送给“post”就可以了。

image-20211202172411434

如果您想要将汽车的速度和温度的属性进行上传,那么您可以先告诉云平台你的汽车要上传“速度”和“温度”两个属性,让云平台先了解你将要上传的数据。然后这时汽车就可以对云平台的“post”主题发送特定格式的字符串,这个字符串是云平台规定好的。比如发送如下字符串:

publish topic=/sys/xxx/yyy/thing/event/property/post, payload={"id":123321,"params":{"carTemperture":12312341,"speed":50},"version":"1.0","method":"thing.event.property.post"}

快速上手

下面开始讲解开发步骤,大致流程如下。

image-20211202170815325

注册Aliyun帐号

进入Aliyun平台注册一个帐号,自己操作

在物联网平台创建实例

首先打开控制台;

image-20211201180142559

打开物联网平台;

image-20211201180239337

自行创建一个实例,这里的实例在本例程中你可以当做它是一个MQTT服务器。

image-20211201180308018

创建产品

创建完实例后,进入实例,新建一个产品

image-20211201180459145

创建一个设备,如下图所示。

image-20211201180903849

添加物模型

在产品中,选择功能定义,编辑功能;

image-20211203211327073

选择自定义功能;

image-20211203211309526

创建一个温度属性,如下;

image-20211202173448629

创建设备

切换页面,点击添加设备。

image-20211201181018577

填写设备信息,如下图,这里的NodeMCU-1是笔者创建的产品;

image-20211201181135846

Tip:产品和设备的管理你可以类比以下例子:Iphone 11 PRO是一个产品,我的11和你的11是两个设备。从这里可以看出,同一个产品的设备具有一样的属性,但是同一个产品不同设备属性的值可能不一样,比如说我的11还有100G内存,你的11只有10G内存的,这里的内存就可以当做一个属性。

创建完设备就可以进行代码的开发了。

Arduino IDE代码开发

下面讲解代码部分,代码部分主要分为几个部分:

  • wifi连接
  • mqtt初始化
  • ntp网络时间获取
  • 数据上报
  • 数据接收

注意事项:

  • 这里的数据上报就是对"post"主题发布信息
  • 这里的数据接收功能当前只能接收到云平台发送了什么内容,这个内容是需要解析的,在后面的教程中会讲解如何解析数据。

在定义物模型的时候,笔者定义了两个属性,分别是开门时间和开门指令,这两个数据分别演示数据上报和数据下发。在NodeMCU运行的时候,会上传当前时间;而在另外一边,云平台会下发开门指令给NoduMCU。

image-20211203211233851

例程

/* 目的:该例程为NodeMCU连接阿里云Iot平台的例程
* 作者:Zeeland
* 最后修改时间:2021年12月2日 18:33:56
* https://gitee.com/zeeland/projects
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <ESP8266WiFiMulti.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp1.aliyun.com",60*60*8, 30*60*1000);
String currentTime;
/* 设备证书信息*/
#define PRODUCT_KEY
"PRODUCT_KEY"
#define DEVICE_NAME
"DEVICE_NAME"
#define DEVICE_SECRET
"DEVICE_SECRET"
#define REGION_ID
"cn-shanghai"
/* Aliyun线上环境域名和端口号,不需要改 */
#define MQTT_SERVER
PRODUCT_KEY ".iot-as-mqtt." REGION_ID ".aliyuncs.com"
#define MQTT_PORT
1883
#define MQTT_USRNAME
DEVICE_NAME "&" PRODUCT_KEY
#define CLIENT_ID
"gmvzwtDHC6.ntance1|securemode=2,signmethod=hmacsha256,timestamp=254604000000|"
// MQTT连接报文参数,请参见MQTT-TCP连接通信文档,文档地址:https://help.aliyun.com/document_detail/73742.html
// 加密明文是参数和对应的值(clientIdesp8266deviceName${deviceName}productKey${productKey}timestamp1234567890)按字典顺序拼接
// 密钥是设备的DeviceSecret
//要使用加密工具,输入以上证书信息加密(时间戳可以省略)
#define MQTT_PASSWD
"a29f727768b161f9073e199ab6e37ee0e3e75f1320d0219a0a204b5bbb1420"
// 发送报文的json格式
#define ALINK_BODY_FORMAT
"{"id":"123","version":"1.0","method":"thing.event.property.post","params":%s}"
// 上报报文主题
#define ALINK_TOPIC_PROP_POST
"/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
unsigned long lastMs = 0;
WiFiClient espClient;
PubSubClient
client(espClient);
ESP8266WiFiMulti wifiMulti;
unsigned int pwm_r=0,pwm_g=0,pwm_b=0;
int openFlag = 0;
void setup()
{
Serial.begin(9600);
Serial.println("[info] Demo Start");
Serial.print("[info] CLIENT_ID:");Serial.println(CLIENT_ID);
Serial.print("[info] MQTT_USRNAME:");Serial.println(MQTT_USRNAME);
Serial.print("[info] MQTT_PASSWD:");Serial.println(MQTT_PASSWD);
// 连接WIFI
wifiInit();
// 初始化Mqtt服务
mqttServeInit();
// 初始化NTP时间服务
timeClient.begin();
}
void loop()
{
//millis()是系统启动到目前的总时间,以下为5s上传一次数据
if (millis() - lastMs >= 3000)
{
// 获取当前时间
lastMs = millis();
// 检查连接状态
mqttCheckConnect();
timeClient.update();
// 获取当前时间
currentTime = timeClient.getFormattedTime();
Serial.print("[info] now time is :");
Serial.println(currentTime);
// 上报消息
mqttIntervalPost();
// 根据下发的数据进行反馈
work();
}
client.loop();
}
void work() {
if(openFlag ==1){
Serial.println("[info] this is the truly answer!!!");
}
}
// 初始化Mqtt服务
void mqttServeInit() {
// 设置MQTT服务器和端口号

client.setServer(MQTT_SERVER, MQTT_PORT);
// 设置MQTT订阅回调函数
client.setCallback(callback);
}
// 收到信息后的回调函数
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("[info]Message arrived,the topic is [");
Serial.print(topic);
Serial.println("] ");
payload[length] = '';
const char* json = (char *)payload;
Serial.println("收到的json:");
Serial.println(json);
DynamicJsonDocument doc(1024);
deserializeJson(doc, json);
JsonObject root = doc.as<JsonObject>();
//云端下发的数据只有一个数据点,因此要判断是哪一个数据点下发了数据
if( root["params"].containsKey("openDoor") )
//containsKey方法为判断json对象是否包含指定字段
{
openFlag = root["params"]["openDoor"];
}
}
// 连接wifi
void wifiInit()
{
wifiMulti.addAP("LAPTOP-RIH1JO89 5592", "12345678"); // 将需要连接的一系列WiFi ID和密码输入这里
wifiMulti.addAP("MI 9", "12345678"); // ESP8266-NodeMCU再启动后会扫描当前网络
wifiMulti.addAP("LAPTOP9#337", "xy1229033519"); // 环境查找是否有这里列出的WiFi ID。如果有
Serial.println("[info] Connecting ...");
// 则尝试使用此处存储的密码进行连接。
int i = 0;
while (wifiMulti.run() != WL_CONNECTED) {
// 此处的wifiMulti.run()是重点。通过wifiMulti.run(),NodeMCU将会在当前
delay(1000);
// 环境中搜索addAP函数所存储的WiFi。如果搜到多个存储的WiFi那么NodeMCU
Serial.print(i++); Serial.print(' ');
// 将会连接信号最强的那一个WiFi信号。
}
// 一旦连接WiFI成功,wifiMulti.run()将会返回“WL_CONNECTED”。这也是
// 此处while循环判断是否跳出循环的条件。
// WiFi连接成功后将通过串口监视器输出连接成功信息 
Serial.print("[info] Connected to ");
Serial.println(WiFi.SSID());
// 通过串口监视器输出连接的WiFi名称
Serial.print("[info] IP address:t");
Serial.println(WiFi.localIP());
// 通过串口监视器输出ESP8266-NodeMCU的IP
}
// 检查设备与MQTT服务器连接情况
void mqttCheckConnect()
{
while (!client.connected())
{
Serial.println("Connecting to MQTT Server ...");
if (client.connect(CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD))
{
Serial.println("MQTT Connected!");
}
else
{
Serial.print("MQTT Connect err:");
Serial.println(client.state());
delay(5000);
}
}
if (client.connected()){
Serial.println("[info] keeping alive");
}
}
/* 上报消息 */
void mqttIntervalPost()
{
char param[128];
char jsonBuf[128];
// 将current转换为字符数组
const char * temp = currentTime.c_str();
//上传的数据在这里编辑,该例程将上报的数据为当前时间
sprintf(param, "{"openTime":"%s"}",temp);
sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
Serial.println("[info] 上传的json:");
Serial.println(jsonBuf);
// 上传数据
boolean d = client.publish( ALINK_TOPIC_PROP_POST, jsonBuf);
if(d==1){
Serial.println("[info] 发送成功");
}else{
Serial.println("[info] 发送失败");
}
}

运行之后,NodeMCU首先会连接Wifi,然后连接aliyunIot平台的服务的对应设备,连接成功了之后,将会把当前的时间的数据上报至云服务器;而在NodeMCU接收到Iot平台发送的开门指令之后,Serial也会做出对应的反应。

image-20211203211621176

图为上报数据

image-20211203211850214

图为成功接收下发数据

注意事项:当出现MQTT连不上时,错误返回值2表示客户端标识符不正确, -4表示用户名或者密码错误。 请做以下检查:

  • 先检查一下库文件PubSubClient.h文件中定义的 MQTT_MAX_PACKET_SIZE的值, 最好要大于1024, MQTT_KEEPALIVE 大于60;
  • 检查一下你的签名和接入参数的设置,可以参考文档 https://help.aliyun.com/document_detail/73742.html?spm=a2c4g.11186623.6.650.3820619bBWPshh 。
    官方文档:CONNECT指令中需包含Keep Alive(保活时间)。保活心跳时间取值范围为30至1200秒。如果心跳时间不在此区间内,物联网平台会拒绝连接。建议取值300秒以上。如果网络不稳定,将心跳时间设置高一些。

参考资料

nodemcu+阿里云(ArduinoIDE)

【NodeMCU_LUA系列】NodeMCU连接阿里云

(五)air800订阅云端数据并进行解析

string、char *、char[] 相互转换转换

最后

以上就是热情皮皮虾为你收集整理的NodeMCU-ESP8266连接阿里云Iot平台进行数据监测的全部内容,希望文章能够帮你解决NodeMCU-ESP8266连接阿里云Iot平台进行数据监测所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(129)

评论列表共有 0 条评论

立即
投稿
返回
顶部