VWED_server/docs/device_quick_start_example.py

730 lines
22 KiB
Python
Raw Normal View History

2025-09-20 16:50:45 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
2025-09-25 10:52:52 +08:00
设备处理器快速入门示例
演示新的简化批量注册接口 - 自动生成MQTT topics
支持华瑞仙工等品牌小车的批量注册和自动消息转发
基于device_ids的通用设备注册方法
2025-09-20 16:50:45 +08:00
"""
def boot():
2025-09-25 10:52:52 +08:00
"""脚本启动函数 - 演示新的简化接口"""
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
print("=== 设备处理器快速入门示例 ===")
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
# 1. 最简单的自动透传(推荐用法)
example_1_auto_forward()
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
# 2. 自定义处理器
example_2_custom_handler()
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
# 3. 指定特定指令类型
example_3_specific_commands()
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
# 4. 仙工品牌示例
example_4_seer_vehicles()
# 5. 混合设备类型示例
example_5_mixed_device_types()
print("=== 设备处理器注册完成 ===")
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
def example_1_auto_forward():
"""示例1: 最简单的自动透传(推荐用法)"""
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
print("1. 批量注册华瑞小车自动透传")
# 批量注册华瑞小车系统自动生成topics和透传逻辑
2025-09-20 16:50:45 +08:00
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["AGV001", "AGV002", "AGV003"],
2025-09-20 16:50:45 +08:00
device_type="vehicle",
2025-09-25 10:52:52 +08:00
brand_name="huarui",
script_id="example_script_001",
description="华瑞小车批量自动透传"
2025-09-20 16:50:45 +08:00
)
2025-09-25 10:52:52 +08:00
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
}
# 使用自定义处理器批量注册
2025-09-20 16:50:45 +08:00
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["AGV001", "AGV002"],
2025-09-20 16:50:45 +08:00
device_type="vehicle",
2025-09-25 10:52:52 +08:00
brand_name="huarui",
handler=my_custom_handler,
script_id="example_script_002",
description="自定义华瑞小车处理器"
2025-09-20 16:50:45 +08:00
)
2025-09-25 10:52:52 +08:00
def example_3_specific_commands():
"""示例3: 指定特定指令类型"""
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
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指令
2025-09-20 16:50:45 +08:00
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["AGV001"],
device_type="vehicle",
brand_name="seer",
command_types=["order", "state"], # 只处理这两种指令
handler=order_and_state_handler,
2025-09-20 16:50:45 +08:00
)
2025-09-25 10:52:52 +08:00
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}
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
# 批量注册仙工小车处理器
2025-09-20 16:50:45 +08:00
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["SEER_001", "SEER_002"],
device_type="vehicle",
brand_name="seer",
handler=seer_handler,
script_id="example_script_004",
description="仙工小车处理器"
2025-09-20 16:50:45 +08:00
)
2025-09-25 10:52:52 +08:00
def example_5_mixed_device_types():
"""示例5: 混合设备类型批量注册"""
print("5. 混合设备类型批量注册")
2025-09-20 16:50:45 +08:00
2025-09-25 10:52:52 +08:00
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}
# 批量注册多个设备(包括小车和其他设备类型)
2025-09-20 16:50:45 +08:00
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["AGV_001", "DOOR_001", "CALLER_001"],
device_type="vehicle", # 主要设备类型
brand_name="huarui",
handler=mixed_handler,
script_id="example_script_005",
description="混合设备批量处理器"
2025-09-20 16:50:45 +08:00
)
def register_door_handler():
"""注册门禁处理器"""
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["door_demo_main"],
device_type="door",
2025-09-20 16:50:45 +08:00
handler=door_access_controller,
2025-09-25 10:52:52 +08:00
script_id="door_demo_001",
2025-09-20 16:50:45 +08:00
description="演示门禁访问控制器"
)
def register_caller_handler():
"""注册呼叫器处理器"""
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["caller_demo_lobby"],
2025-09-20 16:50:45 +08:00
device_type="caller",
handler=caller_signal_processor,
2025-09-25 10:52:52 +08:00
script_id="caller_demo_001",
2025-09-20 16:50:45 +08:00
description="演示呼叫器信号处理器"
)
def register_sensor_handler():
"""注册传感器处理器"""
VWED.device.register_and_run(
2025-09-25 10:52:52 +08:00
device_ids=["sensor_demo_env"],
2025-09-20 16:50:45 +08:00
device_type="sensor",
handler=environmental_processor,
2025-09-25 10:52:52 +08:00
script_id="sensor_demo_001",
2025-09-20 16:50:45 +08:00
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