Selaa lähdekoodia

添加Alexa使用MQTT下发消息的接口

locky 4 vuotta sitten
vanhempi
commit
22640d0f30
3 muutettua tiedostoa jossa 102 lisäystä ja 10 poistoa
  1. 94 6
      Controller/IotCoreController.py
  2. 2 2
      Object/IOTCore/IotObject.py
  3. 6 2
      Object/ResponseObject.py

+ 94 - 6
Controller/IotCoreController.py

@@ -1,13 +1,16 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+import os
 import hashlib
 import json
 import time
 import uuid
-
 import boto3
-from django.views import View
+import requests
 
+from django.views import View
+from Ansjer.config import BASE_DIR
+from base64 import b64encode, encodebytes
 from Controller.DeviceConfirmRegion import Device_Region
 from Model.models import Device_User, Device_Info, iotdeviceInfoModel, UIDCompanySerialModel, \
     SerialNumberModel
@@ -16,6 +19,8 @@ from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
 
+import OpenSSL.crypto as ct
+
 
 class IotCoreView(View):
 
@@ -37,6 +42,8 @@ class IotCoreView(View):
 
         if operation == 'createKeysAndCertificate':
             return self.create_keys_and_certificate(request_dict, response, request)
+        if operation == 'requestPublishMessage':
+            return self.request_publish_message(request_dict, response, request)
         elif operation == 'thingRegroup':
             return self.thing_regroup(request_dict, response, request)
         else:
@@ -47,14 +54,13 @@ class IotCoreView(View):
             else:
                 return response.json(404)
 
-
     # CVM注册  :正使用
     def create_keys_and_certificate(self, request_dict, response, request):
         serial_number = request_dict.get('serial_number', None)
         serial_number_code = request_dict.get('serial_number_code', None)
         token = request_dict.get('token', None)
         time_stamp = request_dict.get('time_stamp', None)
-        device_version = request_dict.get('device_version', None).replace('.', '_') # 物品组命名不能包含'.'
+        device_version = request_dict.get('device_version', None).replace('.', '_')  # 物品组命名不能包含'.'
         language = request_dict.get('language', None)
 
         if serial_number and token and time_stamp and serial_number_code and device_version and language:
@@ -79,7 +85,7 @@ class IotCoreView(View):
                 region_id = Device_Region().get_device_region(ip)
 
                 iotClient = IOTClient(region_id)
-                res = iotClient.create_keys_and_certificate(serial_number, thingGroup)
+                res = iotClient.create_keys_and_certificate(serial_number, thingGroup, response)
                 nowTime = int(time.time())
                 token_iot_number = hashlib.md5((str(uuid.uuid1()) + str(nowTime)).encode('utf-8')).hexdigest()
 
@@ -142,7 +148,7 @@ class IotCoreView(View):
         region_id = Device_Region().get_device_region(ip)
 
         thingName = 'Ansjer_Device_' + serial_number
-        new_thingGroupName = (device_version + '_' + language).replace('.', '_')    # 物品组命名不能包含'.'
+        new_thingGroupName = (device_version + '_' + language).replace('.', '_')  # 物品组命名不能包含'.'
         # 调试参数
         # thingName = 'Ansjer_Device_00EBEX'
         # new_thingGroupName = 'C1Pro_V1_0_1_cn'
@@ -191,3 +197,85 @@ class IotCoreView(View):
 
         else:
             return response.json(444)
+
+    def request_publish_message(self, request_dict, response, request):
+        UID = request_dict.get('UID', None)
+        MSG = request_dict.get('MSG', None)
+
+        if not all([UID, MSG]):
+            return response.json(444)
+
+        try:
+            # 获取检查uid的序列号,如果没有序列号,不使用MQTT下发消息
+            device_info_qs = Device_Info.objects.filter(UID=UID).values('serial_number')
+            serial_number = device_info_qs[0]['serial_number']
+            if serial_number == '':
+                return response.json(10043)
+
+            # 获取数据组织将要请求的url
+            thing_name = 'Ansjer_Device_' + serial_number
+            iot = iotdeviceInfoModel.objects.filter(thing_name__contains=thing_name).values('thing_name', 'endpoint',
+                                                                                            'token_iot_number')
+            thing_name = iot[0]['thing_name']  # IoT core上的物品名: Ansjer_Device_+序列号+企业编码
+            endpoint = iot[0]['endpoint']
+            Token = iot[0]['token_iot_number']
+            # Token = '297a601b3925e04daab5a60280650e09'
+            topic_name = thing_name + '_rtsp_topic'
+
+            # rtsp://rtsp.zositech.org:8554/ZFdqWldXRFpMTkVaYVZEaEJXRXhUV0RFeE1VRT1B
+            # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
+            # https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
+            # POST请求url来发布消息
+            url = 'https://{}/topics/{}?rtsp_command={}'.format(endpoint, topic_name, MSG)
+            authorizer_name = 'Ansjer_Iot_Auth'
+            signature = self.rsa_sign(Token)  # Token签名
+            headers = {'x-amz-customauthorizer-name': authorizer_name, 'Token': Token,
+                       'x-amz-customauthorizer-signature': signature}
+            params = {'rtsp_command': MSG}
+            r = requests.post(url=url, headers=headers, json=params, timeout=2)
+            if r.status_code == 200:
+                return response.json(0)
+            else:
+                # print('发布失败')
+                return response.json(10044)
+        except Exception as e:
+            # print(e)
+            return response.json(500, repr(e))
+
+    def rsa_sign(self, Token):
+        # 私钥签名Token
+        private_key_file = '''-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA5iJzEDPqtGmFMggekVro6C0lrjuC2BjunGkrFNJWpDYzxCzE
+X5jf4/Fq7hcIaQd5sqHugDxPVollSLPe9zNilbrd0sZfU+Ed8gRVuKW9KwfE9XFr
+L0pt6bKRQ0IIRfiZ9TuR0tsQysvcO1GZSXcYfPue3tGM1zOnWFThWDqZ06+sOxzt
+RMRl4yNfbpCG4MfxG3itNXOfrjZv2OMLSXrxmzubSvRpUYSvQPs4fm9302SAnySY
+0MKzx6H6528ZQm/IDDSZy6EmNBIyTRDfxC56vnYcXvqedAQh7jJnjdvt6Q4MhASH
+eIYi1FBSdu2NT6wgpnrqXzx5pq9kR/lnsLID0wIDAQABAoIBAQCiF4GT1/1oNSpr
+ouxk1PNXFPWFUsVGD8mAwVJmx//eiY7MjfuCmdqYYmI+cFqsH2fIOeYSzGfVO9Dq
+9EYHN1oovAWhf7eFDPpajFMUSyiCNmazub8VAAeKowtNpCTPo9pMsDh1m3aoYA4u
+ebrN0+Sbo16y8kWRDgDAZoiR7DSMs8lczk16hwfv5mw8XpNDbaL3Coi4Koe2S1Yh
+2SX3vWFlpd7qF1ZYXuZIp+b8JPrV7n9eUKoFgzj0gqgwQK80CoexIjiOrNMPvkQa
+q+8kCvFjAzKxOK7e8gjM8lMRiGodb61kmYZkkJzFwWO4EaGbl34lfVECd1Ixp3tF
+be0OWAGBAoGBAPSteXDzzToD8ovM7LL11x0jWwI6HOiHu89kZtW566rIezjWBuA2
+TxrcYKM3h9jQRXS3CsMdoIv6XGk5lqM8ADtjn23FBWe/THYLh8bm8JOgh5RRWQDg
+SvkLfi9Ih2mM4NJfmuuDOh3Nze2efLM7+kOZWUQwF2Zx9mL5jvRBk351AoGBAPDI
+sYmT2Li+i5+0vykA2m5uPF8ZOW8BGtAfCZv0suW7BNzSgin78g9WapRd/4p0NNiL
+/nVMqPPCpd1akCUpV+GDWQt0hV+HZjxANE0KWhciQRyo2qvo51j8SWILJSgh0tXC
+aTF8qt6oGw3VN3m57vKhbrlDaz0J/NDJFci6msAnAoGBAOuG6bXPGijUj+//DYKf
+n7jOxdZ49kboEePrtAncdHzri6IEdI3z+WXT6bpzw/LzWUimwldb96WHFNm9s8Hi
+Ch8hIODbnP5naUTgiIzw1XhmONyPCewL/F+LrqX5XVA/alNX8JrwsUrrR2WLAGLQ
+Q3I69XDsEjptTU2tCO0bCs3ZAoGBAJ2lCHfm0JHET230zONvp5N9oREyVqQSuRdh
++syc3TQDyh85w/bw+X6JOaaCFHj1tFPC9Iqf8k4GNspCLPXnp54CfR4+38O3xnvU
+HWoDSRC0YKT++IxtJGriYrlKSr2Hx54kdvLriIPW1D+uRW/xCDza7L9nIKMKEvgv
+b4/IfOEpAoGAeKM9Te7T1VzlAkS0CJOwanzwYV/zrex84WuXxlsGgPQ871lTs5AP
+H1QLfLfFXH+UVrCEC2yv4eml/cqFkpB3gE5i4MQ8GPVIOSs5tsIyl8YUA03vdNdB
+GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
+-----END RSA PRIVATE KEY-----'''
+        # 使用密钥文件方式
+        # private_key_file_path = os.path.join(BASE_DIR, 'static/iotCore/private.pem')#.replace('\\', '/')
+        # private_key_file = open(private_key_file_path, 'r')
+        private_key = ct.load_privatekey(ct.FILETYPE_PEM, private_key_file)
+        signature = ct.sign(private_key, Token.encode('utf8'), 'sha256')
+        signature = encodebytes(signature).decode('utf8').replace('\n', '')
+        # print('signature:', signature)
+        return signature

+ 2 - 2
Object/IOTCore/IotObject.py

@@ -69,7 +69,7 @@ class IOTClient(IOTObject):
         }
         return res
 
-    def create_keys_and_certificate(self, serial_number, thingGroup):
+    def create_keys_and_certificate(self, serial_number, thingGroup, response):
         try:
             result = self.client.create_keys_and_certificate(setAsActive=True)
             res = {
@@ -177,4 +177,4 @@ class IOTClient(IOTObject):
             return res, parameters
         except Exception as e:
             print(e)
-            # return response.json(500, repr(e))
+            return response.json(500, repr(e))

+ 6 - 2
Object/ResponseObject.py

@@ -95,7 +95,9 @@ class ResponseObject(object):
             10039: 'Activation code has been used',
             10040: 'Invalid activation code',
             10041: 'This device has purchased a domestic cloud storage package, and cannot purchase a foreign cloud storage package',
-            10042: 'The device has registered a certificate'
+            10042: 'The device has registered a certificate',
+            10043: 'The device does not have a serial number',
+            10044: 'Request to publish MQTT topic message failed',
         }
         data_cn = {
             0: '成功',
@@ -185,7 +187,9 @@ class ResponseObject(object):
             10039: '激活码已被使用过',
             10040: '无效激活码',
             10041: '此设备已购买过国内云存套餐,无法购买国外云存套餐',
-            10042: '此设备已注册证书'
+            10042: '此设备已注册证书',
+            10043: '此设备没有序列号',
+            10044: '请求发布MQTT主题消息失败',
         }
         if self.lang == 'cn':
             msg = data_cn