单片机
返回首页

玩转 ESP32 + Arduino (十六) 通过mqtt协议连接阿里云

2025-04-07 来源:jianshu

需要用到的库:

  • PubSubClient : 发送和接收MQTT消息

  • ArduinoJson : Json字符串转换库

  • AliyunMqttArduino: 阿里云相关

先做一件事!!!!!!

引入'PubSubClient.h'后

#include 'PubSubClient.h'

打开'PubSubClient.h'

修改如下内容: color{#FF3030}{否则绝对连不上阿里IOT}

一. 阿里云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 #include #include #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] = ''; //为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();

    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 #include #include #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] = ''; //为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();

    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();}


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 锂离子/锂聚合物USB电池充电器

  • 6晶体管H桥

  • AVR LCD温度计—LM35

  • AVR PC步进电机驱动器

  • AVR温度计TCN75

  • JDM2 PIC 18F 编程器

    相关电子头条文章