WiFi ESP8266 MQTT 通信

本教程参考自 FlexLua 官网的ShineBlink学习板栏目。

一、前言

MQTT是一种基于TCP的物联网通信协议,在物联网领域应用非常广泛,基本上所有的云平台都支持设备以MQTT协议接入,所以如果您的设备支持MQTT连接,就可以很容易的对接各云平台(比如ONE NET、阿里云、腾讯云等)。CORE提供的MQTT库函数也十分简单,您只需根据各云平台的规则,在调用MQTT库函数时对传入的参数做相应的调整即可对接各家云平台。

使用Core提供的基于ESP8266 WIFI模块的库函数能够很容易的将Core对接入云平台,涉及的库函数只有如下三个:

LIB_MQTTConfig() --初始化
LIB_MqttRecvSub() --接收
LIB_MqttSendPub() --发送

二、本例程实现功能介绍

CORE向云端(mqtt broker)上传温湿度数据,同时也接受云端下发的命令数据来控制CORE电路板上LED2灯的亮灭。

本例程接入的 OneNet mqtt 云平台,OneNet 的接入方法请参考其官网教程。

三、硬件接线图、材料清单

esp8266连手机热点断断续续 esp8266热点上网_esp8266连手机热点断断续续

  • ESP8266 wifi模块
  • SHT30/31温湿度传感器模块

esp8266连手机热点断断续续 esp8266热点上网_服务器_02

esp8266连手机热点断断续续 esp8266热点上网_esp8266连手机热点断断续续_03

四、完整代码&代码解析

(1)完整代码

代码功能:CORE每隔9秒向云端上传温湿度数据,同时也接受云端下发的数据来控制CORE电路板上LED2灯的亮灭。

--路由器连接参数
ap_ssid = "MyRouterName" --路由器账号
ap_passwd = "MyRouterPswd123" --路由器密码
--MQTT服务器地址(适用于ONE NET平台)
server_addr = "183.230.40.96" --OneNet服务器ip地址,也可以写成"mqtts.heclouds.com"(推荐)
server_port = 1883
--MQTT 连接参数(适用于ONE NET平台)
mqtt_con_clientID = "TestDevice001"
mqtt_con_username = "353255"
mqtt_con_password = "2F5RJwGwytPWvVDB04K7rnw63Dr3D"
--MQTT topic相关参数(适用于ONE NET平台)
mqtt_sub_topic = "$sys/353255/TestDevice001/cmd/request/+"--订阅用
mqtt_pub_topic = "$sys/353255/TestDevice001/dp/post/json" --发布用
--配置D9为普通输出,控制LED2
LIB_GpioOutputConfig("D9","STANDARD")
--使能系统10毫秒定时器开始工作
LIB_10msTimerConfig("ENABLE")
--初始化esp8266 Wifi模块,配置心跳包间隔时间为180秒,该值最好三倍于MQTT的KeepAlive时间
LIB_WifiTcpConfig("UART0","D5",ap_ssid,ap_passwd,server_addr,server_port,180) --180
--配置MQTT底层为WIFI传输(esp8266),并按照如下参数进行MQTT连接,KeepAlive时间=60秒
LIB_MQTTConfig("WIFI",mqtt_con_clientID,mqtt_con_username,mqtt_con_password,"60",mqtt_sub_topic,"QOS0")
--设置sht3x传感器占用SCL0和SDA0引脚,以每秒出10个数据的频率工作,"HIGH"表示最高精度
LIB_Sht3xConfig("IIC0","10","HIGH")
--变量初始化
cnt_10ms = 0
pub_id = 0
temprature = 0.00
humidity = 0.00
--定义10ms中断回调函数
function LIB_10msTimerCallback()
 cnt_10ms = cnt_10ms + 1
end
--开始大循环
while(GC(1) == true)
do
 sht3x_flag,temp,humi = LIB_Sht3xGetResult()
 --如果传感器有新的温湿度数据产生
 if sht3x_flag == 1 then
 temprature = temp
 humidity = humi
 end
 --查询是否收到服务器下发的cmd数据(已订阅的"$sys/353255/TestDevice001/cmd/request/+")
 recv_flag,topic,data = LIB_MqttRecvSub()
 if recv_flag == 1 then
 --根据json路径"$.LED"解析服务器下发的json文本,并执行LED亮灭操作
 Json_Val = LIB_JsonParse(data, "$.LED")
 --服务器下发的是"{"LED":0}"
 if Json_Val == "0" then
 LIB_GpioWrite("D9",1) --LED2灭
 --服务器下发的是"{"LED":1}"
 elseif Json_Val == "1" then
 LIB_GpioWrite("D9",0) --LED2亮
 --服务器下发的是"{"LED":2}"
 elseif Json_Val == "2" then
 LIB_GpioToggle("D9") --LED2亮灭切换
 else 
 LIB_GpioWrite("D9",1) --LED2灭
 end
 --根据收到的topic中的cmdid应答服务器,
 --将收到的topic中"request"替换成"response"后作为应答topic发给服务器
 topic = string.gsub(topic,"request","response") 
 --应答内容可自定义,这里为"Got it!"
 LIB_MqttSendPub("QOS0", topic, "Got it!")
 --延时2秒是为了保证本次publish不被之后的publish覆盖,所以该延时太少可能导致LIB_MqttSendPub失败
 LIB_DelayMs(2000)
 end
 --每9秒发送温湿度度数据给server
 if cnt_10ms >= 900 then
 cnt_10ms = 0
 pub_id = pub_id + 1
 json_str = string.format("{\"id\":%d, \"dp\":{\"temperatrue\":[{\"v\": %.2f,}], \"humidity\":[{\"v\":%.2f,}]}}", pub_id, temprature, humidity)
 --注意json_str的总长度不要超过250字节
 LIB_MqttSendPub("QOS0", mqtt_pub_topic, json_str) --publish
 end
end


如果感兴趣,上面代码中出现的LIB开头的库函数可以在 API文档 中通过Ctrl+F查询。

(2)代码关键部分解析

PART 1 (路由器参数)

--路由器连接参数

ap_ssid = "MyRouterName" --路由器账号
ap_passwd = "MyRouterPswd123" --路由器密码

apssid和appasswd请使用你自己的路由器账号密码。

PART 2(云平台地址)

--MQTT服务器地址(适用于ONE NET平台)

server_addr = "183.230.40.96" --OneNet服务器ip地址,也可以写成"mqtts.heclouds.com"(推荐)
server_port = 1883

serveraddr和serverport是中国移动物联网(ONE NET)MQTT服务的固定IP地址和端口号,请不要改动它。

PART 3(MQTT连接参数)

--MQTT 连接参数(适用于ONE NET平台)

mqtt_con_clientID = "TestDevice001"
mqtt_con_username = "353255"
mqtt_con_password = "version=2018-10-31&res=products%2F353255%2Fdevices%2FTestDevice001&et=1893427200&method=md5&sign=%2F5RJwGwytPWvVDB04K7rnw%3D%3D"

mqttconclientID、mqttconusername、mqttconpassword 这三个参数是设备和服务端建立mqtt连接时所必须的三个参数,如果你曾接入过多个物联网云平台,你会发现它们的异同往往都在这三个参数上。这里我们介绍ONE NET云平台下关于这三个参数的定义规则:

1, mqttconclientID: 设备和服务端建立mqtt连接时,clientID用来标识设备的唯一性,我这里我们使用的是设备名称“TestDevice001”,设备名称应具有唯一性,比如可以用您定义的SN序列号等,这里是我在创建该设备时起的名字"TestDevice001"。

2, mqttconusername:设备和服务端建立mqtt连接时,username用来认证连接的用户名,该值为产品ID

3, mqttconpassword:设备和服务端建立mqtt连接时,password用来认证连接的密码。

PART 4(MQTT订阅、发布、接收)

订阅和发布路径:

--MQTT topic相关参数(适用于ONE NET平台)
mqtt_sub_topic = "$sys/353255/TestDevice001/cmd/request/+"--订阅用
mqtt_pub_topic = "$sys/353255/TestDevice001/dp/post/json" --发布用

mqttsubtopic是用来给设备订阅服务器的命令消息(比如控制LED等)
mqttpubtopic是用来给设备向服务器发布消息(比如温湿度)

回复云平台下发的命令:

--根据收到的topic中的cmdid应答服务器,
--将收到的topic中"request"替换成"response"后作为应答topic发给服务器

topic = string.gsub(topic,"request","response")
 --应答内容可自定义,这里为"Got it!"
 LIB_MqttSendPub("QOS0", topic, "Got it!")

ONE NET平台中的关于设备如何应答平台下发的cmd命令的格式已做了定义

下面举个例子来说明:
如果服务器下发cmd的topic为:$sys/353255/TestDevice001/cmd/request/33ffea0a-e5f1-49d6-a626-ffee1bbd93ef
那么我们应答的topic应该为:$sys/353255/TestDevice001/cmd/response/33ffea0a-e5f1-49d6-a626-ffee1bbd93ef

云平台会自动为每条下发的cmd分配一个cmd id, 例子中的33ffea0a-e5f1-49d6-a626-ffee1bbd93ef即为cmdid。

向云平台发布本地温湿度数

--每9秒发送温湿度度数据给server
 if cnt_10ms >= 900 then
 cnt_10ms = 0
 pub_id = pub_id + 1
 json_str = string.format("{\"id\":%d, \"dp\":{\"temperatrue\":[{\"v\": %.2f,}], \"humidity\":[{\"v\":%.2f,}]}}", pub_id, temprature, humidity)


--注意json_str的总长度不要超过250字节

LIB_MqttSendPub("QOS0", mqtt_pub_topic, json_str) --publish


end

  • 每9秒向云平台pulish一次本地的温湿度数据,数据内容必须是json格式,
  • 例如:
  • {\"id\":1, \"dp\":{\"temperatrue\":[{\"v\": 32.50,}], \"humidity\":[{\"v\":56.00,}]}}
  • pub_id为pulish消息的标识符,每次发送时需递增加1

接收云平台下发的指令

--查询是否收到服务器下发的cmd数据(已订阅的"$sys/353255/TestDevice001/cmd/request/+")
recv_flag,topic,data = LIB_MqttRecvSub()
if recv_flag == 1 then
--根据json路径"$.LED"解析服务器下发的json文本,并执行LED亮灭操作

Json_Val = LIB_JsonParse(data, "$.LED")
 --服务器下发的是"{"LED":0}"
 if Json_Val == "0" then
 LIB_GpioWrite("D9",1) --LED2灭
 --服务器下发的是"{"LED":1}"
 elseif Json_Val == "1" then
 LIB_GpioWrite("D9",0) --LED2亮
 --服务器下发的是"{"LED":2}"
 elseif Json_Val == "2" then
 LIB_GpioToggle("D9") --LED2亮灭切换
 else 
 LIB_GpioWrite("D9",1) --LED2灭
 end


--根据收到的topic中的cmdid应答服务器,
--将收到的topic中"request"替换成"response"后作为应答topic发给服务器
topic = string.gsub(topic,"request","response")
--应答内容可自定义,这里为"Got it!"
LIB_MqttSendPub("QOS0", topic, "Got it!")
--延时2秒是为了保证本次publish不被之后的publish覆盖,所以该延时太少可能导致LIB_MqttSendPub失败
LIB_DelayMs(2000)
end

从云平台下发cmd指令控制CORE上的LED2灯的亮灭:

Ⅰ 鼠标点击进入在对应的设备的“更多操作”中的“下发命令” -->

Ⅱ 然后在弹出的界面中的命令内容中输入“{"LED":2}”,超时时间5秒,返回结果中选择String格式

Ⅲ 最后点击发送,待设备成功收到命令并返回正确的应答后(应答消息中包含“Got it”),我们就可以看到Core电路板上的LED2灯珠由亮变灭或者由灭变亮了。

esp8266连手机热点断断续续 esp8266热点上网_低代码_04