MQTT应用指南

描述

#概述

本文旨在帮助已经购买RAK商业网关产品并且使用内置LoRa Server功能的用户,了解如何通过MQTT订阅商业网关内置LoRa Server的数据,使用户了解商业网关的工作原理,方便用户在自己的应用服务器获取节点数据,达到便捷使用应用服务器完成数据展示和数据分析的目的。

 

本文将以RAK公司的商业网关产品(室内网关RAK7258或室外网关RAK7249)为例,介绍如何配置商业网关使用内置MQTT服务器和私有(外置)MQTT服务器,以及如何订阅节点数据和向节点发送数据等。

 

#LoRaWAN和MQTT简介

本章节介绍LoRaWAN网络和MQTT网络,用于帮助用户对LoRaWAN和MQTT的工作原理有一个简单直观的了解。如果您已经熟悉了LoRaWAN和MQTT的工作原理,可跳过此章节。

#LoRaWAN简介

节点Figure 1: LoRaWAN网络包含的角色

 

从上图可以看出,LoRaWAN网络包括如下3个角色,各个角色的作用如下所示:

  • 终端设备(End Nodes):即节点设备,负责数据采集,并将数据加密后以无线信号的形式传递给网关。
  • 网关(Concentrator/Gateway):将终端发送的数据透传给NS服务器。
  • NS服务器(Network Server):根据数据身份信息、密钥对网关转发的数据进行解密、处理。

RAK简化LoRaWAN实际部署条件,RAK商业网关集成了NS服务器,它配合节点可以轻松搭建LoRaWAN网络。

 

#MQTT简介

MQTT代表MQ遥测传输,是一种发布/订阅极其简单和轻量级的消息传递协议,用于受限设备和低带宽、高延迟或不可靠的网络。设计原则是使网络带宽和设备资源要求最小化以及确保可靠性。这些原则使该协议成为物联网世界的理想选择。

节点Figure 2: MQTT网络角色

 

如上图所示,MQTT网络角色包括如下3个,各个角色的作用如下所示:

  • 发布者(Publisher):发布信息。
  • 订阅者(Subscriber):收集发布者发布的信息。
  • MQTT Broker:接收发布信息并将信息向订阅者进行展示。

MQTT Broker同比是新闻发布网站,发布者是新闻发布成员,订阅者是浏览、查看新闻的用户。

 

#MQTT在LoRaWAN网络中的作用

节点Figure 3: MQTT在LoRaWAN网络中的作用

 

实际应用1:使用RAK商业网关内置的MQTT Broker功能。

RAK商业网关获取数据并发送给内置NS,内置NS将数据发布至内置的MQTT Broker,用户通过第三方程序订阅数据。这种应用情况下,RAK商业网关既是发布者,又是MQTT Broker。

注意:

  • 如果使用网关内置的MQTT Broker,则无法通过公网订阅或发布数据。
  • 网关内置的MQTT Broker仅适用于项目研发和测试阶段,由于内置的MQTT Broker没有密码、证书等验证方式,容易被其他人窃取传感器数据,因此,不建议在生产部署时使用。

 

实际应用2:使用用户私有的MQTT Broker功能。

RAK商业网关获取数据并发送给内置NS,内置NS将数据发布至第三方MQTT Broker,用户通过第三方程序订阅数据。这种应用情况下,RAK商业网关仅为发布者。

#订阅节点数据和向节点发送数据

本节以RAK商业网关为例,介绍如何通过MQTT.fx工具订阅节点上报的数据和向节点发送数据。您可以通过单击MQTT.fx下载MQTT.fx工具(MQTT客户端)。

 

#配置商业网关使用内置服务器

1、在浏览器地址栏中输入商业网关的IP地址192.168.230.1,按"Enter",进入如下界面。

节点Figure 4: 商业网关登录界面

 

2、在打开的商业网关登录界面中输入用户名和密码,单击"Login"。

默认用户名和密码都为root。

3、在左侧导航栏中选择“LoRa Network > Network Settings”。

4、在“LoRaWAN Network Settings”界面上,设置"Mode"为"Network Server"模式。

节点Figure 5: 配置RAK7249使用内置服务器

 

5、单击“Switch mode”切换模式。

约15秒左右,网关即可切换为Network Server模式。在该模式下,商业网关既是网关,又是NS服务器。

 

#添加节点到商业网关的内置服务器

1、在商业网关左侧导航栏中选择“LoRa Network > Application”,进入应用概览页面。

2、输入应用名称,单击“Add”,如下图所示。

注意:

本示例采用"Type1 : Unified Application Key",即同一Application中,所有节点设备使用相同的Application Key。不需要单独为设备设置Application Key。支持通过OTAA自动添加设备。如果您想使用“Type2 : Separate Application Key”,请参考Web 平台配置指南。

节点Figure 6: 新增应用

 

在应用配置页面根据页面提示配置应用信息,如下图所示。

节点Figure 7: 配置应用

 

  • Name:应用名称,用户自定义。
  • Auto Add LoRa Device:是否开启自动添加设备。开启后,如果设备的Application Key与Application EUI通过身份验证,设备将被自动添加到服务器上。
  • Application EUI:标识唯一的应用提供者,开启自动添加设备后需要填写。单击让系统自动生成Application EUI。需与节点设备三元组信息中的“AppEUI”保持一致。
  • Application Key:由应用程序拥有者分配给终端。单击让系统自动生成Application Key。需与节点设备三元组信息中的“AppKey”保持一致。
  • Description:应用描述信息,用户自定义。

注意:您也可以使用Micro USB线连接节点设备到PC,后使用串口工具打开相应端口分别发送AT+APPEUIAT+APPKEY获取Application EUI和Application Key的值后填写到此处,可省去后续配置节点的步骤。本示例采用系统自动生成的方法。

 

4、单击"Save & Apply"保存配置。

5、在系统自动返回的应用概览页面,单击"Edit"进入应用配置页面添加节点。

节点Figure 8: 应用概览页面

 

6、输入节点的Device EUI后,单击“Add”,如下图所示。Device EUI可在节点设备的标签上获取,也可使用Micro USB线连接节点设备到PC,后使用串口工具打开相应端口发送AT+DEVEUI进行查询。

节点Figure 9: 添加节点设备

 

7、在节点配置页面配置节点设备信息,如下图所示。

节点Figure 10: 配置节点设备信息

 

  • Device name:节点设备名称,用户自定义。
  • Class:节点设备类型,需与节点保持一致。这里以节点出厂默认配置Class A为例。
  • Join mode:节点设备的入网方式,需与节点保持一致。这里以节点设备出厂默认配置OTAA为例。
  • Frame-counter Width:报文序号计数器长度。
  • LoRaWAN MAC Version:LoRaWAN协议版本号。
  • LoRaWAN Regional Parameters Reversion:LoRaWAN区域参数版本号。
  • Enable LPTP:是否开启LPTP协议。LPTP协议是RAK自定义的LoRa®报文分片/重组协议,仅部分RAK节点产品(RAK7421、RAK7431及RAK4203)支持。
  • Description:节点的描述信息,用户自定义。

8、单击"Save & Apply"保存配置。

 

#使用商业网关内置的MQTT Broker

用户可通过商业网关内置的Application Server Integration功能使用MQTT客户端订阅NS Topic消息来获取节点数据,也可以使用MQTT客户端向节点发送数据。

 

#配置商业网关使用内置的MQTT Broker

1、在商业网关左侧导航栏中选择"LoRa Network > Global Integration"。

2、在"Application Server Integration"页面上,设置应用服务器集成的相关参数。

如果使用内置的MQTT Broker,则“MQTT Broker Address”和“MQTT Broker Port”参数的值保持默认即可。如果您不了解MQTT协议的topic,建议保持MQTT topic相关参数的默认配置。此处使用内置的MQTT Broker,全部参数保持默认配置,如下图所示。

节点Figure 11: 配置商业网关使用内置的MQTT Broker

 

3、单击"Save & Apply"保存配置。

 

#通过MQTT.fx客户端订阅节点数据

1、打开MQTT.fx工具,主界面如下图所示。

节点Figure 12: MQTT.fx工具主界面

 

2、单击左上角的新建图标,如下图所示。

节点Figure 13: 新建图标

 

3、在下图中红框处输入网关的IP地址。

节点Figure 14: 输入网关的IP地址

 

4、单击“Connect”。最右侧的黑色圆形变成绿色,说明已经成功连接到网关内置的MQTT Broker。

节点Figure 15: 成功连接到网关内置的MQTT Broker

 

5、选择“Subscribe”页签。

6、在“Subscribe”页签的输入框中输入待订阅的topic,单击输入框右侧的“Subscribe”。

输入待订阅的topic时,topic的格式应该与商业网关"Application Server Integration"页面上Uplink Topic的格式保持一致,如下图所示,其中,application_ID需要替换成实际的application ID的值,device_EUI需要替换成节点的device_EUI的值。

节点Figure 16: Uplink Topic参数

 

application ID的值和device_EUI的值请参考下面两个图来获取。

节点Figure 17: 获取application ID

 

节点Figure 18: 获取device_EUI


以上面两个图中获取的application ID和device_EUI的值为例,则需要在输入框中输入的topic为:application/2/device/00d939567c667e1e/rx,如下图所示。

节点Figure 19: 订阅节点上报的数据

 

· 如果要订阅一个应用下的所有节点数据,例如:要订阅应用2下的所有节点数据,则需要输入如下topic:

application/2/device/+/rx

· 如果要订阅所有应用下的所有节点数据,则需要输入如下topic:

application/+/device/+/rx

 

7、使用节点成功join之后发送一条数据。例如:要在节点侧发送一条“HelloRakwireless”,因为节点需要接收16进制的数据,将“Hello Rakwireless”转换为16进制,即“48656c6c6f52616b776972656c657373”,则发送的AT命令如下图所示。

节点Figure 20: 在节点侧发送数据示例

 

8、在MQTT.fx界面上查看已订阅的节点数据,如下图所示。

节点Figure 21: 在MQTT.fx界面上查看已订阅的节点数据

 

上图中"data"字段的值即为节点发送的数据,只是这些数据进行了base64编码,对"data"字段的值进行base64解码后即可看到原始数据。

 

9、查看商业网关web管理界面上节点发送的数据是否与MQTT.fx界面上一致。

节点Figure 22: 查看商业网关web管理界面

 

#通过MQTT.fx客户端向节点发送数据

1、在MQTT.fx工具的主界面上,选择“Publish”页签。

2、在“Publish”页签的输入框2中输入topic,在输入框3中输入{"confirmed": true,"data": "SGVsbG8=","fPort":10},单击“Publish”。

 

注意:

{"confirmed": true,"data": "SGVsbG8=","fPort": 10}中字段的说明如下所示:

"confirmed"的取值包括true和false。
"data"的取值即要发送的数据,需要对数据进行base64编码。
"fPort"的取值即要发送的端口号,有效端口号为1~255。

 

输入topic时,topic的格式应该与商业网关"Application Server Integration"页面上Downlink Topic的格式保持一致,如下图所示,其中,application_ID需要替换成实际的application ID的值,device_EUI需要替换成节点的device_EUI的值。

节点Figure 23: Downlink Topic参数

 

application ID的值和device_EUI的值请参考下面两个图来获取。

节点Figure 24: 获取application ID

 

节点Figure 25: 获取device_EUI

 

以上面两个图中获取的application ID和device_EUI的值为例,则需要在输入框2中输入的topic为:application/2/device/00d939567c667e1e/tx,如下图所示。

节点Figure 26: 通过MQTT.fx向节点发送数据

 

注意:

通过MQTT.fx客户端向节点发送数据后,Class C模式下节点会立刻收到MQTT.fx下发的数据,Class A模式下节点会在下一次上发数据之后收到MQTT.fx下发的数据。

 

3、在节点端查看接收到的数据,如下图所示。

节点Figure 27: 查看节点端接收到的数据

 

#使用用户私有的MQTT Broker

本节介绍在商业网关上配置用户私有的MQTT Broker信息、连接MQTT客户端与用户私有的MQTT Broker、通过MQTT客户端订阅节点数据和通过MQTT客户端向节点发送数据的具体方法。

 

#配置商业网关使用用户私有的MQTT Broker

1、在商业网关左侧导航栏中选择"LoRa Network > Global Integration"。

2、在"Application Server Integration"页面上,设置应用服务器集成的相关参数。

 

如果要使用用户私有的MQTT Broker,则需要配置如下参数。

  • MQTT Broker Address:用户私有的MQTT服务器的IP地址。
  • MQTT Broker Port:MQTT服务器的端口号,默认端口号为1883。
  • Enable User Authentication:打开用户认证开关。
  • Username:访问MQTT服务器的用户名。
  • Password:访问MQTT服务器的用户密码。

如果您不了解MQTT协议的topic,建议保持MQTT topic相关参数的默认配置。

此处使用用户私有的MQTT Broker且保持MQTT topic相关参数的默认配置,如下图所示。

节点Figure 28: 配置商业网关使用用户私有的MQTT Broker

 

3、单击"Save & Apply"保存配置。

 

#连接MQTT.fx客户端至用户私有的MQTT Broker

1、打开MQTT.fx。

2、单击设置图标,如下图所示。

节点Figure 29: 设置图标

 

系统弹出“Edit Connection Profiles”对话框。

3、在“Edit Connection Profiles”对话框中,单击左下角的+

4、设置“Profile Name”、“Broker Address”、"Broker Port",单击“User Credentials”,输入“User Name”和“Password”,如下图所示。

节点Figure 30: 新建Profile并配置参数

 

5、单击右下角的“OK”。

6、“Edit Connection Profiles”对话框自动关闭,MQTT.fx主界面中已自动选择了刚创建的Profile。

7、在MQTT.fx主界面中单击“Connect”。最右侧的黑色圆形变成绿色,说明已经成功连接到用户私有的MQTT Broker。

 

#通过MQTT.fx客户端订阅节点数据

具体方法请参考通过MQTT.fx客户端订阅节点信息

 

#通过MQTT.fx客户端向节点发送数据

具体方法请参考通过MQTT.fx客户端向节点发送数据

前面章节介绍了通过MQTT如何订阅节点的上行数据Uplink以及如何向节点下发数据Downlink,节点还有其他三种类型的数据,分别是Join、Ack和Status。其中Join是节点入网时的信息,Ack是向节点下发数据之后节点回复的确认信息,Status是节点的电池电量信息。

下面将分别介绍这五种数据的具体格式和含义。

 

#Uplink

{

  "applicationID": "1", // 节点所属应用的id

  "applicationName": "test-app", // 节点所属应用的名称

  "devEUI": "3637343457387e11", // 节点的devEUI

  "deviceName": "dev-5205", // 节点名称

  "timestamp": 1592730721, // 接收到节点数据的Unix时间戳 

  "fCnt": 6,

  "fPort": 2,

  "data": "AQIDBA==", // base64编码后的数据,解码之后就是节点实际上发的数据

  "data_encode": "base64", // 数据的编码类型

  "adr": true, // 节点是否开启了adr

  "rxInfo": [ // 所有接收到节点数据的网关信息

​    {

​      "gatewayID": "d896e0fff010611e", // 网关的gateway_id

​      "loRaSNR": 13.3, // 当前网关的信噪比

​      "rssi": -71, // 当前网关的RSSI

​      "location": { // 对应网关的经纬度以及海拔信息

​        "latitude": 0,

​        "longitude": 0,

​        "altitude": 0

​      }

​    }

  ],

  "txInfo": {

​    "frequency": 486300000, // 节点发送数据使用的的频率

​    "dr": 2 // 节点当前的data rate

  }

}

 

#Downlink

{

  "devEUI":"3637343457387e11", // 节点的devEUI信息

  "confirmed": true, // This dl pkt need confirm or not.

  "fPort": 2, // The port will be used for sending this packet

  "data": "AgAAAA==" // 发送给节点的数据,经过base64编码

}

 

#Join

{

  "applicationID": "1",

   "applicationName": "test-app",

  "deviceName": "dev-5205",

  "devEUI": "3637343457387e11",

  "devAddr": "02000001" // Join成功之后分配给节点的短地址

}

 

#Ack

只有服务器给节点下发了confirmed类型的数据后,节点才会回复Ack。

注意:节点不一定立即回复Ack,Ack可能会在节点下一次发送上行数据时携带。

{

  "applicationID": "1",

  "applicationName": "test-app",

  "deviceName": "dev-5205",

  "devEUI": "3637343457387e11",

  "acknowledged": true, 

  "fCnt": 7

}

 

#Device Status

{

  "applicationID": "1",

  "applicationName": "test-app",

  "deviceName": "dev-5205",

  "devEUI": "3637343457387e11",

  "battery": 254, // 电池剩于电量的分级。254表示电源满电状态,1表示电池电量即将耗尽。

  "margin": 8, // 是最近一次成功接收DevStatusReq命令的解调信噪比

  "externalPowerSource": false, // 是否使用了额外的电源

  "batteryLevelUnavailable": false, // 节点的电量级别是否有效

  "batteryLevel": 100 // batteryLevelUnavailabl为true的情况下,batteryLevel表示电量百分比

}

 

#程序示例

以下是使用python代码调用MQTT订阅节点的上行数据并将对应内容打印出来,每收到一条上行数据,程序会主动向节点发送一个下行数据,内容是“Hello rak”。使用代码前请仔细阅读代码注释。

以下源码基于python3运行环境,在运行代码前,需要使用命令pip3 install paho-mqtt安装依赖库。

 

#!/usr/bin/env python 



import json

import base64

import paho.mqtt.client as mqtt

from datetime import datetime

 

\# mqtt服务器IP

mqtt_ip = '111.230.247.253'

\# mqtt服务器端口

mqtt_port = 1883

\# mqtt用户名

mqtt_username = 'rakwireless'

\# mqtt密码

mqtt_password = 'rakwireless.com'

\# mqtt订阅topic。该topic可以订阅所有节点信息

mqtt_rx_topic = 'application/+/device/+/rx'

 

\# 将字符串转换为16进制

def str_to_hex(s):

  return r"\x"+r'\x'.join([hex(ord(c)).replace('0x', '') for c in s])

 

\# 一旦订阅到消息,回调此方法

def on_message(mqttc, obj, msg):

  on_print_rak_node_info(msg.payload)

 

\# 打印订阅到的节点信息

def on_print_node_rx_info(json_rx):

  try:

​    devEUI     = json_rx['devEUI']

​    applicationID        = json_rx['applicationID']

​    applicationName  = json_rx['applicationName']

​    deviceName        = json_rx['deviceName']

​    timestamp      = json_rx['timestamp']

​    fCnt           = json_rx['fCnt']

​    fPort           = json_rx['fPort']

​    data       = json_rx['data']

​    data_hex       = str_to_hex(base64.b64decode(data).decode("utf-8"))

​    \# 将时间戳转换为本地时间

​    str_local_time = datetime.fromtimestamp(timestamp)

 

​    print('---------------- devEUI:[%s] rxpk info -------------------' % devEUI)

​    print('+\t applicationName:\t%s' % applicationName)

​    print('+\t applicationID:\t\t%s' % applicationID)

​    print('+\t deviceName:\t\t%s' % deviceName)

​    print('+\t datetime:\t\t%s' % str_local_time)

​    print('+\t fCnt:\t\t\t%d' % fCnt)

​    print('+\t fPort:\t\t\t%d' % fPort)

​    print('+\t data:\t\t\t%s' % data)

​    print('+\t data_hex:\t\t%s' % data_hex)

​    print('----------------------------------------------------------')

 

 

  except Exception as e:

​    print(e)

  finally:

​    pass

 

\# 订阅到节点的数据之后,向节点发送“Hello rak”字符串

def on_print_rak_node_info(payload):

  json_str = payload.decode()

  try:

​    json_rx = json.loads(json_str)

​    on_print_node_rx_info(json_rx)

 

​    dev_eui = json_rx['devEUI']

​    app_id = json_rx['applicationID']

 

​    \# 商业网关默认的tx topic

​    tx_topic = 'application/%s/device/%s/tx' % (app_id, dev_eui)

​    str_hello = "Hello Rak"

 

​    tx_msg = '{"confirmed":true,"fPort":10,"data":"%s" }' % str(base64.b64encode(str_hello.encode("utf-8")), "utf-8")

 

​    \# 发布消息

​    mqttc.publish(tx_topic, tx_msg, qos=0, retain=False)

​    print('Send \'Hello rak\' to node %s' % dev_eui)

 

  except Exception as e:

​    raise e

  finally:

​    pass

 

mqttc = mqtt.Client()

mqttc.on_message = on_message

 

\# 如果没有用户名和密码,请注释改行

mqttc.username_pw_set(mqtt_username, password=mqtt_password)

 

\# 连接mqtt broker,心跳时间为60s

mqttc.connect(mqtt_ip, mqtt_port, 60)

 

mqttc.subscribe(mqtt_rx_topic, 0)

 

mqttc.loop_forever()
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分