无线传感网

MQTT协议

作者:陈广
日期:2021-5-5


一年多前是准备写这块内容的,但不得不转战RFID写书。RFID忙完后,由于换了NB-IOT芯片,不得不把基础内容重新来一遍,现在终于回到了原来的起点。讲什么内容呢?AM22E使用的是中移物联网的模组,而中移物联网架设了自己的物联网平台:OneNET,OneNET中最常用的协议是MQTT,所以我们从MQTT协议开始。

MQTT协议(Message Queuing Telemetry Transport),翻译过来就是消息队列遥测传输,是IBM公司于1999年提出的,当前最新版本是3.1.1。它设计的初始目的是为了极有限的内存设备和网络带宽很低的网络不可靠的通信,非常适合物联网通信。

MQTT设计背景

任何协议都是为了解决特定问题而出现的,就如HTTP的出现是为了解决浏览器显示服务器内容而生,FTP的出现是为了解决文件在互联网上传输的问题。20世纪90年代中期,IBM公司为了帮助石油天然气公司实现数千英里长的石油和天然气管道的无人值守监控,设计了MQTT协议。

石油天逸气管道线路非常长,会穿越很多无人区,附近没有网络设施,因此使用卫星通讯最为经济。卫星通信延迟高,并且每天都会出现卫星切换时的网络中断,因此需要客户端和服务器端都能够保留消息收发状态,以便在网络恢复正常后继续发送。另一方面,卫星链路带宽低,通信流量费用高昂,因此需要尽量节省传输消息的流量开销。

MQTT是基于TCP协议进行设计的,它解决了传输可靠性的问题。MQTT设计简单、轻巧、便于实现,占用的硬件资源和网络资源非常少,并对网络延迟有完善的处理方案,这些特点使它成为了资源受限的NB-IOT上使用的首选协议。

MQTT的消息类型

MQTT所实现的内容非常简单:消息的订阅和发布。MQTT协议中有三种身份:发布者(Publish)、代理(Broker)、订阅者(Subscribe),其中,发布者和订阅者为网络中的客户端,代理为服务器端。发布者向代理发布消息,订阅者向代理订阅消息,当发布者发布消息时,如果订阅者订阅了该消息,则代理会将此消息推送给订阅者。

MQTT包括以下消息类型:

名称 作用 流向 描述
CONNECT 连接服务器 客户端 → 服务端 客户端到服务端的网络连接建立后, 客户端发送给服务端的第一个报文必须是CONNECT报文。
CONNACK 确认连接请求 服务端 → 客户端 服务端从客户端收到的CONNECT报文后,向客户端响应CONNACK报文。 服务端发送给客户端的第一个报文必须是CONNACK。如果客户端在合理的时间内没有收到服务端的CONNACK报文, 客户端应该关闭网络连接。合理的时间取决于应用的类型和通信基础设施。
PUBLISH 发布消息 双向 向服务器发送发布消息请求
PUBACK 发布确认 双向 QoS 1消息发布收到确认
PUBREC 发布收到 双向 PUBREC报文是对QoS等级2的PUBLISH报文的响应。 它是QoS 2等级协议交换的第二个报文。
PUBREL 发布释放 双向 PUBREL报文是对PUBREC报文的响应。 它是QoS 2等级协议交换的第三个报文。
PUBCOMP 发布完成 双向 PUBCOMP报文是对PUBREL报文的响应。 它是QoS 2等级协议交换的第四个也是最后一个报文。
SUBSCRIBE 订阅主题 客户端 → 服务端 客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。 每个订阅注册客户端关心的一个或多个主题。 为了将应用消息转发给与那些订阅匹配的主题, 服务端发送PUBLISH报文给客户端。 SUBSCRIBE报文也( 为每个订阅) 指定了最大的QoS等级, 服务端根据这个发送应用消息给客户端。
SUBACK 订阅确认 服务端 → 客户端 服务端发送SUBACK报文给客户端, 用于确认它已收到并且正在处理SUBSCRIBE报文。
UNSUBSCRIBE 取消订阅 客户端 → 服务端 客户端发送UNSUBSCRIBE报文给服务端, 用于取消订阅主题。
UNSUBACK 取消订阅确认 服务端 → 客户端 服务端发送UNSUBACK报文给客户端用于确认收到UNSUBSCRIBE报文。
PINGREQ 心跳请求 客户端 → 服务端 客户端发送PINGREQ报文给服务端的。 用于:1. 在没有任何其它控制报文从客户端发给服务的时, 告知服务端客户端还活着。2. 请求服务端发送响应确认它还活着。3. 使用网络以确认网络连接没有断开。
PINGRESP 心跳响应 服务端 → 客户端 服务端发送PINGRESP报文响应客户端的PINGREQ报文。 表示服务端还活着。
DISCONNECT 断开连接 客户端 → 服务端 DISCONNECT报文是客户端发给服务端的最后一个控制报文。 表示客户端正常断开连接。

消息质量(QoS)

MQTT提供了QoS 0,QoS 1和 QoS 2 三个不同等级的消息发送服务质量,收发双方根据业务需要可选择所需的服务等级。MQTT客户端和Broker端底层通过 session 来保障不同的QoS等级。如果直接使用TCP实现业务,需要自己实现类似机制,而MQTT自带这一功能。

  • QoS 0:最多分发一次。消息的传递完全依赖底层的TCP/IP网络,协议里没有定义应答和重试,消息要么只会到达服务端一次,要么根本没有到达。

  • QoS 1:至少分发一次。服务器的消息接收由PUBACK消息进行确认,如果通信链路或发送设备异常,或者指定时间内没有收到确认消息,发送端会重发这条在消息头中设置了DUP位的消息。

  • QoS 2:只分发一次。这是最高级别的消息传递,消息丢失和重复都是不可接受的,使用这个服务质量等级会有额外的开销。

通过下面的例子可以更深刻的理解上面三个传输质量等级。比如目前流行的共享单车智能锁,智能锁可以定时使用QoS level 0质量消息请求服务器,发送单车的当前位置,如果服务器没收到也没关系,反正过一段时间又会再发送一次。之后用户可以通过App查询周围单车位置,找到单车后需要进行解锁,这时候可以使用QoS level 1质量消息,手机App不断的发送解锁消息给单车锁,确保有一次消息能达到以解锁单车。最后用户用完单车后,需要提交付款表单,可以使用QoS level 2质量消息,这样确保只传递一次数据,否则用户就会多付钱了。

遗愿标志(Will Flag)

在可变报文头的连接标志位字段(Connect Flags)里有三个Will标志位:Will Flag、Will QoS和Will Retain Flag,这些Will字段用于监控客户端与服务器之间的连接状况。如果设置了Will Flag,就必须设置Will QoS和Will Retain标志位,消息主体中也必须有Will Topic和Will Message字段。

那遗愿消息是怎么回事呢?服务器与客户端通信时,当遇到异常或客户端心跳超时的情况,MQTT服务器会替客户端发布一个Will消息。当然如果服务器收到来自客户端的DISCONNECT消息,则不会触发Will消息的发送。  因此,Will字段可以应用于设备掉线后需要通知用户的场景。

连接保活心跳机制(Keep Alive Timer)

MQTT客户端可以设置一个心跳间隔时间(Keep Alive Timer),表示在每个心跳间隔时间内发送一条消息。如果在这个时间周期内,没有业务数据相关的消息,客户端会发一个PINGREQ消息,相应的,服务器会返回一个PINGRESP消息进行确认。如果服务器在一个半(1.5)心跳间隔时间周期内没有收到来自客户端的消息,就会断开与客户端的连接。心跳间隔时间最大值大约可以设置为18个小时,0值意味着客户端不断开。

这里只对MQTT协议做一个简单介绍,详细信息,请访问:

MQTT协议中文版 MQTT协议英文版

OneNET的连接

现今几个大的IT公司都架设了自己的物联网云平台,腾讯、阿里、华为、电信,移动的是OneNET,由于AM22E使用的是OneNET,所以我们就讲OneNET,其实学哪个并不是那么重要,思路都是一样的。

注册和认证

首先进入中移物联网公司网站:http://iot.10086.cn/
然后参考以下文档https://open.iot.10086.cn/doc/mqtt/book/get-start/login.html进行账户注册与账户认证。

然后进入MQTT物联网套件页面,单屏幕上方的【立即使用】按钮,进入到MQTT平台。

添加产品

接下来点击【添加产品】按钮,按下图添加一个产品,注意,移动那边会经常更新OneNET,所以界面可能会有所不同,可参考产品创建官方文档

添加完成后,OneNET会自动分配一个产品ID,请记住这个6位数的ID,后面会用到。

添加设备

接下来参考创建设备官方文档为之前添加的产品添加一个设备,只需填入设备名称,这里为:“mqtt_001”。添加完成后,系统会自动为此设备分配一个设备ID,请记住设备ID和设备名称,等下会使用到。

计算密钥

待会我们会用软件模拟设备登录OneNET时,需要使用一个密码,而得到这个密码需要经过较为复杂的计算。密码可以使用工具计算得出,也可以自己编程计算。OneNET官方文档没有把这个密码的生成讲清楚,害我整了半天才连接上服务器。

产品和设备添加完成后,我们收集以下信息:

  • 产品ID:423266
  • 设备ID:713986856
  • 设备名称:mqtt_001
  • 设备的key(可在设备详情内查看):JW/TYMGlz1mQ8vh1KQ313HLHUiiHUt5uvD/wnSCB6t0=

注意:这些是我的信息,不同的人完成操作,除了设备名称,其它的肯定会不一样。

首先到以下链接下载OneNET的token生成工具:

https://open.iot.10086.cn/doc/mqtt/book/manual/auth/tool.html

打开后,按下图所示生成密码:

最终生成的密码为:

version=2018-10-31&res=products%2F423266%2Fdevices%2Fmqtt_001&et=1735660800&method=sha1&sign=sbdInDZQZ7%2FfZWPMefRaeJvNgYk%3D

上图中各参数:

  • res:为访问资源resource,格式为:父资源类/父资源ID/子资源类/子资源ID。
  • et:访问过期时间 expirationTime,unix时间。当一次访问参数中的et时间小于当前时间时,平台会认为访问参数过期从而拒绝该访问。
  • method:签名方法 signatureMethod 支持md5、sha1、sha256

使用MQTT.fx模拟一个设备

MQTT.fx是一款基于Eclipse Paho,使用Java语言编写的MQTT客户端工具,支持通过Topic订阅和发布消息。我们可以在学习AM22E的过程中使用它作为一个调试和模拟工具。我个人强烈建议使用MQTT.fx模拟设备进行学习,因为模拟器是通用的,而不同模组的AT指令不一样,使用模拟器更接近其本质,不要的把自己绑定在特定设备上。首先到以下地址下载MQTT.xf:

MQTT.fx官方下载地址

下载安装完成后,打开MQTT.fx,如下图所示:

单击齿轮图标打开设置窗口,按下图所示填写。

说明一: 由于网址未来有可能会有变动,请到以下文档查找服务器接入网址和端口: https://open.iot.10086.cn/doc/mqtt/book/device-develop/manual.html

单击【User Credentials】填写登录的用户名称密码,按下图所示填写:

最后单击【OK】按钮保存设置并关闭设置窗口。单击【Connect】按钮连接服务器,并单击【Log】按钮查看日志,如下图所示:

最后,在OneNET中查看设备状态,显示“在线”表明我们的设备已经连接成功了。在MQTT.fx中单击【Disconnect】按钮,再观察设备状态,可以发现已经处于离线状态了。

在OneNET中订阅和发布消息

接下来我们尝试给OneNET中的设备订阅和发布消息。首先要订阅,然后消息在发布后才能收到。

订阅消息

MQTTS物联网套件中设备相关服务(存储、命令等)的面向设备的接口,均以topic(主题)的形式提供,设备可以通过 publish 消息到系统topic调用服务接口,也可以订阅系统topic用于接收服务消息通知。OneNET平台暂不支持用户自定义topic,仅限使用系统topic。

为了确定设备上传的消息已被服务器接收,设备可以订阅上传数据点结果消息。设备上传数据点topic命名规则如下:

$sys/{pid}/{device-name}/dp/post/json/+

其中:

  • {pid}:为产品ID
  • {device-name}:为设备名称

打开MQTT.fx,连接成功后,点击【Subscribe】按钮打开订阅面板,按下图所示操作:

发布消息

接下来向设备上传数据点,系统在收到数据点后会自动发布一条数据点上传成功消息,订阅了此消息的设备将收到这条消息。本例中上传数据点和订阅消息的设备为同一设备。

发布topic命名规则如下:

$sys/{pid}/{device-name}/dp/post/json

在MQTT.fx中点击【Publish】按钮,打开发布面板,按下图所示操作,上传的数据必须为json格式:

{
    "id": 001,        
    "dp": {             
        "temperatrue": [{     
            "v": 30,
        }],
        "power": [{     
            "v": 4.5,        
        }]
    }
}

点击【Subscribe】按钮打开订阅面板,可以看到已经从平台收到了数据点上传成功的消息,如下图所示:

接下来更改id号和温度,再上传两个数据点:

{
    "id": 002,        
    "dp": {             
        "temperatrue": [{     
            "v": 25,
        }],
        "power": [{     
            "v": 4.5,        
        }]
    }
}

{
    "id": 003,        
    "dp": {             
        "temperatrue": [{     
            "v": 21,
        }],
        "power": [{     
            "v": 4.5,        
        }]
    }
}

查看订阅面板,看看是否收到上传成功消息。

在OneNET平台查看上传的数据点

登录OneNET平台,进入到设备列表面板,找到mqtt_001设备。点击【数据流】打开数据流面板,如下图所示:

可以看到,我们上传的数据中包含了两个类型的数据,一个是temperatrue,另一个是power。

点击 temperatrue 查看温度数据流:

注意:最后三个点是我们刚才上传的温度数据。

;

© 2018 - IOT小分队文章发布系统 v0.3