需要用到的库:
- PubSubClient : 发送和接收MQTT消息
- ArduinoJson : Json字符串转换库
- AliyunMqttArduino: 阿里云相关
先做一件事!!!!!!
引入"PubSubClient.h"后
#include "PubSubClient.h"
打开"PubSubClient.h"
修改如下内容:
一. 阿里云MQTT协议
关于MQTT协议, 请参考文章:https://zhuanlan.zhihu.com/p/89057819
请参考我之前整理的文档:
【腾讯文档】MQTT连接阿里云示例(1)https://docs.qq.com/sheet/DWXBaUE9nWmZVaGJX
如果使用了AliyunMqttArduino, 就不需要关系协议的报文和加密方式了
二. 主要函数
首先创建一个mqtt客户端
WiFiClient espClient; //创建网络连接客户端
PubSubClient mqttClient(espClient); //通过网络客户端连接创建mqtt连接客户端
1. 连接阿里云 connectAliyunMQTT
connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET)
返回值: 连接结果
2. 判断是否连接了 mqttClient.connected()
mqttClient.connected()
3. mqtt客户端状态 mqttClient.state()
mqttClient.state()
返回: 状态码
状态码 | 含义 |
---|---|
0 | 连接成功 |
1 | 不正确的协议版本 |
2 | 无效的登录信息 |
3 | 连接不上服务器 |
4 | 用户名密码错误 |
5 | 未授权 |
6~255 | 备用 |
4. 发布主题消息
mqttClient.publish(主题, 内容)
mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf)
5. setCallback-- 设置收到命令下发时的回调
mqttClient.setCallback(callback); //绑定收到set主题时的回调(命令下发回调)
6. 客户端监听消息队列 mqttClient.loop();
三. 一个点灯的例子(创建产品和设备)
首先, 创建产品:
其次, 为产品添加设备
第三, 查看设备关键信息:
四. 一个点灯的例子(ESP32连接上述产品和设备)
#include <Arduino.h>
#include <ArduinoJson.h>
#include <aliyun_mqtt.h>
#include "PubSubClient.h"
#include "WiFi.h"
#include "Ticker.h"
#define WIFI_SSID "anny" //wifi名
#define WIFI_PASSWD "20141208" //wifi密码
#define PRODUCT_KEY "a17lGhkKwXs" //产品ID
#define DEVICE_NAME "esp32LightHome" //设备名
#define DEVICE_SECRET "14fb77db62910b887dd28c5e449f406e" //设备key
//设备下发命令的set主题
#define ALINK_TOPIC_PROP_SET "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/service/property/set"
//设备上传数据的post主题
#define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
//设备post上传数据要用到一个json字符串, 这个是拼接postJson用到的一个字符串
#define ALINK_METHOD_PROP_POST "thing.event.property.post"
//这是post上传数据使用的模板
#define ALINK_BODY_FORMAT "{\"id\":\"%u\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":%s}"
#define LED_B 2 //定义LED灯的引脚
int postMsgId = 0; //记录已经post了多少条
Ticker tim1; //这个定时器是为了每5秒上传一次数据
/*------------------------------------------------------------------------------------------*/
WiFiClient espClient; //创建网络连接客户端
PubSubClient mqttClient(espClient); //通过网络客户端连接创建mqtt连接客户端
//连接WIFI相关函数
void setupWifi()
{
delay(10);
Serial.println("连接WIFI");
WiFi.begin(WIFI_SSID, WIFI_PASSWD);
while (!WiFi.isConnected())
{
Serial.print(".");
delay(500);
}
Serial.println("OK");
Serial.println("Wifi连接成功");
}
//重连函数, 如果客户端断线,可以通过此函数重连
void clientReconnect()
{
while (!mqttClient.connected()) //再重连客户端
{
Serial.println("reconnect MQTT...");
if (connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET))
{
Serial.println("connected");
}
else
{
Serial.println("failed");
Serial.println(mqttClient.state());
Serial.println("try again in 5 sec");
delay(5000);
}
}
}
//mqtt发布post消息(上传数据)
void mqttPublish()
{
if (mqttClient.connected())
{
//先拼接出json字符串
char param[32];
char jsonBuf[128];
sprintf(param, "{\"LightSwitch\":%d}", digitalRead(LED_B)); //我们把要上传的数据写在param里
postMsgId += 1;
sprintf(jsonBuf, ALINK_BODY_FORMAT, postMsgId, ALINK_METHOD_PROP_POST, param);
//再从mqtt客户端中发布post消息
if (mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf))
{
Serial.print("Post message to cloud: ");
Serial.println(jsonBuf);
}
else
{
Serial.println("Publish message to cloud failed!");
}
}
}
//收到set主题的命令下发时的回调函数,(接收命令)
void callback(char *topic, byte *payload, unsigned int length)
{
if (strstr(topic, ALINK_TOPIC_PROP_SET))
//如果收到的主题里包含字符串ALINK_TOPIC_PROP_SET(也就是收到/sys/a17lGhkKwXs/esp32LightHome/thing/service/property/set主题)
{
Serial.println("收到下发的命令主题:");
Serial.println(topic);
Serial.println("下发的内容是:");
payload[length] = '\0'; //为payload添加一个结束附,防止Serial.println()读过了
Serial.println((char *)payload);
//接下来是收到的json字符串的解析
DynamicJsonDocument doc(100);
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.println("parse json failed");
return;
}
JsonObject setAlinkMsgObj = doc.as<JsonObject>();
serializeJsonPretty(setAlinkMsgObj, Serial);
Serial.println();
//这里是一个点灯小逻辑
int lightSwitch = setAlinkMsgObj["params"]["LightSwitch"];
digitalWrite(LED_B, lightSwitch);
mqttPublish(); //由于将来做应用可能要获取灯的状态,所以在这里发布一下
}
}
void setup()
{
pinMode(LED_B, OUTPUT);
Serial.begin(115200);
setupWifi();
if (connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET))
{
Serial.println("MQTT服务器连接成功!");
};
mqttClient.setCallback(callback); //绑定收到set主题时的回调(命令下发回调)
tim1.attach(5, mqttPublish); //启动每5秒发布一次消息
}
void loop()
{
//检测有没有断线
if (!WiFi.isConnected()) //先看WIFI是否还在连接
{
setupWifi();
}
else //如果WIFI连接了,
{
if (!mqttClient.connected()) //再看mqtt连接了没
{
Serial.println("mqtt disconnected!Try reconnect now...");
Serial.println(mqttClient.state());
clientReconnect();
}
}
//mqtt客户端监听
mqttClient.loop();
}
五. 温湿度数据 GPS数据上传及命令下发(创建产品和设备)
1. 创建产品
创建完后,我们发现系统已经自动创建了一些功能定义
2. 创建设备
3. 找到设备的关键信息
4. 如果想给产品增加功能可以...
找到产品的功能页面, 点击"编辑草稿"
最后发布新的物模型
六. 温湿度数据 GPS数据上传及命令下发(创建产品和设备)
非常简单的修改, 只修改了要发送json里的param
注意同步修改param和json的内存占用大小
#include <Arduino.h>
#include <ArduinoJson.h>
#include <aliyun_mqtt.h>
#include "PubSubClient.h"
#include "WiFi.h"
#include "Ticker.h"
#define WIFI_SSID "anny" //wifi名
#define WIFI_PASSWD "20141208" //wifi密码
#define PRODUCT_KEY "a1AYa96sZMJ" //产品ID
#define DEVICE_NAME "EspTempAndHumi_D001" //设备名
#define DEVICE_SECRET "a23249cb179feee41ca2f8f38525113d" //设备key
//设备下发命令的set主题
#define ALINK_TOPIC_PROP_SET "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/service/property/set"
//设备上传数据的post主题
#define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
//设备post上传数据要用到一个json字符串, 这个是拼接postJson用到的一个字符串
#define ALINK_METHOD_PROP_POST "thing.event.property.post"
//这是post上传数据使用的模板
#define ALINK_BODY_FORMAT "{\"id\":\"%u\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":%s}"
#define LED_B 2 //定义LED灯的引脚
int postMsgId = 0; //记录已经post了多少条
Ticker tim1; //这个定时器是为了每5秒上传一次数据
/*------------------------------------------------------------------------------------------*/
WiFiClient espClient; //创建网络连接客户端
PubSubClient mqttClient(espClient); //通过网络客户端连接创建mqtt连接客户端
//连接WIFI相关函数
void setupWifi()
{
delay(10);
Serial.println("连接WIFI");
WiFi.begin(WIFI_SSID, WIFI_PASSWD);
while (!WiFi.isConnected())
{
Serial.print(".");
delay(500);
}
Serial.println("OK");
Serial.println("Wifi连接成功");
}
//重连函数, 如果客户端断线,可以通过此函数重连
void clientReconnect()
{
while (!mqttClient.connected()) //再重连客户端
{
Serial.println("reconnect MQTT...");
if (connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET))
{
Serial.println("connected");
}
else
{
Serial.println("failed");
Serial.println(mqttClient.state());
Serial.println("try again in 5 sec");
delay(5000);
}
}
}
//mqtt发布post消息(上传数据)
void mqttPublish()
{
if (mqttClient.connected())
{
//先拼接出json字符串
char param[82];
char jsonBuf[178];
sprintf(param, "{\"CurrentHumidity\":%.1f,\"CurrentTemperature\":%.1f,\"ESPLight_Pin2\":%d}", 22.2, 35.5, digitalRead(LED_B)); //我们把要上传的数据写在param里
postMsgId += 1;
sprintf(jsonBuf, ALINK_BODY_FORMAT, postMsgId, ALINK_METHOD_PROP_POST, param);
//再从mqtt客户端中发布post消息
if (mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf))
{
Serial.print("Post message to cloud: ");
Serial.println(jsonBuf);
}
else
{
Serial.println("Publish message to cloud failed!");
}
}
}
//收到set主题的命令下发时的回调函数,(接收命令)
void callback(char *topic, byte *payload, unsigned int length)
{
if (strstr(topic, ALINK_TOPIC_PROP_SET))
//如果收到的主题里包含字符串ALINK_TOPIC_PROP_SET(也就是收到/sys/a17lGhkKwXs/esp32LightHome/thing/service/property/set主题)
{
Serial.println("收到下发的命令主题:");
Serial.println(topic);
Serial.println("下发的内容是:");
payload[length] = '\0'; //为payload添加一个结束附,防止Serial.println()读过了
Serial.println((char *)payload);
//接下来是收到的json字符串的解析
DynamicJsonDocument doc(100);
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.println("parse json failed");
return;
}
JsonObject setAlinkMsgObj = doc.as<JsonObject>();
serializeJsonPretty(setAlinkMsgObj, Serial);
Serial.println();
//这里是一个点灯小逻辑
int lightSwitch = setAlinkMsgObj["params"]["ESPLight_Pin2"];
digitalWrite(LED_B, lightSwitch);
mqttPublish(); //由于将来做应用可能要获取灯的状态,所以在这里发布一下
}
}
void setup()
{
pinMode(LED_B, OUTPUT);
Serial.begin(115200);
setupWifi();
if (connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET))
{
Serial.println("MQTT服务器连接成功!");
};
mqttClient.setCallback(callback); //绑定收到set主题时的回调(命令下发回调)
tim1.attach(5, mqttPublish); //启动每5秒发布一次消息
}
void loop()
{
//检测有没有断线
if (!WiFi.isConnected()) //先看WIFI是否还在连接
{
setupWifi();
}
else //如果WIFI连接了,
{
if (!mqttClient.connected()) //再看mqtt连接了没
{
Serial.println("mqtt disconnected!Try reconnect now...");
Serial.println(mqttClient.state());
clientReconnect();
}
}
//mqtt客户端监听
mqttClient.loop();
}
网友评论