197 lines
6.2 KiB
Python
197 lines
6.2 KiB
Python
import time
|
||
from concurrent.futures import ThreadPoolExecutor
|
||
|
||
import requests
|
||
from enum import Enum
|
||
from typing import Optional, Dict, Any
|
||
|
||
|
||
class DeviceStatus(Enum):
|
||
"""设备状态枚举"""
|
||
NORMAL = 0
|
||
ABNORMAL = 1
|
||
|
||
|
||
class ErrorCode(Enum):
|
||
"""错误代码枚举"""
|
||
EMERGENCY_STOP = 1
|
||
EQUIPMENT_ERROR = 2
|
||
|
||
|
||
class AndonEndpoint(Enum):
|
||
"""API端点枚举"""
|
||
HEARTBEAT = "/heartbeat"
|
||
JOB_START = "/job_start"
|
||
JOB_END = "/job_end"
|
||
JOB_ERROR = "/job_error"
|
||
CALL = "/call"
|
||
|
||
|
||
class SimpleAndonSender:
|
||
"""简化版 Andon 发送器"""
|
||
|
||
def __init__(self, server_ip: str = "192.168.2.1", port: int = 5100, timeout: int = 5):
|
||
self.base_url = f"http://{server_ip}:{port}"
|
||
self.timeout = timeout
|
||
|
||
# 状态记录
|
||
self.last_start: Optional[int] = None
|
||
self.last_end: Optional[int] = None
|
||
self.error_status = True
|
||
self.stop_status = True
|
||
self.call_status = True
|
||
|
||
# 消息队列
|
||
self.thread_pool = ThreadPoolExecutor(max_workers=5, thread_name_prefix="AndonSender")
|
||
|
||
# 会话对象,支持连接池
|
||
self.session = requests.Session()
|
||
|
||
def send_mes_thread(self, m_values, device_id=1):
|
||
|
||
self.thread_pool.submit(self.send_all_status, device_id, m_values)
|
||
|
||
def send_all_status(self, device_id: int, m_values: list) -> None:
|
||
"""发送所有状态"""
|
||
print("发送心跳")
|
||
self._post(AndonEndpoint.HEARTBEAT, {"id": device_id, "status": 1})
|
||
|
||
# 解析状态值
|
||
status = self._parse_status_values(m_values)
|
||
print(status)
|
||
|
||
# 处理作业状态
|
||
self._handle_job_status(device_id, status)
|
||
|
||
# 处理信号状态(按优先级)
|
||
self._handle_signal_status(device_id, status)
|
||
|
||
def _parse_status_values(self, m_values: list) -> Dict[str, int]:
|
||
"""解析状态值"""
|
||
return {
|
||
'start': int(m_values[1]), # 开始工作状态位
|
||
'end': int(m_values[12]), # 结束工作状态位
|
||
'stop': int(m_values[11]), # 急停状态位
|
||
'call': int(m_values[10]), # 呼叫状态位
|
||
'error': int(m_values[2]) # 异常状态位
|
||
}
|
||
|
||
def _handle_job_status(self, device_id: int, status: Dict[str, int]) -> None:
|
||
"""处理作业状态"""
|
||
# 开始工作检测
|
||
if status['start'] == 1 and self.last_start != 1:
|
||
print("发送作业开始")
|
||
self._post(AndonEndpoint.JOB_START, {"id": device_id, "elapsed_time": 0})
|
||
self.last_start = 1
|
||
|
||
# 结束工作检测
|
||
if status['end'] == 1:
|
||
print("发送作业结束")
|
||
self._post(AndonEndpoint.JOB_END, {"id": device_id})
|
||
self.last_start = 0
|
||
self.last_end = 0
|
||
|
||
def _handle_signal_status(self, device_id: int, status: Dict[str, int]) -> None:
|
||
"""处理信号状态(按优先级:呼叫 > 异常 > 急停)"""
|
||
call_handled = self._handle_call_status(device_id, status['call'])
|
||
|
||
if not call_handled:
|
||
error_handled = self._handle_error_status(device_id, status['error'])
|
||
|
||
if not error_handled:
|
||
self._handle_stop_status(device_id, status['stop'])
|
||
|
||
def _handle_call_status(self, device_id: int, call_value: int) -> bool:
|
||
"""处理呼叫状态"""
|
||
if call_value == 1:
|
||
print("发送呼叫")
|
||
self._post(AndonEndpoint.CALL, {"id": device_id, "call_status": 1})
|
||
self.call_status = True
|
||
return True
|
||
elif call_value == 0 and self.call_status:
|
||
print("发送呼叫复位")
|
||
self._post(AndonEndpoint.CALL, {"id": device_id, "call_status": 0})
|
||
self.call_status = False
|
||
return False
|
||
|
||
def _handle_error_status(self, device_id: int, error_value: int) -> bool:
|
||
"""处理异常状态"""
|
||
if error_value == 1:
|
||
print("发送异常")
|
||
self._post(AndonEndpoint.JOB_ERROR, {
|
||
"id": device_id,
|
||
"error_type": 1,
|
||
"error_code": ErrorCode.EQUIPMENT_ERROR.value
|
||
})
|
||
self.error_status = True
|
||
return True
|
||
elif error_value == 0 and self.error_status:
|
||
print("发送异常复位")
|
||
self._post(AndonEndpoint.JOB_ERROR, {
|
||
"id": device_id,
|
||
"error_type": 0,
|
||
"error_code": ErrorCode.EQUIPMENT_ERROR.value
|
||
})
|
||
self.error_status = False
|
||
return False
|
||
|
||
def _handle_stop_status(self, device_id: int, stop_value: int) -> bool:
|
||
"""处理急停状态"""
|
||
if stop_value == 1:
|
||
print("紧急停止")
|
||
self._post(AndonEndpoint.JOB_ERROR, {
|
||
"id": device_id,
|
||
"error_type": 1,
|
||
"error_code": ErrorCode.EMERGENCY_STOP.value
|
||
})
|
||
self.stop_status = True
|
||
return True
|
||
elif stop_value == 0 and self.stop_status:
|
||
print("紧急停止复位")
|
||
self._post(AndonEndpoint.JOB_ERROR, {
|
||
"id": device_id,
|
||
"error_type": 0,
|
||
"error_code": ErrorCode.EMERGENCY_STOP.value
|
||
})
|
||
self.stop_status = False
|
||
return False
|
||
|
||
def _post(self, endpoint: AndonEndpoint, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||
"""发送POST请求"""
|
||
url = f"{self.base_url}{endpoint.value}"
|
||
|
||
try:
|
||
response = self.session.post(url, json=data, timeout=self.timeout)
|
||
response.raise_for_status() # 如果状态码不是200,抛出异常
|
||
return response.json()
|
||
except Exception as e:
|
||
print(f"发送失败到 {url}: {e}")
|
||
return None
|
||
|
||
|
||
if __name__ == '__main__':
|
||
"""主函数 - 监听键盘输入并调用自定义方法"""
|
||
andon_sender = SimpleAndonSender(server_ip='127.0.0.1', port=5100)
|
||
# device_id = 1 # 默认设备ID
|
||
"""
|
||
0000000000000
|
||
|
||
# stop
|
||
0000000000010
|
||
|
||
# error
|
||
0010000000000
|
||
|
||
#
|
||
0000000000001
|
||
|
||
0100000000000
|
||
|
||
"""
|
||
|
||
# while True:
|
||
# cmd = input("> ").strip()
|
||
# print(cmd)
|
||
# andon_sender.send_mes_thread(cmd)
|
||
# time.sleep(1)
|