概述
若大家还想了解如何通过HTTP 协议接入OneNET,请参考:
强力讲解如何将ESP8266 接入中移OneNET 平台
强力讲解如何用ESP8266 通过HTTP 协议与OneNET 信息交互
※ 本文相关文件(大家不用留言获取了,可以直接去下载):
《WiFi模块、连接OneNET等资料.zip》
目录
- 步入正题
- 一、CONNECT 请求
- 二、Subscribe 请求
- 三、Publish 请求
- 四、发送更新数据
- 五、心跳请求
在此我使用的是官方的ESP8266 的MQTT SDK 进行接入测试。
首先大家需要把MQTT SDK 移植到自己的板子上,这里面还是有很多坑的,建议大家下载两个不同版本的SDK 进行比对,因为你往往能在另一个版本的SDK 中找到你所需要的东西。
其实一开始接入平台之前的移植也就只是改一下串口什么的而已,并没有太多需要改动的地方,真正需要调试的时候是在进行接入、上传、订阅发布…时。
如果你运气好的话,说不定根本不需要太多调试,反正我的运气不怎么好 ????
接下来的内容都是基于大家对MQTT 协议的格式、特性等有一定了解的前提上。
步入正题
一、CONNECT 请求
这是一个CONNECT 请求函数:
void Connect_MQTT(void)
{
/* mqtt连接 */
MqttSample_Connect(ctx, PROD_ID, SN, ctx->devid, keep_alive, clean_session);
bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
MqttBuffer_Reset(ctx->mqttbuf);
Delay_ms(1000);
err = Mqtt_RecvPkt(ctx->mqttctx);
UART4_Clear();
}
由于MQTT 每种请求都有特定的格式,所以不管是Connect、Publish、Subscribe等都需要先给报文进行格式化。
MqttSample_Connect
的作用就是对ctx
进行Connect 报文格式化(ctx
是一个通用的结构体,其中包含报文字节数、报文缓存区、host、port、deviceID 等必要信息)。
有了Connect 报文后,就可以通过Mqtt_SendPkt
将报文发送出去了。
这是通过Connect 请求成功连接OneNET 的串口信息(数据经过处理):
product id: 123456
sn: 001
deviceid: 233386196
keepalive: 120
cleansession: 0
QoS: 0
before send
send one pkt
10 22
00 04 23 51 54 88 04 C0 00 78
00 09 A5 32 34 33 D2 36 31 39 22 00 06 32 12 34 32 31 33 00 44 30 30 88
AT+CIPSEND=36
OK
> SendCmd 443 cmd:AT+CIPSEND=36
,rsp:AT+CIPSEND=36
OK
>
send
Recv 36 bytes
SEND OK
+IPD,4: Rcv:
20 02 00 00
<Mqtt_RecvPkt>: rcv 4 data from OneNET
Success to connect to the server, flags(0), code(0).
我们可以看到,发送Connect 实际上只是发送这样一段数据:
send one pkt
10 22
00 04 23 51 54 88 04 C0 00 78
00 09 A5 32 34 33 D2 36 31 39 22 00 06 32 12 34 32 31 33 00 44 30 30 88
这是十六进制的,我们需要知道其中到底发送了什么数据,除了用WireShark 抓包分析之外,我们也可以直接把数据转化为字符:16进制到文本字符串的转换
我的包转换之后就是这样:
可以看到,我们发送的数据包里面就包含了协议类型,设备ID,产品ID等信息。
并且
大家可以按照所发送的十六进制数据对照着MQTT Connect 数据包查看该数据包对于可变报头各个参数的详细设置:
MQTT协议(二)>>> 【CONNECT】连接服务器
我们还可以注意到,我们发送了Connect 后返回了4字节数据20 02 00 00
,这就是CONNACK-确认连接请求
MQTT协议(三)>>> 【CONNACK】确认连接请求
二、Subscribe 请求
void Subscribe_MQTT(void)
{
MqttSample_Subscribe(ctx, topics, 1); //可一次订阅多个,本例只用只订阅一个topic
bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
MqttBuffer_Reset(ctx->mqttbuf);
Delay_ms(1000);
}
MqttSample_Subscribe
是一个Subscribe 报文格式化函数,该函数中,我们需要指定订阅话题的名称topics。
然后通过Mqtt_SendPkt
发送报文。
before send
send one pkt
80 09
00 02 00 04 68 75 6D 69 00
AT+CIPSEND=11
OK
> SendCmd 443 cmd:AT+CIPSEND=11
,rsp:AT+CIPSEND=11
OK
>
send
Recv 11 bytes
SEND OK
+IPD,5:?
看看到底发出去什么数据:
可以看到,我订阅的话题名称是“humi”
然后通过OneNET 模拟助手模拟另一台设备发布“humi” 信息,ESP8266就可以收到。
三、Publish 请求
void Publish_MQTT(void)
{
MqttSample_Publish(ctx, temp, humi);
bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
MqttBuffer_Reset(ctx->mqttbuf);
}
MqttSample_Publish
是一个Publish 报文格式化函数,该函数中,我们需要指定发布内容的数据,其中发布的topic 在函数内部定义。
然后通过Mqtt_SendPkt
发送数据。
<MqttSample_Publish>: public temp : key pressed, temp: 66, humi: 0
before send
send one pkt
32 26
00 04 74 65 6D 70 00 01
6B 65 79 20 70 72 65 73 73 65 64 2C 20 74 65 6D 70 3A 20 36 36 2C 20 68 75 6D 69 3A 20 30
AT+CIPSEND=40
OK
> SendCmd 443 cmd:AT+CIPSEND=40
,rsp:AT+CIPSEND=40
OK
>
send
Recv 40 bytes
SEND OK
+IPD,4:@
数据转换后:
四、发送更新数据
void Send_Data(void)
{
/* 上传数据 */
MqttSample_Savedata(ctx, temp, humi);
bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
MqttBuffer_Reset(ctx->mqttbuf);
}
MqttSample_Savedata
是一个json 格式化函数,该函数是一个壳子函数(即内部还有一个核心函数,除了核心函数外没有其他有关代码),核心函数为MqttSample_Savedata11
。MqttSample_Savedata11
函数中有一段组织json 语句格式的代码。
char json[]="{"datastreams":[{"id":"temp","datapoints":[{"value":%d}]},{"id":"humi","datapoints":[{"value":%d}]}]}";
即更新的数据流名称和数量都在此设置。
所以在MqttSample_Savedata
中我们需要指定发布内容的数据。
然后通过Mqtt_SendPkt
发送数据。
Qos: 1 Type: 1
Topic: $dp
Pakect ID: 1
QoS: 1
Payload: {"datastreams":[{"id":"temp","datapoints":[{"value":66}]},{"id":"humi","datapoints":[{"value":0}]}]}
before send
send one pkt
32 6E
00 03 24 64 70 00 01
01 00 64 7B 22 64 61 74 61 73 74 72 65 61 6D 73 22 3A 5B 7B 22 69 64 22 3A 22 74 65 6D 70 22 2C 22 64 61 74 61 70 6F 69 6E 74 73 22 3A 5B 7B 22 76 61 6C 75 65 22 3A 36 36 7D 5D 7D 2C 7B 22 69 64 22 3A 22 68 75 6D 69 22 2C 22 64 61 74 61 70 6F 69 6E 74 73 22 3A 5B 7B 22 76 61 6C 75 65 22 3A 30 7D 5D 7D 5D 7D
AT+CIPSEND=112
OK
> SendCmd 443 cmd:AT+CIPSEND=112
,rsp:AT+CIPSEND=112
OK
>
sen
Recv 112 bytes
SEND OK
+IPD,4:@
OneNET 中规定:设备使用 publish 报文来上传数据点,其中TopicName 为"$dp"($dp 是系统上传数据点的指令,该报文Payload 部分中为json 格式数据。
我们可以看到,其实更新数据流也相当于发布一个Topic 信息。
将发送的信息转化后:
五、心跳请求
void Pingreq_MQTT(void)
{
MqttSample_CmdPing(ctx);
bytes = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
MqttBuffer_Reset(ctx->mqttbuf);
}
MqttSample_CmdPing
是心跳包格式化函数,由于心跳请求只是一个"C000" 的双字节十六进制数据,故不需要带入其他参数。
然后通过Mqtt_SendPkt
发送数据。
before send
send one pkt
C0 00
AT+CIPSEND=2
OK
> SendCmd 443 cmd:AT+CIPSEND=2
,rsp:AT+CIPSEND=2
OK
>
send
Recv 2 bytes
SEND OK
+IPD,2:?
最后
以上就是丰富人生为你收集整理的强力讲解如何用ESP8266 通过MQTT 协议接入中移OneNET 云平台步入正题的全部内容,希望文章能够帮你解决强力讲解如何用ESP8266 通过MQTT 协议接入中移OneNET 云平台步入正题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复