VWED_server/docs/device_handler_examples.md

44 KiB
Raw Blame History

VWED设备处理器使用示例文档

概述

本文档详细说明了在VWED在线脚本中如何使用更新后的设备处理器功能特别是对VDA5050协议的支持。

核心特点:

  • 消息透传模式: 消息直接透传,不进行编解码处理,保持原始数据格式
  • 内置MQTT服务: 集成自己的MQTT客户端自主管理连接和重连
  • 多设备类型支持: 支持vehicle、door、caller、lift、sensor、robot等设备类型
  • 多品牌支持: 支持huarui、seer、quicktron、geek等主流设备品牌
  • 注册即运行: 调用 VWED.device.register_and_run() 后立即开始监听MQTT消息
  • 自动处理: 消息到达时自动调用您定义的处理函数
  • 自动转发: 处理完成后自动发送到指定topic
  • 持续运行: 一次注册,持续处理消息直到手动停止
  • 脚本ID自动关联: script_id 参数由系统在热加载时自动传入,无需用户手动提供

1. VDA5050协议小车设备示例

1.1 VDA5050小车注册和处理

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def boot():
    """VDA5050小车处理脚本启动函数"""
    
    # 注册华睿小车处理器(消息透传模式)
    VWED.device.register_and_run(
        device_id="huarui_agv_001",
        device_type="vehicle",
        listen_topics=["vda5050/v2/huarui_agv_001/state", "vda5050/v2/huarui_agv_001/factsheet"],
        forward_topics=["fleet/huarui_agv_001/status"],
        handler=vda5050_vehicle_handler,
        device_brand="huarui",
        protocol_type="vda5050",  # 协议类型
        description="华睿小车处理器"
    )

def vda5050_vehicle_handler(message):
    """VDA5050小车消息处理器"""
    
    device_id = message.device_id
    payload = message.payload
    
    VWED.log.sync_info(f"收到VDA5050小车 {device_id} 消息: {payload}")
    
    # 根据消息内容处理(消息透传,保持原始格式)
    # 可以根据实际消息格式调整解析逻辑
    message_type = payload.get('message_type', payload.get('command_type', 'unknown'))
    
    if message_type == 'state_response' or 'driving' in payload:
        # 处理状态响应
        driving = payload.get('driving', False)
        paused = payload.get('paused', False)
        operating_mode = payload.get('operating_mode', 'unknown')
        battery_state = payload.get('battery_state', {})
        agv_position = payload.get('agv_position', {})
        
        VWED.log.sync_info(f"小车状态 - 运行: {driving}, 暂停: {paused}, 模式: {operating_mode}")
        VWED.log.sync_info(f"电池状态: {battery_state}")
        VWED.log.sync_info(f"位置: {agv_position}")
        
        # 检查低电量警告
        battery_charge = battery_state.get('batteryCharge', 100)
        if battery_charge < 20:
            VWED.log.sync_warning(f"小车 {device_id} 电量不足: {battery_charge}%")
            
            # 发送低电量警报
            alert = {
                "type": "low_battery_alert",
                "device_id": device_id,
                "battery_level": battery_charge,
                "timestamp": VWED.util.now()
            }
            
            return {
                "forward": True,
                "topics": ["fleet/alerts", "fleet/huarui_agv_001/status"],
                "payload": [alert, payload]
            }
        
    elif message_type == 'factsheet_response' or 'manufacturer' in payload:
        # 处理设备信息响应
        manufacturer = payload.get('manufacturer', '')
        serial_number = payload.get('serial_number', '')
        type_spec = payload.get('type_specification', {})
        
        VWED.log.sync_info(f"设备信息 - 制造商: {manufacturer}, 序列号: {serial_number}")
        
        # 存储设备信息到缓存
        VWED.data.set(f"device_info_{device_id}", {
            "manufacturer": manufacturer,
            "serial_number": serial_number,
            "type_specification": type_spec,
            "updated_at": VWED.util.now()
        })
    
    # 默认转发消息
    return {
        "forward": True,
        "payload": {
            "device_id": device_id,
            "original_data": payload,
            "processed_at": VWED.util.now()
        }
    }

# VDA5050指令发送示例
def send_vda5050_order_example():
    """发送VDA5050订单指令示例"""
    
    # 构建订单数据
    order_data = {
        "order_id": f"order_{int(VWED.util.timestamp())}",
        "nodes": [
            {
                "nodeId": "pickup_station",
                "sequenceId": 1,
                "nodePosition": {"x": 10.5, "y": 20.3, "theta": 0.0, "mapId": "warehouse_map"},
                "actions": [
                    {
                        "actionType": "pick",
                        "actionId": "pick_001",
                        "actionDescription": "Pick up cargo",
                        "blockingType": "HARD",
                        "actionParameters": [
                            {"key": "load_type", "value": "box"},
                            {"key": "weight", "value": "5"}
                        ]
                    }
                ]
            },
            {
                "nodeId": "delivery_station",
                "sequenceId": 2,
                "nodePosition": {"x": 30.0, "y": 45.0, "theta": 1.57, "mapId": "warehouse_map"},
                "actions": [
                    {
                        "actionType": "drop",
                        "actionId": "drop_001",
                        "actionDescription": "Drop cargo",
                        "blockingType": "HARD"
                    }
                ]
            }
        ],
        "edges": [
            {
                "edgeId": "edge_pickup_to_delivery",
                "sequenceId": 1,
                "startNodeId": "pickup_station",
                "endNodeId": "delivery_station",
                "maxSpeed": 1.5,
                "actions": []
            }
        ]
    }
    
    # 发送订单
    VWED.device.send_order("huarui_agv_001", order_data)
    VWED.log.sync_info("订单已发送")

def send_emergency_stop():
    """发送紧急停止指令"""
    
    emergency_actions = [
        {
            "actionType": "cancelOrder",
            "actionId": f"emergency_stop_{int(VWED.util.timestamp())}",
            "actionDescription": "Emergency stop - cancel current order",
            "blockingType": "HARD"
        }
    ]
    
    VWED.device.send_instant_action("huarui_agv_001", emergency_actions)
    VWED.log.sync_warning("紧急停止指令已发送")

def request_vehicle_state():
    """请求小车状态"""
    
    VWED.device.request_state("huarui_agv_001")
    VWED.log.sync_info("状态查询请求已发送")

1.2 门设备即时动作示例

def boot():
    """门设备VDA5050即时动作处理"""
    
    # 注册门设备处理器
    VWED.device.register_and_run(
        device_id="door_001",
        device_type="door",
        listen_topics=["door/door_001/status"],
        forward_topics=["facility/door_001/events"],
        handler=door_instant_action_handler,
        device_brand="standard",
        protocol_type="vda5050",
        description="门设备处理器"
    )

def door_instant_action_handler(message):
    """门设备即时动作处理器"""
    
    device_id = message.device_id
    payload = message.payload
    
    VWED.log.sync_info(f"收到门设备 {device_id} 消息: {payload}")
    
    door_status = payload.get('door_status', 'unknown')
    
    if door_status == 'access_requested':
        # 处理门禁访问请求
        card_id = payload.get('card_id')
        
        # 验证访问权限
        if is_authorized_card(card_id):
            # 发送开门指令
            open_actions = [
                {
                    "actionType": "open",
                    "actionId": f"open_{int(VWED.util.timestamp())}",
                    "actionDescription": f"Open door for card {card_id}",
                    "blockingType": "SOFT",
                    "actionParameters": [
                        {"key": "duration", "value": "5"},  # 开门5秒
                        {"key": "card_id", "value": card_id}
                    ]
                }
            ]
            
            VWED.device.send_instant_action("door_001", open_actions, "door/door_001/control")
            VWED.log.sync_info(f"已授权开门: {card_id}")
            
            return {
                "forward": True,
                "payload": {
                    "event": "access_granted",
                    "card_id": card_id,
                    "timestamp": VWED.util.now()
                }
            }
        else:
            VWED.log.sync_warning(f"未授权访问被拒绝: {card_id}")
            
            return {
                "forward": True,
                "payload": {
                    "event": "access_denied",
                    "card_id": card_id,
                    "reason": "unauthorized",
                    "timestamp": VWED.util.now()
                }
            }
    
    return {"forward": True, "payload": payload}

def is_authorized_card(card_id):
    """检查卡片是否有权限"""
    authorized_cards = VWED.data.get("authorized_cards", ["CARD001", "CARD002", "CARD003"])
    return card_id in authorized_cards

1.3 通用设备即时动作示例

def boot():
    """传感器设备即时动作处理"""
    
    # 注册传感器设备
    VWED.device.register_and_run(
        device_id="temp_sensor_001",
        device_type="sensor",
        listen_topics=["sensors/temperature/001/data"],
        forward_topics=["environmental/alerts"],
        handler=sensor_instant_action_handler,
        device_brand="standard",
        protocol_type="vda5050",
        description="温度传感器处理器"
    )

def sensor_instant_action_handler(message):
    """传感器即时动作处理器"""
    
    device_id = message.device_id
    payload = message.payload
    temperature = payload.get('temperature', 0)
    
    VWED.log.sync_info(f"传感器 {device_id} 温度: {temperature}°C")
    
    if temperature > 35:
        # 温度过高,发送冷却指令
        cooling_actions = [
            {
                "actionType": "cooling_control",
                "actionId": f"cool_{int(VWED.util.timestamp())}",
                "actionDescription": "Activate cooling system",
                "blockingType": "SOFT",
                "actionParameters": [
                    {"key": "target_temp", "value": "25"},
                    {"key": "priority", "value": "high"}
                ]
            }
        ]
        
        VWED.device.send_instant_action("temp_sensor_001", cooling_actions, "hvac/control")
        
        return {
            "forward": True,
            "payload": {
                "alert_type": "temperature_high",
                "temperature": temperature,
                "action_taken": "cooling_activated",
                "timestamp": VWED.util.now()
            }
        }
    
    return {"forward": False}  # 正常温度不转发

2. 传统协议小车设备示例

1.1 基本小车命令处理

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def boot():
    """脚本启动函数"""
    
    # 注册并运行AGV设备处理器
    VWED.device.register_and_run(
        device_id="agv_001",
        device_type="vehicle",
        listen_topics=["factory/agv/command"],
        forward_topics=["factory/agv/execute"],
        handler=agv_command_processor,
        device_brand="standard",
        protocol_type="vda5050",
        description="AGV命令处理器 - 添加安全检查"
    )

def agv_command_processor(message):
    """AGV命令处理逻辑 - 消息到达时自动执行"""
    
    # 记录接收到的消息
    VWED.log.sync_info(f"收到AGV命令: {message.payload}")
    
    command = message.payload.get("command")
    
    if command == "move":
        # 添加安全检查逻辑
        x = message.payload.get("x", 0)
        y = message.payload.get("y", 0)
        speed = message.payload.get("speed", 100)
        
        # 限制最大速度
        safe_speed = min(speed, 50)
        
        # 检查坐标范围
        if x < 0 or x > 1000 or y < 0 or y > 800:
            VWED.log.sync_warning(f"AGV坐标超出安全范围: x={x}, y={y}")
            return {
                "forward": False,  # 不转发
                "response": {
                    "status": "error",
                    "message": "坐标超出安全范围"
                },
                "response_topic": "factory/agv/response"
            }
        
        # 构建安全的移动命令
        safe_command = {
            "command": "move_safe",
            "x": x,
            "y": y,
            "speed": safe_speed,
            "safety_check": True,
            "timestamp": VWED.util.now(),
            "processed_by": "agv_001_processor"
        }
        
        VWED.log.sync_info(f"AGV安全命令已生成: 速度限制 {speed} -> {safe_speed}")
        
        return {
            "forward": True,
            "payload": safe_command
        }
    
    elif command == "stop":
        # 紧急停止 - 直接转发
        emergency_stop = {
            "command": "emergency_stop",
            "reason": message.payload.get("reason", "manual_stop"),
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "payload": emergency_stop
        }
    
    else:
        # 未知命令 - 记录并拒绝
        VWED.log.sync_warning(f"未知AGV命令: {command}")
        return {
            "forward": False,
            "response": {
                "status": "error", 
                "message": f"不支持的命令: {command}"
            },
            "response_topic": "factory/agv/response"
        }

MQTT消息流转示例:

输入topic: factory/agv/command
输入消息: {"command": "move", "x": 100, "y": 200, "speed": 80}

处理后输出topic: factory/agv/execute  
输出消息: {"command": "move_safe", "x": 100, "y": 200, "speed": 50, "safety_check": true, "timestamp": "2024-01-01T12:00:00", "processed_by": "agv_001_processor"}

1.2 多AGV协调处理

def boot():
    """多AGV统一处理"""
    
    # 注册AGV车队控制器
    VWED.device.register_and_run(
        device_id="agv_fleet_controller",
        device_type="vehicle",
        listen_topics=["factory/agv/+/command"],  # 监听所有AGV命令
        forward_topics=["factory/agv/coordination"],
        handler=agv_fleet_coordinator,
        device_brand="standard",
        protocol_type="vda5050",
        description="AGV车队协调器"
    )

def agv_fleet_coordinator(message):
    """AGV车队协调逻辑"""
    
    # 解析AGV ID
    topic_parts = message.topic.split("/")
    agv_id = topic_parts[2] if len(topic_parts) > 2 else "unknown"
    
    command = message.payload.get("command")
    
    if command == "move":
        # 检查路径冲突
        x = message.payload.get("x")
        y = message.payload.get("y")
        
        # 获取其他AGV位置从缓存中
        other_agvs = VWED.data.get("agv_positions", {})
        
        # 简单的冲突检测
        conflict_detected = False
        for other_id, other_pos in other_agvs.items():
            if other_id != agv_id:
                distance = ((x - other_pos["x"])**2 + (y - other_pos["y"])**2)**0.5
                if distance < 50:  # 50cm安全距离
                    conflict_detected = True
                    break
        
        if conflict_detected:
            # 发送等待指令
            wait_command = {
                "command": "wait",
                "reason": "path_conflict",
                "retry_after": 3,  # 3秒后重试
                "timestamp": VWED.util.now()
            }
            
            VWED.log.sync_warning(f"AGV {agv_id} 路径冲突,指令等待")
            
            return {
                "forward": True,
                "topics": [f"factory/agv/{agv_id}/execute"],
                "payload": wait_command
            }
        else:
            # 更新AGV位置缓存
            other_agvs[agv_id] = {"x": x, "y": y, "timestamp": VWED.util.now()}
            VWED.data.set("agv_positions", other_agvs)
            
            # 转发原始命令
            return {
                "forward": True,
                "topics": [f"factory/agv/{agv_id}/execute"],
                "payload": message.payload
            }
    
    # 默认转发
    return {
        "forward": True,
        "topics": [f"factory/agv/{agv_id}/execute"], 
        "payload": message.payload
    }

2. 门禁(Door)设备处理示例

2.1 基本门禁控制

def boot():
    """门禁系统处理器"""
    
    VWED.device.register_and_run(
        device_id="door_main_entrance",
        device_type="door",
        listen_topics=["building/door/access_request"],
        forward_topics=["building/door/control"],
        handler=door_access_controller,
        device_brand="standard",
        protocol_type="vda5050",
        description="主入口门禁控制器"
    )

def door_access_controller(message):
    """门禁访问控制逻辑"""
    
    # 获取访问请求信息
    card_id = message.payload.get("card_id")
    door_id = message.payload.get("door_id", "main_entrance")
    request_time = message.payload.get("timestamp", VWED.util.now())
    
    VWED.log.sync_info(f"门禁访问请求: 卡号={card_id}, 门={door_id}")
    
    # 权限验证逻辑
    if not card_id:
        return {
            "forward": False,
            "response": {"status": "error", "message": "缺少卡号"},
            "response_topic": "building/door/response"
        }
    
    # 检查黑名单
    blacklist = VWED.data.get("door_blacklist", [])
    if card_id in blacklist:
        VWED.log.sync_warning(f"黑名单卡号访问被拒绝: {card_id}")
        
        return {
            "forward": False,
            "response": {
                "status": "denied",
                "reason": "blacklist",
                "card_id": card_id,
                "timestamp": request_time
            },
            "response_topic": "building/door/response"
        }
    
    # 检查白名单
    whitelist = VWED.data.get("door_whitelist", [
        "CARD001", "CARD002", "CARD003"  # 默认白名单
    ])
    
    if card_id in whitelist:
        # 授权开门
        open_command = {
            "action": "open",
            "door_id": door_id,
            "card_id": card_id,
            "authorized_by": "door_main_entrance",
            "open_duration": 5,  # 开门5秒
            "timestamp": request_time
        }
        
        # 记录访问日志
        access_log = VWED.data.get("door_access_log", [])
        access_log.append({
            "card_id": card_id,
            "door_id": door_id,
            "status": "granted",
            "timestamp": request_time
        })
        
        # 只保留最近100条记录
        if len(access_log) > 100:
            access_log = access_log[-100:]
        VWED.data.set("door_access_log", access_log)
        
        VWED.log.sync_info(f"门禁访问已授权: {card_id}")
        
        return {
            "forward": True,
            "payload": open_command
        }
    else:
        # 未授权卡号
        VWED.log.sync_warning(f"未授权卡号访问被拒绝: {card_id}")
        
        return {
            "forward": False,
            "response": {
                "status": "denied",
                "reason": "unauthorized",
                "card_id": card_id,
                "timestamp": request_time
            },
            "response_topic": "building/door/response"
        }

2.2 门禁状态监控

def boot():
    """门禁状态监控"""
    
    # 监控门禁状态
    VWED.device.register_and_run(
        device_id="door_status_monitor",
        device_type="door",
        listen_topics=["building/door/+/status"],
        forward_topics=["building/security/alerts"],
        handler=door_status_monitor,
        device_brand="standard",
        protocol_type="vda5050",
        description="门禁状态监控器"
    )

def door_status_monitor(message):
    """门禁状态监控逻辑"""
    
    # 解析门ID
    topic_parts = message.topic.split("/")
    door_id = topic_parts[2] if len(topic_parts) > 2 else "unknown"
    
    status = message.payload.get("status")
    timestamp = message.payload.get("timestamp", VWED.util.now())
    
    # 更新门状态缓存
    door_states = VWED.data.get("door_states", {})
    door_states[door_id] = {
        "status": status,
        "timestamp": timestamp,
        "last_update": VWED.util.now()
    }
    VWED.data.set("door_states", door_states)
    
    # 异常状态检测
    if status == "forced_open":
        # 门被强制打开 - 发送安全警报
        alert = {
            "type": "security_alert",
            "level": "high",
            "door_id": door_id,
            "event": "forced_open",
            "message": f"门 {door_id} 被强制打开",
            "timestamp": timestamp,
            "requires_action": True
        }
        
        VWED.log.sync_error(f"安全警报: 门 {door_id} 被强制打开")
        
        return {
            "forward": True,
            "payload": alert
        }
    
    elif status == "open_timeout":
        # 门打开超时 - 发送提醒
        alert = {
            "type": "maintenance_alert",
            "level": "medium",
            "door_id": door_id,
            "event": "open_timeout",
            "message": f"门 {door_id} 打开时间过长",
            "timestamp": timestamp,
            "requires_action": False
        }
        
        VWED.log.sync_warning(f"维护提醒: 门 {door_id} 打开时间过长")
        
        return {
            "forward": True,
            "payload": alert
        }
    
    # 正常状态 - 不转发
    return {"forward": False}

3. 呼叫器(Caller)设备处理示例

3.1 基本呼叫处理

def boot():
    """呼叫器处理系统"""
    
    VWED.device.register_and_run(
        device_id="caller_lobby_01",
        device_type="caller",
        listen_topics=["building/caller/signal"],
        forward_topics=["building/caller/response", "building/notification/broadcast"],
        handler=caller_signal_processor,
        device_brand="standard",
        protocol_type="vda5050",
        description="大厅呼叫器信号处理器"
    )

def caller_signal_processor(message):
    """呼叫器信号处理逻辑"""
    
    caller_id = message.payload.get("caller_id")
    signal_type = message.payload.get("signal_type")
    location = message.payload.get("location", "unknown")
    priority = message.payload.get("priority", "normal")
    
    VWED.log.sync_info(f"收到呼叫信号: {caller_id} - {signal_type} ({priority})")
    
    # 根据信号类型处理
    if signal_type == "emergency":
        # 紧急呼叫 - 立即响应
        emergency_response = {
            "type": "emergency_response",
            "caller_id": caller_id,
            "location": location,
            "status": "received",
            "response_time": "immediate",
            "assigned_staff": "security_team",
            "message": "紧急响应团队已派遣",
            "timestamp": VWED.util.now()
        }
        
        # 广播紧急通知
        emergency_broadcast = {
            "type": "emergency_broadcast",
            "level": "critical",
            "message": f"紧急呼叫: {location} ({caller_id})",
            "location": location,
            "caller_id": caller_id,
            "timestamp": VWED.util.now()
        }
        
        VWED.log.sync_error(f"紧急呼叫处理: {caller_id} 位置: {location}")
        
        return {
            "forward": True,
            "topics": ["building/caller/response", "building/notification/broadcast"],
            "payload": [emergency_response, emergency_broadcast]
        }
    
    elif signal_type == "service":
        # 服务请求 - 分配服务人员
        service_response = {
            "type": "service_response", 
            "caller_id": caller_id,
            "location": location,
            "status": "queued",
            "estimated_time": "5-10 minutes",
            "queue_position": get_queue_position(location),
            "message": "服务请求已接收,请稍候",
            "timestamp": VWED.util.now()
        }
        
        VWED.log.sync_info(f"服务请求处理: {caller_id}")
        
        return {
            "forward": True,
            "topics": ["building/caller/response"],
            "payload": service_response
        }
    
    elif signal_type == "information":
        # 信息查询 - 提供自动回复
        info_response = {
            "type": "information_response",
            "caller_id": caller_id,
            "location": location,
            "status": "completed",
            "information": get_location_info(location),
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "topics": ["building/caller/response"],
            "payload": info_response
        }
    
    else:
        # 未知信号类型
        error_response = {
            "type": "error_response",
            "caller_id": caller_id,
            "status": "error",
            "message": f"不支持的信号类型: {signal_type}",
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "topics": ["building/caller/response"],
            "payload": error_response
        }

def get_queue_position(location):
    """获取队列位置"""
    queue = VWED.data.get(f"service_queue_{location}", [])
    return len(queue) + 1

def get_location_info(location):
    """获取位置信息"""
    location_data = {
        "lobby": "大厅 - 营业时间: 8:00-18:00, 电话: 123-456-7890",
        "elevator": "电梯区域 - 共6部电梯, 楼层: B1-F20",
        "parking": "停车场 - 地下3层, 收费标准: 5元/小时"
    }
    return location_data.get(location, "暂无相关信息")

3.2 呼叫器多级响应

def boot():
    """多级呼叫响应系统"""
    
    VWED.device.register_and_run(
        device_id="caller_escalation_manager",
        device_type="caller",
        listen_topics=["building/caller/+/urgent"],
        forward_topics=["building/staff/notification"],
        handler=caller_escalation_handler,
        device_brand="standard",
        protocol_type="vda5050",
        description="呼叫升级管理器"
    )

def caller_escalation_handler(message):
    """呼叫升级处理逻辑"""
    
    # 解析呼叫器ID
    topic_parts = message.topic.split("/")
    caller_id = topic_parts[2] if len(topic_parts) > 2 else "unknown"
    
    urgency_level = message.payload.get("urgency", "medium")
    repeat_count = message.payload.get("repeat_count", 1)
    last_response_time = message.payload.get("last_response_time")
    
    # 升级逻辑
    if repeat_count >= 3:
        # 第3次重复呼叫 - 升级到管理层
        escalation = {
            "type": "management_escalation",
            "caller_id": caller_id,
            "urgency": "high",
            "repeat_count": repeat_count,
            "reason": "multiple_unattended_calls",
            "notify_roles": ["supervisor", "manager"],
            "message": f"呼叫器 {caller_id} 连续{repeat_count}次呼叫未响应",
            "timestamp": VWED.util.now()
        }
        
        VWED.log.sync_warning(f"呼叫升级到管理层: {caller_id} ({repeat_count}次)")
        
        return {
            "forward": True,
            "payload": escalation
        }
    
    elif repeat_count == 2:
        # 第2次重复呼叫 - 通知高级员工
        notification = {
            "type": "senior_staff_notification",
            "caller_id": caller_id,
            "urgency": "medium",
            "repeat_count": repeat_count,
            "notify_roles": ["senior_staff"],
            "message": f"呼叫器 {caller_id} 重复呼叫,请优先处理",
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "payload": notification
        }
    
    else:
        # 首次呼叫 - 正常通知
        notification = {
            "type": "normal_notification",
            "caller_id": caller_id,
            "urgency": urgency_level,
            "notify_roles": ["staff"],
            "message": f"呼叫器 {caller_id} 请求服务",
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "payload": notification
        }

4. 综合设备处理示例

4.1 智能楼宇综合管理

def boot():
    """智能楼宇综合管理系统"""
    
    # 环境监控
    VWED.device.register_and_run(
        device_id="environmental_monitor",
        device_type="sensor",
        listen_topics=["building/sensors/+/data"],
        forward_topics=["building/hvac/control", "building/alerts"],
        handler=environmental_processor,
        description="环境监控处理器"
    )
    
    # 电梯调度
    VWED.device.register_and_run(
        device_id="elevator_scheduler",
        device_type="lift",
        listen_topics=["building/elevator/call"],
        forward_topics=["building/elevator/+/command"],
        handler=elevator_scheduler,
        description="电梯调度器"
    )
    
    # 安全系统集成
    VWED.device.register_and_run(
        device_id="security_integrator",
        device_type="custom",
        listen_topics=["building/security/+/event"],
        forward_topics=["building/security/response"],
        handler=security_event_processor,
        description="安全系统集成器"
    )

def environmental_processor(message):
    """环境数据处理"""
    
    # 解析传感器ID
    topic_parts = message.topic.split("/")
    sensor_id = topic_parts[2] if len(topic_parts) > 2 else "unknown"
    
    temperature = message.payload.get("temperature")
    humidity = message.payload.get("humidity")
    air_quality = message.payload.get("air_quality")
    
    controls = []
    alerts = []
    
    # 温度控制
    if temperature is not None:
        if temperature > 26:
            controls.append({
                "device": "hvac",
                "action": "cool",
                "target_temp": 24,
                "reason": f"温度过高: {temperature}°C"
            })
        elif temperature < 20:
            controls.append({
                "device": "hvac", 
                "action": "heat",
                "target_temp": 22,
                "reason": f"温度过低: {temperature}°C"
            })
    
    # 湿度控制
    if humidity is not None:
        if humidity > 70:
            controls.append({
                "device": "dehumidifier",
                "action": "on",
                "target_humidity": 60,
                "reason": f"湿度过高: {humidity}%"
            })
    
    # 空气质量监控
    if air_quality is not None and air_quality < 50:
        alerts.append({
            "type": "air_quality_alert",
            "level": "medium",
            "sensor_id": sensor_id,
            "value": air_quality,
            "message": "空气质量较差,建议开启新风系统"
        })
    
    # 返回控制指令和警报
    responses = []
    if controls:
        responses.append(("building/hvac/control", {"controls": controls, "timestamp": VWED.util.now()}))
    if alerts:
        responses.append(("building/alerts", {"alerts": alerts, "timestamp": VWED.util.now()}))
    
    if responses:
        return {
            "forward": True,
            "topics": [topic for topic, _ in responses],
            "payload": [payload for _, payload in responses]
        }
    
    return {"forward": False}

def elevator_scheduler(message):
    """电梯调度逻辑"""
    
    floor_from = message.payload.get("from_floor")
    floor_to = message.payload.get("to_floor")
    priority = message.payload.get("priority", "normal")
    
    # 获取电梯状态
    elevator_status = VWED.data.get("elevator_status", {
        "elevator_1": {"current_floor": 1, "status": "idle"},
        "elevator_2": {"current_floor": 10, "status": "busy"},
        "elevator_3": {"current_floor": 5, "status": "idle"}
    })
    
    # 选择最佳电梯
    best_elevator = None
    min_distance = float('inf')
    
    for elevator_id, status in elevator_status.items():
        if status["status"] == "idle":
            distance = abs(status["current_floor"] - floor_from)
            if distance < min_distance:
                min_distance = distance
                best_elevator = elevator_id
    
    if best_elevator:
        # 分配电梯
        command = {
            "elevator_id": best_elevator,
            "action": "goto",
            "from_floor": floor_from,
            "to_floor": floor_to,
            "priority": priority,
            "estimated_time": min_distance * 3,  # 假设每层3秒
            "timestamp": VWED.util.now()
        }
        
        # 更新电梯状态
        elevator_status[best_elevator]["status"] = "busy"
        VWED.data.set("elevator_status", elevator_status)
        
        return {
            "forward": True,
            "topics": [f"building/elevator/{best_elevator}/command"],
            "payload": command
        }
    else:
        # 无空闲电梯 - 加入队列
        queue = VWED.data.get("elevator_queue", [])
        queue.append({
            "from_floor": floor_from,
            "to_floor": floor_to,
            "priority": priority,
            "request_time": VWED.util.now()
        })
        VWED.data.set("elevator_queue", queue)
        
        return {
            "forward": False,
            "response": {
                "status": "queued",
                "position": len(queue),
                "estimated_wait": len(queue) * 30  # 每个请求30秒
            },
            "response_topic": "building/elevator/response"
        }

def security_event_processor(message):
    """安全事件处理"""
    
    event_type = message.payload.get("event_type")
    location = message.payload.get("location")
    severity = message.payload.get("severity", "medium")
    
    if event_type == "intrusion_detected":
        # 入侵检测 - 立即响应
        response = {
            "action": "lockdown",
            "location": location,
            "alert_level": "high",
            "notify_security": True,
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "payload": response
        }
    
    elif event_type == "fire_alarm":
        # 火警 - 疏散程序
        response = {
            "action": "evacuation",
            "location": location,
            "alert_level": "critical",
            "notify_fire_dept": True,
            "timestamp": VWED.util.now()
        }
        
        return {
            "forward": True,
            "payload": response
        }
    
    # 其他事件正常处理
    return {
        "forward": True,
        "payload": message.payload
    }

5. 设备处理器管理功能

5.1 设备状态监控

def boot():
    """设备管理和监控"""
    
    # 注册设备状态监控
    VWED.device.register_and_run(
        device_id="device_status_monitor", 
        device_type="custom",
        listen_topics=["system/device/+/heartbeat"],
        forward_topics=["system/alerts"],
        handler=device_heartbeat_monitor,
        description="设备心跳监控器"
    )
    
    # 定时检查设备状态
    VWED.timer.interval(
        seconds=60,  # 每分钟检查一次
        handler=check_device_status
    )

def device_heartbeat_monitor(message):
    """设备心跳监控"""
    
    device_id = message.payload.get("device_id")
    status = message.payload.get("status")
    timestamp = message.payload.get("timestamp", VWED.util.now())
    
    # 更新设备心跳记录
    heartbeats = VWED.data.get("device_heartbeats", {})
    heartbeats[device_id] = {
        "status": status,
        "last_heartbeat": timestamp,
        "updated_at": VWED.util.now()
    }
    VWED.data.set("device_heartbeats", heartbeats)
    
    # 如果设备状态异常,发送警报
    if status in ["error", "offline", "malfunction"]:
        alert = {
            "type": "device_alert",
            "device_id": device_id,
            "status": status,
            "message": f"设备 {device_id} 状态异常: {status}",
            "timestamp": timestamp,
            "requires_attention": True
        }
        
        return {
            "forward": True,
            "payload": alert
        }
    
    return {"forward": False}

def check_device_status():
    """定时检查设备状态"""
    
    current_time = VWED.util.timestamp()
    heartbeats = VWED.data.get("device_heartbeats", {})
    
    for device_id, info in heartbeats.items():
        last_heartbeat = info.get("last_heartbeat")
        
        if last_heartbeat:
            # 检查是否超过5分钟没有心跳
            if current_time - last_heartbeat > 300:  # 5分钟
                VWED.log.sync_warning(f"设备 {device_id} 心跳超时")
                
                # 发送超时警报
                VWED.device.sync_publish_message(
                    topic="system/alerts",
                    payload={
                        "type": "device_timeout",
                        "device_id": device_id,
                        "last_seen": last_heartbeat,
                        "timeout_duration": current_time - last_heartbeat,
                        "timestamp": VWED.util.now()
                    }
                )

5.2 设备处理器动态管理

def boot():
    """动态设备管理"""
    
    # 设备管理控制器
    VWED.device.register_and_run(
        device_id="device_manager",
        device_type="custom",
        listen_topics=["system/device/control"],
        forward_topics=["system/device/response"],
        handler=device_management_handler,
        description="设备动态管理控制器"
    )

def device_management_handler(message):
    """设备管理控制处理"""
    
    action = message.payload.get("action")
    device_id = message.payload.get("device_id")
    
    if action == "status":
        # 获取设备状态
        status = VWED.device.get_handler_status(device_id)
        
        return {
            "forward": True,
            "payload": {
                "action": "status_response",
                "device_id": device_id,
                "status": status,
                "timestamp": VWED.util.now()
            }
        }
    
    elif action == "stop":
        # 停止设备处理器
        try:
            VWED.device.stop_handler(device_id)
            
            return {
                "forward": True,
                "payload": {
                    "action": "stop_response",
                    "device_id": device_id,
                    "status": "stopped",
                    "timestamp": VWED.util.now()
                }
            }
        except Exception as e:
            return {
                "forward": True,
                "payload": {
                    "action": "stop_response",
                    "device_id": device_id,
                    "status": "error",
                    "error": str(e),
                    "timestamp": VWED.util.now()
                }
            }
    
    elif action == "restart":
        # 重启设备处理器
        try:
            VWED.device.restart_handler(device_id)
            
            return {
                "forward": True,
                "payload": {
                    "action": "restart_response",
                    "device_id": device_id,
                    "status": "restarted",
                    "timestamp": VWED.util.now()
                }
            }
        except Exception as e:
            return {
                "forward": True,
                "payload": {
                    "action": "restart_response",
                    "device_id": device_id,
                    "status": "error",
                    "error": str(e),
                    "timestamp": VWED.util.now()
                }
            }
    
    elif action == "list":
        # 获取所有设备列表
        handlers = VWED.device.get_running_handlers()
        
        return {
            "forward": True,
            "payload": {
                "action": "list_response",
                "handlers": handlers,
                "timestamp": VWED.util.now()
            }
        }
    
    else:
        return {
            "forward": True,
            "payload": {
                "action": "error_response",
                "message": f"不支持的操作: {action}",
                "timestamp": VWED.util.now()
            }
        }

6. 调试和故障排除

6.1 设备处理器调试

def boot():
    """设备处理器调试模式"""
    
    # 启用调试模式
    debug_mode = True
    
    if debug_mode:
        # 注册调试设备处理器
        VWED.device.register_and_run(
            device_id="debug_processor",
            device_type="custom",
            listen_topics=["debug/+/+"],  # 监听所有调试消息
            forward_topics=[],
            handler=debug_message_handler,
            description="调试消息处理器"
        )

def debug_message_handler(message):
    """调试消息处理"""
    
    # 详细记录消息信息
    VWED.log.sync_info(f"调试消息 - Topic: {message.topic}")
    VWED.log.sync_info(f"调试消息 - Payload: {message.payload}")
    VWED.log.sync_info(f"调试消息 - Device: {message.device_id}")
    VWED.log.sync_info(f"调试消息 - Type: {message.device_type}")
    VWED.log.sync_info(f"调试消息 - Timestamp: {message.timestamp}")
    
    # 保存调试日志
    debug_logs = VWED.data.get("debug_logs", [])
    debug_logs.append({
        "topic": message.topic,
        "payload": message.payload,
        "device_id": message.device_id,
        "device_type": message.device_type.value if hasattr(message.device_type, 'value') else str(message.device_type),
        "timestamp": message.timestamp,
        "processed_at": VWED.util.now()
    })
    
    # 只保留最近50条调试日志
    if len(debug_logs) > 50:
        debug_logs = debug_logs[-50:]
    VWED.data.set("debug_logs", debug_logs)
    
    # 不转发调试消息
    return {"forward": False}

def get_debug_statistics():
    """获取调试统计信息"""
    
    handlers = VWED.device.get_running_handlers()
    debug_logs = VWED.data.get("debug_logs", [])
    
    return {
        "total_handlers": handlers.get("device_count", 0),
        "running_handlers": handlers.get("running_devices", 0),
        "debug_log_count": len(debug_logs),
        "last_debug_time": debug_logs[-1]["processed_at"] if debug_logs else None
    }

总结

本文档提供了VWED设备处理器的完整使用示例包括

主要功能

  1. 设备类型支持 - 小车、门禁、呼叫器、电梯、传感器等
  2. 注册即运行 - 一次注册持续监听和处理MQTT消息
  3. 自动转发 - 处理完成后自动发送到指定topic
  4. 动态管理 - 支持运行时启停、重启设备处理器
  5. 状态监控 - 实时监控设备状态和处理统计

关键特点

  • 分离式设计 - 注册和处理逻辑分离,保持代码清晰
  • 消息驱动 - MQTT消息自动触发处理无需手动调用
  • 错误处理 - 完善的异常处理和重试机制
  • 扩展性强 - 支持自定义设备类型和处理逻辑
  • 易于调试 - 详细的日志记录和调试功能

使用建议

  1. 根据实际设备类型选择合适的device_type
  2. 合理设置listen_topics和forward_topics
  3. 在处理函数中添加充分的错误处理
  4. 使用VWED.log记录关键操作日志
  5. 利用VWED.data缓存必要的状态信息

通过这些示例您可以快速掌握VWED设备处理器的使用方法实现复杂的设备逻辑处理和MQTT消息转发。