#!/usr/bin/env python # -*- coding: utf-8 -*- """ 设备处理器快速入门示例 演示新的简化批量注册接口 - 自动生成MQTT topics 支持华瑞、仙工等品牌小车的批量注册和自动消息转发 基于device_ids的通用设备注册方法 """ def boot(): """脚本启动函数 - 演示新的简化接口""" print("=== 设备处理器快速入门示例 ===") # 1. 最简单的自动透传(推荐用法) example_1_auto_forward() # 2. 自定义处理器 example_2_custom_handler() # 3. 指定特定指令类型 example_3_specific_commands() # 4. 仙工品牌示例 example_4_seer_vehicles() # 5. 混合设备类型示例 example_5_mixed_device_types() print("=== 设备处理器注册完成 ===") def example_1_auto_forward(): """示例1: 最简单的自动透传(推荐用法)""" print("1. 批量注册华瑞小车自动透传") # 批量注册华瑞小车,系统自动生成topics和透传逻辑 VWED.device.register_and_run( device_ids=["AGV001", "AGV002", "AGV003"], device_type="vehicle", brand_name="huarui", script_id="example_script_001", description="华瑞小车批量自动透传" ) print("华瑞小车批量注册成功") # 系统会自动: # 监听: oagv/v2/VWED_001_IRAYPLE/+/order 等 # 转发: uagv/v2.0.0/IRAYPLE/AGV001/order 等 def example_2_custom_handler(): """示例2: 自定义处理器""" print("2. 自定义华瑞小车处理器") def my_custom_handler(message): """自定义消息处理器""" print(f"收到消息: {message.topic}") print(f"载荷: {message.payload}") # 可以修改消息内容 modified_payload = message.payload.copy() modified_payload["processed_by"] = "my_script" modified_payload["processed_at"] = VWED.util.now() # 返回处理结果 return { "forward": True, # 是否转发 "payload": modified_payload, # 修改后的载荷 "topics": message.target_topics # 转发到的topics } # 使用自定义处理器批量注册 VWED.device.register_and_run( device_ids=["AGV001", "AGV002"], device_type="vehicle", brand_name="huarui", handler=my_custom_handler, script_id="example_script_002", description="自定义华瑞小车处理器" ) def example_3_specific_commands(): """示例3: 指定特定指令类型""" print("3. 指定特定指令类型") def order_and_state_handler(message): """只处理order和state指令""" command_type = message.topic.split('/')[-1] if command_type == "order": print(f"处理订单指令: {message.payload}") elif command_type == "state": print(f"处理状态消息: {message.payload}") return { "forward": True, "payload": message.payload } # 只监听和转发order和state指令 VWED.device.register_and_run( device_ids=["AGV001"], device_type="vehicle", brand_name="seer", command_types=["order", "state"], # 只处理这两种指令 handler=order_and_state_handler, ) def example_4_seer_vehicles(): """示例4: 仙工品牌小车处理""" print("4. 仙工品牌小车处理") def seer_handler(message): """仙工小车处理器""" print(f"仙工小车消息: {message.topic}") # 根据消息类型进行不同处理 command_type = message.topic.split('/')[-1] if command_type == "state": # 状态消息特殊处理 battery_level = message.payload.get("batteryLevel", 100) if battery_level < 20: print(f"警告:小车电量低 {battery_level}%") return {"forward": True, "payload": message.payload} # 批量注册仙工小车处理器 VWED.device.register_and_run( device_ids=["SEER_001", "SEER_002"], device_type="vehicle", brand_name="seer", handler=seer_handler, script_id="example_script_004", description="仙工小车处理器" ) def example_5_mixed_device_types(): """示例5: 混合设备类型批量注册""" print("5. 混合设备类型批量注册") def mixed_handler(message): """混合设备处理器""" print(f"混合设备处理器收到消息: {message.topic}") device_id = message.topic.split('/')[-2] # 提取设备ID print(f"设备 {device_id} 发送消息") return {"forward": True, "payload": message.payload} # 批量注册多个设备(包括小车和其他设备类型) VWED.device.register_and_run( device_ids=["AGV_001", "DOOR_001", "CALLER_001"], device_type="vehicle", # 主要设备类型 brand_name="huarui", handler=mixed_handler, script_id="example_script_005", description="混合设备批量处理器" ) def register_door_handler(): """注册门禁处理器""" VWED.device.register_and_run( device_ids=["door_demo_main"], device_type="door", handler=door_access_controller, script_id="door_demo_001", description="演示门禁访问控制器" ) def register_caller_handler(): """注册呼叫器处理器""" VWED.device.register_and_run( device_ids=["caller_demo_lobby"], device_type="caller", handler=caller_signal_processor, script_id="caller_demo_001", description="演示呼叫器信号处理器" ) def register_sensor_handler(): """注册传感器处理器""" VWED.device.register_and_run( device_ids=["sensor_demo_env"], device_type="sensor", handler=environmental_processor, script_id="sensor_demo_001", description="演示环境传感器处理器" ) # ==================== 设备处理函数 ==================== def agv_command_processor(message): """AGV命令处理函数 - MQTT消息到达时自动执行""" 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) # 限制最大速度为50 safe_speed = min(speed, 50) # 构建安全移动命令 safe_command = { "command": "move_safe", "x": x, "y": y, "speed": safe_speed, "safety_check": True, "original_speed": speed, "processed_by": "agv_demo_001", "timestamp": VWED.util.now() } if speed != safe_speed: VWED.log.sync_warning(f"AGV速度已限制: {speed} -> {safe_speed}") VWED.log.sync_info(f"AGV安全命令生成: {safe_command}") return { "forward": True, "payload": safe_command } elif command == "stop": # 停止命令 - 直接转发 stop_command = { "command": "emergency_stop", "reason": message.payload.get("reason", "manual"), "timestamp": VWED.util.now() } VWED.log.sync_info("AGV紧急停止命令") return { "forward": True, "payload": stop_command } else: # 未知命令 VWED.log.sync_warning(f"AGV未知命令: {command}") return { "forward": False, "response": { "status": "error", "message": f"不支持的命令: {command}" }, "response_topic": "demo/agv/response" } def huarui_agv_processor(message): """华睿AGV处理函数 - 支持华睿协议自动编码/解码""" VWED.log.sync_info(f"华睿AGV收到消息: {message.payload}") # 由于启用了auto_encode=True,华睿协议已自动解码message.payload # 这里收到的是标准格式的数据 action = message.payload.get("action") if action == "status_update": # 状态更新 - 添加业务逻辑处理 status = message.payload.get("status") position = message.payload.get("position", {}) battery = message.payload.get("battery", 0) VWED.log.sync_info(f"华睿AGV状态: {status}, 位置: {position}, 电量: {battery}%") # 低电量预警 if battery < 20: VWED.log.sync_warning(f"华睿AGV电量不足: {battery}%") # 发送充电指令(会自动编码为华睿协议格式) return { "forward": True, "payload": { "action": "move", "x": 0, # 充电桩位置 "y": 0, "speed": 30, "task_id": f"charge_{VWED.util.timestamp()}" } } # 正常状态,无需特殊处理 return {"forward": False} else: VWED.log.sync_info(f"华睿AGV消息已处理: {action}") return {"forward": False} def seer_agv_processor(message): """仙工AGV处理函数 - 支持仙工协议自动编码/解码""" VWED.log.sync_info(f"仙工AGV收到消息: {message.payload}") # 仙工协议已自动解码,这里处理标准格式数据 action = message.payload.get("action") if action == "status_update": status = message.payload.get("status") position = message.payload.get("position", {}) velocity = message.payload.get("velocity", 0) VWED.log.sync_info(f"仙工AGV状态: {status}, 位置: {position}, 速度: {velocity}") # 仙工特定的逻辑处理 if status == "error": VWED.log.sync_error("仙工AGV出现错误,发送重启指令") # 发送重启指令(会自动编码为仙工协议格式) return { "forward": True, "payload": { "action": "stop", "reason": "error_recovery" } } return {"forward": False} else: VWED.log.sync_info(f"仙工AGV消息已处理: {action}") return {"forward": False} def door_access_controller(message): """门禁访问控制函数""" card_id = message.payload.get("card_id") door_id = message.payload.get("door_id", "main") VWED.log.sync_info(f"门禁访问请求: 卡号={card_id}, 门={door_id}") # 简单的白名单验证 whitelist = ["DEMO001", "DEMO002", "DEMO003"] if card_id in whitelist: # 授权开门 open_command = { "action": "open", "door_id": door_id, "card_id": card_id, "authorized": True, "open_duration": 5, # 5秒 "timestamp": VWED.util.now() } 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", "card_id": card_id, "reason": "unauthorized", "timestamp": VWED.util.now() }, "response_topic": "demo/door/response" } def caller_signal_processor(message): """呼叫器信号处理函数""" caller_id = message.payload.get("caller_id") signal_type = message.payload.get("signal_type", "service") location = message.payload.get("location", "unknown") VWED.log.sync_info(f"呼叫信号: {caller_id} - {signal_type} @ {location}") if signal_type == "emergency": # 紧急呼叫 response = { "type": "emergency_response", "caller_id": caller_id, "location": location, "status": "received", "response_team": "security", "estimated_time": "2 minutes", "message": "紧急响应团队已派遣", "timestamp": VWED.util.now() } VWED.log.sync_error(f"紧急呼叫处理: {caller_id}") elif signal_type == "service": # 服务请求 response = { "type": "service_response", "caller_id": caller_id, "location": location, "status": "queued", "queue_position": 1, "estimated_time": "5 minutes", "message": "服务请求已接收", "timestamp": VWED.util.now() } VWED.log.sync_info(f"服务请求处理: {caller_id}") else: # 其他类型 response = { "type": "info_response", "caller_id": caller_id, "status": "received", "message": "请求已收到", "timestamp": VWED.util.now() } return { "forward": True, "payload": response } def environmental_processor(message): """环境传感器处理函数""" sensor_id = message.payload.get("sensor_id") temperature = message.payload.get("temperature") humidity = message.payload.get("humidity") VWED.log.sync_info(f"环境数据: 传感器={sensor_id}, 温度={temperature}°C, 湿度={humidity}%") control_commands = [] # 温度控制逻辑 if temperature is not None: if temperature > 26: control_commands.append({ "device": "ac", "action": "cool", "target_temp": 24, "reason": f"温度过高: {temperature}°C" }) VWED.log.sync_info(f"启动制冷: 目标温度24°C") elif temperature < 20: control_commands.append({ "device": "heater", "action": "heat", "target_temp": 22, "reason": f"温度过低: {temperature}°C" }) VWED.log.sync_info(f"启动加热: 目标温度22°C") # 湿度控制逻辑 if humidity is not None and humidity > 70: control_commands.append({ "device": "dehumidifier", "action": "on", "target_humidity": 60, "reason": f"湿度过高: {humidity}%" }) VWED.log.sync_info(f"启动除湿: 目标湿度60%") if control_commands: # 有控制指令需要发送 hvac_control = { "sensor_id": sensor_id, "controls": control_commands, "timestamp": VWED.util.now() } return { "forward": True, "payload": hvac_control } else: # 环境正常,不需要控制 VWED.log.sync_info("环境参数正常,无需调整") return {"forward": False} # ==================== 测试和管理函数 ==================== def test_device_handlers(): """测试设备处理器功能""" VWED.log.sync_info("开始测试设备处理器...") # 测试AGV VWED.device.sync_publish_message( topic="demo/agv/command", payload={ "command": "move", "x": 100, "y": 200, "speed": 80 } ) # 测试门禁 VWED.device.sync_publish_message( topic="demo/door/access_request", payload={ "card_id": "DEMO001", "door_id": "main_entrance" } ) # 测试呼叫器 VWED.device.sync_publish_message( topic="demo/caller/signal", payload={ "caller_id": "LOBBY_01", "signal_type": "service", "location": "main_lobby" } ) # 测试传感器 VWED.device.sync_publish_message( topic="demo/sensor/data", payload={ "sensor_id": "ENV_001", "temperature": 28, "humidity": 75 } ) VWED.log.sync_info("设备处理器测试完成") def get_device_status(): """获取所有设备处理器状态""" handlers = VWED.device.get_running_handlers() VWED.log.sync_info("=== 设备处理器状态 ===") VWED.log.sync_info(f"设备总数: {handlers.get('device_count', 0)}") VWED.log.sync_info(f"运行中: {handlers.get('running_devices', 0)}") devices = handlers.get("devices", {}) for device_id, status in devices.items(): VWED.log.sync_info(f"设备 {device_id}: 消息处理 {status.get('total_messages', 0)} 条") return handlers # ==================== 工具函数 ==================== def stop_all_handlers(): """停止所有设备处理器(用于测试)""" handlers = ["agv_demo_001", "door_demo_main", "caller_demo_lobby", "sensor_demo_env"] for device_id in handlers: try: VWED.device.stop_handler(device_id) VWED.log.sync_info(f"已停止设备处理器: {device_id}") except Exception as e: VWED.log.sync_warning(f"停止设备处理器失败 {device_id}: {e}") def show_device_types(): """显示支持的设备类型""" device_types = VWED.device.get_device_types() VWED.log.sync_info(f"支持的设备类型: {', '.join(device_types)}") return device_types def show_device_brands(): """显示支持的设备品牌""" device_brands = VWED.device.get_device_brands() VWED.log.sync_info(f"支持的设备品牌: {', '.join(device_brands)}") return device_brands def show_available_protocols(): """显示所有可用的协议""" protocols = VWED.device.get_protocols() VWED.log.sync_info("=== 可用的设备协议 ===") for protocol_key, protocol_info in protocols.items(): brand = protocol_info.get("brand", "unknown") device_type = protocol_info.get("device_type", "unknown") commands = protocol_info.get("supported_commands", []) VWED.log.sync_info(f"协议: {protocol_key}") VWED.log.sync_info(f" 品牌: {brand}") VWED.log.sync_info(f" 设备类型: {device_type}") VWED.log.sync_info(f" 支持指令: {', '.join(commands)}") VWED.log.sync_info("") return protocols def test_protocol_encoding(): """测试协议编码功能""" VWED.log.sync_info("=== 测试协议编码功能 ===") # 测试华睿协议编码 huarui_test = VWED.device.test_protocol_encoding( protocol_key="huarui_vehicle", test_command={ "action": "move", "x": 100, "y": 200, "speed": 50, "task_id": "test_001" } ) if huarui_test["success"]: VWED.log.sync_info("华睿协议编码测试成功:") VWED.log.sync_info(f" 原始指令: {huarui_test['original']}") VWED.log.sync_info(f" 编码后: {huarui_test['encoded']}") else: VWED.log.sync_error(f"华睿协议编码测试失败: {huarui_test['error']}") # 测试仙工协议编码 seer_test = VWED.device.test_protocol_encoding( protocol_key="seer_vehicle", test_command={ "action": "move", "x": 150, "y": 250, "speed": 1500, # 仙工使用mm/s "task_id": "test_002" } ) if seer_test["success"]: VWED.log.sync_info("仙工协议编码测试成功:") VWED.log.sync_info(f" 原始指令: {seer_test['original']}") VWED.log.sync_info(f" 编码后: {seer_test['encoded']}") else: VWED.log.sync_error(f"仙工协议编码测试失败: {seer_test['error']}") return {"huarui": huarui_test, "seer": seer_test} def register_custom_protocol_example(): """注册自定义协议示例""" def my_encode(command): """自定义编码函数""" return { "header": { "version": "1.0", "timestamp": VWED.util.timestamp() }, "body": { "cmd_type": command.get("action", "unknown"), "params": command } } def my_decode(response): """自定义解码函数""" body = response.get("body", {}) return { "action": "status_update", "data": body, "decoded_at": VWED.util.now() } # 注册自定义协议 VWED.device.register_custom_protocol( protocol_key="my_custom_agv", brand="my_brand", device_type="vehicle", encode_func=my_encode, decode_func=my_decode, supported_commands=["move", "stop", "pause", "status"] ) VWED.log.sync_info("自定义协议注册完成") # 测试自定义协议 test_result = VWED.device.test_protocol_encoding( protocol_key="my_custom_agv", test_command={ "action": "move", "x": 300, "y": 400 } ) if test_result["success"]: VWED.log.sync_info("自定义协议测试成功:") VWED.log.sync_info(f" 编码结果: {test_result['encoded']}") else: VWED.log.sync_error(f"自定义协议测试失败: {test_result['error']}") return test_result