Dish_Recognition/service/device_status.py

100 lines
3.0 KiB
Python

# 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 '设备状态未上报'