100 lines
3.0 KiB
Python
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 '设备状态未上报'
|