DeviceReportController.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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 django.http import JsonResponse
  13. from django.views import View
  14. from django.core.exceptions import ValidationError
  15. from Model.models import DeviceDailyReport
  16. from Service.DevicePushService import DevicePushService
  17. TIME_LOGGER = logging.getLogger('time')
  18. ERROR_INFO_LOGGER = logging.getLogger('error_info')
  19. class DeviceReportView(View):
  20. def post(self, request, *args, **kwargs):
  21. operation = kwargs.get('operation')
  22. if operation == 'batteryLevel':
  23. return self.handle_battery_report(request.POST)
  24. return JsonResponse(
  25. {'code': 404, 'msg': 'Operation not found'},
  26. status=404
  27. )
  28. def handle_battery_report(self, data):
  29. try:
  30. # 验证并解码设备令牌
  31. etk = data.get('etk')
  32. TIME_LOGGER.info(f'设备电池报告参数:{data}')
  33. if not etk:
  34. raise ValidationError('Missing etk parameter')
  35. uid = DevicePushService.decode_uid(etk, None)
  36. if len(uid) not in (14, 20):
  37. raise ValidationError('Invalid device UID format')
  38. # 参数提取和类型转换
  39. wake_sleep = self.parse_int_param(data, 'pirWakeupCount') + self.parse_int_param(data, 'mqttWakeupCount')
  40. report_params = {
  41. 'human_detection': self.parse_int_param(data, 'humanDetection'),
  42. 'pir_wakeup_count': self.parse_int_param(data, 'pirWakeupCount'),
  43. 'mqtt_wakeup_count': self.parse_int_param(data, 'mqttWakeupCount'),
  44. 'wake_sleep': wake_sleep,
  45. 'working_hours': self.parse_int_param(data, 'workingHours'),
  46. 'battery_level': self.parse_int_param(data, 'batteryLevel'),
  47. 'report_time': self.parse_int_param(data, 'reportTime') - 3600,
  48. 'channel': int(data.get('channel', 1))
  49. }
  50. # 时间戳验证
  51. report_date = datetime.fromtimestamp(report_params['report_time'], tz=timezone.utc)
  52. # 数据库操作
  53. n_time = int(time.time())
  54. DeviceDailyReport.objects.create(
  55. device_id=uid,
  56. type=1,
  57. report_date=report_date,
  58. **report_params,
  59. created_time=n_time,
  60. updated_time=n_time
  61. )
  62. TIME_LOGGER.info(f'设备保存电池报告uid: {uid}')
  63. return JsonResponse({'code': 0, 'msg': 'Report saved successfully'})
  64. except ValidationError as e:
  65. ERROR_INFO_LOGGER.warning(f'Validation error: {e.message}', exc_info=True)
  66. return JsonResponse({'code': 400, 'msg': e.message}, status=400)
  67. except Exception as e:
  68. ERROR_INFO_LOGGER.error(f'Unexpected error: {str(e)}', exc_info=True)
  69. return JsonResponse(
  70. {'code': 500, 'msg': 'Internal server error'},
  71. status=500
  72. )
  73. @classmethod
  74. def parse_int_param(cls, data, param_name):
  75. """辅助方法:安全提取并转换整型参数"""
  76. value = data.get(param_name)
  77. if not value:
  78. raise ValidationError(f'Missing {param_name} parameter')
  79. try:
  80. return int(value)
  81. except ValueError:
  82. raise ValidationError(f'Invalid {param_name} format')