野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 10857|回复: 2

【转】基于麒麟座开发板2.0的MQTT实现例程

[复制链接]
发表于 2017-7-7 09:26:58 | 显示全部楼层 |阅读模式
OneNET现已全面适配标准MQTT协议,相信这一功能的增加回大大便于开发者进行设备的接入。
OneNET提供了MQTT 的 C语言版本的SDK供大家使用,接下来我们将利用该SDK,将MQTT协议移植到麒麟座开发板上,希望这边文章能对希望使用MQTT接入OneNET的开发者提供一定帮助。

(本例中使用的SDK、调试工具、以及说明文档,均可以在线文档中的MQTT专区下载到)


1 下载SDK
首先进入我们的MQTT说明专区,找到C语言SDK下载链接,下载SDK。


mqtt文件夹.jpg (0 Bytes, 下载次数: 717)
下载附件
2016-12-9 13:16 上传





其中:
mqtt/config.h   mqtt/mqtt.h  mqtt/mqtt_buffer.h  src/mqtt.c   src/mqtt_buffer.c  为MQTT相关的.c 以及.h文件
sample/c/sample.c  是使用示例文件

2 代码的移植
将上述.c 以及 .h 文件复制到 开发板的工程中 Protocol/mqtt目录下,在工程中添加mqtt.c以及mqtt_buffer.c文件(记得修改Include Path 路径)
由于SDK是在linux环境下编译以及测试的,移植到STM32环境下带来了平台的差异性。
主要记得修改如下地方:
1、修改MQTT相关的.h文件的include路径,使之与工程环境相匹配
2、屏蔽掉原来的assert函数,和inline关键字
3、修改分配的缓冲区的大小
    主要是  MqttSample_Init()函数中的Mqtt_InitContext() 函数,SDK中分配了 1<<20大小的字节,由于STM32资源有限,这里需要改小一点,本例中为1000字节
4、修改接口的初始化、收、发函数。
    原SDK是在linux系统中利用网口来实现通信,而开发板中使用串口连接通信模块的形式实现通信,相关的函数都需要作相应的修改,详见代码文件


3 代码示例
源代码如下:


OneNET_Demo_v0_8266_mqtt.rar (5.35 MB, 下载次数: 4536)  
2016-12-22 09:25 上传
点击文件名下载附件





本例中的代码流程如下图:


QQ截图20161209155653.jpg (0 Bytes, 下载次数: 713)
下载附件
2016-12-9 16:37 上传






开发板资源分配如下:


QQ截图20161209170524.jpg (0 Bytes, 下载次数: 705)
下载附件
2016-12-9 17:06 上传






代码中需要修改的参数位置:
main.c   
line 40:

  • #define PROD_ID     "70901"             //修改为自己的产品ID
  • #define SN          "201608160002"      //修改为自己的设备唯一序列号
  • #define REG_CODE    "6TM7OkhNsTjATvFx"  //修改为自己的产品注册码

复制代码


line 789


  • char *topics[] = {"test_topic", "test_topic2"};   //订阅的topic

复制代码

esp8266.h  
line1 :


  • #define SSID        "PHICOMM_2590BC"              //修改为自己的WIFI热点名
  • #define PASSWD      "1234567890"              //修改为自己的WIFI密码

复制代码


4 SDK 使用示例
MQTT
连接

  • struct MqttSampleContext ctx[1];
  • MqttSample_Connect(ctx, PROD_ID, SN, ctx->devid, keep_alive, clean_session);
  • bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
  • MqttBuffer_Reset(ctx->mqttbuf);

复制代码


MQTT
订阅

  • struct MqttSampleContext ctx[1];
  • MqttSample_Subscribe(ctx, topics, 1);   //可一次订阅多个,本例只用只订阅一个topic
  • bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
  • MqttBuffer_Reset(ctx->mqttbuf);

复制代码

MQTT
发布消息

  • struct MqttSampleContext ctx[1];
  • MqttSample_Publish(ctx, temp, humi);
  • bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
  • MqttBuffer_Reset(ctx->mqttbuf);

复制代码


MQTT
回复命令

  • struct MqttSampleContext ctx[1];
  • MqttSample_RespCmd(ctx, "cmd received");
  • bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
  • MqttBuffer_Reset(ctx->mqttbuf);

复制代码



MQTT
上传数据


  • struct MqttSampleContext ctx[1];
  • MqttSample_Savedata(ctx, temp, humi);
  • bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
  • MqttBuffer_Reset(ctx->mqttbuf);


复制代码

接收数据解析


  • err = Mqtt_RecvPkt(ctx->mqttctx);
  • USART2_Clear();

复制代码

5 代码接入测试


使用MQTT simulate device 来模拟同产品目录下的另外一个设备


两个设备.jpg (0 Bytes, 下载次数: 785)
下载附件
2016-12-9 18:05 上传






打开设备电源,在调试串口目录下可以看到调试信息


WIFI初始化.jpg (0 Bytes, 下载次数: 708)
下载附件
2016-12-9 18:04 上传






设备注册.jpg (0 Bytes, 下载次数: 1139)
下载附件
2016-12-9 18:05 上传






设备连接.jpg (0 Bytes, 下载次数: 707)
下载附件
2016-12-9 18:05 上传






订阅.jpg (0 Bytes, 下载次数: 788)
下载附件
2016-12-9 18:05 上传






上传数据.jpg (0 Bytes, 下载次数: 785)
下载附件
2016-12-9 18:05 上传






使用模拟设备与平台建立连接


模拟设备连接.jpg (0 Bytes, 下载次数: 714)
下载附件
2016-12-9 18:13 上传






可以看到产品topic列表中已经有开发板所创建的 test_topic订阅自动创建



5.1 topic发布以及接收测试
在订阅框中输入key_press ,点击订阅(该topic为开发板按键发布消息的topic)


订阅key_press.jpg (0 Bytes, 下载次数: 711)
下载附件
2016-12-9 18:26 上传






按下开发板上的key2,见调试信息:


按键2触发消息发布.jpg (0 Bytes, 下载次数: 712)
下载附件
2016-12-9 18:27 上传






触发消息之后,在模拟器侧,就可以收到该topic的消息了


模拟软件收到topic消息.jpg (0 Bytes, 下载次数: 789)
下载附件
2016-12-9 18:27 上传







使用模拟软件,向test_topic发送一则消息


模拟软件发送topic.jpg (0 Bytes, 下载次数: 785)
下载附件
2016-12-9 18:31 上传






在开发板侧,可以从调试信息中看到,已经收到了该topic消息


开发板收到topic消息.jpg (0 Bytes, 下载次数: 885)
下载附件
2016-12-9 18:31 上传








至此,topic的订阅与发布测试已完成。




5.2  命令下发与应答测试
在线发送命令给开发板


发送命令.jpg (0 Bytes, 下载次数: 706)
下载附件
2016-12-9 18:35 上传






在调试信息中可以看到以及接收了该命令并成功解析


接收命令.jpg (0 Bytes, 下载次数: 962)
下载附件
2016-12-9 18:35 上传






此时LED7已经被点亮


点灯.jpg (0 Bytes, 下载次数: 787)
下载附件
2016-12-9 18:38 上传






根据调试信息可以看出,该命令的uuid为   8c14d921-8d10-5ef3-ac40-ea0befa250c7
使用API可以获取该命令的执行状态


sent.jpg (0 Bytes, 下载次数: 789)
下载附件
2016-12-9 18:40 上传






当前状态为 已发送  

按下开发板上的key3 ,进行命令回复,回复内容为 “cmd receive


命令应答.jpg (0 Bytes, 下载次数: 787)
下载附件
2016-12-9 18:45 上传






再次进行API调用,查看命令状态:


命令应答检测.jpg (0 Bytes, 下载次数: 789)
下载附件
2016-12-9 18:46 上传






可见状态变为,应答已接收

通过API获取命令回复内容:


获取响应.jpg (0 Bytes, 下载次数: 2225)
下载附件
2016-12-9 18:47 上传






可以看出,命令的应答内容,已经可以通过API成功获取到。

至此,平台命令的下发以及命令响应功能已全部完成。
(完)

回复

使用道具 举报

发表于 2017-7-7 11:24:01 | 显示全部楼层
帮顶              
回复 支持 反对

使用道具 举报

发表于 2017-12-13 16:26:50 | 显示全部楼层
楼主:
    我按照你的方法移植,有一个函数报了警告assignment in condition,我检查了一下,判断句里出现了赋值操作,不知道这句代码怎么理解
struct DataPointPktInfo *Mqtt_GetDataPointPktInfo(struct MqttBuffer *buf)
{
    struct MqttExtent *fix_head = buf->first_ext;
    struct MqttExtent *first_payload;
    struct DataPointPktInfo *info;

    if(!fix_head) {
        return NULL;
    }

    if(MQTT_PKT_PUBLISH != (((uint8_t)(fix_head->payload[0])) >> 4)){
        return NULL;
    }

    if(!(fix_head->next) || !(first_payload = fix_head->next->next) ||
       (MQTT_DPTYPE_TRIPLE != first_payload->payload[0]))
{
        return NULL;
    }

    if(first_payload->len != 2 + sizeof(struct DataPointPktInfo)) {
        return NULL;
    }

    info = (struct DataPointPktInfo*)(first_payload->payload + 2);
    if(DATA_POINT_PKT_TAG != info->tag) {
        return NULL;
    }

    return info;
}
回复 支持 反对

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-22 04:40 , Processed in 0.028917 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表