创建项目及AI生成基本代码
This commit is contained in:
1
internal/__init__.py
Normal file
1
internal/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# internal package
|
||||
6
internal/core/__init__.py
Normal file
6
internal/core/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# 核心业务逻辑模块
|
||||
# 包含中继器的主要业务逻辑实现
|
||||
|
||||
from .relay import RelayService
|
||||
|
||||
__all__ = ['RelayService']
|
||||
289
internal/core/relay.py
Normal file
289
internal/core/relay.py
Normal file
@@ -0,0 +1,289 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
中继器核心服务模块
|
||||
实现持续运行的中继器服务,处理与平台的通信
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
import threading
|
||||
import asyncio
|
||||
import websockets
|
||||
from datetime import datetime
|
||||
from queue import Queue, Empty
|
||||
|
||||
from config import config
|
||||
from internal.protocol.lora import LoRaHandler
|
||||
from internal.protocol.websocket import WebSocketClient
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RelayService:
|
||||
"""中继器服务类"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化中继器服务"""
|
||||
self.device_id = config._config.get('relay', {}).get('device_id', '1')
|
||||
self.name = config._config.get('relay', {}).get('name', '默认中继器')
|
||||
self.running = False
|
||||
self.lora_handler = None
|
||||
self.websocket_client = None
|
||||
self.command_queue = Queue()
|
||||
self.response_queue = Queue()
|
||||
self.loop = None
|
||||
|
||||
logger.info(f"初始化中继器服务: ID={self.device_id}, 名称={self.name}")
|
||||
|
||||
def initialize(self):
|
||||
"""初始化中继器服务"""
|
||||
logger.info("开始初始化中继器服务")
|
||||
|
||||
# 初始化LoRa协议处理器
|
||||
self.lora_handler = LoRaHandler(config)
|
||||
self.lora_handler.initialize()
|
||||
|
||||
logger.info("中继器服务初始化完成")
|
||||
|
||||
def start(self):
|
||||
"""启动中继器服务"""
|
||||
logger.info("启动中继器服务")
|
||||
self.running = True
|
||||
|
||||
# 在新线程中运行异步事件循环
|
||||
websocket_thread = threading.Thread(target=self._run_websocket_loop, daemon=True)
|
||||
websocket_thread.start()
|
||||
|
||||
# 启动命令处理线程
|
||||
command_thread = threading.Thread(target=self._command_loop, daemon=True)
|
||||
command_thread.start()
|
||||
|
||||
# 主循环
|
||||
self._main_loop()
|
||||
|
||||
def stop(self):
|
||||
"""停止中继器服务"""
|
||||
logger.info("停止中继器服务")
|
||||
self.running = False
|
||||
|
||||
# 断开WebSocket连接
|
||||
if self.websocket_client:
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.websocket_client.disconnect(),
|
||||
self.loop
|
||||
)
|
||||
|
||||
def _run_websocket_loop(self):
|
||||
"""运行WebSocket事件循环"""
|
||||
# 创建新的事件循环
|
||||
self.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(self.loop)
|
||||
|
||||
# 运行事件循环
|
||||
self.loop.run_until_complete(self._websocket_main())
|
||||
|
||||
async def _websocket_main(self):
|
||||
"""WebSocket主协程"""
|
||||
# 创建WebSocket客户端
|
||||
self.websocket_client = WebSocketClient(self)
|
||||
|
||||
# 连接到平台
|
||||
if await self.websocket_client.connect():
|
||||
# 启动心跳任务
|
||||
heartbeat_task = asyncio.create_task(self._heartbeat_routine())
|
||||
|
||||
# 监听平台消息
|
||||
await self.websocket_client.listen()
|
||||
|
||||
# 取消心跳任务
|
||||
heartbeat_task.cancel()
|
||||
else:
|
||||
logger.error("无法连接到平台")
|
||||
|
||||
async def _heartbeat_routine(self):
|
||||
"""心跳协程"""
|
||||
logger.info("心跳协程启动")
|
||||
|
||||
try:
|
||||
while self.running:
|
||||
if self.websocket_client and self.websocket_client.is_connected():
|
||||
await self.websocket_client.send_heartbeat()
|
||||
|
||||
# 每30秒发送一次心跳
|
||||
await asyncio.sleep(30)
|
||||
except asyncio.CancelledError:
|
||||
logger.info("心跳协程被取消")
|
||||
except Exception as e:
|
||||
logger.error(f"心跳协程发生错误: {e}")
|
||||
|
||||
logger.info("心跳协程停止")
|
||||
|
||||
def _main_loop(self):
|
||||
"""主循环"""
|
||||
logger.info("中继器服务主循环开始")
|
||||
|
||||
try:
|
||||
while self.running:
|
||||
# 短暂休眠以避免过度占用CPU
|
||||
time.sleep(0.1)
|
||||
except KeyboardInterrupt:
|
||||
logger.info("收到中断信号,正在停止服务...")
|
||||
except Exception as e:
|
||||
logger.error(f"主循环发生错误: {e}")
|
||||
finally:
|
||||
self.stop()
|
||||
logger.info("中继器服务已停止")
|
||||
|
||||
def _command_loop(self):
|
||||
"""命令处理循环"""
|
||||
logger.info("命令处理线程启动")
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
# 处理命令队列中的指令
|
||||
try:
|
||||
command_data = self.command_queue.get(timeout=1)
|
||||
self._process_command(command_data)
|
||||
self.command_queue.task_done()
|
||||
except Empty:
|
||||
# 队列为空,继续循环
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"命令处理线程发生错误: {e}")
|
||||
|
||||
logger.info("命令处理线程停止")
|
||||
|
||||
def _process_command(self, command_data):
|
||||
"""处理平台指令"""
|
||||
try:
|
||||
logger.info(f"处理平台指令: {command_data}")
|
||||
|
||||
command_type = command_data.get('type')
|
||||
command_name = command_data.get('command')
|
||||
|
||||
if command_type == 'command':
|
||||
if command_name == 'control_device':
|
||||
self._handle_control_device(command_data)
|
||||
elif command_name == 'query_device_status':
|
||||
self._handle_query_device_status(command_data)
|
||||
elif command_name == 'query_all_device_status':
|
||||
self._handle_query_all_device_status(command_data)
|
||||
else:
|
||||
logger.warning(f"未知指令: {command_name}")
|
||||
self._send_error_response(command_data, f"未知指令: {command_name}")
|
||||
elif command_type == 'heartbeat':
|
||||
self._handle_heartbeat(command_data)
|
||||
elif command_type == 'system':
|
||||
# 处理系统消息
|
||||
logger.info(f"收到系统消息: {command_name}")
|
||||
else:
|
||||
logger.warning(f"未知消息类型: {command_type}")
|
||||
self._send_error_response(command_data, f"未知消息类型: {command_type}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理指令时发生错误: {e}")
|
||||
self._send_error_response(command_data, f"处理指令时发生错误: {str(e)}")
|
||||
|
||||
def _handle_control_device(self, command_data):
|
||||
"""处理设备控制指令"""
|
||||
data = command_data.get('data', {})
|
||||
device_id = data.get('device_id')
|
||||
action = data.get('action')
|
||||
|
||||
logger.info(f"控制设备: ID={device_id}, 动作={action}")
|
||||
|
||||
if self.lora_handler and config.simulation_enabled:
|
||||
result = self.lora_handler.send_command('control_device', data)
|
||||
# 发送响应到平台
|
||||
self._send_command_response(command_data, result)
|
||||
|
||||
def _handle_query_device_status(self, command_data):
|
||||
"""处理查询设备状态指令"""
|
||||
data = command_data.get('data', {})
|
||||
device_id = data.get('device_id')
|
||||
|
||||
logger.info(f"查询设备状态: ID={device_id}")
|
||||
|
||||
if self.lora_handler and config.simulation_enabled:
|
||||
result = self.lora_handler.send_command('query_device_status', data)
|
||||
# 发送响应到平台
|
||||
self._send_command_response(command_data, result)
|
||||
|
||||
def _handle_query_all_device_status(self, command_data):
|
||||
"""处理查询所有设备状态指令"""
|
||||
logger.info("查询所有设备状态")
|
||||
|
||||
if self.lora_handler and config.simulation_enabled:
|
||||
result = self.lora_handler.send_command('query_all_device_status', {})
|
||||
# 发送响应到平台
|
||||
self._send_command_response(command_data, result)
|
||||
|
||||
def _handle_heartbeat(self, command_data):
|
||||
"""处理心跳消息"""
|
||||
logger.info("收到平台心跳消息")
|
||||
|
||||
# 发送心跳响应
|
||||
response = {
|
||||
"type": "response",
|
||||
"command": "heartbeat",
|
||||
"status": "success",
|
||||
"message": "心跳响应",
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
|
||||
self._send_response(response)
|
||||
|
||||
def _send_command_response(self, command_data, result_data):
|
||||
"""发送指令响应"""
|
||||
response = {
|
||||
"type": "response",
|
||||
"command": command_data.get('command'),
|
||||
"data": result_data,
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
|
||||
self._send_response(response)
|
||||
|
||||
def _send_error_response(self, command_data, error_message):
|
||||
"""发送错误响应"""
|
||||
response = {
|
||||
"type": "response",
|
||||
"command": command_data.get('command', 'unknown'),
|
||||
"status": "failed",
|
||||
"message": error_message,
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
|
||||
self._send_response(response)
|
||||
|
||||
def _send_response(self, response):
|
||||
"""发送响应到平台"""
|
||||
if self.websocket_client and self.websocket_client.is_connected():
|
||||
# 在事件循环中发送响应
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.websocket_client.send_message(response),
|
||||
self.loop
|
||||
)
|
||||
else:
|
||||
logger.warning("WebSocket未连接,无法发送响应")
|
||||
|
||||
def handle_platform_command(self, command_json):
|
||||
"""
|
||||
处理来自平台的指令(供外部调用)
|
||||
|
||||
Args:
|
||||
command_json (str): JSON格式的指令字符串
|
||||
"""
|
||||
try:
|
||||
command_data = json.loads(command_json)
|
||||
self.command_queue.put(command_data)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"无效的JSON格式: {e}")
|
||||
except Exception as e:
|
||||
logger.error(f"处理平台指令时发生错误: {e}")
|
||||
2
internal/protocol/__init__.py
Normal file
2
internal/protocol/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# 协议处理模块
|
||||
# 处理与各种通信协议相关的功能
|
||||
57
internal/protocol/base.py
Normal file
57
internal/protocol/base.py
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
协议处理基类模块
|
||||
"""
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProtocolHandler(ABC):
|
||||
"""协议处理基类"""
|
||||
|
||||
def __init__(self, config):
|
||||
"""
|
||||
初始化协议处理器
|
||||
|
||||
Args:
|
||||
config: 配置对象
|
||||
"""
|
||||
self.config = config
|
||||
self.device_manager = None
|
||||
logger.info(f"初始化 {self.__class__.__name__}")
|
||||
|
||||
@abstractmethod
|
||||
def initialize(self):
|
||||
"""初始化协议处理器"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def send_command(self, command, data):
|
||||
"""
|
||||
发送命令到设备
|
||||
|
||||
Args:
|
||||
command (str): 命令类型
|
||||
data (dict): 命令数据
|
||||
|
||||
Returns:
|
||||
dict: 命令执行结果
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def receive_response(self):
|
||||
"""
|
||||
接收设备响应
|
||||
|
||||
Returns:
|
||||
dict: 设备响应数据
|
||||
"""
|
||||
pass
|
||||
2
internal/protocol/coap/__init__.py
Normal file
2
internal/protocol/coap/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# CoAP协议处理模块
|
||||
# 处理受限应用协议,轻量级的RESTful协议,适用于资源受限设备
|
||||
6
internal/protocol/lora/__init__.py
Normal file
6
internal/protocol/lora/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# LoRa协议处理模块
|
||||
# 处理LoRa物理层通信相关功能
|
||||
|
||||
from .handler import LoRaHandler
|
||||
|
||||
__all__ = ['LoRaHandler']
|
||||
192
internal/protocol/lora/handler.py
Normal file
192
internal/protocol/lora/handler.py
Normal file
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
LoRa协议处理模块
|
||||
处理LoRa物理层通信相关功能
|
||||
支持四级结构:平台->中继->区域主控->普通设备
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
import random
|
||||
from ..base import ProtocolHandler
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LoRaHandler(ProtocolHandler):
|
||||
"""LoRa协议处理器"""
|
||||
|
||||
def __init__(self, config):
|
||||
"""
|
||||
初始化LoRa协议处理器
|
||||
|
||||
Args:
|
||||
config: 配置对象
|
||||
"""
|
||||
super().__init__(config)
|
||||
self.initialized = False
|
||||
logger.info("初始化LoRa协议处理器")
|
||||
|
||||
def initialize(self):
|
||||
"""初始化LoRa协议处理器"""
|
||||
logger.info("开始初始化LoRa通信")
|
||||
|
||||
# 模拟LoRa硬件初始化
|
||||
time.sleep(0.5)
|
||||
self.initialized = True
|
||||
|
||||
# 如果启用模拟模式,初始化设备管理器
|
||||
if self.config.simulation_enabled:
|
||||
from internal.simulation import DeviceManager, AreaController, NormalDevice
|
||||
self.device_manager = DeviceManager()
|
||||
|
||||
# 根据配置创建模拟区域主控设备
|
||||
controllers = {}
|
||||
for controller_config in self.config.simulation_controllers:
|
||||
controller = AreaController(
|
||||
device_id=controller_config['id'],
|
||||
lora_address=controller_config['lora_address'],
|
||||
status=controller_config.get('status', 'stopped')
|
||||
)
|
||||
self.device_manager.add_controller(controller)
|
||||
controllers[controller.device_id] = controller
|
||||
|
||||
# 根据配置创建模拟普通设备,并关联到区域主控
|
||||
for device_config in self.config.simulation_devices:
|
||||
device = NormalDevice(
|
||||
device_id=device_config['id'],
|
||||
device_type=device_config['type'],
|
||||
rs485_bus=device_config['rs485_bus'],
|
||||
rs485_address=device_config['rs485_address'],
|
||||
controller_id=device_config['controller_id'],
|
||||
status=device_config.get('status', 'stopped')
|
||||
)
|
||||
self.device_manager.add_device(device)
|
||||
|
||||
# 将设备添加到对应的区域主控中
|
||||
controller_id = device_config['controller_id']
|
||||
if controller_id in controllers:
|
||||
controllers[controller_id].add_device(device)
|
||||
|
||||
logger.info(f"模拟模式已启用,创建了 {len(controllers)} 个区域主控和 {len(self.config.simulation_devices)} 个普通设备")
|
||||
else:
|
||||
logger.info("真实模式,需要连接LoRa硬件")
|
||||
|
||||
logger.info("LoRa协议处理器初始化完成")
|
||||
|
||||
def send_command(self, command, data):
|
||||
"""
|
||||
通过LoRa发送命令到设备
|
||||
|
||||
Args:
|
||||
command (str): 命令类型
|
||||
data (dict): 命令数据
|
||||
|
||||
Returns:
|
||||
dict: 命令执行结果
|
||||
"""
|
||||
if not self.initialized:
|
||||
logger.error("LoRa协议处理器未初始化")
|
||||
return {
|
||||
"status": "failed",
|
||||
"message": "LoRa协议处理器未初始化"
|
||||
}
|
||||
|
||||
logger.info(f"通过LoRa发送命令: {command}, 数据: {data}")
|
||||
|
||||
# 如果启用模拟模式,直接处理命令
|
||||
if self.config.simulation_enabled and self.device_manager:
|
||||
result = self._handle_simulated_command(command, data)
|
||||
logger.info(f"模拟命令处理结果: {result}")
|
||||
return result
|
||||
|
||||
# 真实模式下需要实际发送命令到LoRa设备
|
||||
logger.info("真实模式下发送命令到LoRa设备")
|
||||
# 这里应该是实际的LoRa通信代码
|
||||
# 暂时返回模拟响应
|
||||
time.sleep(0.1) # 模拟通信延迟
|
||||
return {
|
||||
"status": "success" if random.choice([True, False]) else "failed",
|
||||
"message": "命令发送成功" if random.choice([True, False]) else "命令发送失败",
|
||||
"data": {
|
||||
"device_id": data.get("device_id", "unknown"),
|
||||
"timestamp": time.time()
|
||||
}
|
||||
}
|
||||
|
||||
def receive_response(self):
|
||||
"""
|
||||
从LoRa接收设备响应
|
||||
|
||||
Returns:
|
||||
dict: 设备响应数据
|
||||
"""
|
||||
if not self.initialized:
|
||||
logger.error("LoRa协议处理器未初始化")
|
||||
return {
|
||||
"status": "failed",
|
||||
"message": "LoRa协议处理器未初始化"
|
||||
}
|
||||
|
||||
logger.info("从LoRa接收设备响应")
|
||||
|
||||
# 如果启用模拟模式,返回模拟响应
|
||||
if self.config.simulation_enabled and self.device_manager:
|
||||
# 在模拟模式下,我们假设命令已经直接处理完成,不需要单独接收响应
|
||||
logger.info("模拟模式下命令已直接处理完成")
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "模拟响应",
|
||||
"data": {}
|
||||
}
|
||||
|
||||
# 真实模式下需要实际从LoRa设备接收响应
|
||||
logger.info("真实模式下从LoRa设备接收响应")
|
||||
# 这里应该是实际的LoRa通信代码
|
||||
# 暂时返回模拟响应
|
||||
time.sleep(0.1) # 模拟通信延迟
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "接收响应成功",
|
||||
"data": {
|
||||
"response_data": "sample_data",
|
||||
"timestamp": time.time()
|
||||
}
|
||||
}
|
||||
|
||||
def _handle_simulated_command(self, command, data):
|
||||
"""
|
||||
处理模拟命令
|
||||
|
||||
Args:
|
||||
command (str): 命令类型
|
||||
data (dict): 命令数据
|
||||
|
||||
Returns:
|
||||
dict: 命令执行结果
|
||||
"""
|
||||
logger.info(f"处理模拟命令: {command}")
|
||||
|
||||
if command == "control_device":
|
||||
device_id = data.get("device_id")
|
||||
action = data.get("action")
|
||||
return self.device_manager.control_device(device_id, action)
|
||||
elif command == "query_device_status":
|
||||
device_id = data.get("device_id")
|
||||
return self.device_manager.query_device_status(device_id)
|
||||
elif command == "query_all_device_status":
|
||||
statuses = self.device_manager.query_all_device_status()
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "查询所有设备状态成功",
|
||||
"data": statuses
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"status": "failed",
|
||||
"message": f"不支持的命令: {command}"
|
||||
}
|
||||
2
internal/protocol/lorawan/__init__.py
Normal file
2
internal/protocol/lorawan/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# LoRaWAN协议处理模块
|
||||
# 处理基于LoRa物理层的广域网协议功能,包括设备认证、加密和网络管理
|
||||
2
internal/protocol/lwm2m/__init__.py
Normal file
2
internal/protocol/lwm2m/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# LwM2M协议处理模块
|
||||
# 处理轻量级机器到机器协议,提供设备管理、固件更新等功能
|
||||
2
internal/protocol/senml/__init__.py
Normal file
2
internal/protocol/senml/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# SenML数据格式处理模块
|
||||
# 处理传感器标记语言,标准化的传感器数据表示格式
|
||||
6
internal/protocol/websocket/__init__.py
Normal file
6
internal/protocol/websocket/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# WebSocket通信处理模块
|
||||
# 处理与猪场主控的WebSocket通信
|
||||
|
||||
from .client import WebSocketClient
|
||||
|
||||
__all__ = ['WebSocketClient']
|
||||
143
internal/protocol/websocket/client.py
Normal file
143
internal/protocol/websocket/client.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
WebSocket客户端模块
|
||||
用于与平台建立WebSocket连接并处理通信
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import websockets
|
||||
from datetime import datetime
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from config import config
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WebSocketClient:
|
||||
"""WebSocket客户端类"""
|
||||
|
||||
def __init__(self, relay_service):
|
||||
"""
|
||||
初始化WebSocket客户端
|
||||
|
||||
Args:
|
||||
relay_service: 中继器服务实例
|
||||
"""
|
||||
self.relay_service = relay_service
|
||||
self.device_id = config._config.get('relay', {}).get('device_id', '1')
|
||||
self.host = config._config.get('websocket', {}).get('host', 'localhost')
|
||||
self.port = config._config.get('websocket', {}).get('port', 8086)
|
||||
self.timeout = config._config.get('websocket', {}).get('timeout', 5)
|
||||
self.websocket = None
|
||||
self.connected = False
|
||||
self.running = False
|
||||
|
||||
logger.info(f"初始化WebSocket客户端: device_id={self.device_id}, host={self.host}, port={self.port}")
|
||||
|
||||
async def connect(self):
|
||||
"""建立WebSocket连接"""
|
||||
try:
|
||||
# 构建连接URL
|
||||
params = urlencode({'device_id': self.device_id})
|
||||
uri = f"ws://{self.host}:{self.port}/ws/device?{params}"
|
||||
|
||||
logger.info(f"正在连接到平台: {uri}")
|
||||
|
||||
# 建立WebSocket连接(移除了timeout参数以兼容新版本websockets库)
|
||||
self.websocket = await websockets.connect(uri)
|
||||
self.connected = True
|
||||
self.running = True
|
||||
|
||||
logger.info("成功连接到平台")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"连接平台失败: {e}")
|
||||
self.connected = False
|
||||
return False
|
||||
|
||||
async def disconnect(self):
|
||||
"""断开WebSocket连接"""
|
||||
logger.info("断开WebSocket连接")
|
||||
self.running = False
|
||||
|
||||
if self.websocket:
|
||||
await self.websocket.close()
|
||||
self.websocket = None
|
||||
|
||||
self.connected = False
|
||||
logger.info("WebSocket连接已断开")
|
||||
|
||||
async def send_message(self, message):
|
||||
"""
|
||||
发送消息到平台
|
||||
|
||||
Args:
|
||||
message (dict): 要发送的消息
|
||||
"""
|
||||
if not self.connected or not self.websocket:
|
||||
logger.warning("WebSocket未连接,无法发送消息")
|
||||
return False
|
||||
|
||||
try:
|
||||
message_str = json.dumps(message, ensure_ascii=False)
|
||||
await self.websocket.send(message_str)
|
||||
logger.debug(f"发送消息到平台: {message_str}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"发送消息失败: {e}")
|
||||
return False
|
||||
|
||||
async def listen(self):
|
||||
"""监听平台消息"""
|
||||
if not self.connected or not self.websocket:
|
||||
logger.error("WebSocket未连接,无法监听消息")
|
||||
return
|
||||
|
||||
logger.info("开始监听平台消息")
|
||||
|
||||
try:
|
||||
async for message in self.websocket:
|
||||
try:
|
||||
# 解析收到的消息
|
||||
message_data = json.loads(message)
|
||||
logger.info(f"收到平台消息: {message_data}")
|
||||
|
||||
# 将消息传递给中继器服务处理
|
||||
self.relay_service.handle_platform_command(message)
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"解析平台消息失败: {e}")
|
||||
except Exception as e:
|
||||
logger.error(f"处理平台消息时发生错误: {e}")
|
||||
|
||||
except websockets.exceptions.ConnectionClosed:
|
||||
logger.warning("WebSocket连接已关闭")
|
||||
self.connected = False
|
||||
except Exception as e:
|
||||
logger.error(f"监听平台消息时发生错误: {e}")
|
||||
self.connected = False
|
||||
|
||||
async def send_heartbeat(self):
|
||||
"""发送心跳消息"""
|
||||
if not self.connected:
|
||||
return False
|
||||
|
||||
heartbeat_msg = {
|
||||
"type": "heartbeat",
|
||||
"device_id": self.device_id,
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
|
||||
return await self.send_message(heartbeat_msg)
|
||||
|
||||
def is_connected(self):
|
||||
"""检查是否已连接"""
|
||||
return self.connected
|
||||
6
internal/simulation/__init__.py
Normal file
6
internal/simulation/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# 模拟模块
|
||||
# 用于在没有实际设备的情况下模拟场内子系统设备
|
||||
|
||||
from .device_interface import SimulatedDevice, DeviceManager, AreaController, NormalDevice
|
||||
|
||||
__all__ = ['SimulatedDevice', 'DeviceManager', 'AreaController', 'NormalDevice']
|
||||
480
internal/simulation/device_interface.py
Normal file
480
internal/simulation/device_interface.py
Normal file
@@ -0,0 +1,480 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
设备模拟接口模块,用于模拟场内子系统设备
|
||||
支持四级结构:平台->中继->区域主控->普通设备
|
||||
"""
|
||||
|
||||
import random
|
||||
import time
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeviceType(Enum):
|
||||
"""设备类型枚举"""
|
||||
AREA_CONTROLLER = "area_controller" # 区域主控
|
||||
NORMAL_DEVICE = "normal_device" # 普通设备
|
||||
|
||||
|
||||
class SimulatedDevice:
|
||||
"""模拟设备基类"""
|
||||
|
||||
def __init__(self, device_id, device_type, status="stopped"):
|
||||
"""
|
||||
初始化模拟设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
device_type (DeviceType): 设备类型
|
||||
status (str): 初始状态
|
||||
"""
|
||||
self.device_id = device_id
|
||||
self.device_type = device_type
|
||||
self.status = status
|
||||
self.created_at = time.time()
|
||||
logger.info(f"创建模拟设备: ID={device_id}, 类型={device_type.value}, 状态={status}")
|
||||
|
||||
|
||||
class AreaController(SimulatedDevice):
|
||||
"""区域主控设备"""
|
||||
|
||||
def __init__(self, device_id, lora_address, status="stopped"):
|
||||
"""
|
||||
初始化区域主控设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
lora_address (str): LoRa地址
|
||||
status (str): 初始状态
|
||||
"""
|
||||
super().__init__(device_id, DeviceType.AREA_CONTROLLER, status)
|
||||
self.lora_address = lora_address
|
||||
self.devices = {} # 管理的普通设备
|
||||
logger.info(f"创建区域主控: ID={device_id}, LoRa地址={lora_address}")
|
||||
|
||||
def add_device(self, device):
|
||||
"""
|
||||
添加普通设备到区域主控
|
||||
|
||||
Args:
|
||||
device (NormalDevice): 普通设备实例
|
||||
"""
|
||||
self.devices[device.device_id] = device
|
||||
logger.info(f"区域主控 {self.device_id} 添加设备: {device.device_id}")
|
||||
|
||||
def remove_device(self, device_id):
|
||||
"""
|
||||
从区域主控移除普通设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
"""
|
||||
if device_id in self.devices:
|
||||
del self.devices[device_id]
|
||||
logger.info(f"区域主控 {self.device_id} 移除设备: {device_id}")
|
||||
|
||||
def get_device(self, device_id):
|
||||
"""
|
||||
获取区域主控下的普通设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
|
||||
Returns:
|
||||
NormalDevice: 普通设备实例,如果不存在则返回None
|
||||
"""
|
||||
return self.devices.get(device_id)
|
||||
|
||||
def get_all_devices(self):
|
||||
"""
|
||||
获取区域主控下的所有普通设备
|
||||
|
||||
Returns:
|
||||
list: 所有普通设备实例的列表
|
||||
"""
|
||||
return list(self.devices.values())
|
||||
|
||||
|
||||
class NormalDevice(SimulatedDevice):
|
||||
"""普通设备"""
|
||||
|
||||
def __init__(self, device_id, device_type, rs485_bus, rs485_address, controller_id, status="stopped"):
|
||||
"""
|
||||
初始化普通设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
device_type (str): 设备类型(如风机、水帘等)
|
||||
rs485_bus (str): 485总线号
|
||||
rs485_address (str): 485总线地址
|
||||
controller_id (str): 所属区域主控ID
|
||||
status (str): 初始状态
|
||||
"""
|
||||
super().__init__(device_id, DeviceType.NORMAL_DEVICE, status)
|
||||
self.device_type = device_type
|
||||
self.rs485_bus = rs485_bus
|
||||
self.rs485_address = rs485_address
|
||||
self.controller_id = controller_id
|
||||
logger.info(f"创建普通设备: ID={device_id}, 类型={device_type}, "
|
||||
f"485总线={rs485_bus}, 485地址={rs485_address}, 所属主控={controller_id}")
|
||||
|
||||
|
||||
class DeviceManager:
|
||||
"""设备管理器"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化设备管理器"""
|
||||
self.controllers = {} # 区域主控设备
|
||||
self.devices = {} # 所有普通设备
|
||||
logger.info("初始化设备管理器")
|
||||
|
||||
def add_controller(self, controller):
|
||||
"""
|
||||
添加区域主控设备
|
||||
|
||||
Args:
|
||||
controller (AreaController): 区域主控设备实例
|
||||
"""
|
||||
self.controllers[controller.device_id] = controller
|
||||
logger.info(f"添加区域主控到管理器: {controller.device_id}")
|
||||
|
||||
def remove_controller(self, controller_id):
|
||||
"""
|
||||
移除区域主控设备
|
||||
|
||||
Args:
|
||||
controller_id (str): 区域主控设备ID
|
||||
"""
|
||||
if controller_id in self.controllers:
|
||||
# 同时移除该主控下的所有普通设备
|
||||
controller = self.controllers[controller_id]
|
||||
for device_id in list(controller.devices.keys()):
|
||||
if device_id in self.devices:
|
||||
del self.devices[device_id]
|
||||
del self.controllers[controller_id]
|
||||
logger.info(f"从管理器移除区域主控: {controller_id}")
|
||||
|
||||
def get_controller(self, controller_id):
|
||||
"""
|
||||
获取区域主控设备
|
||||
|
||||
Args:
|
||||
controller_id (str): 区域主控设备ID
|
||||
|
||||
Returns:
|
||||
AreaController: 区域主控设备实例,如果不存在则返回None
|
||||
"""
|
||||
controller = self.controllers.get(controller_id)
|
||||
if controller:
|
||||
logger.debug(f"获取区域主控: {controller_id}")
|
||||
else:
|
||||
logger.warning(f"尝试获取不存在的区域主控: {controller_id}")
|
||||
return controller
|
||||
|
||||
def get_all_controllers(self):
|
||||
"""
|
||||
获取所有区域主控设备
|
||||
|
||||
Returns:
|
||||
list: 所有区域主控设备实例的列表
|
||||
"""
|
||||
logger.info(f"获取所有区域主控,共 {len(self.controllers)} 个")
|
||||
return list(self.controllers.values())
|
||||
|
||||
def add_device(self, device):
|
||||
"""
|
||||
添加普通设备
|
||||
|
||||
Args:
|
||||
device (NormalDevice): 普通设备实例
|
||||
"""
|
||||
self.devices[device.device_id] = device
|
||||
logger.info(f"添加普通设备到管理器: {device.device_id}")
|
||||
|
||||
def remove_device(self, device_id):
|
||||
"""
|
||||
移除普通设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
"""
|
||||
if device_id in self.devices:
|
||||
del self.devices[device_id]
|
||||
logger.info(f"从管理器移除普通设备: {device_id}")
|
||||
|
||||
def get_device(self, device_id):
|
||||
"""
|
||||
获取普通设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
|
||||
Returns:
|
||||
NormalDevice: 普通设备实例,如果不存在则返回None
|
||||
"""
|
||||
device = self.devices.get(device_id)
|
||||
if device:
|
||||
logger.debug(f"获取普通设备: {device_id}")
|
||||
else:
|
||||
logger.warning(f"尝试获取不存在的普通设备: {device_id}")
|
||||
return device
|
||||
|
||||
def get_all_devices(self):
|
||||
"""
|
||||
获取所有普通设备
|
||||
|
||||
Returns:
|
||||
list: 所有普通设备实例的列表
|
||||
"""
|
||||
logger.info(f"获取所有普通设备,共 {len(self.devices)} 个")
|
||||
return list(self.devices.values())
|
||||
|
||||
def control_device(self, device_id, action):
|
||||
"""
|
||||
控制指定设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
action (str): 控制动作
|
||||
|
||||
Returns:
|
||||
dict: 控制结果
|
||||
"""
|
||||
logger.info(f"控制设备: ID={device_id}, 动作={action}")
|
||||
|
||||
# 先尝试查找普通设备
|
||||
device = self.get_device(device_id)
|
||||
if device:
|
||||
return self._control_normal_device(device, action)
|
||||
|
||||
# 再尝试查找区域主控设备
|
||||
controller = self.get_controller(device_id)
|
||||
if controller:
|
||||
return self._control_area_controller(controller, action)
|
||||
|
||||
result = {
|
||||
"device_id": device_id,
|
||||
"status": "failed",
|
||||
"message": f"设备 {device_id} 不存在"
|
||||
}
|
||||
logger.error(f"控制设备失败: 设备 {device_id} 不存在")
|
||||
return result
|
||||
|
||||
def _control_normal_device(self, device, action):
|
||||
"""
|
||||
控制普通设备
|
||||
|
||||
Args:
|
||||
device (NormalDevice): 普通设备实例
|
||||
action (str): 控制动作
|
||||
|
||||
Returns:
|
||||
dict: 控制结果
|
||||
"""
|
||||
logger.info(f"控制普通设备 {device.device_id}: 动作={action}")
|
||||
|
||||
if action == "on":
|
||||
device.status = "running"
|
||||
result = {
|
||||
"device_id": device.device_id,
|
||||
"status": "success",
|
||||
"message": f"设备 {device.device_id} 已开启"
|
||||
}
|
||||
logger.info(f"普通设备 {device.device_id} 开启成功")
|
||||
return result
|
||||
elif action == "off":
|
||||
device.status = "stopped"
|
||||
result = {
|
||||
"device_id": device.device_id,
|
||||
"status": "success",
|
||||
"message": f"设备 {device.device_id} 已关闭"
|
||||
}
|
||||
logger.info(f"普通设备 {device.device_id} 关闭成功")
|
||||
return result
|
||||
else:
|
||||
result = {
|
||||
"device_id": device.device_id,
|
||||
"status": "failed",
|
||||
"message": f"不支持的操作: {action}"
|
||||
}
|
||||
logger.warning(f"普通设备 {device.device_id} 不支持的操作: {action}")
|
||||
return result
|
||||
|
||||
def _control_area_controller(self, controller, action):
|
||||
"""
|
||||
控制区域主控设备
|
||||
|
||||
Args:
|
||||
controller (AreaController): 区域主控设备实例
|
||||
action (str): 控制动作
|
||||
|
||||
Returns:
|
||||
dict: 控制结果
|
||||
"""
|
||||
logger.info(f"控制区域主控 {controller.device_id}: 动作={action}")
|
||||
|
||||
if action == "on":
|
||||
controller.status = "running"
|
||||
result = {
|
||||
"device_id": controller.device_id,
|
||||
"status": "success",
|
||||
"message": f"区域主控 {controller.device_id} 已开启"
|
||||
}
|
||||
logger.info(f"区域主控 {controller.device_id} 开启成功")
|
||||
return result
|
||||
elif action == "off":
|
||||
controller.status = "stopped"
|
||||
result = {
|
||||
"device_id": controller.device_id,
|
||||
"status": "success",
|
||||
"message": f"区域主控 {controller.device_id} 已关闭"
|
||||
}
|
||||
logger.info(f"区域主控 {controller.device_id} 关闭成功")
|
||||
return result
|
||||
else:
|
||||
result = {
|
||||
"device_id": controller.device_id,
|
||||
"status": "failed",
|
||||
"message": f"不支持的操作: {action}"
|
||||
}
|
||||
logger.warning(f"区域主控 {controller.device_id} 不支持的操作: {action}")
|
||||
return result
|
||||
|
||||
def query_device_status(self, device_id):
|
||||
"""
|
||||
查询指定设备状态
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
|
||||
Returns:
|
||||
dict: 设备状态信息
|
||||
"""
|
||||
logger.info(f"查询设备状态: ID={device_id}")
|
||||
|
||||
# 先尝试查找普通设备
|
||||
device = self.get_device(device_id)
|
||||
if device:
|
||||
return self._query_normal_device_status(device)
|
||||
|
||||
# 再尝试查找区域主控设备
|
||||
controller = self.get_controller(device_id)
|
||||
if controller:
|
||||
return self._query_area_controller_status(controller)
|
||||
|
||||
result = {
|
||||
"device_id": device_id,
|
||||
"status": "failed",
|
||||
"message": f"设备 {device_id} 不存在"
|
||||
}
|
||||
logger.error(f"查询设备状态失败: 设备 {device_id} 不存在")
|
||||
return result
|
||||
|
||||
def _query_normal_device_status(self, device):
|
||||
"""
|
||||
查询普通设备状态
|
||||
|
||||
Args:
|
||||
device (NormalDevice): 普通设备实例
|
||||
|
||||
Returns:
|
||||
dict: 设备状态信息
|
||||
"""
|
||||
logger.info(f"查询普通设备 {device.device_id} 状态")
|
||||
|
||||
# 模拟一些随机的设备数据
|
||||
if device.status == "running":
|
||||
power = random.randint(200, 240)
|
||||
current = random.uniform(4.0, 6.0)
|
||||
result = {
|
||||
"device_id": device.device_id,
|
||||
"device_type": device.device_type,
|
||||
"status": device.status,
|
||||
"rs485_bus": device.rs485_bus,
|
||||
"rs485_address": device.rs485_address,
|
||||
"controller_id": device.controller_id,
|
||||
"power": power,
|
||||
"current": round(current, 2)
|
||||
}
|
||||
logger.info(f"普通设备 {device.device_id} 状态: 运行中, 功率={power}V, 电流={round(current, 2)}A")
|
||||
return result
|
||||
else:
|
||||
result = {
|
||||
"device_id": device.device_id,
|
||||
"device_type": device.device_type,
|
||||
"status": device.status,
|
||||
"rs485_bus": device.rs485_bus,
|
||||
"rs485_address": device.rs485_address,
|
||||
"controller_id": device.controller_id,
|
||||
"power": 0,
|
||||
"current": 0.0
|
||||
}
|
||||
logger.info(f"普通设备 {device.device_id} 状态: 已停止")
|
||||
return result
|
||||
|
||||
def _query_area_controller_status(self, controller):
|
||||
"""
|
||||
查询区域主控状态
|
||||
|
||||
Args:
|
||||
controller (AreaController): 区域主控设备实例
|
||||
|
||||
Returns:
|
||||
dict: 设备状态信息
|
||||
"""
|
||||
logger.info(f"查询区域主控 {controller.device_id} 状态")
|
||||
|
||||
result = {
|
||||
"device_id": controller.device_id,
|
||||
"device_type": "area_controller",
|
||||
"status": controller.status,
|
||||
"lora_address": controller.lora_address,
|
||||
"managed_devices": len(controller.devices)
|
||||
}
|
||||
logger.info(f"区域主控 {controller.device_id} 状态: {controller.status}, 管理设备数: {len(controller.devices)}")
|
||||
return result
|
||||
|
||||
def query_all_device_status(self):
|
||||
"""
|
||||
查询所有设备状态
|
||||
|
||||
Returns:
|
||||
list: 所有设备状态信息列表
|
||||
"""
|
||||
logger.info("查询所有设备状态")
|
||||
statuses = []
|
||||
|
||||
# 添加区域主控状态
|
||||
for controller in self.controllers.values():
|
||||
status_info = {
|
||||
"device_id": controller.device_id,
|
||||
"device_type": "area_controller",
|
||||
"status": controller.status,
|
||||
"lora_address": controller.lora_address,
|
||||
"managed_devices": len(controller.devices)
|
||||
}
|
||||
statuses.append(status_info)
|
||||
logger.debug(f"区域主控 {controller.device_id} 状态: {controller.status}")
|
||||
|
||||
# 添加普通设备状态
|
||||
for device in self.devices.values():
|
||||
status_info = {
|
||||
"device_id": device.device_id,
|
||||
"device_type": device.device_type,
|
||||
"status": device.status,
|
||||
"rs485_bus": device.rs485_bus,
|
||||
"rs485_address": device.rs485_address,
|
||||
"controller_id": device.controller_id
|
||||
}
|
||||
statuses.append(status_info)
|
||||
logger.debug(f"普通设备 {device.device_id} 状态: {device.status}")
|
||||
|
||||
logger.info(f"查询所有设备状态完成,共 {len(statuses)} 个设备")
|
||||
return statuses
|
||||
227
internal/simulation/devices.py
Normal file
227
internal/simulation/devices.py
Normal file
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
模拟设备模块,用于创建和管理模拟设备
|
||||
"""
|
||||
|
||||
import random
|
||||
import time
|
||||
import logging
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SimulatedDevice:
|
||||
"""模拟设备类"""
|
||||
|
||||
def __init__(self, device_id, device_type, status="stopped"):
|
||||
"""
|
||||
初始化模拟设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
device_type (str): 设备类型
|
||||
status (str): 初始状态
|
||||
"""
|
||||
self.device_id = device_id
|
||||
self.device_type = device_type
|
||||
self.status = status
|
||||
self.created_at = time.time()
|
||||
logger.info(f"创建模拟设备: ID={device_id}, 类型={device_type}, 状态={status}")
|
||||
|
||||
def control(self, action):
|
||||
"""
|
||||
控制设备
|
||||
|
||||
Args:
|
||||
action (str): 控制动作 ('on' 或 'off')
|
||||
|
||||
Returns:
|
||||
dict: 控制结果
|
||||
"""
|
||||
logger.info(f"控制设备 {self.device_id}: 动作={action}")
|
||||
|
||||
if action == "on":
|
||||
self.status = "running"
|
||||
result = {
|
||||
"device_id": self.device_id,
|
||||
"status": "success",
|
||||
"message": f"设备 {self.device_id} 已开启"
|
||||
}
|
||||
logger.info(f"设备 {self.device_id} 开启成功")
|
||||
return result
|
||||
elif action == "off":
|
||||
self.status = "stopped"
|
||||
result = {
|
||||
"device_id": self.device_id,
|
||||
"status": "success",
|
||||
"message": f"设备 {self.device_id} 已关闭"
|
||||
}
|
||||
logger.info(f"设备 {self.device_id} 关闭成功")
|
||||
return result
|
||||
else:
|
||||
result = {
|
||||
"device_id": self.device_id,
|
||||
"status": "failed",
|
||||
"message": f"不支持的操作: {action}"
|
||||
}
|
||||
logger.warning(f"设备 {self.device_id} 不支持的操作: {action}")
|
||||
return result
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
获取设备状态
|
||||
|
||||
Returns:
|
||||
dict: 设备状态信息
|
||||
"""
|
||||
logger.info(f"查询设备 {self.device_id} 状态")
|
||||
|
||||
# 模拟一些随机的设备数据
|
||||
if self.status == "running":
|
||||
power = random.randint(200, 240)
|
||||
current = random.uniform(4.0, 6.0)
|
||||
result = {
|
||||
"device_id": self.device_id,
|
||||
"status": self.status,
|
||||
"power": power,
|
||||
"current": round(current, 2)
|
||||
}
|
||||
logger.info(f"设备 {self.device_id} 状态: 运行中, 功率={power}V, 电流={round(current, 2)}A")
|
||||
return result
|
||||
else:
|
||||
result = {
|
||||
"device_id": self.device_id,
|
||||
"status": self.status,
|
||||
"power": 0,
|
||||
"current": 0.0
|
||||
}
|
||||
logger.info(f"设备 {self.device_id} 状态: 已停止")
|
||||
return result
|
||||
|
||||
|
||||
class DeviceManager:
|
||||
"""设备管理器"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化设备管理器"""
|
||||
self.devices = {}
|
||||
logger.info("初始化设备管理器")
|
||||
|
||||
def add_device(self, device):
|
||||
"""
|
||||
添加设备
|
||||
|
||||
Args:
|
||||
device (SimulatedDevice): 模拟设备实例
|
||||
"""
|
||||
self.devices[device.device_id] = device
|
||||
logger.info(f"添加设备到管理器: {device.device_id}")
|
||||
|
||||
def remove_device(self, device_id):
|
||||
"""
|
||||
移除设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
"""
|
||||
if device_id in self.devices:
|
||||
del self.devices[device_id]
|
||||
logger.info(f"从管理器移除设备: {device_id}")
|
||||
|
||||
def get_device(self, device_id):
|
||||
"""
|
||||
获取设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
|
||||
Returns:
|
||||
SimulatedDevice: 设备实例,如果不存在则返回None
|
||||
"""
|
||||
device = self.devices.get(device_id)
|
||||
if device:
|
||||
logger.debug(f"获取设备: {device_id}")
|
||||
else:
|
||||
logger.warning(f"尝试获取不存在的设备: {device_id}")
|
||||
return device
|
||||
|
||||
def get_all_devices(self):
|
||||
"""
|
||||
获取所有设备
|
||||
|
||||
Returns:
|
||||
list: 所有设备实例的列表
|
||||
"""
|
||||
logger.info(f"获取所有设备,共 {len(self.devices)} 个设备")
|
||||
return list(self.devices.values())
|
||||
|
||||
def control_device(self, device_id, action):
|
||||
"""
|
||||
控制指定设备
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
action (str): 控制动作
|
||||
|
||||
Returns:
|
||||
dict: 控制结果
|
||||
"""
|
||||
logger.info(f"控制设备: ID={device_id}, 动作={action}")
|
||||
device = self.get_device(device_id)
|
||||
if device:
|
||||
return device.control(action)
|
||||
else:
|
||||
result = {
|
||||
"device_id": device_id,
|
||||
"status": "failed",
|
||||
"message": f"设备 {device_id} 不存在"
|
||||
}
|
||||
logger.error(f"控制设备失败: 设备 {device_id} 不存在")
|
||||
return result
|
||||
|
||||
def query_device_status(self, device_id):
|
||||
"""
|
||||
查询指定设备状态
|
||||
|
||||
Args:
|
||||
device_id (str): 设备ID
|
||||
|
||||
Returns:
|
||||
dict: 设备状态信息
|
||||
"""
|
||||
logger.info(f"查询设备状态: ID={device_id}")
|
||||
device = self.get_device(device_id)
|
||||
if device:
|
||||
return device.get_status()
|
||||
else:
|
||||
result = {
|
||||
"device_id": device_id,
|
||||
"status": "failed",
|
||||
"message": f"设备 {device_id} 不存在"
|
||||
}
|
||||
logger.error(f"查询设备状态失败: 设备 {device_id} 不存在")
|
||||
return result
|
||||
|
||||
def query_all_device_status(self):
|
||||
"""
|
||||
查询所有设备状态
|
||||
|
||||
Returns:
|
||||
list: 所有设备状态信息列表
|
||||
"""
|
||||
logger.info("查询所有设备状态")
|
||||
statuses = []
|
||||
for device in self.devices.values():
|
||||
status_info = {
|
||||
"device_id": device.device_id,
|
||||
"device_type": device.device_type,
|
||||
"status": device.status
|
||||
}
|
||||
statuses.append(status_info)
|
||||
logger.debug(f"设备 {device.device_id} 状态: {device.status}")
|
||||
logger.info(f"查询所有设备状态完成,共 {len(statuses)} 个设备")
|
||||
return statuses
|
||||
187
internal/simulation/websocket.py
Normal file
187
internal/simulation/websocket.py
Normal file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
模拟WebSocket通信模块,用于模拟与猪场主控的WebSocket通信
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from .devices import DeviceManager, SimulatedDevice
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SimulatedWebSocketServer:
|
||||
"""模拟WebSocket服务器"""
|
||||
|
||||
def __init__(self, config):
|
||||
"""
|
||||
初始化模拟WebSocket服务器
|
||||
|
||||
Args:
|
||||
config: 配置对象
|
||||
"""
|
||||
self.config = config
|
||||
self.device_manager = DeviceManager()
|
||||
self._initialize_devices()
|
||||
logger.info("模拟WebSocket服务器初始化完成")
|
||||
|
||||
def _initialize_devices(self):
|
||||
"""初始化模拟设备"""
|
||||
logger.info("开始初始化模拟设备")
|
||||
# 根据配置创建模拟设备
|
||||
for device_config in self.config.simulation_devices:
|
||||
device = SimulatedDevice(
|
||||
device_id=device_config['id'],
|
||||
device_type=device_config['type'],
|
||||
status=device_config.get('status', 'stopped')
|
||||
)
|
||||
self.device_manager.add_device(device)
|
||||
logger.info(f"模拟设备初始化完成,共创建 {len(self.config.simulation_devices)} 个设备")
|
||||
|
||||
def handle_message(self, message_str):
|
||||
"""
|
||||
处理接收到的消息
|
||||
|
||||
Args:
|
||||
message_str (str): JSON格式的消息字符串
|
||||
|
||||
Returns:
|
||||
dict: 响应消息
|
||||
"""
|
||||
logger.info(f"收到消息: {message_str}")
|
||||
|
||||
try:
|
||||
message = json.loads(message_str)
|
||||
msg_type = message.get('type')
|
||||
logger.info(f"消息类型: {msg_type}")
|
||||
|
||||
if msg_type == 'heartbeat':
|
||||
return self._handle_heartbeat(message)
|
||||
elif msg_type == 'command':
|
||||
command = message.get('command')
|
||||
logger.info(f"命令类型: {command}")
|
||||
if command == 'control_device':
|
||||
return self._handle_control_device(message)
|
||||
elif command == 'query_device_status':
|
||||
return self._handle_query_device_status(message)
|
||||
elif command == 'query_all_device_status':
|
||||
return self._handle_query_all_device_status(message)
|
||||
|
||||
# 未知消息类型
|
||||
result = {
|
||||
"type": "response",
|
||||
"status": "failed",
|
||||
"message": f"未知消息类型: {msg_type}",
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
logger.warning(f"未知消息类型: {msg_type}")
|
||||
return result
|
||||
except json.JSONDecodeError:
|
||||
result = {
|
||||
"type": "response",
|
||||
"status": "failed",
|
||||
"message": "无效的JSON格式",
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
logger.error("无效的JSON格式")
|
||||
return result
|
||||
|
||||
def _handle_heartbeat(self, message):
|
||||
"""
|
||||
处理心跳消息
|
||||
|
||||
Args:
|
||||
message (dict): 心跳消息
|
||||
|
||||
Returns:
|
||||
dict: 心跳响应
|
||||
"""
|
||||
logger.info("处理心跳消息")
|
||||
result = {
|
||||
"type": "response",
|
||||
"command": "heartbeat",
|
||||
"status": "success",
|
||||
"message": "心跳响应",
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
logger.info("心跳响应已发送")
|
||||
return result
|
||||
|
||||
def _handle_control_device(self, message):
|
||||
"""
|
||||
处理设备控制命令
|
||||
|
||||
Args:
|
||||
message (dict): 控制命令消息
|
||||
|
||||
Returns:
|
||||
dict: 控制响应
|
||||
"""
|
||||
data = message.get('data', {})
|
||||
device_id = data.get('device_id')
|
||||
action = data.get('action')
|
||||
|
||||
logger.info(f"处理设备控制命令: 设备ID={device_id}, 动作={action}")
|
||||
result = self.device_manager.control_device(device_id, action)
|
||||
|
||||
response = {
|
||||
"type": "response",
|
||||
"command": "control_device",
|
||||
"data": result,
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
logger.info(f"设备控制命令处理完成: {response}")
|
||||
return response
|
||||
|
||||
def _handle_query_device_status(self, message):
|
||||
"""
|
||||
处理查询设备状态命令
|
||||
|
||||
Args:
|
||||
message (dict): 查询命令消息
|
||||
|
||||
Returns:
|
||||
dict: 状态响应
|
||||
"""
|
||||
data = message.get('data', {})
|
||||
device_id = data.get('device_id')
|
||||
|
||||
logger.info(f"处理查询设备状态命令: 设备ID={device_id}")
|
||||
result = self.device_manager.query_device_status(device_id)
|
||||
|
||||
response = {
|
||||
"type": "response",
|
||||
"command": "query_device_status",
|
||||
"data": result,
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
logger.info(f"设备状态查询完成: {response}")
|
||||
return response
|
||||
|
||||
def _handle_query_all_device_status(self, message):
|
||||
"""
|
||||
处理查询所有设备状态命令
|
||||
|
||||
Args:
|
||||
message (dict): 查询命令消息
|
||||
|
||||
Returns:
|
||||
dict: 状态响应
|
||||
"""
|
||||
logger.info("处理查询所有设备状态命令")
|
||||
result = self.device_manager.query_all_device_status()
|
||||
|
||||
response = {
|
||||
"type": "response",
|
||||
"command": "query_all_device_status",
|
||||
"data": result,
|
||||
"timestamp": datetime.utcnow().isoformat() + 'Z'
|
||||
}
|
||||
logger.info(f"所有设备状态查询完成,共 {len(result)} 个设备")
|
||||
return response
|
||||
Reference in New Issue
Block a user