VWED_server/docs/sc/设备处理器相关.md

568 lines
15 KiB
Markdown
Raw Normal View History

2025-10-01 15:20:55 +08:00
# 设备处理器模块文档Python 版本)
## 概述
设备处理器模块提供了基于 VDA5050 协议的设备管理框架,支持 MQTT 通信用于监听和处理各类设备AGV小车、门、电梯等的消息并自动转发到指定的 topic。
## 核心概念
### 设备类型 (DeviceType)
系统支持以下设备类型:
- `vehicle`: 小车/AGV
- `door`: 门
- `caller`: 呼叫器
- `lift`: 电梯
- `custom`: 自定义设备
### 设备品牌 (DeviceBrand)
系统支持以下品牌:
- `huarui`: 华睿
- `seer`: 仙工
- `hikrobot`: 海康机器人
- `standard`: 标准协议
- `custom`: 自定义品牌
### 指令类型 (CommandType)
根据设备类型不同,支持的指令类型:
- **小车设备**`order``state``factsheet``instantActions`
- **其他设备**`instantActions`
## API 方法
### 注册并运行设备处理器
```python
VWED.device.register_and_run(
device_ids: List[str],
device_type: str = "vehicle",
brand_name: str = "huarui",
command_type: str = None,
handler: Callable = None,
description: str = ""
)
```
**说明**:批量注册设备处理器,系统会自动:
1. 根据设备品牌和类型生成 MQTT topics
2. 订阅相应的 topics
3. 开始监听消息
4. 消息到达时自动调用处理函数
5. 自动转发处理结果
**参数**
- `device_ids`: List[str] - 设备ID列表必需
- `device_type`: str - 设备类型,默认 "vehicle"
- `brand_name`: str - 设备品牌,默认 "huarui"
- `command_type`: str - 指令类型(必需),如 "order"、"state"、"instantActions"
- `handler`: Callable - 消息处理函数(必需)
- `description`: str - 设备描述信息
**返回值**
- List[str] - 成功注册的设备ID列表
**处理函数格式**
处理函数接收一个 `DeviceMessage` 对象作为参数,并返回一个字典,指示如何处理消息。
```python
def handler(message):
"""
消息处理函数
参数:
message: DeviceMessage对象包含以下属性
- device_id: str - 设备ID
- device_type: DeviceType - 设备类型
- topic: str - 接收消息的topic
- payload: dict - 消息载荷(已解析为字典)
- timestamp: float - 消息时间戳
返回值: dict - 处理结果,支持以下字段:
{
"forward": bool, # 是否转发消息可选默认True
"payload": dict, # 要转发的消息载荷(可选,默认使用原始消息)
"response_topic": str, # 自定义响应topic可选
"response": dict # 自定义响应消息载荷可选需配合response_topic
}
"""
# 处理逻辑
return {"forward": True}
```
**返回值格式约束**
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| forward | bool | 否 | 是否转发消息,默认 True |
| payload | dict | 否 | 转发的消息载荷,默认使用原始消息 |
| response_topic | str | 否 | 自定义响应的 topic |
| response | dict | 否 | 自定义响应的消息载荷,需配合 response_topic |
**注意事项**
- 返回值必须是字典类型
- `payload``response` 必须是字典类型
- 如果提供 `response`,必须同时提供 `response_topic`
### 使用示例
#### 示例1批量注册华瑞小车处理 order 指令
```python
def agv_order_processor(message):
"""处理AGV订单指令"""
VWED.log.info(f"收到订单: 设备 {message.device_id}")
VWED.log.info(f"订单内容: {message.payload}")
# 提取订单信息
order_id = message.payload.get("orderId")
nodes = message.payload.get("nodes", [])
# 可以在这里添加业务逻辑,比如:
# - 验证订单有效性
# - 记录到数据库
# - 通知其他系统
# 直接透传到设备
return {
"forward": True # 使用原始消息转发
}
# 注册处理器
VWED.device.register_and_run(
device_ids=["AGV001", "AGV002", "AGV003"],
device_type="vehicle",
brand_name="huarui",
command_type="order",
handler=agv_order_processor,
description="华瑞小车order指令处理器"
)
```
#### 示例2修改消息后转发
```python
def agv_state_processor(message):
"""处理AGV状态消息添加额外信息后转发"""
state_data = message.payload
# 添加额外的业务信息
enhanced_state = {
**state_data,
"processed_at": VWED.get_current_time(),
"system_status": "online",
"battery_warning": state_data.get("batteryState", {}).get("batteryCharge", 100) < 20
}
# 转发修改后的消息
return {
"forward": True,
"payload": enhanced_state
}
VWED.device.register_and_run(
device_ids=["AGV001", "AGV002"],
device_type="vehicle",
brand_name="huarui",
command_type="state",
handler=agv_state_processor,
description="AGV状态处理器增强版"
)
```
#### 示例3不转发仅记录
```python
def agv_monitor(message):
"""仅监控AGV消息不转发"""
# 记录到数据库
VWED.db.execute_update(
"INSERT INTO agv_logs (device_id, message, created_at) VALUES (?, ?, ?)",
[message.device_id, str(message.payload), VWED.get_current_time()]
)
# 不转发
return {"forward": False}
VWED.device.register_and_run(
device_ids=["AGV001"],
device_type="vehicle",
brand_name="huarui",
command_type="state",
handler=agv_monitor,
description="AGV监控仅记录"
)
```
#### 示例4发送自定义响应
```python
def door_controller(message):
"""门控制器,接收指令后返回确认"""
action = message.payload.get("instantActions", [])
if action:
action_type = action[0].get("actionType")
# 处理开门/关门指令
if action_type == "openDoor":
VWED.log.info(f"门 {message.device_id} 正在开启...")
result = "success"
elif action_type == "closeDoor":
VWED.log.info(f"门 {message.device_id} 正在关闭...")
result = "success"
else:
result = "unknown_action"
# 不转发原始消息,发送自定义响应
return {
"forward": False,
"response_topic": f"devices/door/{message.device_id}/response",
"response": {
"device_id": message.device_id,
"action": action_type,
"result": result,
"timestamp": VWED.get_current_time()
}
}
return {"forward": False}
VWED.device.register_and_run(
device_ids=["DOOR001", "DOOR002"],
device_type="door",
brand_name="huarui",
command_type="instantActions",
handler=door_controller,
description="门设备控制器"
)
```
#### 示例5条件转发
```python
def smart_forwarder(message):
"""根据条件决定是否转发"""
battery = message.payload.get("batteryState", {}).get("batteryCharge", 100)
# 电量低于20%时不转发,发送告警
if battery < 20:
VWED.log.warning(f"设备 {message.device_id} 电量过低: {battery}%")
# 发送告警消息到告警topic
return {
"forward": False,
"response_topic": "alerts/battery/low",
"response": {
"device_id": message.device_id,
"battery": battery,
"alert_level": "critical",
"timestamp": VWED.get_current_time()
}
}
# 正常转发
return {"forward": True}
VWED.device.register_and_run(
device_ids=["AGV001", "AGV002", "AGV003"],
device_type="vehicle",
brand_name="huarui",
command_type="state",
handler=smart_forwarder,
description="智能转发器(低电量告警)"
)
```
### 停止设备处理器
```python
VWED.device.stop_handler(device_id: str)
```
**说明**:停止指定设备处理器的运行
**参数**
- `device_id`: str - 设备ID
**示例**
```python
# 停止设备处理器
VWED.device.stop_handler("AGV001")
```
### 获取运行中的处理器列表
```python
VWED.device.get_running_handlers() -> Dict[str, Any]
```
**说明**:获取所有正在运行的设备处理器信息
**返回值**:包含所有设备处理器状态的字典
**示例**
```python
handlers = VWED.device.get_running_handlers()
VWED.log.info(f"运行中的处理器: {handlers}")
```
### 获取设备处理器状态
```python
VWED.device.get_handler_status(device_id: str) -> Dict[str, Any]
```
**说明**:获取指定设备处理器的运行状态
**参数**
- `device_id`: str - 设备ID
**返回值**:设备处理器状态信息
**示例**
```python
status = VWED.device.get_handler_status("AGV001")
VWED.log.info(f"设备状态: {status}")
```
### 主动发布MQTT消息
```python
await VWED.device.publish_message(topic: str, payload: Any)
```
**说明**:主动向指定 topic 发布 MQTT 消息(异步方法)
**参数**
- `topic`: str - MQTT topic
- `payload`: dict - 消息载荷
**示例**
```python
# 异步发布
await VWED.device.publish_message(
topic="factory/agv/command",
payload={"action": "move", "x": 100, "y": 200}
)
# 或使用同步方式
VWED.device.sync_publish_message(
topic="factory/agv/command",
payload={"action": "move", "x": 100, "y": 200}
)
```
### 获取支持的设备类型
```python
VWED.device.get_device_types() -> List[str]
```
**说明**:获取系统支持的所有设备类型
**返回值**:设备类型列表
**示例**
```python
types = VWED.device.get_device_types()
VWED.log.info(f"支持的设备类型: {types}")
# 输出: ['vehicle', 'door', 'caller', 'lift', 'conveyor', 'sensor', 'robot', 'camera', 'scanner', 'custom']
```
### 获取支持的设备品牌
```python
VWED.device.get_device_brands() -> List[str]
```
**说明**:获取系统支持的所有设备品牌
**返回值**:设备品牌列表
**示例**
```python
brands = VWED.device.get_device_brands()
VWED.log.info(f"支持的设备品牌: {brands}")
# 输出: ['huarui', 'seer', 'quicktron', 'geek', 'mushiny', 'flashhold', 'hikrobot', 'standard', 'custom']
```
## 完整应用示例
### 场景AGV车队管理系统
```python
# AGV订单处理器
def process_agv_order(message):
"""处理AGV订单"""
order_data = message.payload
order_id = order_data.get("orderId")
# 记录订单到数据库
VWED.db.execute_update(
"INSERT INTO agv_orders (device_id, order_id, data, created_at) VALUES (?, ?, ?, ?)",
[message.device_id, order_id, str(order_data), VWED.get_current_time()]
)
VWED.log.info(f"AGV {message.device_id} 收到订单 {order_id}")
# 透传订单到设备
return {"forward": True}
# AGV状态监控
def monitor_agv_state(message):
"""监控AGV状态并记录关键信息"""
state = message.payload
battery = state.get("batteryState", {}).get("batteryCharge", 100)
position = state.get("agvPosition", {})
errors = state.get("errors", [])
# 更新设备状态到数据库
VWED.db.execute_update(
"UPDATE agv_devices SET battery=?, position_x=?, position_y=?, last_update=? WHERE device_id=?",
[battery, position.get("x"), position.get("y"), VWED.get_current_time(), message.device_id]
)
# 处理错误
if errors:
for error in errors:
VWED.log.error(f"AGV {message.device_id} 错误: {error.get('errorDescription')}")
# 发送告警
VWED.device.sync_publish_message(
topic=f"alerts/agv/{message.device_id}/error",
payload={
"device_id": message.device_id,
"error": error,
"timestamp": VWED.get_current_time()
}
)
# 低电量告警
if battery < 20:
VWED.log.warning(f"AGV {message.device_id} 电量低: {battery}%")
VWED.device.sync_publish_message(
topic=f"alerts/agv/{message.device_id}/battery",
payload={
"device_id": message.device_id,
"battery": battery,
"level": "warning",
"timestamp": VWED.get_current_time()
}
)
# 转发状态
return {"forward": True}
# 注册华瑞AGV处理器
VWED.device.register_and_run(
device_ids=["HR_AGV001", "HR_AGV002", "HR_AGV003"],
device_type="vehicle",
brand_name="huarui",
command_type="order",
handler=process_agv_order,
description="华瑞AGV订单处理器"
)
VWED.device.register_and_run(
device_ids=["HR_AGV001", "HR_AGV002", "HR_AGV003"],
device_type="vehicle",
brand_name="huarui",
command_type="state",
handler=monitor_agv_state,
description="华瑞AGV状态监控"
)
# 注册仙工AGV处理器
VWED.device.register_and_run(
device_ids=["SEER_AGV001", "SEER_AGV002"],
device_type="vehicle",
brand_name="seer",
command_type="order",
handler=process_agv_order,
description="仙工AGV订单处理器"
)
VWED.device.register_and_run(
device_ids=["SEER_AGV001", "SEER_AGV002"],
device_type="vehicle",
brand_name="seer",
command_type="state",
handler=monitor_agv_state,
description="仙工AGV状态监控"
)
VWED.log.info("AGV车队管理系统已启动")
```
## 常见问题
### 1. 如何处理多个品牌的设备?
分别为每个品牌注册处理器,系统会自动根据品牌生成正确的 MQTT topic。
```python
# 华瑞设备
VWED.device.register_and_run(
device_ids=["HR_001", "HR_002"],
brand_name="huarui",
command_type="order",
handler=handler_func
)
# 仙工设备
VWED.device.register_and_run(
device_ids=["SEER_001", "SEER_002"],
brand_name="seer",
command_type="order",
handler=handler_func
)
```
### 2. 一个设备可以注册多个处理器吗?
可以,但需要处理不同的指令类型:
```python
# 处理order指令
VWED.device.register_and_run(
device_ids=["AGV001"],
command_type="order",
handler=order_handler
)
# 处理state指令
VWED.device.register_and_run(
device_ids=["AGV001"],
command_type="state",
handler=state_handler
)
```
### 3. 返回值必须是字典吗?
是的,必须返回字典类型,否则会记录错误日志并忽略该返回值。
### 4. 如何调试消息处理?
使用日志记录消息内容:
```python
def debug_handler(message):
VWED.log.info(f"收到消息:")
VWED.log.info(f" 设备ID: {message.device_id}")
VWED.log.info(f" Topic: {message.topic}")
VWED.log.info(f" 载荷: {message.payload}")
return {"forward": True}
```
## 注意事项
1. **处理函数必须返回字典**:返回值格式必须符合约定
2. **payload 必须是字典类型**:转发和响应的 payload 都必须是字典
3. **批量注册时所有设备使用相同的处理函数**:如果需要不同的处理逻辑,分别注册
4. **处理函数应该快速返回**:避免长时间阻塞,影响其他消息处理
5. **异常处理**:系统会自动捕获异常并记录日志,但建议在处理函数中添加适当的异常处理
6. **资源清理**:脚本停止时会自动清理所有注册的设备处理器