Ver Fonte

增加Alxea的对象检测ChangeReport接口

zhuo há 1 mês atrás
pai
commit
3860d5a080
1 ficheiros alterados com 147 adições e 4 exclusões
  1. 147 4
      controller/deviceStatus.py

+ 147 - 4
controller/deviceStatus.py

@@ -58,6 +58,8 @@ class deviceStatus(TemplateView):
             return self.changeReportSwitch(request_dict)
         elif operation == 'deleteSwitch':
             return self.deleteSwitch(request_dict)
+        elif operation == 'objectDetectionSensorChangeReport':
+            return self.objectDetectionSensorChangeReport(request_dict)
 
     def saveAccessToken(self, request_dict):
         token = request_dict.get("token", '')
@@ -739,7 +741,148 @@ class deviceStatus(TemplateView):
             'content-type': "application/x-www-form-urlencoded",
             'cache-control': "no-cache"
         }
-        res = requests.post(auth_request_url, payload, headers)
-        request_json = res.json()
-        logger.info('--------请求更新token响应{}--------'.format(request_json))
-        return request_json
+        try:
+            res = requests.post(auth_request_url, data=payload, headers=headers, timeout=5)
+            res.raise_for_status()
+            request_json = res.json()
+            logger.info('--------请求更新token响应{}--------'.format(request_json))
+            return request_json
+        except requests.exceptions.RequestException as e:
+            logger.error(f'刷新token请求异常: {e}')
+            return {'error': str(e)}
+
+    def objectDetectionSensorChangeReport(self, request_dict):
+        logger = logging.getLogger('django')
+        logger.info('--------发送ChangeReport事件--------')
+
+        # 获取请求参数
+        uid = request_dict.get('uid')  # 客户端传入的唯一设备标识
+        object_classes = request_dict.get('object_classes', [])
+        cause_type = request_dict.get('cause_type', 'PHYSICAL_INTERACTION')
+        skill_name = request_dict.get('skill_name', 'Anlapus')  # 默认技能名称
+
+        logger.info(f'uid: {uid}, object_classes: {object_classes}')
+
+        if not uid:
+            return JsonResponse({'code': 111, 'msg': '缺少必要参数: uid'})
+
+        try:
+            # 1. 通过UID查询设备信息
+            device = UidRtspModel.objects.filter(uid=uid).first()
+            if not device:
+                logger.error(f'未找到设备信息: uid={uid}')
+                return JsonResponse({'code': 404, 'msg': '设备未注册'})
+
+            user_id = device.user_id
+            endpoint_id = device.uid  # 使用设备UID作为endpoint_id
+
+            # 2. 通过用户ID获取Alexa授权信息
+            alexa_auth = AlexaAuthModel.objects.filter(
+                userID=user_id,
+                skill_name=skill_name
+            ).first()
+
+            if not alexa_auth:
+                logger.error(f'未找到Alexa授权信息: user_id={user_id}, skill={skill_name}')
+                return JsonResponse({'code': 403, 'msg': '未授权Alexa服务'})
+
+            # 3. 检查并刷新access token
+            now_time = int(time.time())
+            if now_time > alexa_auth.expiresTime:
+                res = self.getRefreshToken(alexa_auth.refresh_token, skill_name)
+                if 'error' in res:
+                    logger.error('刷新Token失败')
+                    return JsonResponse({'code': 401, 'msg': 'Token刷新失败'})
+
+                # 更新数据库中的token
+                alexa_auth.access_token = res['access_token']
+                alexa_auth.refresh_token = res['refresh_token']
+                alexa_auth.expiresTime = now_time + 3000
+                alexa_auth.updTime = now_time
+                alexa_auth.save()
+                current_access_token = res['access_token']
+            else:
+                current_access_token = alexa_auth.access_token
+
+            # 4. 构造时间戳
+            time_of_sample = datetime.datetime.now(timezone.utc).isoformat()
+            time_of_sample = time_of_sample.split('.')[0] + 'Z'
+
+            # 5. 构造ChangeReport事件
+            properties = []
+            if object_classes:
+                properties.append({
+                    "namespace": "Alexa.SmartVision.ObjectDetectionSensor",
+                    "name": "objectDetectionClasses",
+                    "value": object_classes,
+                    "timeOfSample": time_of_sample,
+                    "uncertaintyInMilliseconds": 0
+                })
+
+            payload = {
+                "event": {
+                    "header": {
+                        "namespace": "Alexa",
+                        "name": "ChangeReport",
+                        "messageId": str(uuid.uuid4()),
+                        "payloadVersion": "3"
+                    },
+                    "endpoint": {
+                        "scope": {
+                            "type": "BearerToken",
+                            "token": current_access_token
+                        },
+                        "endpointId": endpoint_id
+                    },
+                    "payload": {
+                        "change": {
+                            "cause": {
+                                "type": cause_type
+                            },
+                            "properties": properties
+                        }
+                    }
+                },
+                "context": {
+                    "properties": [{
+                        "namespace": "Alexa.EndpointHealth",
+                        "name": "connectivity",
+                        "value": {"value": "OK"},
+                        "timeOfSample": time_of_sample,
+                        "uncertaintyInMilliseconds": 60000
+                    }]
+                }
+            }
+
+            # 6. 发送到Alexa事件网关
+            api_uri = ALEXA_EVENT_API.get(alexa_auth.alexa_region)
+            if not api_uri:
+                logger.error(f'无效的区域配置: {alexa_auth.alexa_region}')
+                return JsonResponse({'code': 400, 'msg': '区域配置错误'})
+
+            headers = {
+                "Authorization": f"Bearer {current_access_token}",
+                "Content-Type": "application/json"
+            }
+
+            response = requests.post(api_uri, json=payload, headers=headers, timeout=10)
+            logger.info(f'Alexa响应: {response.status_code}, {response.text}')
+
+            if response.status_code == 202:
+                return JsonResponse({'code': 200, 'msg': '事件发送成功'})
+            else:
+                logger.error(f'Alexa返回错误: {response.status_code}, {response.text}')
+                return JsonResponse({
+                    'code': 500,
+                    'msg': 'Alexa服务错误',
+                    'alexa_status': response.status_code,
+                    'alexa_response': response.text
+                })
+
+        except Exception as e:
+            logger.exception(f'处理ChangeReport异常: {str(e)}')
+            return JsonResponse({
+                'code': 500,
+                'msg': f'服务器错误: {str(e)}'
+            })
+