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

15 KiB
Raw Blame History

设备处理器模块文档Python 版本)

概述

设备处理器模块提供了基于 VDA5050 协议的设备管理框架,支持 MQTT 通信用于监听和处理各类设备AGV小车、门、电梯等的消息并自动转发到指定的 topic。

核心概念

设备类型 (DeviceType)

系统支持以下设备类型:

  • vehicle: 小车/AGV
  • door: 门
  • caller: 呼叫器
  • lift: 电梯
  • custom: 自定义设备

设备品牌 (DeviceBrand)

系统支持以下品牌:

  • huarui: 华睿
  • seer: 仙工
  • hikrobot: 海康机器人
  • standard: 标准协议
  • custom: 自定义品牌

指令类型 (CommandType)

根据设备类型不同,支持的指令类型:

  • 小车设备orderstatefactsheetinstantActions
  • 其他设备instantActions

API 方法

注册并运行设备处理器

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 对象作为参数,并返回一个字典,指示如何处理消息。

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

注意事项

  • 返回值必须是字典类型
  • payloadresponse 必须是字典类型
  • 如果提供 response,必须同时提供 response_topic

使用示例

示例1批量注册华瑞小车处理 order 指令

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修改消息后转发

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不转发仅记录

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发送自定义响应

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条件转发

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="智能转发器(低电量告警)"
)

停止设备处理器

VWED.device.stop_handler(device_id: str)

说明:停止指定设备处理器的运行

参数

  • device_id: str - 设备ID

示例

# 停止设备处理器
VWED.device.stop_handler("AGV001")

获取运行中的处理器列表

VWED.device.get_running_handlers() -> Dict[str, Any]

说明:获取所有正在运行的设备处理器信息

返回值:包含所有设备处理器状态的字典

示例

handlers = VWED.device.get_running_handlers()
VWED.log.info(f"运行中的处理器: {handlers}")

获取设备处理器状态

VWED.device.get_handler_status(device_id: str) -> Dict[str, Any]

说明:获取指定设备处理器的运行状态

参数

  • device_id: str - 设备ID

返回值:设备处理器状态信息

示例

status = VWED.device.get_handler_status("AGV001")
VWED.log.info(f"设备状态: {status}")

主动发布MQTT消息

await VWED.device.publish_message(topic: str, payload: Any)

说明:主动向指定 topic 发布 MQTT 消息(异步方法)

参数

  • topic: str - MQTT topic
  • payload: dict - 消息载荷

示例

# 异步发布
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}
)

获取支持的设备类型

VWED.device.get_device_types() -> List[str]

说明:获取系统支持的所有设备类型

返回值:设备类型列表

示例

types = VWED.device.get_device_types()
VWED.log.info(f"支持的设备类型: {types}")
# 输出: ['vehicle', 'door', 'caller', 'lift', 'conveyor', 'sensor', 'robot', 'camera', 'scanner', 'custom']

获取支持的设备品牌

VWED.device.get_device_brands() -> List[str]

说明:获取系统支持的所有设备品牌

返回值:设备品牌列表

示例

brands = VWED.device.get_device_brands()
VWED.log.info(f"支持的设备品牌: {brands}")
# 输出: ['huarui', 'seer', 'quicktron', 'geek', 'mushiny', 'flashhold', 'hikrobot', 'standard', 'custom']

完整应用示例

场景AGV车队管理系统

# 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。

# 华瑞设备
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. 一个设备可以注册多个处理器吗?

可以,但需要处理不同的指令类型:

# 处理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. 如何调试消息处理?

使用日志记录消息内容:

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. 资源清理:脚本停止时会自动清理所有注册的设备处理器