200 lines
7.8 KiB
Python
Raw Normal View History

2025-09-25 10:52:52 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
VWED.device 模块 - 设备处理器注册并运行
"""
import asyncio
from typing import Dict, Any, List, Union, Callable
from ..device_handler_service import get_device_service, DeviceType, DeviceBrand, get_protocol_registry
from ..script_registry_service import get_global_registry
from utils.logger import get_logger
class VWEDDeviceModule:
"""VWED.device 模块 - 设备处理器注册并运行"""
def __init__(self, script_id: str):
self.script_id = script_id
self.device_service = get_device_service()
self.registry = get_global_registry()
self.logger = get_logger(f"script.{script_id}.device")
def register_and_run(self, device_ids: List[str], device_type: Union[str, DeviceType] = DeviceType.VEHICLE,
brand_name: str = "huarui", command_type: str = None,
handler: Callable = None, description: str = "",
device_brand: str = None, protocol_key: str = None,
auto_encode: bool = True, **kwargs):
"""批量注册并运行设备处理器(新接口)
系统会自动
1. 根据设备品牌和类型生成MQTT topics
2. 订阅相应的topics
3. 开始监听消息
4. 消息到达时自动调用处理函数
5. 自动转发处理结果
使用方式
# 批量注册华瑞小车处理order指令
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指令处理器"
)
# 批量注册仙工小车处理state指令
VWED.device.register_and_run(
device_ids=["SEER001", "SEER002"],
device_type="vehicle",
brand_name="seer",
command_type="state",
handler=seer_state_processor,
description="仙工小车state指令处理器"
)
# 批量注册门设备处理instantActions指令
VWED.device.register_and_run(
device_ids=["DOOR001", "DOOR002"],
device_type="door",
brand_name="huarui",
command_type="instantActions",
handler=door_processor,
description="门设备instantActions指令处理器"
)
Args:
device_ids: 设备ID列表必需- 支持批量注册
device_type: 设备类型默认vehicle
brand_name: 设备品牌huarui或seer默认huarui
command_type: 指令类型必需- 只能处理一种指令类型"order""state""factsheet""instantActions"
handler: 消息处理函数必需
description: 设备描述信息
device_brand: 设备品牌兼容参数建议使用brand_name
protocol_key: 自定义协议标识已弃用
auto_encode: 是否自动编码已弃用
**kwargs: 其他配置参数
"""
if handler is None:
raise ValueError("handler参数不能为空")
if not device_ids or len(device_ids) == 0:
raise ValueError("device_ids参数不能为空")
# 确保device_type是DeviceType枚举
if isinstance(device_type, str):
try:
device_type = DeviceType(device_type)
except ValueError:
valid_types = [dt.value for dt in DeviceType]
raise ValueError(f"device_type参数错误'{device_type}' 不是有效的设备类型。支持的类型有:{', '.join(valid_types)}")
# 兼容性处理如果提供了device_brand使用它覆盖brand_name
if device_brand is not None:
brand_name = device_brand
# 过滤已弃用的参数
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['listen_topics', 'forward_topics', 'protocol_key', 'auto_encode']}
# 调用新的设备服务批量注册接口
registered_device_ids = self.device_service.register_and_run(
device_ids=device_ids,
device_type=device_type,
brand_name=brand_name,
command_type=command_type,
handler=handler,
script_id=self.script_id,
description=description,
**filtered_kwargs
)
brand_info = f" (品牌: {brand_name})" if brand_name else ""
self.logger.info(f"设备处理器批量注册成功: {len(registered_device_ids)}{device_type.value} 设备{brand_info}")
return registered_device_ids
def stop_handler(self, device_id: str):
"""停止指定设备处理器的运行"""
self.device_service.stop_handler(device_id)
self.logger.info(f"设备处理器已停止: {device_id}")
def restart_handler(self, device_id: str):
"""重启设备处理器"""
# 获取设备配置
handler_info = self.registry.get_device_handler(device_id)
if not handler_info:
raise ValueError(f"设备处理器不存在: {device_id}")
# 先停止
self.stop_handler(device_id)
# 重新注册并运行
self.register_and_run(
device_id=handler_info["device_id"],
device_type=handler_info["device_type"],
listen_topics=handler_info["listen_topics"],
forward_topics=handler_info["forward_topics"],
handler=handler_info["handler"],
description=handler_info["description"]
)
self.logger.info(f"设备处理器已重启: {device_id}")
def get_running_handlers(self) -> Dict[str, Any]:
"""获取所有正在运行的设备处理器"""
return self.device_service.get_running_handlers()
def get_handler_status(self, device_id: str) -> Dict[str, Any]:
"""获取设备处理器状态"""
return self.device_service.get_handler_status(device_id)
async def publish_message(self, topic: str, payload: Any):
"""主动发布MQTT消息
使用方式
await VWED.device.publish_message(
topic="factory/agv/command",
payload={"action": "move", "x": 100, "y": 200}
)
"""
await self.device_service.publish_message(topic, payload)
self.logger.info(f"MQTT消息已发布: {topic}")
def sync_publish_message(self, topic: str, payload: Any):
"""同步方式发布MQTT消息"""
asyncio.create_task(self.publish_message(topic, payload))
def subscribe_topic(self, topic: str, handler: Callable):
"""订阅额外的MQTT topic
注意这是临时订阅建议使用register_and_run进行完整的设备注册
"""
# 创建临时设备ID
temp_device_id = f"temp_{self.script_id}_{topic.replace('/', '_')}"
self.register_and_run(
device_id=temp_device_id,
device_type="custom",
listen_topics=[topic],
forward_topics=[],
handler=handler,
description=f"临时订阅topic: {topic}"
)
return temp_device_id
def unsubscribe_topic(self, device_id: str):
"""取消订阅topic通过停止设备处理器"""
self.stop_handler(device_id)
def get_device_types(self) -> List[str]:
"""获取支持的设备类型列表"""
return [dt.value for dt in DeviceType]
def get_device_brands(self) -> List[str]:
"""获取支持的设备品牌列表"""
return [db.value for db in DeviceBrand]
2025-10-01 15:20:55 +08:00