소스 검색

推送新增电池电量上报接口

zhangdongming 3 달 전
부모
커밋
deed76db0f
3개의 변경된 파일119개의 추가작업 그리고 1개의 파일을 삭제
  1. 2 1
      AnsjerPush/urls.py
  2. 94 0
      Controller/DeviceReportController.py
  3. 23 0
      Model/models.py

+ 2 - 1
AnsjerPush/urls.py

@@ -1,7 +1,7 @@
 from django.urls import path, re_path
 
 from Controller import DetectController, ShadowController, DetectControllerV2, AiController, gatewayController, \
-    PowerWarningController, InitController, CustomizedPushController
+    PowerWarningController, InitController, CustomizedPushController, DeviceReportController
 from Controller.ComboCron import ComboCronPushController
 from Controller.Cron import CronTaskController
 
@@ -19,5 +19,6 @@ urlpatterns = [
     re_path(r'^gatewayService/(?P<operation>.*)$', gatewayController.GatewayView.as_view()),
     re_path('unicom/device/combo/(?P<operation>.*)$', ComboCronPushController.ComboCronPushView.as_view()),
     re_path('customized_push/(?P<operation>.*)', CustomizedPushController.CustomizedPushView.as_view()),
+    re_path('push/device/report/(?P<operation>.*)$', DeviceReportController.DeviceReportView.as_view()),
     re_path('cron/create/(?P<operation>.*)', CronTaskController.CronTaskView.as_view()),
 ]

+ 94 - 0
Controller/DeviceReportController.py

@@ -0,0 +1,94 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : DeviceReportController.py
+@Time    : 2025/4/8 16:33
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import logging
+import time
+from datetime import datetime, timezone
+
+from django.http import JsonResponse
+from django.views import View
+from django.core.exceptions import ValidationError
+
+from Model.models import DeviceDailyReport
+from Service.DevicePushService import DevicePushService
+
+TIME_LOGGER = logging.getLogger('time')
+ERROR_INFO_LOGGER = logging.getLogger('error_info')
+
+
+class DeviceReportView(View):
+    def post(self, request, *args, **kwargs):
+        operation = kwargs.get('operation')
+        if operation == 'batteryLevel':
+            return self.handle_battery_report(request.POST)
+        return JsonResponse(
+            {'code': 404, 'msg': 'Operation not found'},
+            status=404
+        )
+
+    def handle_battery_report(self, data):
+        try:
+            # 验证并解码设备令牌
+            etk = data.get('etk')
+            TIME_LOGGER.info(f'设备电池报告参数:{data}')
+            if not etk:
+                raise ValidationError('Missing etk parameter')
+
+            uid = DevicePushService.decode_uid(etk, None)
+            if len(uid) not in (14, 20):
+                raise ValidationError('Invalid device UID format')
+
+            # 参数提取和类型转换
+            wake_sleep = self.parse_int_param(data, 'pirWakeupCount') + self.parse_int_param(data, 'mqttWakeupCount')
+            report_params = {
+                'human_detection': self.parse_int_param(data, 'humanDetection'),
+                'pir_wakeup_count': self.parse_int_param(data, 'pirWakeupCount'),
+                'mqtt_wakeup_count': self.parse_int_param(data, 'mqttWakeupCount'),
+                'wake_sleep': wake_sleep,
+                'working_hours': self.parse_int_param(data, 'workingHours'),
+                'battery_level': self.parse_int_param(data, 'batteryLevel'),
+                'report_time': self.parse_int_param(data, 'reportTime') - 10800,
+            }
+
+            # 时间戳验证
+            report_date = datetime.fromtimestamp(report_params['report_time'], tz=timezone.utc)
+
+            # 数据库操作
+            n_time = int(time.time())
+            DeviceDailyReport.objects.create(
+                device_id=uid,
+                type=1,
+                report_date=report_date,
+                **report_params,
+                created_time=n_time,
+                updated_time=n_time
+            )
+
+            TIME_LOGGER.info(f'设备保存电池报告uid: {uid}')
+            return JsonResponse({'code': 0, 'msg': 'Report saved successfully'})
+
+        except ValidationError as e:
+            ERROR_INFO_LOGGER.warning(f'Validation error: {e.message}', exc_info=True)
+            return JsonResponse({'code': 400, 'msg': e.message}, status=400)
+        except Exception as e:
+            ERROR_INFO_LOGGER.error(f'Unexpected error: {str(e)}', exc_info=True)
+            return JsonResponse(
+                {'code': 500, 'msg': 'Internal server error'},
+                status=500
+            )
+
+    @classmethod
+    def parse_int_param(cls, data, param_name):
+        """辅助方法:安全提取并转换整型参数"""
+        value = data.get(param_name)
+        if not value:
+            raise ValidationError(f'Missing {param_name} parameter')
+        try:
+            return int(value)
+        except ValueError:
+            raise ValidationError(f'Invalid {param_name} format')

+ 23 - 0
Model/models.py

@@ -3484,3 +3484,26 @@ class PushLog(models.Model):
         db_table = 'push_log'
         verbose_name = '推送日志'
         app_label = 'db2'
+
+
+class DeviceDailyReport(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    device_id = models.CharField(default='', max_length=32, verbose_name='设备ID')
+    type = models.SmallIntegerField(default=0, verbose_name=u'统计类型0:默认1:电耗统计')
+    battery_level = models.IntegerField(default=0, verbose_name='23:59电量百分比')
+    report_date = models.DateTimeField(blank=True, null=True, verbose_name=u'统计日期时间')
+    report_time = models.IntegerField(default=0, verbose_name='设备上报时间戳')
+    human_detection = models.IntegerField(default=0, verbose_name='人形检测次数')
+    working_hours = models.IntegerField(default=0, verbose_name='工作时长/秒')
+    wake_sleep = models.IntegerField(default=0, verbose_name='唤醒休眠次数')
+    pir_wakeup_count = models.IntegerField(default=0, verbose_name='PIR唤醒次数')
+    mqtt_wakeup_count = models.IntegerField(default=0, verbose_name='mqtt唤醒次数')
+    channel = models.IntegerField(default=1, blank=True, verbose_name=u'设备通道')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'device_daily_report'
+        verbose_name = '设备日报记录表'
+        verbose_name_plural = verbose_name
+        app_label = 'db2'