OneNET平臺(tái)HTTP推送服務(wù)接入
在使用OneNET平臺(tái)時(shí),如果我們自己開(kāi)發(fā)應(yīng)用,基本上會(huì)有獲取設(shè)備的上下線信息以及設(shè)備上傳的數(shù)據(jù)點(diǎn)的需求。
為了滿足上述的需求,我們有以下兩種方法:
使用OneNET的HTTP RESTful API輪詢獲取設(shè)備上下線狀態(tài)以及數(shù)據(jù)點(diǎn)
使用OneNET提供的數(shù)據(jù)推送的服務(wù),實(shí)時(shí)推送設(shè)備上下線狀態(tài)以及數(shù)據(jù)點(diǎn)至自己的服務(wù)器。
本篇我主要講解OneNET平臺(tái)的多協(xié)議產(chǎn)品如何使用HTTP推送服務(wù)。其中我在文章演示時(shí)的后臺(tái)開(kāi)發(fā)語(yǔ)言使用python
官方文檔
我們先來(lái)看下OneNET官方關(guān)于HTTP推送的一些說(shuō)明。
平臺(tái)提供數(shù)據(jù)推送功能,可以將平臺(tái)作為客戶端,將相關(guān)信息以HTTP/HTTPS請(qǐng)求的方式,發(fā)送給應(yīng)用服務(wù)器。
其中,相關(guān)信息包括:
- 設(shè)備新增數(shù)據(jù)點(diǎn)消息
- 設(shè)備上下線消息
- 設(shè)備對(duì)于下行命令的應(yīng)答信息(僅限NB設(shè)備)
平臺(tái)發(fā)起的HTTP請(qǐng)求主要包括:
- GET:用于用戶所配置的URL有效性驗(yàn)證
- POST:用于推送新增數(shù)據(jù)點(diǎn)消息、設(shè)備上下線消息以及設(shè)備對(duì)于下行命令的應(yīng)答信息
推送服務(wù)提供數(shù)據(jù)過(guò)濾功能,用戶可以以數(shù)據(jù)流模板為過(guò)濾條件,過(guò)濾掉例如設(shè)備的頻繁的周期性上報(bào)等大量時(shí)間不敏感數(shù)據(jù),只推送用戶自己關(guān)心的實(shí)時(shí)性要求較高的數(shù)據(jù)。

推送功能提供數(shù)據(jù)壓縮的功能,用戶可以設(shè)置數(shù)據(jù)量以及時(shí)間的壓縮方式,將一定時(shí)間內(nèi)的一定量的多包單信息報(bào)文,合并成為一包包含多條信息的json數(shù)據(jù),可以大大減少應(yīng)用服務(wù)器的處理壓力。

OneNET配置演示
下面,我們直接進(jìn)行演示,這里我基于Modbus協(xié)議的產(chǎn)品(其它協(xié)議使用方法是一樣的)進(jìn)行演示。
服務(wù)配置指南

點(diǎn)擊OneNET控制臺(tái)左側(cè)列表的"數(shù)據(jù)推送\HTTP推送"

消息推送的控制頁(yè)面如下

接下來(lái),我們首先添加一條全局推送。

啟動(dòng)web服務(wù)
添加全局推送就是要添加一個(gè)支持OneNET相應(yīng)開(kāi)發(fā)規(guī)則的URL,首先我們先準(zhǔn)備一個(gè)能正常訪問(wèn)的URL,比如我這里的:
http://IP:8001/he/data/push/global
**一定要先確保該URL鏈接能 正常訪問(wèn)、正常訪問(wèn)、正常訪問(wèn)! **

我此時(shí)的python源碼為:
from flask import Flask
from flask import request
import hashlib
import base64
app = Flask(__name__)
# OneNET全局推送鏈接
@app.route("/he/data/push/global", methods=['GET'])
def he_data_push_global():
return 'Hello IOT'
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True,port = 8001)
點(diǎn)擊"添加全局推送"

填寫(xiě)相關(guān)的信息:
URL:http://IP:8001/he/data/push/global
Token:token
消息加密方式:明文模式
數(shù)據(jù)推送:全部數(shù)據(jù)流

然后點(diǎn)擊"添加"按鈕,此時(shí)OneNET會(huì)彈出如下信息:

大概的意思是"鑒權(quán)失敗,驗(yàn)證Token失敗"。同時(shí),當(dāng)你點(diǎn)擊"添加"按鈕后,你可以看到你填寫(xiě)的URL會(huì)接收到如下一個(gè)請(qǐng)求:
GET /onenet?msg=LeoTAq&signature=/7hXrr3IpM538Z1uHvxSlA==&nonce=B0k7pDoe

開(kāi)發(fā)指南
可以看到URL后面攜帶了三個(gè)參數(shù)msg、signature、nonce,好了,這就要涉及到OneNET URL驗(yàn)證的問(wèn)題了。
在使用推送服務(wù)時(shí),OneNET作為客戶端,而用戶的第三方應(yīng)用是作為服務(wù)器,第三方應(yīng)用需要支持URL驗(yàn)證以及數(shù)據(jù)接收兩部分服務(wù)。

用戶在配置頁(yè)面完成配置并點(diǎn)擊“添加”時(shí),OneNET平臺(tái)會(huì)向填寫(xiě)URL地址發(fā)送HTTP GET請(qǐng)求進(jìn)行URL驗(yàn)證,請(qǐng)求形式示例如下:
http://url?msg=xxx&nonce=xxx&signature=xxx
其中,url為用戶在頁(yè)面配置時(shí)填寫(xiě)的URL,nonce、msg、signature用于URL及token的驗(yàn)證
token驗(yàn)證過(guò)程如下:
- 將配置頁(yè)面中配置的token與URL中的nonce、msg的值計(jì)算MD5,并且編碼為Base64字符串值
- 將上一步中Base64字符串值通過(guò)URL Decode計(jì)算后的值與請(qǐng)求參數(shù)signature的值進(jìn)行對(duì)比,如果相等則表示token驗(yàn)證成功
- 如果token驗(yàn)證成功,返回msg參數(shù)值,表示URL驗(yàn)證通過(guò)。
但是,還有一點(diǎn),OneNET作了特別說(shuō)明:
如果用戶不想驗(yàn)證token,可以選擇跳過(guò)MD5計(jì)算過(guò)程,直接返回msg參數(shù)值
也就是說(shuō),只要你的URL返回請(qǐng)求中的msg值,那就說(shuō)明URL驗(yàn)證通過(guò)。我們先不對(duì)token進(jìn)行校驗(yàn),我們簡(jiǎn)單一點(diǎn),直接獲取并返回URL中的msg參數(shù)。流程跑通之后,我們?cè)傺芯縯oken驗(yàn)證的問(wèn)題。
如下,我修改了服務(wù)端的Python代碼:
@app.route("/he/data/push/global", methods=['GET'])
def he_data_push_global():
msg = request.args.get('msg') or None
signature = request.args.get('signature') or None
nonce = request.args.get('nonce') or None
if not all([msg, signature, nonce]):
return 'invalid parameter'
return msg
然后再點(diǎn)擊"添加"按鈕,

此時(shí)可以看到,全局推送URL添加成功。
數(shù)據(jù)推送的內(nèi)容
設(shè)備上下線信息
設(shè)備新增數(shù)據(jù)點(diǎn)消息
OneNET平臺(tái)以HTTP POST請(qǐng)求形式向第三方平臺(tái)URL地址推送數(shù)據(jù),第三方平臺(tái)接收到數(shù)據(jù)后需要返回 HTTP 200,否則OneNET會(huì)認(rèn)為此次推送無(wú)效并重試。
推送數(shù)據(jù)相關(guān)信息以JSON串的形式置于HTTP請(qǐng)求中的body部分,其中各個(gè)字段的含義如下:

既然OneNET是以POST形式推送數(shù)據(jù),那么我們就得在我們服務(wù)器指定的URL支持POST連接,我修改服務(wù)器端代碼如下:
@app.route("/he/data/push/global", methods=['GET', 'POST'])
def he_data_push_global():
if request.method == 'POST':
print('**** Receive Post Data *****')
data = request.data.decode('utf-8')
print(data)
return 'POST SUCCESS'
msg = request.args.get('msg') or None
signature = request.args.get('signature') or None
nonce = request.args.get('nonce') or None
if not all([msg, signature, nonce]):
return 'invalid parameter'
return msg
服務(wù)端沒(méi)有做什么內(nèi)容,只是打印輸出POST傳遞過(guò)來(lái)的Body數(shù)據(jù)。

