DeviceReportController.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : DeviceReportController.py
  4. @Time : 2025/4/8 16:33
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import logging
  10. import time
  11. from datetime import datetime, timezone
  12. from http.client import responses
  13. from django.http import JsonResponse
  14. from django.views import View
  15. from django.core.exceptions import ValidationError
  16. from Model.models import DeviceDailyReport
  17. from Service.DevicePushService import DevicePushService
  18. TIME_LOGGER = logging.getLogger('time')
  19. ERROR_INFO_LOGGER = logging.getLogger('error_info')
  20. class DeviceReportView(View):
  21. def post(self, request, *args, **kwargs):
  22. operation = kwargs.get('operation')
  23. if operation == 'batteryLevel':
  24. return self.handle_battery_report(request.POST)
  25. return JsonResponse(
  26. {'code': 404, 'msg': 'Operation not found'},
  27. status=404
  28. )
  29. def handle_battery_report(self, data):
  30. try:
  31. # 验证并解码设备令牌
  32. etk = data.get('etk')
  33. TIME_LOGGER.info(f'设备电池报告参数:{data}')
  34. if not etk:
  35. raise ValidationError('Missing etk parameter')
  36. uid = DevicePushService.decode_uid(etk, None)
  37. if len(uid) not in (14, 20):
  38. raise ValidationError('Invalid device UID format')
  39. # 数据库操作
  40. n_time = int(time.time())
  41. TIME_LOGGER.info(f'电池电量上报uid:{uid}{data}')
  42. # 参数提取和类型转换
  43. wake_sleep = self.parse_int_param(data, 'pirWakeupCount') + self.parse_int_param(data, 'mqttWakeupCount')
  44. report_params = {
  45. 'human_detection': self.parse_int_param(data, 'humanDetection'),
  46. 'pir_wakeup_count': self.parse_int_param(data, 'pirWakeupCount'),
  47. 'mqtt_wakeup_count': self.parse_int_param(data, 'mqttWakeupCount'),
  48. 'wake_sleep': wake_sleep,
  49. 'working_hours': self.parse_int_param(data, 'workingHours'),
  50. 'battery_level': self.parse_int_param(data, 'batteryLevel'),
  51. 'report_time': n_time - 43200,
  52. 'channel': int(data.get('channel', 1))
  53. }
  54. # 若人体检测、PIR唤醒、MQTT唤醒、工作时长均为0,判定为无效数据,返回失败
  55. if (report_params['human_detection'] == 0
  56. and report_params['pir_wakeup_count'] == 0
  57. and report_params['mqtt_wakeup_count'] == 0
  58. and report_params['working_hours'] == 0
  59. ):
  60. return JsonResponse({
  61. 'code': 0,
  62. 'msg': 'Reporting failed',
  63. 'channel': report_params['channel']
  64. })
  65. # 时间戳验证
  66. report_date = datetime.fromtimestamp(report_params['report_time'], tz=timezone.utc)
  67. DeviceDailyReport.objects.create(
  68. device_id=uid,
  69. type=1,
  70. report_date=report_date,
  71. **report_params,
  72. created_time=n_time,
  73. updated_time=n_time
  74. )
  75. TIME_LOGGER.info(f'设备保存电池报告uid: {uid}')
  76. return JsonResponse({'code': 0, 'msg': 'Report saved successfully', 'channel': report_params['channel']})
  77. except ValidationError as e:
  78. ERROR_INFO_LOGGER.warning(f'Validation error: {e.message}', exc_info=True)
  79. return JsonResponse({'code': 400, 'msg': e.message}, status=400)
  80. except Exception as e:
  81. ERROR_INFO_LOGGER.error(f'Unexpected error: {str(e)}', exc_info=True)
  82. return JsonResponse(
  83. {'code': 500, 'msg': 'Internal server error'},
  84. status=500
  85. )
  86. @classmethod
  87. def parse_int_param(cls, data, param_name):
  88. """辅助方法:安全提取并转换整型参数"""
  89. value = data.get(param_name)
  90. if not value:
  91. raise ValidationError(f'Missing {param_name} parameter')
  92. try:
  93. return int(value)
  94. except ValueError:
  95. raise ValidationError(f'Invalid {param_name} format')