Files
Feeding_control_system/service/device_monitor_thread.py

149 lines
5.8 KiB
Python

import configparser
from typing import Dict, Union
from icmplib import ping, ICMPLibError
from PySide6.QtCore import QThread, Signal
class DeviceMonitorThread(QThread):
connect_success = Signal(str, int) # 成功信号:设备名称(str) + 延迟毫秒数(int)
connect_failed = Signal(str) # 失败信号:设备名称(str)
state_result = Signal(str, int) # 全局状态(str: normal/warning/error) + 异常设备数量(int)
check_finished = Signal() # 本轮检测结束
def __init__(self, config_path = "config/monitor_config.ini", parent=None):
super().__init__(parent)
# 初始化你的原有配置参数,完全不变
self.config_path = config_path
self.ping_timeout_ms = 2000
self.ping_count = 2
self.check_interval = 10 # 默认检测间隔10秒
self.warning_delay = 30 # 默认的警告的网络延迟(单位: ms)
self.is_stop = False # 线程停止标志位
self.force_check = False # 立即检测标志
def _ping_device(self, ip: str, timeout_ms: int = 2000) -> Union[int, None]:
"""设备连接状态检测"""
try:
response = ping(
ip,
count=self.ping_count,
timeout=timeout_ms / 1000,
privileged=False,
interval=0.1
)
if response.is_alive:
return int(response.avg_rtt)
return None
except ICMPLibError as e:
print(f"IP[{ip}] ICMP异常: {str(e)}")
return None
except Exception as e:
print(f"IP[{ip}] 未知异常: {str(e)}")
return None
def _read_device_config(self) -> Dict[str, str]:
"""读取ini配置文件"""
device_dict = {}
config = configparser.ConfigParser()
try:
config.read(self.config_path, encoding="utf-8")
for section in config.sections():
if "ip" in config[section]:
device_ip = config[section]["ip"].strip()
device_dict[section] = device_ip
except FileNotFoundError:
print(f"配置文件[{self.config_path}]不存在,请检查路径!")
except Exception as e:
print(f"读取配置文件失败: {str(e)}")
return device_dict
def run(self) -> None:
"""网络设备检测"""
print("✅ 设备检测线程已启动")
self.is_stop = False # 重置停止标志位
while True:
# 线程退出
if self.is_stop:
break
# 批量检测所有设备
device_dict = self._read_device_config()
check_result = {} # 所有设备的检测结果
if not device_dict:
print("设备检测线程: 未读取到任何设备配置!")
else:
for device_name, device_ip in device_dict.items():
if self.is_stop:
break
delay_ms = self._ping_device(device_ip, self.ping_timeout_ms)
if delay_ms is not None:
self.connect_success.emit(device_name, delay_ms) # 发送成功信号
else:
self.connect_failed.emit(device_name) # 发送失败信号
check_result[device_name] = delay_ms
# 本轮检测完成
self.check_finished.emit()
# 设备状态统计
self._calc_device_state(check_result)
# 等待指定间隔后,继续下一次检测
# self.msleep(self.check_interval * 1000)
sleep_total_ms = self.check_interval * 1000
sleep_slice_ms = 200 # 每次休眠200ms
sleep_count = int(sleep_total_ms / sleep_slice_ms)
for _ in range(sleep_count):
if self.is_stop: # 每次休眠后检测退出标志
break
if self.force_check:
self.force_check = False
break
self.msleep(sleep_slice_ms)
# ============ 设备状态统计 ============
def _calc_device_state(self, check_result:dict):
offline_count = 0 # 离线设备数
delay_warn_count = 0# 延迟超30ms的设备数
# 遍历结果统计
for delay in check_result.values():
if delay is None:
offline_count += 1
elif delay >= self.warning_delay:
delay_warn_count += 1
# 按优先级判定全局状态
if offline_count > 0:
# 设备异常 → error + 离线(异常)数量
self.state_result.emit("error", offline_count)
elif delay_warn_count > 0:
# 全部在线但有延迟超标 → warning + 延迟超标数量
self.state_result.emit("warning", delay_warn_count)
else:
# 全部在线且延迟都<30ms → normal + 0
self.state_result.emit("normal", 0)
# ============ 修改检测间隔 ============
def set_check_interval(self, interval: int):
"""
修改检测时间间隔
:param interval: 间隔秒数(int)
"""
if isinstance(interval, int) and interval >= 3:
self.check_interval = interval
# ============ 修改警告延迟 ============
def set_warning_delay(self, delay:int):
if isinstance(delay, int) and delay >= 1:
self.warning_delay = delay
# ============ 停止检测线程============
def stop_thread(self):
self.is_stop = True
self.wait()
print("设备检测线程已退出")
# ============ 立即检测============
def force_immediate_check(self):
"""马上执行新一轮设备检测"""
self.force_check = True