一、MQTT 介绍
MQTT 是一种低开销、低带宽占用的即时通讯协议,可以用极少的代码和带宽为远程设备提供实时可靠的消息服务。它适用于硬件性能低下的设备以及网络状况不佳的环境,因此在物联网(IoT)小型设备和移动应用等方面有广泛应用。
MQTT 采用发布/订阅通信模型,客户端可以发布消息到主题(Topic),也可以订阅主题来接收消息。这种模式解耦了消息的发送者和接收者。
MQTT 的消息传递质量分为三种:最多一次(QoS 0)不保证交付,至少一次(QoS 1)确保至少到达但可能重复,只有一次(QoS 2)确保仅到达一次。
二、演示功能概述
本 demo 通过使用 Air724UG 开发板,带你快速体验通过 MQTT 协议进行数据接收与发送。
三、准备硬件环境
3.1 Air724UG 开发板
准备一块 Air724UG-NFM 开发板,如下图所示:
点击链接购买:Air724UG-NFM 开发板淘宝购买链接 ;
此开发板的详细使用说明参考:Air724UG 产品手册 中的《EVB_Air724UG_AXX 开发板使用说明》,写这篇文章时最新版本的使用说明为:《EVB_Air724UG_A14 开发板使用说明》;开发板使用过程中遇到任何问题,可以直接参考这份使用说明文档。
3.2 SIM 卡
请准备一张可以正常上网的 SIM 卡,该卡可以是物联网卡或者您的个人手机卡。
特别提醒:请确保 SIM 卡未欠费且网络功能正常,以便顺利进行后续操作。
3.3 PC 电脑
请准备一台配备 USB 接口且能够正常上网的 windows7 以及以上系统的电脑。
3.4 数据通信线
请准备一根用于连接 EVB_Air724UG_A14 开发板和 PC 电脑的数据线,该数据线将实现业务逻辑的控制与交互。
- USB 数据线:此数据线不仅用于为测试板供电,还用于查看数据日志。其一端为 Micro-B 接口(俗称老安卓口),用于连接 EVB_Air724UG_A14 开发板;另一端为标准 USB 接口,连接 PC 电脑。
3.5 组装硬件环境
3.5.1 请按照 SIM 卡槽上的指示方向正确插入 SIM 卡,务必确保插入方向正确,避免插反导致损坏!
通常,插入 SIM 卡的步骤如下:
- 将 SIM 卡槽的卡扣向 OPEN 的方向推,然后抬起。
- 将 SIM 卡对准卡槽形状,SIM 卡金属接触面朝下,再将卡口合上,朝 CLOSE 方向推,能够关上就说明 SIM 卡已经安装到位。
3.5.2 USB 数据线,连接电脑和 Air724UG 开发板:
1. 如下图,位于上方的 USB 接口(上方红框)直接用 micro USB 数据线连接 PC 供电。
2. 如下图,使用 USB 线缆,插入左侧的 USB 端口,将开发板左侧的电源拨动开关拨至“ON”。长按开机按钮 3 秒钟。
注意:A 所指示的框图区域,拨码开关 1 和 2 的位置需拨至上方与下图保持一致,以确保开发板能够正常工作。
3. 如下图,此时位置 1 的电源红灯会处于常亮,如果开发板是 AT 版本的固件,位置 2 的绿灯会闪烁(LUA 固件不带脚本时绿灯不亮)
四、准备软件环境
注:以下软件下载链接,不能点击下载的请复制后,粘贴到浏览器 URL 地址栏进行下载;
4.1 PC 上 MQTT 客户端
MQTT 下载链接 https://www.emqx.com/zh
4.2 Luatools
下载地址:Luatools v3 下载调试工具。
4.3 core 固件和源码脚本
底层 core 下载地址:Air724UG SDK&Demo
烧录脚本以及 lib 脚本下载地址:Air724UG SDK&Demo
4.4 安装驱动程序
1. 如果发现启动设备后,打开电脑的设备管理器,出现下图情况,需要安装驱动程序,Air724UG_USB 驱动下载地址:点击此处
2. 安装成功后打开设备管理器,会出现如下界面:
五、代码示例介绍
5.1 MQTT 配置
5.1.1 MQTT 的 4 个重要配置
- "lbsmqtt.airm2m.com"(MQTT 服务器地址,这里使用合宙提供公用测试服务器)
- 1884(MQTT 端口)
- "user"(MQTT 服务器登录用户名)
- "password"(MQTT 服务器登录密码)
5.1.2 MQTT 的 2 个重要主题
- /qos0topic(设备发布主题,可在 mqttOutMsg.lua 源码 18 行,可自行修改)
- /event0(设备订阅主题,可在 mqttTask.lua 源码 39 行,可自行修改)
5.2 完整程序清单
1. mqttOutMsg.lua 是 MQTT 客户端数据发送处理
module(...,package.seeall)
--数据发送的消息队列
local msgQueue = {}
--这个函数用于将MQTT消息插入到一个消息队列
local function insertMsg(topic,payload,qos,user)
table.insert(msgQueue,{t=topic,p=payload,q=qos,user=user})
sys.publish("APP_SOCKET_SEND_DATA")
end
--这是发布QoS0消息后的回调函数,用于处理发布结果
local function pubQos0TestCb(result)
log.info("mqttOutMsg.pubQos0TestCb",result)
if result then sys.timerStart(pubQos0Test,10000) end
end
--发布一个QoS0的MQTT消息
function pubQos0Test()
insertMsg("/qos0topic","Hello mqtt",0,{cb=pubQos0TestCb})
end
--这是发布QoS1消息后的回调函数,用于处理发布结果
local function pubQos1TestCb(result)
log.info("mqttOutMsg.pubQos1TestCb",result)
if result then sys.timerStart(pubQos1Test,20000) end
end
--发布一个中文QoS0的MQTT消息
function pubQos1Test()
insertMsg("/中文qos1topic","中文qos1data",1,{cb=pubQos1TestCb})
end
--- 初始化“MQTT客户端数据发送”
-- @return 无
-- @usage mqttOutMsg.init()
function init()
pubQos0Test()
pubQos1Test()
end
--- 去初始化“MQTT客户端数据发送”
-- @return 无
-- @usage mqttOutMsg.unInit()
function unInit()
sys.timerStop(pubQos0Test)
sys.timerStop(pubQos1Test)
while #msgQueue>0 do
local outMsg = table.remove(msgQueue,1)
if outMsg.user and outMsg.user.cb then outMsg.user.cb(false,outMsg.user.para) end
end
end
--- MQTT客户端数据发送处理
-- @param mqttClient,MQTT客户端对象
-- @return 处理成功返回true,处理出错返回false
-- @usage mqttOutMsg.proc(mqttClient)
function proc(mqttClient)
while #msgQueue>0 do
local outMsg = table.remove(msgQueue,1)
local result = mqttClient:publish(outMsg.t,outMsg.p,outMsg.q)
if outMsg.user and outMsg.user.cb then outMsg.user.cb(result,outMsg.user.para) end
if not result then return end
end
return true
end
2. mqttInMsg.lua 是 MQTT 客户端数据接收处理
module(...,package.seeall)
--- MQTT客户端数据接收处理
-- @param mqttClient,MQTT客户端对象
-- @return 处理成功返回true,处理出错返回false
-- @usage mqttInMsg.proc(mqttClient)
function proc(mqttClient)
local result,data
while true do
result,data = mqttClient:receive(60000,"APP_SOCKET_SEND_DATA")
--接收到数据
if result then
log.info("mqttInMsg.proc",data.topic,string.toHex(data.payload))
--TODO:根据需求自行处理data.payload
else
break
end
end
return result or data=="timeout" or data=="APP_SOCKET_SEND_DATA"
end
3. mqttTask.lua 是 MQTT 客户端处理框架
module(...,package.seeall)
require"misc"
require"mqtt"
require"mqttOutMsg"
require"mqttInMsg"
local ready = false
--- MQTT连接是否处于激活状态
-- @return 激活状态返回true,非激活状态返回false
-- @usage mqttTask.isReady()
function isReady()
return ready
end
--启动MQTT客户端任务
sys.taskInit(
function()
local retryConnectCnt = 0
while true do
if not socket.isReady() then
retryConnectCnt = 0
--等待网络环境准备就绪,超时时间是5分钟
sys.waitUntil("IP_READY_IND",300000)
end
if socket.isReady() then
local imei = misc.getImei()
--创建一个MQTT客户端
local mqttClient = mqtt.client(imei,600,"user","password")
--阻塞执行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("lbsmqtt.airm2m.com",1884,"tcp") then
retryConnectCnt = 0
ready = true
--订阅主题
if mqttClient:subscribe({["/event0"]=0, ["/中文event1"]=1}) then
mqttOutMsg.init()
--循环处理接收和发送的数据
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
mqttOutMsg.unInit()
end
ready = false
else
retryConnectCnt = retryConnectCnt+1
end
--断开MQTT连接
mqttClient:disconnect()
if retryConnectCnt>=5 then link.shut() retryConnectCnt=0 end
sys.wait(5000)
else
--进入飞行模式,20秒之后,退出飞行模式
net.switchFly(true)
sys.wait(20000)
net.switchFly(false)
end
end
end
)
六、功能验证
6.1 开机
1. 如图通过 TYPE-C 线将开发板与电脑连接
2. 如果在设备管理器的端口栏下多出这几个 USB 设备,即代表开机成功!
6.2 打开 Luatool 软件工具并进入项目管理测试页面
如果提示更新,就点击更新后重启,确保你的 Luatools 的版本大于或者等于 3.0.6 版本
6.3 新建项目
底层 CORE 和脚本以及资源前面我们已经下载好了,按照下图的步骤操作就行
6.4 按如下步骤进行程序烧录
6.5 打开 MQTT 客户端应用程序并配置
6.5.1 MQTT 客户端基本配置
ProfileName:合宙(可修改为你想要的名称)
BrokerAddress:http://lbsmqtt.airm2m.com (合宙提供的免费测试服务器,也可修改为自己的服务器)
BrokerPort:1883 (端口号)
UserName:user
Password:password
6.5.2 两个重要主题
设备发布主题:/qos0topic (设备向服务器发送数据使用)
设备订阅主题:/event0 (接收服务器数据主题)
6.6 开发板发送数据给 MQTT 客户端
开发板发送的数据为"Hello mqtt"
6.6 MQTT 客户端给开发板发送数据
我们只需要将 string.toHex(data.payload)替换为 data.payload,这样 log 就会直接输出 payload 的原始字符串内容
总结
至此,我们已使用 Air724UG 开发板完成了 MQTT 通信的基本功能。
给读者的话
本篇文章由
胡海江
开发;本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;
请登录合宙技术交流论坛,点击文档找错赢奖金-Air724UG-LuatOS-网络驱动-MQTT-通信;
用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;
我们会迅速核实并且修改文档;
同时也会为您累计找错积分,您还可能赢取月度找错奖金!