物联网控制台数据同步--客户端Python脚本

2021-07-30 17:59:51 浏览数 (1)

用户的个性化业务需求需要将产品下所有设备上报的数据传输至用户自有的服务器上进行处理,平台提供了 HTTP 转发服务,将设备上报数据实时 POST 到用户的 HTTP 服务器的能力。

客户需要一个HTTP的服务器去接收控制台传过来的设备信息。http服务器需要具备的功能如下:

  • 通过token验证签名
  • 接收控制台同步的设备信息

操作步骤

  1. 登录 物联网开发平台 ,选择【公共实例】或您购买的【标准企业实例】。
  2. 进入项目列表页面,单击【项目 ID】进入项目详情页。
  3. 单击左侧菜单【数据同步】 进入数据同步配置页面,数据同步在未设置时,默认生效状态都为关闭,HTTP 服务地址为空。
  4. 选择需要设置数据同步的产品,单击设备列表中的【设置】,即可设置该产品需要同步的 HTTP 服务地址。

5.弹出设置弹窗,输入需要设置的 HTTP 服务 URL以及token,并单击【保存】。

6.URL 保存成功后,跳转到列表页,可开启该产品的【生效状态】,完成该产品的数据同步配置。

7.如需配置项目中的多个产品,需要逐一对产品进行配置。

demo示例如下:

代码语言:python代码运行次数:0复制
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
import logging
import hashlib
from sys import argv

#用户设置token
token = "test"

class Handler(BaseHTTPRequestHandler):
    def _set_response(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_GET(self):#处理get请求
        logging.info("GET request,nPath: %snHeaders:n%sn", str(self.path), str(self.headers))#打印get请求
        if str(self.path) == "/api/explorer":#判断URL的路径
            a = self.checkSignature(token)
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            self.wfile.write(bytes(a,encoding = "utf8"))#返回验证参数

    def do_POST(self):
        content_length = int(self.headers['Content-Length'])  # <--- Gets the size of data
        post_data = self.rfile.read(content_length)  # <--- Gets the data itself
        logging.info("POST request,nPath: %snHeaders:n%snnBody:n%sn",
                     str(self.path), str(self.headers), post_data.decode('utf-8'))#打印post请求
        if str(self.path) == "/api/explorer":#判断URL路径
            self.explorerHandle(post_data)#处理数据
            return
        data = json.dumps({'code': 404, 'status': 'not found'})
        self.send_response(404)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        self.wfile.write(data.encode('utf-8'))

    def explorerHandle(self, body):#处理数据函数
        # 处理explorer请求
        file = open("device_report.txt", 'w')
        res =json.dumps(json.loads(body),cls=MyEncoder)#转换格式  bytes -> dict
        file.write(res)  # 写入文件

    def checkSignature(self,token):#模拟控制台加密算法生成数字签名与请求中的签名相对比
        signature = self.headers.get_all("signature")[0]
        Echostr = self.headers.get_all("Echostr")
        s = []
        s.append(token)
        s.append(self.headers.get_all("timestamp")[0])
        s.append(self.headers.get_all("nonce")[0])
        s.sort()
        tmpArr = s[0]   s[1]   s[2]
        
        sha1 = hashlib.sha1()
        sha1.update(tmpArr.encode('utf-8'))
        res = sha1.hexdigest()
        
        if res == signature:
            return Echostr[0]
        self.send_response(401)

class MyEncoder(json.JSONEncoder):#将post请求的参数由HTTPMessage转换成json
    def default(self, obj):
        if isinstance(obj, bytes):
            return str(obj, encoding='utf-8');
        return json.JSONEncoder.default(self, obj)


def run(server_class=HTTPServer, handler_class=Handler, port=3000):
    logging.basicConfig(level=logging.INFO)
    server_address = ('0.0.0.0', port)
    httpd = server_class(server_address, handler_class)
    logging.info('Starting httpd...n')
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()
    logging.info('Stopping httpd...n')


if __name__ == '__main__':
   
    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()

用户收到的token验证的get请求如下:

代码语言:javascript复制
GET / HTTP/1.1
Host: **.**.**.**:4443
User-Agent: Go-http-client/1.1
Content-Type: application/json
Echostr: UPWIAFASvDUFcTEE
Nonce: testrance
Signature: abb6c316a8134596d825c5a1295bfa6f7657664d
Timestamp: 1623149590
Accept-Encoding: gzip

用户收到返回的验证参数是:

代码语言:javascript复制
HTTP/1.1 200 OK
Date: Tue, 08 Jun 2021 10:53:10 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8

UPWIAFASvDUFcTEE

用户收到控制台同步的信息如下:

代码语言:javascript复制
{
"payload": {
    "clientToken": "DEP****YAS4-38",
    "method": "report",
    "params": {
        "brightness": 58,
        "color": 2,
        "name": "dev001",
        "power_switch": 1
    }
},
"seq": 1000000000,
"timestamp": 1579055948,
"topic": "$thing/up/property/DEP****YAS4/dev001",
"devicename": "dev001",
"productid": "DEP****YAS4"
}

0 人点赞