先注册Tlink云平台账号(网址),注册成功后找到开发者中心,查看Tlink云平台的MQTT协议说明。添加一个设备,把模块的电压,信号强度和灯状态上传云平台,Tlink提供的APP和微信控制灯开关,连接协议选MQTT。
Air302模块与Tlink云平台通信使用Json格式通信。
在Tlink云的开发者中心查看MQTT通信格式要求,写程序会用到,如下:
连接域名和端口号:每一种协议的连接服务器地址和端口号都不一样,请登录平台>设备管理>进入设置连接界面查看。
客户端ID:发布和订阅是在同一个设备进行时,客户端ID只需要一个,可以直接使用设备序列号当做客户端ID,如果存在多个设备进行订阅,需要在平台获取新的客户端ID。
用户名密码:用户名(User Name):同平台的登录帐号一样。 密码(Password):同平台的登录密码一样(注:修改登录密码会导致设备无法连接,企业版可单独设置用户名密码)。
发布主题:发布主题:设备序列号,指设备发布上行数据到平台的主题。
订阅主题:订阅主题:设备序列号/+,指设备接收下行数据时订阅的主题。这里利用了通配符的概念,订阅该主题可以接收该设备所有传感器的下行数据(传感器下行数据所使用的主题为序列号/传感器ID)。
JSON格式的消息内容............
main.lua如下,程序的思路见下方参考链接。程序连接MQTT平台收发数据还稳定,在时间长不发数据,云平台下发数据会有四五秒的延迟。之后在研究一下。
PROJECT = "tlink_demo"
VERSION = "1.0.0"
-- 引入必要的库文件(lua编写), 内部库不需要require
local sys = require "sys"
local mqtt = require "mqtt"
log.info("version", _VERSION, VERSION)
-- GPIO 和 PWM 相关 -------------------------------
-- 网络灯 GPIO19/PWM5
NETLED = gpio.setup(19, 0, gpio.PULLUP) -- 初始化GPIO19, 并设置为低电平
gpio.set(19, 0) -- 设置为高电平
----发送数据table---------------
local vPowerSwitch = 0
--数据发送的消息队列,缓冲作用
local msgQueue = {}
function insertMsg( )
rssi_value = nbiot.rssi()
--rgb_led = gpio.get(19)
adc.open(1) -- VBAT电压
vbt = adc.read(1)
local re = {
sensorDatas = {
{
sensorsId = 200456308,
flag = 'dianya',
value = vbt
},
{
sensorsId = '200456309',
flag = 'xinhao',
value = rssi_value
},
{
sensorsId = 200456387,
flag = 'deng',
switcher = vPowerSwitch
}
}
}
payload = json.encode(re)
table.insert(msgQueue,{topic='O5UUTBP9146XN0L5',payload=payload,qos=1})
end
--循环120s执行插入数据
sys.timerLoopStart(insertMsg, 120000)
--灯闪烁线程-------------------------------
--[[sys.taskInit(function()
while 1 do
-- 一闪一闪亮晶晶
NETLED(0)
sys.wait(1000)
NETLED(1)
sys.wait(1500)
--log.info("gpio", "18", G18())
end
end)
]]
--接受发送函数----------------------------
--- MQTT客户端数据接收处理
-- @param mqttClient,MQTT客户端对象
-- @return 处理成功返回true,处理出错返回false
-- @usage mqttInMsg.proc(mqttClient)
function mqttInMsg_proc(mqttClient)
local result,data
while true do
result,data = mqttClient:receive(5000)
--接收到数据
if result then
--TODO:根据需求自行处理data.payload
log.info("mqttInMsg_proc",string.toHex(data.payload))
log.info("mqttc", "mqttc:receive!!!!", result or nil ,data or nil)
local tjsondata,res,errinfo = json.decode(data.payload)
if res then
vPowerSwitch = tjsondata['sensorDatas'][1]['switcher']
gpio.set(19, vPowerSwitch)
--接受数据成功后返回灯的状态,因为要更新web页面灯开关的状态
insertMsg()
mqttOutMsg_proc(mqttClient)
log.info("vPowerSwitch!!!!!", vPowerSwitch)
else log.info("json decode faile",errinfo)
end
--uart.write(1,"\r\n topic = "..data.topic .. " paload = " ..data.payload) --通过串口1发送出去
--如果mqttOutMsg中有等待发送的数据,则立即退出本循环
if waitForSend() then return true end
else
break
end
end
return result or data=="timeout"
end
--- MQTT客户端是否有数据等待发送
-- @return 有数据等待发送返回true,否则返回false
-- @usage mqttOutMsg.waitForSend()
function waitForSend()
return #msgQueue > 0
end
--- MQTT客户端数据发送处理
-- @param mqttClient,MQTT客户端对象
-- @return 处理成功返回true,处理出错返回false
-- @usage mqttOutMsg.proc(mqttClient)
function mqttOutMsg_proc(mqttClient)
while #msgQueue>0 do
local outMsg = table.remove(msgQueue,1)
local result = mqttClient:publish(outMsg.topic,outMsg.payload,outMsg.qos)
log.info("mqttOutMsg_proc", outMsg.topic,outMsg.payload,outMsg.qos)
--if outMsg.user and outMsg.user.cb then outMsg.user.cb(result,outMsg.user.para) end
if not result then return end
end
log.info("mqttOutMsg_proc", 'msgQueue length zero')
return true
end
--连接mqtt线程----------------------------
local host, port, selfid = 'mq.tlink.io', 1883, 'O5UUTBP9146XN0L5'
local mqttClientId = selfid
local mqttUsername = 'xxxxxxxxxxx' --换成自己的Tlink登录名
local mqttPassword = 'xxxxxxxxxxx' --Tlink登录密码
sys.taskInit(
function()
local retryConnectCnt = 0
while true do
if not socket.isReady() then
retryConnectCnt = 0
--等待网络环境准备就绪,超时时间是30s
log.info("net", "wait for network ready")
sys.waitUntil("NET_READY",30000)
end
--是否获取到分配的IP(是否连上网)
if socket.isReady() then
log.info("net", "network ready")
--创建一个MQTT客户端
local mqttClient = mqtt.client(mqttClientId, 60, mqttUsername, mqttPassword)
--阻塞执行MQTT CONNECT动作,直至成功
--如果使用ssl连接,打开mqttClient:connect("lbsmqtt.airm2m.com",1884,"tcp_ssl",{caCert="ca.crt"}),根据自己的需求配置
--mqttClient:connect("lbsmqtt.airm2m.com",1884,"tcp_ssl",{caCert="ca.crt"})
if mqttClient:connect(host, port,"tcp") then
--连接成功
log.info("mqttClient","Connet ok!")
retryConnectCnt = 0 --失败次数清零
--ready = true
--订阅主题
if mqttClient:subscribe({["O5UUTBP9146XN0L5".."/+"]=0}) then --xxx代表的是序列号
log.info("mqttClient","subscribe ok!")
--订阅成功,发布第一次消息,先把消息写入table在调用发布函数
insertMsg()
mqttOutMsg_proc(mqttClient)
--mqttOutMsg.insertMsg("xxx","Iccid = " .. sim.getIccid(),0)--这个没啥用
--循环处理接收和发送的数据
while true do
if not mqttInMsg_proc(mqttClient) then
log.error("mqttTask.mqttInMsg.proc error")
break
end
if not mqttOutMsg_proc(mqttClient) then
log.error("mqttTask.mqttOutMsg proc error")
break
end
end
end
--ready = false
else
log.info("mqttTask.mqttClient","Connet fail!")
retryConnectCnt = retryConnectCnt+1 --失败次数加一
end
--断开MQTT连接
mqttClient:disconnect()
if retryConnectCnt>=5 then retryConnectCnt=0 end
sys.wait(5000)
else
--进入飞行模式,5秒之后,退出飞行模式
nbiot.setCFUN(0)
sys.wait(5000)
log.info("net", "I am in fly mode")
nbiot.setCFUN(1)
end
end
end
)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
一个小细节,就是在Tlink云的控制台控制灯的开关,需要设备把接受到的值在返回给服务器,改变开关图标,这样服务器才能确定下发数据是否成功,如图。可在程序中,当模块接收到数据后紧接着发布数据就可以了。
参考:【2G模组Air202开发】Lua脚本编程实现MQTT协议连接Tlink平台
合宙Luat / LuatOS@Air302 V0003 正式版