# coding=utf-8 """定时向管理系统上报本机设备状态。""" import socket import threading import time from dao.settings import ( DISH_BASE_CODE, DISH_BASE_NAME, DISH_DEVICE_CODE, DISH_DEVICE_NAME, DISH_DEVICE_STATUS_ENABLED, DISH_DEVICE_STATUS_INTERVAL, ) from service.mgmt_client import MgmtApiError, build_device_status_payload, post_device_status try: from importlib.metadata import version as _pkg_version except Exception: _pkg_version = None def _local_ip(): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: s.connect(('8.8.8.8', 80)) return s.getsockname()[0] finally: s.close() except Exception: return '' def _app_version(): return '1.0.0' class DeviceStatusReporter: """后台线程:周期性 POST 设备状态。""" def __init__(self, interval=None, enabled=None): self.interval = int(interval if interval is not None else DISH_DEVICE_STATUS_INTERVAL) if self.interval < 10: self.interval = 10 self.enabled = DISH_DEVICE_STATUS_ENABLED if enabled is None else bool(enabled) self._stop = threading.Event() self._thread = None self._last_ok = None self._last_error = None def start(self): if not self.enabled: print('[INFO] device status reporter disabled') return if self._thread and self._thread.is_alive(): return self._stop.clear() self._thread = threading.Thread(target=self._loop, name='DeviceStatusReporter', daemon=True) self._thread.start() print(f'[OK] device status reporter started (every {self.interval}s)') def stop(self): self._stop.set() def report_once(self, online=True, status=1): payload = build_device_status_payload( device_code=DISH_DEVICE_CODE, device_name=DISH_DEVICE_NAME, base_code=DISH_BASE_CODE, base_name=DISH_BASE_NAME, status=status, online=online, ip=_local_ip(), app_version=_app_version(), ) try: post_device_status(payload) self._last_ok = payload.get('reportedAt') self._last_error = None print(f"[OK] device status reported: {payload.get('deviceCode')} online={online}") return True except MgmtApiError as exc: self._last_error = str(exc) print(f'[WARN] device status report failed: {exc}') return False def _loop(self): # 启动立刻报一次 self.report_once(online=True, status=1) while not self._stop.wait(self.interval): self.report_once(online=True, status=1) def status_text(self): if self._last_error: return f'设备状态上报失败: {self._last_error[:40]}' if self._last_ok: return f'设备状态已上报 {self._last_ok}' return '设备状态未上报'