125|0

174

帖子

0

资源

一粒金砂(高级)

【建筑施工监测与安防系统】十一、Kaluga MQTT连接OneNET [复制链接]

        参考ESP32 IDF的案例“mqtt/tcp”(..\esp-idf-v4.4\examples\protocols\mqtt\tcp)引入MQTT Client功能,使得Kaluga板可以连接OneNET(本人采用MQTT旧版,非加密)。

1、官方mqtt/tcp案例说明

        IDF中有关联网及协议应用的案例大多依靠另一个联网案例实现Wi-Fi接入,这个案例就是“..\esp-idf-v4.4\examples\common_components\protocol_examples_common”。所以在移植MQTT案例到自己的项目时,要注意自己做好Wi-Fi接入。

 

image-20220922154643-1.png

图11-1 mqtt/tcp案例的主要函数

 

2、mqtt移植到自己项目

        这里不介绍如何实现Wi-Fi接入了,不清楚的朋友可以去看本人的第七篇帖子。将mqtt/tcp的源码拷贝到自己的项目中,当然相关函数都要进行修改。首先是原案例需要导入的头文件:

 

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"

#include "esp_log.h"
#include "mqtt_client.h"

 

        然后就是回调函数,下面代码本人加了注释的两个地方,是在下觉得需要关注的点,一个是断联后原案例只是给个控制台输出,这里加上重连函数调用。另一个是接收到OneNET发送命令的处理分支,后续可以在这里加入命令解析和处理代码。

 

// 原案例封装的一个输出错误信息的函数,在事件回调中被调用
void log_error_if_nonzero(const char *message, int error_code) {
    if(error_code != 0) {
        ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
    }
}

void mqtt_event_handler(void *handler_args, 
    esp_event_base_t base, int32_t event_id, void *event_data) {
    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;
    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
        msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
        ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
        ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

        msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
        ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
        esp_mqtt_client_reconnect(client); //by author. reconnect
        break;

    case MQTT_EVENT_SUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
        msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
        ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
        break;
    case MQTT_EVENT_UNSUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_PUBLISHED:
        ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_DATA:
        ESP_LOGI(TAG, "MQTT_EVENT_DATA"); //by author. OneNET order
        printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
        printf("DATA=%.*s\r\n", event->data_len, event->data);
        break;
    case MQTT_EVENT_ERROR:
        ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
        if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
            log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
            log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
            log_error_if_nonzero("captured as transport's socket errno",  event->error_handle->esp_transport_sock_errno);
            ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
        }
        break;
    default:
        ESP_LOGI(TAG, "Other event id:%d", event->event_id);
        break;
    }
}

 

        然后是原案例的接入函数mqtt_app_start()这里做了修改——原例也没法直接用,缺少必要的配置(如:client_id,username等)。MQTT相关操作(连接、发布等)都需要一个“句柄”(esp_mqtt_client_handle_t类型),原案例是定义在函数中的局部量,因为事件回调可以得到这个句柄变量的传参所以无所谓。但是要单独编写发布数据包函数,就需要将句柄定义为全局量了。

 

esp_mqtt_client_handle_t client;
void aita_StartMqtt(void) {
    esp_mqtt_client_config_t mqtt_cfg = {
        .host = "183.230.40.39", // OneNET MQTT服务器IP
        .port = 6002,             // OneNET MQTT服务器端口
        .client_id = "deviceid",// 设备ID,请替换成自己的
        .username = "userid",    // 用户ID,请替换成自己的
        .password = "authorization", // 鉴权信息,请替换成自己的
    };

    client = esp_mqtt_client_init(&mqtt_cfg);
    /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(client);
}

 

         再编写一个发送函数,注意data也就是发布数据包的载荷(payload)需要按照OneNET平台的格式要求就行封装,不清楚的朋友可以查看本人的ESP32 C3测评帖子

 

void aita_PubMqtt(const char *data, int len) {
    esp_mqtt_client_publish(client, "$dp", data, len, 0, 0);
}

 

        最后,结合本人的上篇帖子,在定时器回调中调用aita_PubMqtt(),暂时还是功能测试,就将定时器的启用时间发送到OneNET平台上。

 

static void periodic_timer_callback(void* arg) {
    int64_t time_since_boot = esp_timer_get_time();
    char dat[80];
    sprintf(dat, "{\"tick\":%d}", (int)time_since_boot);
    char buf[83];
    int len = strlen(dat);
    buf[0] = 0x03;
    buf[1] = len>>8;
    buf[2] = len&0xff;
    memcpy(buf+3, dat, len);
    buf[3+len] = 0;
    aita_PubMqtt(buf, 3+len);
    // ESP_LOGI(TAG, "periodic timer called, time since boot: %lld us", 
    //                 time_since_boot);
    // aita_InitSNTP();
}

 

image-20220922154643-2.png

图11-2 OneNET收到数据的展示

 

 


回复
您需要登录后才可以回帖 登录 | 注册

相关帖子
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
    关闭
    站长推荐上一条 1/10 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表