ESP8266学习进阶协议类(3)——MQTT接入

实现物联网远程获取家里的数据难吗?本文告诉你不难!!!

简述MQTT

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。(摘自互联网)

对MQTT协议不是很了解的可以参考菜鸟教程,网上也有很多大佬讲得很好,可以去了解一下,这里就默认大家对MQTT有一定的了解哈;

在8266中实现

在8266-RTOS-SDK中有提供两种使用MQTT的API接口,有应该是乐鑫自己封装好的一套,也有IBM paho的MQTT接口,初学者使用乐鑫提供的可能更好上手,所以本文基于乐鑫的来讲解和使用,paho提供的后续再补发一章。

首先需要在 make menuconfig 下修改MQTT的配置:

点击 component config

在这里插入图片描述

选中 MQTT

在这里插入图片描述

选择需要使用的组件接口,这里选 ESP-MQTT

在这里插入图片描述

在这里插入图片描述

然后保存退出即可,如果该配置没有配置好,编译代码的时候会报错,会提示某些头文件找不到。


使用

头文件

#include "mqtt_client.h"   //ESP-MQTT

也是挑几个用到的函数来讲吧,想了解更多的自行去查阅源码;


MQTT客户端配置结构,重要的有进行注释,不太需要过于关注的就没有中文注释

typedef struct {
    mqtt_event_callback_t event_handle;     /*!< 针对MQTT事件的回调函数 */
    const char *host;                       /*!< MQTT服务端的IP地址 */
    const char *uri;                        /*!< 完成MQTT代理URI */
    uint32_t port;                          /*!< MQTT服务端端口 */
    const char *client_id;                  /*!< MQTT客户端的ID,可以不写,有默认的 */
    const char *username;                   /*!< MQTT账号(接入平台的话就不是简单的账号名了) */
    const char *password;                   /*!< MQTT密码(接入平台的话就不是简单的密码了) */
    const char *lwt_topic;                  /*!< LWT 临终遗嘱啥的 message topic (NULL by default) */
    const char *lwt_msg;                    /*!< LWT message (NULL by default) */
    int lwt_qos;                            /*!< LWT message qos */
    int lwt_retain;                         /*!< LWT retained message flag */
    int lwt_msg_len;                        /*!< LWT message length */
    int disable_clean_session;              /*!< mqtt clean session, default clean_session is true */
    int keepalive;                          /*!< mqtt keepalive, default is 120 seconds */
    bool disable_auto_reconnect;            /*!< this mqtt client will reconnect to server (when errors/disconnect). Set disable_auto_reconnect=true to disable */
    void *user_context;                     /*!< pass user context to this option, then can receive that context in ``event->user_context`` */
    int task_prio;                          /*!< MQTT task priority, default is 5, can be changed in ``make menuconfig`` */
    int task_stack;                         /*!< MQTT task stack size, default is 6144 bytes, can be changed in ``make menuconfig`` */
    int buffer_size;                        /*!< size of MQTT send/receive buffer, default is 1024 */
    const char *cert_pem;                   /*!< Pointer to certificate data in PEM format for server verify (with SSL), default is NULL, not required to verify the server */
    const char *client_cert_pem;            /*!< Pointer to certificate data in PEM format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided. */
    const char *client_key_pem;             /*!< Pointer to private key data in PEM format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided. */
    esp_mqtt_transport_t transport;         /*!< overrides URI transport */
} esp_mqtt_client_config_t;

MQTT客户端的所有配置信息都在该结构体中进行初始化配置;


MQTT初始化函数

esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config)
参数解析
configMQTT客户端配置结构

返回值:为初始化好的MQTT客户端的句柄,可以通过这个句柄获取MQTT客户端的所有动作


MQTT客户端启动函数

esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client)
参数解析
clientMQTT客户端句柄

配置好所有基本信息并初始化后调用该函数即可完成启动;


MQTT客户端发布消息

int esp_mqtt_client_publish(esp_mqtt_client_handle_t client, const char *topic, const char *data, int len, int qos, int retain)
参数解析
clientMQTT客户端句柄
topic要发布的topic
data要发布的内容
len内容长度,不确定长度可以填0,函数内部会自动调用strlen进行测量
qosMQTT QOS等级
retain这个我也不清楚是啥,不好乱猜,填0就好

返回:返回的是消息的ID


订阅消息

int esp_mqtt_client_subscribe(esp_mqtt_client_handle_t client, const char *topic, int qos)
参数解析
clientMQTT客户端句柄
topic要订阅的topic
qosMQTT QOS等级

返回:订阅成功的消息ID


取消订阅

esp_err_t esp_mqtt_client_unsubscribe(esp_mqtt_client_handle_t client, const char *topic);
参数解析
clientMQTT客户端句柄
topic要订阅的topic

销毁MQTT客户端

esp_err_t esp_mqtt_client_destroy(esp_mqtt_client_handle_t client);

参数:传入MQTT客户端句柄即可释放资源;


具体代码实现

测试历程实现:

  • 实现连接MQTT代理器
  • 按键发布消息
  • 实时监控连接状态,通过OLED显示

MQTT的初始化配置及开启

static void mqtt_app_start(void)
{
    mqtt_event_group = xEventGroupCreate();

    esp_mqtt_client_config_t mqtt_cfg = {
        .host = "192.168.1.20",			//MQTT服务器的IP
        .port = 1883,				   //端口
        .username = "esp8266",			//接入名
        .password = "123456",            //密码
        .event_handle = mqtt_event_handler,
    };
    
    client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_start(client);
}

esp_mqtt_client_config_t mqtt_cfg 按需配置即可,不用所有的都要自己写

使用按键发送数据

这里用的是轻触按键,每触碰一次就会通过 topic:/esp8266/post 往MQTT服务器发布一条 “hello” 信息

static void key_init(void)
{
    gpio_config_t io_conf;

    io_conf.intr_type = GPIO_INTR_DISABLE;  //失能中断
    io_conf.mode = GPIO_MODE_INPUT;         //输入模式
    io_conf.pin_bit_mask = SEND_KEY_PIN_SEL;//指定GPIO14作为按键引脚
    io_conf.pull_down_en = 1;               //下拉
    io_conf.pull_up_en = 0;

    gpio_config(&io_conf); 
}

static void send_hello(void *arg)
{
    key_init();     //按键初始化

    while(1)
    {
        if(gpio_get_level(SEND_KEY_PIN) && MQTT_ONLINE == 1){
            esp_mqtt_client_publish(client, "/esp8266/post", "hello", 0, 1, 0);
        }
        vTaskDelay(50 / portTICK_RATE_MS);  //给个短延时,避免看门狗超时复位
    }
}

MQTT事件回调函数

//MQTT事件回调函数
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)  
{
    esp_mqtt_client_handle_t client = event->client;

    memset(MQTT_STATUS_BUFF, 0 ,sizeof(MQTT_STATUS_BUFF));

    switch (event->event_id) {				//监听MQTT事件
        case MQTT_EVENT_CONNECTED:		//成功连接事件
            ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
            MQTT_ONLINE = 1;
            esp_mqtt_client_subscribe(client, "/esp8266/set", 0); //默认订阅  
            strcpy(MQTT_STATUS_BUFF, "MQTT CONNECTED");

            break;
        case MQTT_EVENT_DISCONNECTED:		//失去连接
            ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
            MQTT_ONLINE = 0;
            strcpy(MQTT_STATUS_BUFF, "MQTT DISCONNECTED");
            break;
        case MQTT_EVENT_SUBSCRIBED:			//成功订阅
            strcpy(MQTT_STATUS_BUFF, "MQTT SUBSCRIBED");
            break;
        case MQTT_EVENT_UNSUBSCRIBED:		//取消订阅
            strcpy(MQTT_STATUS_BUFF, "MQTT UNSUBSCRIBED");
            break;
        case MQTT_EVENT_PUBLISHED:			//成功发布
            strcpy(MQTT_STATUS_BUFF, "MQTT PUBLISHED");
            break;
        case MQTT_EVENT_DATA:				//接收到数据
            ESP_LOGI(TAG, "MQTT_EVENT_DATA");
            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
            printf("DATA=%.*s\r\n", event->data_len, event->data);
            strcpy(MQTT_STATUS_BUFF, "MQTT RECEIVE");
            break;
        case MQTT_EVENT_ERROR:				//错误事件
            ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
            strcpy(MQTT_STATUS_BUFF, "MQTT ERROR");
            break;
    }
    xEventGroupSetBits(mqtt_event_group, MQTT_STATUS_BIT);
    return ESP_OK;
}

实物展示:

配合测试的还有MQTT小工具MQTT.fx,两者同时连上我树莓派里的MQTT代理器

在这里插入图片描述

ESP8266,OLED显示的是 MQTT ONLINE,这里使用的是轻触按键,具体电路接线看源码

在这里插入图片描述

触发开关后,向MQTT代理器推送消息,MQTT.fx会订阅8266发布的topic

在这里插入图片描述

MQTT.fx接收:

在这里插入图片描述
做到这一步,想想如果我们的MQTT代理器是在云端,然后8266采集的数据是室内传感器采集的数据的话,我们是不是实现了远程监控的功能,前面的铺垫就都有了用武之地了!

以上只是部分代码的解析,具体完整代码见我的GitHub,如有帮助请点个赞,谢谢~


我的GITHUB

我的个人博客

CSDN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大棋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值