# -*- 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') # 数据库操作 n_time = int(time.time()) TIME_LOGGER.info(f'电池电量上报uid:{uid}{data}') # 参数提取和类型转换 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': n_time - 43200, 'channel': int(data.get('channel', 1)) } # 若人体检测、PIR唤醒、MQTT唤醒、工作时长均为0,判定为无效数据,返回失败 if (report_params['human_detection'] == 0 and report_params['pir_wakeup_count'] == 0 and report_params['mqtt_wakeup_count'] == 0 and report_params['working_hours'] == 0 ): return JsonResponse({ 'code': 0, 'msg': 'Reporting failed', 'channel': report_params['channel'] }) # 时间戳验证 report_date = datetime.fromtimestamp(report_params['report_time'], tz=timezone.utc) 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', 'channel': report_params['channel']}) 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')