目录
MQTT协议(订阅-广播模式、QoS+Will、低质量网络)
本项目以火灾环境参数的数据采集为例,搭建了一个基于MQTT协议与Lora无线自组网的数据采集系统,同时服务器支持处理HTTP、WEBSOCKET请求,并可以在此基础上提供WEB服务。
以下是该项目的结构框架:

MQ7气体传感器对一氧化碳的灵敏度高,这种传感器可检测多种含一氧化碳的气体,是一款适合多种应用的低成本传感器。其使用的气敏材料是在清洁空气中电导率较低的二氧化锡(SnO2)。采用高低温循环检测方式低温(1.5v加热)检测一氧化碳,高温(5.0v加热)清洗低温时吸附的杂散气体,传感器的电导率随空气中一氧化碳气体浓度增加而增大,使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。MQ135的工作原理与MQ7类似,对氨气、硫化物和苯系蒸汽较为灵敏,对烟雾的检测也很理想。
两种模块均可采用3.3V或5V供电,单总线模式输出,可选择数字输出或模拟输出。在数字输出的情况下可输出二值检测信号,如果检测到气体浓度超出一定阈值则输出高电平,反之输出低电平。
本项目选用模拟输出方式。主控MCU通过3.3V/12位的模拟-数字转换器(ADC),采集模拟电位,再通过电压与气体浓度的函数关系计算出检测气体的浓度,即百万分率(ppm)。
可以检测火焰或者波长在 760 纳米~1100 纳米范围内的光源,常用于近距离的火焰检测。单总线方式输出。
DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH, 温度-20~+60℃。供电电压3.3~5.5V(直流),输出为单总线数字信号,分辨率湿度1%RH,温度0.1℃。
温度测量范围为: -40°C至85°C的温度,精度为±1.0°C;压强测量范围为:300至1100 hPa(海拔9000m至-500m)的大气压。采用IIC方式输出数据,SCL为时钟线,SDI为数据线。
常用的STM32F1系列单片机,外设丰富,资料较多。
· 通过ADC测量MQ7、MQ135的模拟输出,并计算气体浓度
· 实现IIC通信读取BMP180模块,获得气压、温度和海拔信息
· 通过单总线通信读取DHT11、KY026模块数据
· 通过串口方式与LoRa模块通信(详见下文)
· 当读取的任一数据超出安全阈值时通过LED和蜂鸣器在本地发出警报
本项目采用Lora通信模块实现了由多个数据采集终端节点到Lora网关的星状结构的无线自组网。其中,网关负责接收和整理来自各个终端的数据,并将数据通过WIFI传送至互联网(服务器),并将来自服务器的指令分发至指定终端。
LoRa,即远距离无线电(LongRangeRadio),原本是一种物理层的线性调频扩频调制技术,最早由法国几位年轻人创立的一家创业公司Cycleo推出,2012年美国Semtech公司收购了Cycleo,并将这一调制技术封装到芯片中,基于LoRa技术开发出一整套LoRa通信芯片解决方案,包括用于网关和终端上不同款的LoRa芯片,开启了LoRa芯片产品化之路。2015年组建的LoRa联盟至今已成长为由Cisco、IBM、中兴通讯、腾讯云、阿里巴巴等众多知名厂商支持的产业生态。与这一生态相关的技术标准、产品设计、应用案例都是由多个厂商共同参与推动的,这也是形成目前庞大产业生态更为关键的元素。
作为一种扩频调制技术,LoRa的抗干扰能力强、传输距离远而传输速率低,通过广播而非连接通信。LoRa主要在全球免费频段运行(即非授权频段),包括433、868、915MHz等。LoRa网络构架由终端节点、网关、网络服务器和应用服务器四部分组成,应用数据可双向传输。因此,一个网关便可控制较多设备,并且布网方式较为灵活,可大幅度降低建设成本。
· 传输距离:城镇可达5KM,郊区可达15KM
· 工作频率:ISM频段,包括433MHz、470MHz、868MHz、915MHz等
· 标准:IEEE 802.15.4g、LoRaWAN
· 调制方式:基于扩频技术,属于CSS的一个变种,具有前向纠错(FEC)能力,是Semtech公司私有专利技术。
· 容量:一个LoRa网关可连接成千上万个LoRa节点
· 安全性:AES128位加密
· 传输速率:18b/s~62.5kb/s
正如前文所言,LoRa网关最重要的功能是实现在自组网内将来自终端节点的无线电信号的接收和转换,并将转换得到的数据发送至互联网,反之亦然。在本项目中,网关的设计方案是由集成了WIFI单元的ESP32作为主控MCU,连接LoRa模块收发信号,并通过LCD屏幕和按键实现网络信息的查看和控制。
本项目选用的LoRa模块型号是ATK-MWCC68D,是正点原子新推出的一款体积小、 微功率、低功耗、高性能远距离LORA 无线串口模块。模块设计是采用高效的 ISM 频段射频 LLCC68 扩频芯片,模块的工作频率 410Mhz~493Mhz,以 1Mhz 频率为步进信道,共 84 个信道,可在线修改串口速率,发射功率,空中速率、工作模式、自定义通讯密钥等各种参数。
基本电气参数如下:
| 36*20mm(不含 SMA 接头和天线) | |
| 工作频段 | 410-493Mhz(共 84 个通道),1Mhz,出厂默认 433Mhz |
| 调制方式 | LoRa 扩频 |
| 通信距离 | 约 5000 米(测试条件:晴朗、空旷,最大功率 22dbm,空中速率 1.2Kbps, 天线增益 3dbi) |
| 发射功率 | 最大 22dBm(约 158mW),6 级可调 |
| 空中速率 | 7 级可调(1.2、2.4、4.8、9.6、19.2、38.4、62.5Kbps) |
| 工作电压 | 3.3~5V |
| 发射电流 | 140ma(22dbm 158mw 电压 5V) |
| 接收电流 | 12.6ma(模式 0、模式 1),最低 2uA(模式 2+2S 唤醒) |
| 睡眠电流 | 1.9uA |
| 通信接口 | UART 串口,8N1、8E1、8O1,从 1200-115200 共 8 种波特率(默认 115200、8N1) |
| 发射长度 | 内部环形 FIFO 缓存 1K 字节,内部自动分包发送。某些空速与波特率组合,可发送无限长度数据包。 |
| 接收长度 | 内部环形 FIFO 缓存 1K 字节,内部自动分包发送。某些空速与波特率组合可 发送无限长度数据包。 |
| 模块地址 | 可配置 65536 个地址(便于组网支持广播和定向传输) |
| 网络地址 | 可配置 256 个地址(便于组网中继) |
| 接收 灵敏度 | -126dBm@1.2Kbps(接收灵敏度和串口波特率、延迟时间无关) |
| 天线形式 | SMA 天线 |
| 工作温度 | -40~+85℃ |
| 存储温度 | -40~+125℃ |
| 尺寸 | 20*36mm |

· 在配置功能下使用AT指令对模块参数进行配置
AT指令列表:
| 指令 | 作用 |
| AT | 测试模块响应情况 |
| AT+MODEL? | 查询设备型号 |
| AT+CGMR? | 获取软件版本号 |
| ATE1 | 指令回显 |
| ATE0 | 指令不回显 |
| AT+RESET | 模块复位(重启) |
| AT+DEFAULT | 恢复出厂设置 |
| AT+FLASH= | 参数保存 |
| AT+ADDR=? | 查询设备配置地址范围 |
| AT+ADDR? | 查询设备地址 |
| AT+ADDR= | 配置设备地址 |
| AT+TPOWER=? | 查询发射功率配置范围 |
| AT+TPOWER? | 查询发射功率 |
| AT+TPOWER= | 配置发射功率 |
| AT+CWMODE=? | 查询配置工作模式范围 |
| AT+CWMODE? | 查询工作模式 |
| AT+CWMODE= | 配置工作模式 |
| AT+TMODE=? | 查询配置发送模式范围 |
| AT+TMODE? | 查询发送模式 |
| AT+TMODE= | 配置发送模式 |
| AT+WLRATE=? | 查询无线速率和信道配置范围 |
| AT+WLRATE? | 查询无线速率和信道 |
| AT+WLRATE= | 配置无线速率和信道 |
| AT+WLTIME=? | 查询配置休眠时间范围 |
| AT+WLTIME? | 查询休眠时间 |
| AT+WLTIME= | 配置休眠时间 |
| AT+UART=? | 查询串口配置范围 |
| AT+UART? | 查询串口配置 |
| AT+UART= | 配置串口 |
| AT+NETID=? | 查询网络地址设置范围 |
| AT+NETID? | 查询网络地址 |
| AT+NETID= | 配置网络地址 |
| AT+PACKSIZE=? | 查询数据包大小设置范围 |
| AT+PACKSIZE? | 查询数据包大小设置 |
| AT+PACKSIZE= | 配置数据包大小 |
| AT+DATAKEY=? | 查询数据密钥设置范围 |
模块工作参数配置范围:
| 模块工作参数 | |
| 串口波特率(bps) | 1200-115200 |
| 校验位 | 无、偶检验、奇校验 |
| 空中速率(单位: Kbps) | 1.2、 2.4、 4.8、 9.6、 19.2、 38.4、 62.5 |
| 休眠时间(单位:秒) | 1、 2 |
| 模块地址 | 0-65535 |
| 网络地址 | 0-255 |
| 通信信道 | 0-83(410-493Mhz 1Mhz 间隔) |
| 发射功率(单位: dBm) | 9、 11、 14、 17、 20、 22 |
| 工作模式 | 一般模式、唤醒模式、省电模式、信号强度模式、睡眠模式、中继模式 |
| 发送模式 | 透明传输、定向传输 |
| 数据包大小 | 32、 64、 128、 240 |
| 数据密钥 | 0-FFFFFFFF |
参数作用说明
| 参数 | 说明 |
| 设备地址 | 用于区分设备的自身地址 |
| 网络地址 | 用于区分网络,相互通信时,需设置为相同 |
| 空中速率 | 无线传输速率,速率高距离近,速率低距离远 |
| 休眠时间 | 对接收方来说是监听间隔的时间,对于发射方来说,是持续发射唤醒码的时间。当模块工作模式在“唤醒模式”时,会在用户数据前自动添加配置休眠时间的唤醒码, 当模块工作模式在“省电模式”时,以配置的休眠时间为监听间隔的时间。 |
| 串口波特率、校验位 | 无线通信下的串口参数。 |
| 信道检测 | 启动后,无线数据发射前会进行信道监听,一定程度上避开干扰,但会带来数据的延迟。最大停留 2 秒时间,达到2 秒后会强制发送。 |
· 主要通信功能
一般模式(模式0)
| 发射 | 模块接收来自串口的用户数据,当用户输入数据达到自定义数据包的字节时,模块将启动无线发射,此时用户可以继续输入需要发射的数据,当用户传输的字节小于数据包时,模块等待 10MS 时间接收,若无用户数据继续输入,则认为数据终止,此时模块将所有数据无线发出。当模块开始发送第一包用户数据时, AUX 引脚将输出高电平,当模块把所有数据启动发射后, AUX 输出低电平。此时表明最后一包无线数据已经发射完毕,用户可以继续输入数据。通过模式 0 发出的数据包, 可被处于模式 0、 1、 3、 5 的模块收到。 |
| 接收 | 模块一直打开无线接收功能,可以接收来自模式 0、 1、 3、 5 发出的数据包。收 |
唤醒模式(模式1)
| 发射 | 模块启动数据包发射的条件与 AUX 功能等于模式 0,唯一不同的是:模块会在每个数据包前自动添加唤醒码(休眠时间),唤醒码的长度取决于用户参数中设置的休眠时间。 |
| 接收 | 等同于模式 0。 |
省电模式(模式2)
| 发射 | 模块处于休眠状态,串口将关闭,无法接收来自外部串口数据,所以该模式不具有无线发射的功能。 |
| 接收 | 在模式 2 下,要求发射方必须工作在模式 1,无线模块定时监听唤醒码,一旦收到有效的唤醒码后,模块将持续处于接收状态,在等待整个有效数据包接收接收完毕,然后模块将 AUX 输出高电平后,打开串口将收到的无线数据通过 TXD发出,完毕后将 AUX 输出低电平。无线模块将继续进制“休眠-监听”的工作状态,通过设置不同的唤醒时间,模块具有不同的接收响应延迟和功耗,用户需要在通讯延迟时间和平均功耗之间取得一个平衡点。 |
信号强度模式(模式3)
本功能可查看通讯双方的信号强度,评估双方的通信质量提供参考
| 发射 | 同一般模式(模式 0)一致。 |
| 接收 | 输出信号强度的信息,如图 2.3.3.1 所示。 |
| 注意 | SNR:信噪比(越大越稳定), RSSI:接收信号的强度指示(越大越稳定) |
睡眠模式(模式4)
| 发送 | 无法发送数据。 |
| 接收 | 无法接收数据。 |
| 注意 | 睡眠模式下,模块处于深度睡眠, 串口关闭, 功耗为最低。可通过 MD0 引脚上升沿电平进行唤醒,唤醒后模块重新配置。 |
中继模式(模式5)
| 发射 | 串口关闭,无法接收来自外部的串口数据。 |
| 接收 | 该模式下,自身的网络地址无效,模块地址不再作为地址,而是作为网络地址的转发,若接收到其中一个网络的数据,则转发到另一个网络。 |
本项目选用ESP-WROOM-32开发板作为网关主控。

ESP32-WROOM-32 是一款通用型 Wi-Fi + Bluetooth + Bluetooth LE MCU 模组,功能强大,用途广泛,可以用于低功耗传感器网络和要求极高的任务,例如语音编码、音频流和 MP3 解码等。
此款模组的核心是 ESP32-D0WDQ6 芯片,具有可扩展、自适应的特点。两个 CPU 核可以被单独控制。时钟频率的调节范围为 80 MHz 到 240 MHz。用户可以切断 CPU 的电源,利用低功耗协处理器来不断地监测外设的状态变化或某些模拟量是否超出阈值。ESP32 还集成了丰富的外设,包括电容式触摸传感器、霍尔传感器、低噪声传感放大器,SD 卡接口、以太网接口、高速 SDIO/SPI、UART、I2S 和 I2C 等。
模组集成了传统蓝牙、低功耗蓝牙和 Wi-Fi,具有广泛的用途:Wi-Fi 支持极大范围的通信连接,也支持通过路由器直接连接互联网;而蓝牙可以让用户连接手机或者广播 Bluetooth LE Beacon 以便于信号检测。ESP32 芯片的睡眠电流小于 5 µA,使其适用于电池供电的可穿戴电子设备。模组支持的数据传输速率高达 150 Mbps,天线输出功率达到 20 dBm,可实现最大范围的无线通信。因此,这款模组具有行业领先的技术规格,在高集成度、无线传输距离、功耗以及网络联通等方面性能极佳。
ESP32 的操作系统是带有 LwIP 的 freeRTOS,还内置了带有硬件加速功能的 TLS 1.2。芯片同时支持 OTA 加密升级,方便用户在产品发布之后继续升级。
· 开发工具
主控程序使用的开发工具为VSCode,借助PlatFormIO插件实现了与常见的Arduino开发板同样的开发方式,库函数丰富且易于调试。
· 连接方式
通过串口与ATK-MWCC68D连接,接收的消息按照MQTT协议的内容进行包装后再通过WIFI串口发送至互联网。
· MQTT协议的实现
利用PubSubClient库实现MQTT Client。PubSubClient库封装了TCP连接过程和MQTT消息的解析与包装,提供了方便的API,便于程序的开发。
· 网关信息展示
通过驱动LCD屏幕将当前网关连接的终端数、电量、网络状况等信息进行展示
· 消息队列管理
网关作为数据传输的中心结点,需要整理来自多个数据采集结点的数据发送至服务器。根据数据到达网关的时间、数据的相对重要程度不同,可对不同数据记录在消息队列中的顺序(发送优先级,尤其是在网络条件较差的情况下)以及其MQTT报文中的QoS(服务质量)等级等参数进行设置和管理。
本项目的服务器软件基于开源项目mqtt-push进行二次开发。开发工具为IDEA,开发语言为Java,项目管理工具为MAVEN。
原项目地址:
Clone链接:
原项目基于Netty框架开发。Netty是由JBOSS提供的一个Java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于NIO(Non-blocking IO,非阻塞IO)的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程。
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择器)。
传统的的BIO基于字节流或者字符流进行操作 ,而NIO基于Channel和Buffer进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector用于监听多个通道的事件(比如连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
Netty三大特性:
· 并发高
Netty是一款基于NIO(Nonblocking IO),非阻塞开发的网络通信框架,对比BIO(Blocking IO),他的并发性能得到了很大的提高。
· 传输快
Java的内存有堆内存、栈内存和字符串常量池等等,其中堆内存是占用内存空间最大的一块,也是Java存放对象的地方。一般我们的数据如果需要IO读取到堆内存,中间需要经过Socket的缓冲区,也就是说一个数据会被拷贝两次才能到达他的终点,如果数据量大,就会造成不必要的资源浪费。
Netty针对这种情况,使用了NIO中的另一大特性–零拷贝,当他需要接受数据时,他就会直接从IO读到了那块内存中去,在netty里面通过ByteBuf可以直接对这些数据进行直接操作,从而加快了传输速度。
· 封装好
经过BIO,NIO,Netty分别实现网络编程代码,区别非常明显。
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
类似HTTP协议。MQTT协议也有自己的格式,如下:
[ Fixed Header | Variable Header | Payload]
Fixed Header: 固定报头,MQTT协议分很多种类型,如连接,发布,订阅,心跳等。其中固定头是必须的,所有类型的MQTT协议中,都必须包含固定头。
Variable Header:可变报头,可变头部不是可选的意思,而是指这部分在有些协议类型中存在,在有些协议中不存在。
Payload:消息载体,就是消息内容。与可变头一样,在有些协议类型中有消息内容,有些协议类型中没有消息内容。
MQTT协议共包含14种报文类型:
| 名字 | 报文流动方向 | 描述 |
| Reserved | 禁止 | 保留 |
| CONNECT | 客户端到服务端 | 客户端请求连接服务端 |
| CONNACK | 服务端到客户端 | 连接报文确认 |
| PUBLISH | 两个方向都允许 | 发布消息 |
| PUBACK | 两个方向都允许 | QoS 1 消息发布收到确认 |
| PUBREC | 两个方向都允许 | 发布收到(保证交付第一步) |
| PUBREL | 两个方向都允许 | 发布释放(保证交付第二步 ) |
| PUBCOMP | 两个方向都允许 | QoS 2 消息发布完成(保证交互第三步) |
| SUBSCRIBE | 客户端到服务端 | 客户端订阅请求 |
| SUBACK | 服务端到客户端 | 订阅请求报文确认 |
| UNSUBSCRIBE | 客户端到服务端 | 客户端取消订阅请求 |
| UNSUBACK | 服务端到客户端 | 取消订阅报文确认 |
| PINGREQ | 客户端到服务端 | 心跳请求 |
| PINGRESP | 服务端到客户端 | 心跳响应 |
| DISCONNECT | 客户端到服务端 | 客户端断开连接 |
| Reserved | 禁止 | 保留 |
根据报文类型的不同,协议同一位置的字段和参数也会不同。
· 固定报头
固定报头主要分为两部分:首字节(字节1)和剩余消息报文长度(1-4字节)。
首字节用于表示MQTT消息的报文类型以及某些类型的控制标记,如上图。高4位(bit7~bit4)表示协议类型,总共可以表示16种协议类型,其中0000和1111是保留字段。首字节的低4位(bit3~bit0)用来表示某些报文类型的控制字段。
实际上只有少数报文类型有控制位,比如PUBLISH消息。当发布PUBLISH消息时,如果DUP字段(bit 3)设置为1,表明这是一条重复消息,否则是第一次发布消息。为了保证消息的可靠性传递,当QoS设置为1时,客户端或服务器发布消息时,需要得到对方的确认(PUBACK),如果一段时间后没收到PUBACK,那么会再次发送当前消息,并将DUP字段标记为1。QoS用来表明QoS等级,如果Bit 1和Bit 2都为0,表示QoS 0。如果Bit 1为1,表示QoS 1。如果Bit 2为1,表示QoS 2。如果同时将Bit 1和Bit 2都设置成1,那么客户端或服务器认为这是一条非法的消息,会关闭当前连接。目前Bit[3-0]只在PUBLISH协议中使用有效,并且表中指明了是MQTT 3.1.1版本。对于其它MQTT协议版本,内容可能不同。
·QoS 0:至多1次,消息发布完全依赖底层TCP/IP网络。
·QoS 1:至少1次,如果发送方没有收到接收方的回复(即使成功接收),则认为发生了丢包,会重发。
·QoS 2:“反复确认”,保证成功接收的相同的消息只有一条。
剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。
· 可变报头
有些报文类型包含可变头部,如PUBLISH,SUBSCRIBE,CONNECT等等。可变头部在固定头部和消息内容之间,其内容根据报文类型不同而不同。Packet Identifier(消息ID)是一种常见的可变头部,一个消息ID包含2字节,高字节在前,低字节在后。
· 消息载体
有些报文类型是包含Payload的,Payload意思是消息载体的意思,如PUBLISH的Payload就是指消息内容。而CONNECT的Payload则包含Client Identifier,Will Topic,Will Message,Username,Password等信息。
特别的遗嘱机制:遗嘱消息可以看作是一个简化版的 PUBLISH 消息,包含 Topic, Payload, QoS 等字段。遗嘱消息会在设备与服务端连接时,通过 CONNECT 报文指定,然后在设备意外断线时由服务端将该遗嘱消息发布到连接时指定的遗嘱主题(Will Topic)上。
包含Payload的报文类型如下:
| 报文类型 | 是否包含Payload |
| CONNECT | YES |
| PUBLISH | 可选 |
| SUBSCRIBE | YES |
| SUBACK | YES |
| UNSUBSCRIBE | YES |
服务器同样支持HTTP协议访问。Http服务程序入口位于mqtt-getway模块,\mqtt-getway\src\main\java\io\mqttpush\getway\http\HttpGetWayServer.java。Controller包中提供了Controller抽象类,并实现了两个子类(FormController和FullTextController)。
原项目只对POST请求进行处理。可以对Controller包进行二次开发以处理其他类型的请求,实现新的web功能。在数据的传递与解析方面,一般使用JSON(JavaScript Object Notation,一个常见的轻量级的数据交换格式)进行数据交互。
同HTTP网关类似,该服务器同样支持处理遵循WebSocket协议的请求。
为持久保存实时数据,本项目添加了数据库功能,使用的MySQL。MySQL是一个开放源码的小型关联式数据库管理系统。服务器启动前需要安装MySQL数据库并创建数据表。本项目开发了JDBCHandler工具类,可以较为方便地通过JDBC在服务器程序中连接和操作数据库,并更好地支持数据库响应网络请求。
· 开发工具:Android Studio
· 开发语言:Java
· 项目管理工具:Gradle
·实现各类MQTT报文的收发,包括CONNECT报文、SUBSCRIBE报文、PUBLISH报文等
·部分功能在“服务”中实现,支持后台运行
·支持HTTP请求,消息内容通过JSON格式封装,可访问服务器数据库中的各种信息
·支持RTSP流媒体传输