• 学习太极创客 — MQTT 第二章(七)ESP8266 MQTT 遗嘱应用


    视频链接:http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-tuttorial/mqtt-tutorial/esp8266-last-will/
    资料链接:http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-tuttorial/mqtt-tutorial/esp8266-last-will/

    示例1:MQTT 遗嘱基本应用

    本示例程序将实现 ESP8266 的最基本 MQTT 遗嘱应用。程序使用 connect 函数对遗嘱消息实现设置。

    /**********************************************************************
    项目名称/Project          : 零基础入门学用物联网
    程序名称/Program name     : last_will_no_retain
    团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
    作者/Author              : CYNO朔
    日期/Date(YYYYMMDD)     : 20201223
    程序目的/Purpose          : 
    本程序旨在演示如何设置客户端遗嘱机制。客户端在连接服务器时,设置遗嘱的主题和信息。
     
    MQTT服务器会定时检查客户端是否仍然与服务器连接。为了实现这一检查,服务器将会根据以下
    内容进行检查.
    1. 客户端连接时会提供心跳时间间隔(Keep Alive)。
    2. 如果在心跳时间间隔时长内,客户端向服务器发布了消息,则
       服务器会认为客户端与服务器保持连接无误。
    3. 如果在心跳时间间隔时长内,客户端没有向服务端发布消息,
       客户端会向服务端发送pingreq信息。此信息由PubSubClient库自动发送。
    4. 我们可以通过setKeepAlive函数控制心跳时间间隔时长,或者可以通过PubSubClient.h
       的#define MQTT_KEEPALIVE 15来设置心跳时间间隔时长。
    4. 在心跳时间间隔的1.5倍时长内,如果服务端没有收到客户端信息也没有pingreq。
       那么服务端将会执行客户端遗嘱机制。
     
    默认情况下,设备的心跳时间间隔时长为15秒。这是在PubSubClient.h中通过以下语句定义的:
    #define MQTT_KEEPALIVE 15
     
    若要修改keep-alive时间,可修改以上头文件,或者使用setKeepAlive函数实现。
     
    对于PubSubClient,遗嘱QoS允许使用0,1。
    -----------------------------------------------------------------------
    本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
    该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
    http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-client/http-request/
    ***********************************************************************/
    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
     
    // 设置wifi接入信息(请根据您的WiFi信息进行修改)
    const char* ssid = "FAST_153C80";
    const char* password = "123456798";
    const char* mqttServer = "test.ranye-iot.net";
    // 如以上MQTT服务器无法正常连接,请前往以下页面寻找解决方案
    // http://www.taichi-maker.com/public-mqtt-broker/
     
    WiFiClient wifiClient;
    PubSubClient mqttClient(wifiClient);
     
    // 遗嘱设置
    const char* willMsg = "CLIENT-OFFLINE"; // 遗嘱消息内容
    const int willQoS = 0;                   // 遗嘱QoS
    const bool willRetain = false;           // 遗嘱保留
     
    void setup() {
      Serial.begin(9600);               // 启动串口通讯
      
      //设置ESP8266工作模式为无线终端模式
      WiFi.mode(WIFI_STA);
      
      // 连接WiFi
      connectWifi();
      
      // 设置MQTT服务器和端口号
      mqttClient.setServer(mqttServer, 1883);
      mqttClient.setKeepAlive(10); // 设置心跳间隔时间
      
      // 连接MQTT服务器
      connectMQTTserver();
    }
     
    void loop() {
      // 如果开发板未能成功连接服务器,则尝试连接服务器
      if (!mqttClient.connected()) {
        connectMQTTserver();
      }
     
       // 处理信息以及心跳
       mqttClient.loop();
    }
     
    // 连接MQTT服务器并订阅信息
    void connectMQTTserver(){
      
      // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
      String clientId = "esp8266-" + WiFi.macAddress();
     
      // 建立遗嘱主题。主题名称以Taichi-Maker-为前缀,后面添加设备的MAC地址,最后
      // 以“-Will”结尾,这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
      String willString = "Taichi-Maker-" + WiFi.macAddress() + "-Will";
      char willTopic[willString.length() + 1];  
      strcpy(willTopic, willString.c_str());
     
      // 连接MQTT服务器,在连接过程中提供以下参数:
      // 客户端ID,遗嘱主题,遗嘱QoS,遗嘱保留,遗嘱信息
      if (mqttClient.connect(clientId.c_str(), willTopic, willQoS, willRetain, willMsg)){ 
        Serial.println("MQTT Server Connected.");
        Serial.print("Server Address: ");Serial.println(mqttServer);
        Serial.print("ClientId: ");Serial.println(clientId);
        Serial.print("Will Topic: ");Serial.println(willTopic);    
      } else {
        Serial.print("MQTT Server Connect Failed. Client State:");
        Serial.println(mqttClient.state());
        delay(5000);
      }   
    }
     
    // ESP8266连接wifi
    void connectWifi(){
     
      WiFi.begin(ssid, password);
     
      //等待WiFi连接,成功连接后输出成功信息
      while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.print(".");
      }
      Serial.println("");
      Serial.println("WiFi Connected!");  
      Serial.println(""); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    下面,来看下程序代码中的重要内容。

    1、首先是遗嘱设置,

    // 遗嘱设置
    const char* willMsg = "CLIENT-OFFLINE";  // 遗嘱消息内容
    const int willQoS = 0;                   // 遗嘱QoS
    const bool willRetain = false;           // 遗嘱信息保留标志
    
    • 1
    • 2
    • 3
    • 4

    2、设置心跳间隔时间,单位为 秒

    mqttClient.setKeepAlive(10); // 设置心跳间隔时间
    
    • 1

    3、连接MQTT服务器 connectMQTTserver();看下该函数的具体内容。

    // 连接MQTT服务器并订阅信息
    void connectMQTTserver(){
      
      // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
      String clientId = "esp8266-" + WiFi.macAddress();
     
      // 建立遗嘱主题。主题名称以Taichi-Maker-为前缀,后面添加设备的MAC地址,最后
      // 以“-Will”结尾,这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
      String willString = "Taichi-Maker-" + WiFi.macAddress() + "-Will";
      char willTopic[willString.length() + 1];  
      strcpy(willTopic, willString.c_str());
     
      // 连接MQTT服务器,在连接过程中提供以下参数:
      // 客户端ID,遗嘱主题,遗嘱QoS,遗嘱保留,遗嘱信息
      if (mqttClient.connect(clientId.c_str(), willTopic, willQoS, willRetain, willMsg)){ 
        Serial.println("MQTT Server Connected.");
        Serial.print("Server Address: ");Serial.println(mqttServer);
        Serial.print("ClientId: ");Serial.println(clientId);
        Serial.print("Will Topic: ");Serial.println(willTopic);    
      } else {
        Serial.print("MQTT Server Connect Failed. Client State:");
        Serial.println(mqttClient.state());
        delay(5000);
      }   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    下面再来看下程序的运行结果,打开串口监视器。

    在这里插入图片描述

    接下来,打开 MQTT.fx 这个软件来订阅下该主题。

    在这里插入图片描述

    接下来,断开 ESP8266 开发板的电源,造成意外断开 MQTT 服务器连接的现象。

    过了大概有几秒中的时间后, 接收到遗嘱信息。

    在这里插入图片描述

    示例2:利用 MQTT 遗嘱实现设备在线状态发布

    本示例将实现 2-6 MQTT 遗嘱这节课中的 “MQTT遗嘱使用建议” 示例。通过以下程序,ESP8266客户端可以利用遗嘱机制来实时的将当前在线与否状态通过服务端进行发布。也就是说,其它客户端只要订阅ESP8266客户端的遗嘱主题就可以马上了解该客户端是否在线。

    /**********************************************************************
    项目名称/Project          : 零基础入门学用物联网
    程序名称/Program name     : last_will_retain
    团队/Team                : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
    作者/Author              : CYNO朔
    日期/Date(YYYYMMDD)     : 20201223
    程序目的/Purpose          : 
    本程序旨在演示如何设置客户端遗嘱机制。客户端在连接服务器时,设置遗嘱的主题和信息。
    本客户端所发布的遗嘱消息为保留消息。其它客户端可通过订阅本客户端的遗嘱主题获取本
    客户端是否在线的状态信息。
    -----------------------------------------------------------------------
    本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。
    该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页:
    http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/iot-c/esp8266-nodemcu-web-client/http-request/
    ***********************************************************************/
    #include <ESP8266WiFi.h>
    #include <PubSubClient.h>
     
    // 设置wifi接入信息(请根据您的WiFi信息进行修改)
    const char* ssid = "FAST_153C80";
    const char* password = "123456798";
    const char* mqttServer = "test.ranye-iot.net";
    // 如以上MQTT服务器无法正常连接,请前往以下页面寻找解决方案
    // http://www.taichi-maker.com/public-mqtt-broker/
     
    WiFiClient wifiClient;
    PubSubClient mqttClient(wifiClient);
     
    // 遗嘱设置
    const char* willMsg = "CLIENT-OFFLINE"; // 遗嘱消息内容
    const int willQoS = 0;                   // 遗嘱QoS
    const bool willRetain = true;           // 遗嘱保留
     
    void setup() {
      Serial.begin(9600);               // 启动串口通讯
      
      //设置ESP8266工作模式为无线终端模式
      WiFi.mode(WIFI_STA);
      
      // 连接WiFi
      connectWifi();
      
      // 设置MQTT服务器和端口号
      mqttClient.setServer(mqttServer, 1883);
      mqttClient.setKeepAlive(10); // 设置心跳间隔时间
      
      // 连接MQTT服务器
      connectMQTTserver();
    }
     
    void loop() {
      // 如果开发板未能成功连接服务器,则尝试连接服务器
      if (!mqttClient.connected()) {
        connectMQTTserver();
      }
     
       // 处理信息以及心跳
       mqttClient.loop();
    }
     
    // 连接MQTT服务器并订阅信息
    void connectMQTTserver(){
      
      // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
      String clientId = "esp8266-" + WiFi.macAddress();
     
      // 建立遗嘱主题。主题名称以Taichi-Maker-为前缀,后面添加设备的MAC地址,最后
      // 以“-Will”结尾,这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
      String willString = "Taichi-Maker-" + WiFi.macAddress() + "-Will";
      char willTopic[willString.length() + 1];  
      strcpy(willTopic, willString.c_str());
     
      // 连接MQTT服务器,在连接过程中提供以下参数:
      // 客户端ID,遗嘱主题,遗嘱QoS,遗嘱保留,遗嘱信息
      if (mqttClient.connect(clientId.c_str(), willTopic, willQoS, willRetain, willMsg)){ 
        Serial.println("MQTT Server Connected.");
        Serial.print("Server Address: ");Serial.println(mqttServer);
        Serial.print("ClientId: ");Serial.println(clientId);
        Serial.print("Will Topic: ");Serial.println(willTopic);    
        publishOnlineStatus();     //发布在线状态
      } else {
        Serial.print("MQTT Server Connect Failed. Client State:");
        Serial.println(mqttClient.state());
        delay(5000);
      }   
    }
     
    // 发布信息
    void publishOnlineStatus(){
      // 建立遗嘱主题。主题名称以Taichi-Maker-为前缀,后面添加设备的MAC地址,最后
      // 以“-Will”结尾,这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
      String willString = "Taichi-Maker-" + WiFi.macAddress() + "-Will";
      char willTopic[willString.length() + 1];  
      strcpy(willTopic, willString.c_str());
     
      // 建立设备在线的消息。此信息将以保留形式向遗嘱主题发布
      String onlineMessageString = "CLIENT-ONLINE"; 
      char onlineMsg[onlineMessageString.length() + 1];   
      strcpy(onlineMsg, onlineMessageString.c_str());
      
      // 向遗嘱主题发布设备在线消息
      if(mqttClient.publish(willTopic, onlineMsg, true)){
        Serial.print("Published Online Message: ");Serial.println(onlineMsg);    
      } else {
        Serial.println("Online Message Publish Failed."); 
      }
    }
     
    // ESP8266连接wifi
    void connectWifi(){
     
      WiFi.begin(ssid, password);
     
      //等待WiFi连接,成功连接后输出成功信息
      while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.print(".");
      }
      Serial.println("");
      Serial.println("WiFi Connected!");  
      Serial.println(""); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    首先,来看下程序的运行效果,通过串口监视器输出结果如下,

    在这里插入图片描述

    之后,打开 MQTT.fx 软件,

    刚一订阅该主题,就接收到信息。

    在这里插入图片描述

    下面,尝试让客户端意外断线(ESP8266 开发板断电),过个几秒钟之后,收到断线的消息。

    在这里插入图片描述

    接着,再将开发板通上电,当开发板重新连接到 MQTT 服务器后,订阅该主题的客户端就立刻收到了消息。

    在这里插入图片描述

    从而,我们就可以通过订阅遗嘱主题达到实时监控发布(客户)端在线状态情况。

    我们下面再来看看程序,看看其究竟是如何实现的?

    1、遗嘱设置 —— 保留标志位设置为 true

    // 遗嘱设置
    const char* willMsg = "CLIENT-OFFLINE"; // 遗嘱消息内容
    const int willQoS = 0;                  // 遗嘱QoS
    const bool willRetain = true;           // 遗嘱保留
    
    • 1
    • 2
    • 3
    • 4

    2、设置心跳间隔时间,没有必要发送过于频繁,过于频繁会耗费网络资源,这里为了演示能够尽快的出来效果,所以设置的时间比较小。

     mqttClient.setKeepAlive(10);
    
    • 1

    3、连接 MQTT 服务器的函数 connectMQTTserver

    // 连接MQTT服务器并订阅信息
    void connectMQTTserver(){
      
      // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
      String clientId = "esp8266-" + WiFi.macAddress();
     
      // 建立遗嘱主题。主题名称以Taichi-Maker-为前缀,后面添加设备的MAC地址,最后
      // 以“-Will”结尾,这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
      String willString = "Taichi-Maker-" + WiFi.macAddress() + "-Will";
      char willTopic[willString.length() + 1];  
      strcpy(willTopic, willString.c_str());
     
      // 连接MQTT服务器,在连接过程中提供以下参数:
      // 客户端ID,遗嘱主题,遗嘱QoS,遗嘱保留,遗嘱信息
      if (mqttClient.connect(clientId.c_str(), willTopic, willQoS, willRetain, willMsg)){ 
        Serial.println("MQTT Server Connected.");
        Serial.print("Server Address: ");Serial.println(mqttServer);
        Serial.print("ClientId: ");Serial.println(clientId);
        Serial.print("Will Topic: ");Serial.println(willTopic);    
        publishOnlineStatus();     //发布在线状态
      } else {
        Serial.print("MQTT Server Connect Failed. Client State:");
        Serial.println(mqttClient.state());
        delay(5000);
      }   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    当 ESP8266 开发板连接 MQTT 服务器成功之后,就会通过串口打印输出 “客户端ID,遗嘱主题,遗嘱QoS,遗嘱保留,遗嘱信息” 等一系列信息,然后通过 publishOnlineStatus() 函数发布在线状态。

    publishOnlineStatus函数的内容如下,

    // 发布信息
    void publishOnlineStatus(){
      // 建立遗嘱主题。主题名称以Taichi-Maker-为前缀,后面添加设备的MAC地址,最后
      // 以“-Will”结尾,这是为确保不同ESP8266客户端的遗嘱主题名称各不相同。
      String willString = "Taichi-Maker-" + WiFi.macAddress() + "-Will";
      char willTopic[willString.length() + 1];  
      strcpy(willTopic, willString.c_str());
     
      // 建立设备在线的消息。此信息将以保留形式向遗嘱主题发布
      String onlineMessageString = "CLIENT-ONLINE"; 
      char onlineMsg[onlineMessageString.length() + 1];   
      strcpy(onlineMsg, onlineMessageString.c_str());
      
      // 向遗嘱主题发布设备在线消息
      if(mqttClient.publish(willTopic, onlineMsg, true)){
        Serial.print("Published Online Message: ");Serial.println(onlineMsg);    
      } else {
        Serial.println("Online Message Publish Failed."); 
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    重点是将遗嘱信息以保留的形式发布,只有这样,客户端(ESP8266 开发板)一连接到 MQTT 服务器就能将设备在线消息给发送出去。

    注意:遗嘱消息和 MQTT 消息都被设置为了保留消息。遗嘱消息和 MQTT 消息的主题是同一个

    遗嘱消息被设置为保留消息的目的是,当 ESP8266 开发板(客户端)不在线时,当有客户端订阅该遗嘱主题时,可以立刻接收到遗嘱信息,并且当 ESP8266 开发板(客户端)意外离线时,也会向订阅该主题的客户端发送不在线的信息。

    MQTT 消息被设置为保留消息的目的是,当有客户端刚订阅该主题时就能够立即收到 MQTT 消息。

  • 相关阅读:
    Java——线程&进程
    JavaSE之IO流加强
    简单的金属探测器电路
    Fabric.js 控制元素层级
    基于jsp+mysql+ssm大学本科考研服务系统-计算机毕业设计
    【计算机网络】网络编程 Socket
    CSS:filter(滤镜)属性
    【UniApp】-uni-app概述
    如何进行一篇论文的阅读
    C专家编程 第4章 令人震惊的事实:数组和指针并不相同 4.3 什么是声明,什么是定义
  • 原文地址:https://blog.csdn.net/xuechanba/article/details/125494110