一、 概述
为实现节能环保需求,拓扑未来公司推出轻量级,使用简单的远程空调控制解决方案。该方案集成了现场环境温湿度采集功能,设备管理功能,远程控制功能。支持本地自动控制模式和远程控制模式,自动模式下,用记可设定温度、湿度阈值,当环境温湿度达到设定值即自动打开空调和风机,低于回差值即自动关闭。远程模式下,用户可网页或APP直接开启和关闭空调和风机,或者在服务端设置定时开关,服务器会定时发送开关命令到本地终端设备。
方案说明图
该方案的后台是Thingsboard,使用MQTT协议连接,根据官方文档提供的API,我们实现了遥测上报,属性上报和下发响应,RPC上报和下发响应。这篇文章用来说明这些API的使用。
二、 Thingsboard MQTT API使用
以下API的数据内容都使用json格式,如下:
{
"stringKey":"value1",
"booleanKey":true,
"doubleKey":42.0,
"longKey":73,
"jsonKey": {
"someNumber": 42,
"someArray": [1,2,3],
"someNestedObject": {"key": "value"}
}
}
- 遥测上报
遥测是属性的时间序列,设备定时或不定时上报属性值,服务器会更新最新值,同时会保存值和时间到数据库,这样就能查看该属性随时间的变化情况了。遥测只能设备端上报,服务端只读不可写。要上报遥测,只需要把所有遥测的值封装成json格式,用以下主题publish到服务器即可:
v1/devices/me/telemetry
例如以下python代码,产生了一个随机温度值,封装为一个字典并转为json格式字符串,然后publish到服务端。
# MQTT 发送遥测
def mqtt_send_telemetry():
temp_val = urandom.uniform(18, 35)
dict_telemetry = {'env_temperature': round(temp_val, 1)}
msg = ujson.dumps(dict_telemetry)
g_mqtt_client.publish(b"v1/devices/me/telemetry", msg)
- 属性上报和下发
属性支持设备端上报,设备读取服务端属性值(这里没用到),服务端写属性值并下发到设备端。要上报和响应属性值,设备端只需要publish和订阅以下主题即可:
v1/devices/me/attributes
上报属性例子:
# MQTT 发送数据
def mqtt_publish_attributes(data):
dict_attributes = {'attributes':data}
msg = ujson.dumps(dict_attributes)
g_mqtt_client.publish(b"v1/devices/me/attributes", msg)
- 服务端 RPC
RPC - Remote Process Control,远程控制。类似一个类提供的方法,支持外部调用(远程调用),须要指定方法名,可以指定0个或多个参数,Thingsboard规定都是json格式。设备端要先订阅以下主题,才能收到服务端的RPC:
v1/devices/me/rpc/request/+
服务端RPC下发时,主题名与上面订阅差不多,最后的'+'号会被改为一个数字,是一个递增流水号,用来标识某次RPC调用,设备端响应时,应当publish同一个流水号,这样服务端才知道这个响应与哪个请求对应。以下是设备端收到服务端RPC请求打印出来的内容:
mqtt recv topic:b'v1/devices/me/rpc/request/22', msg:b'{"method":"rpc_test","params":{}}'
设备端响应的主题是:
v1/devices/me/rpc/response/$request_id
上面"$request_id"就是请求时下发的流水号,例如上面请求时的流水号是22,那么响应的主题应该是:
v1/devices/me/rpc/response/22
- 设备端 RPC
设备端有时也需要向服务端发起请求,例如对时,上报告警等,主题如下:
v1/devices/me/rpc/request/+
如前面提及,需要把上面的'+'号改为流水号,下面是上报告警的例子:
# 发送告警RPC到服务端
def mqtt_send_rpc_test():
global g_mqtt_client
TOPIC_REQUEST = b'v1/devices/me/rpc/request/55'
dict_attributes = {}
rtc = RTC().datetime()
rtcString = ("%d-%d-%d %d:%d:%d" % (rtc[0], rtc[1], rtc[2], rtc[4], rtc[5], rtc[6]))
dict_attributes['method'] = "overTemperature"
dict_attributes['params'] = {
"clientId":"CxUFDKHbWy8gLnD6QeGa",
"temperature":65.5,
"temp_warning_flag":True,
"device_rtc":rtcString
}
msg = dict_dump(dict_attributes)
if g_mqtt_client != None or g_mqtt_client.connect_state == True:
g_mqtt_client.send_with_topic(TOPIC_REQUEST, msg.encode())
print("request RPC: topic = {}, msg = {}".format(TOPIC_REQUEST, msg))
服务器端收到的内容如下:
request RPC:
topic = b'v1/devices/me/rpc/request/55',
msg = {"method":"overTemperature", "params":{"device_rtc":"2024-9-21 16:6:34", "clientId":"CxUFDKHbWy8gLnD6QeGa", "temperature":65.5, "temp_warning_flag":true}}
(END)