一、 概述
為實(shí)現(xiàn)節(jié)能環(huán)保需求,拓?fù)湮磥砉就瞥鲚p量級(jí),使用簡(jiǎn)單的遠(yuǎn)程空調(diào)控制解決方案。該方案集成了現(xiàn)場(chǎng)環(huán)境溫濕度采集功能,設(shè)備管理功能,遠(yuǎn)程控制功能。支持本地自動(dòng)控制模式和遠(yuǎn)程控制模式,自動(dòng)模式下,用記可設(shè)定溫度、濕度閾值,當(dāng)環(huán)境溫濕度達(dá)到設(shè)定值即自動(dòng)打開空調(diào)和風(fēng)機(jī),低于回差值即自動(dòng)關(guān)閉。遠(yuǎn)程模式下,用戶可網(wǎng)頁(yè)或APP直接開啟和關(guān)閉空調(diào)和風(fēng)機(jī),或者在服務(wù)端設(shè)置定時(shí)開關(guān),服務(wù)器會(huì)定時(shí)發(fā)送開關(guān)命令到本地終端設(shè)備。

該方案的后臺(tái)是Thingsboard,使用MQTT協(xié)議連接,根據(jù)官方文檔提供的API,我們實(shí)現(xiàn)了遙測(cè)上報(bào),屬性上報(bào)和下發(fā)響應(yīng),RPC上報(bào)和下發(fā)響應(yīng)。這篇文章用來說明這些API的使用。
二、 Thingsboard MQTT API使用
以下API的數(shù)據(jù)內(nèi)容都使用json格式,如下:
{
"stringKey":"value1",
"booleanKey":true,
"doubleKey":42.0,
"longKey":73,
"jsonKey": {
"someNumber": 42,
"someArray": [1,2,3],
"someNestedObject": {"key": "value"}
}
}
-
遙測(cè)上報(bào)
遙測(cè)是屬性的時(shí)間序列,設(shè)備定時(shí)或不定時(shí)上報(bào)屬性值,服務(wù)器會(huì)更新最新值,同時(shí)會(huì)保存值和時(shí)間到數(shù)據(jù)庫(kù),這樣就能查看該屬性隨時(shí)間的變化情況了。遙測(cè)只能設(shè)備端上報(bào),服務(wù)端只讀不可寫。要上報(bào)遙測(cè),只需要把所有遙測(cè)的值封裝成json格式,用以下主題publish到服務(wù)器即可:
v1/devices/me/telemetry
例如以下python代碼,產(chǎn)生了一個(gè)隨機(jī)溫度值,封裝為一個(gè)字典并轉(zhuǎn)為json格式字符串,然后publish到服務(wù)端。
# MQTT 發(fā)送遙測(cè)
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)
-
屬性上報(bào)和下發(fā)
屬性支持設(shè)備端上報(bào),設(shè)備讀取服務(wù)端屬性值(這里沒用到),服務(wù)端寫屬性值并下發(fā)到設(shè)備端。要上報(bào)和響應(yīng)屬性值,設(shè)備端只需要publish和訂閱以下主題即可:
v1/devices/me/attributes
上報(bào)屬性例子:
# MQTT 發(fā)送數(shù)據(jù)
def mqtt_publish_attributes(data):
dict_attributes = {'attributes':data}
msg = ujson.dumps(dict_attributes)
g_mqtt_client.publish(b"v1/devices/me/attributes", msg)
-
服務(wù)端 RPC
RPC - Remote Process Control,遠(yuǎn)程控制。類似一個(gè)類提供的方法,支持外部調(diào)用(遠(yuǎn)程調(diào)用),須要指定方法名,可以指定0個(gè)或多個(gè)參數(shù),Thingsboard規(guī)定都是json格式。設(shè)備端要先訂閱以下主題,才能收到服務(wù)端的RPC:
v1/devices/me/rpc/request/+
服務(wù)端RPC下發(fā)時(shí),主題名與上面訂閱差不多,最后的'+'號(hào)會(huì)被改為一個(gè)數(shù)字,是一個(gè)遞增流水號(hào),用來標(biāo)識(shí)某次RPC調(diào)用,設(shè)備端響應(yīng)時(shí),應(yīng)當(dāng)publish同一個(gè)流水號(hào),這樣服務(wù)端才知道這個(gè)響應(yīng)與哪個(gè)請(qǐng)求對(duì)應(yīng)。以下是設(shè)備端收到服務(wù)端RPC請(qǐng)求打印出來的內(nèi)容:
mqtt recv topic:b'v1/devices/me/rpc/request/22', msg:b'{"method":"rpc_test","params":{}}'
設(shè)備端響應(yīng)的主題是:
v1/devices/me/rpc/response/$request_id
上面"$request_id"就是請(qǐng)求時(shí)下發(fā)的流水號(hào),例如上面請(qǐng)求時(shí)的流水號(hào)是22,那么響應(yīng)的主題應(yīng)該是:
v1/devices/me/rpc/response/22
-
設(shè)備端 RPC
設(shè)備端有時(shí)也需要向服務(wù)端發(fā)起請(qǐng)求,例如對(duì)時(shí),上報(bào)告警等,主題如下:
v1/devices/me/rpc/request/+
如前面提及,需要把上面的'+'號(hào)改為流水號(hào),下面是上報(bào)告警的例子:
# 發(fā)送告警RPC到服務(wù)端
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))
服務(wù)器端收到的內(nèi)容如下:
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)