创建项目及AI生成基本代码
This commit is contained in:
		
							
								
								
									
										6
									
								
								config/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								config/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | # 配置文件目录 | ||||||
|  | # 存放不同环境的配置文件 | ||||||
|  |  | ||||||
|  | from .config import Config, config | ||||||
|  |  | ||||||
|  | __all__ = ['Config', 'config'] | ||||||
							
								
								
									
										62
									
								
								config/config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								config/config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  |  | ||||||
|  | """ | ||||||
|  | 配置模块,用于加载和管理中继器的配置 | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import yaml | ||||||
|  | import os | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Config: | ||||||
|  |     """配置类,用于加载和访问配置项""" | ||||||
|  |      | ||||||
|  |     def __init__(self, config_file="config/config.yaml"): | ||||||
|  |         """ | ||||||
|  |         初始化配置类 | ||||||
|  |          | ||||||
|  |         Args: | ||||||
|  |             config_file (str): 配置文件路径 | ||||||
|  |         """ | ||||||
|  |         # 获取项目根目录 | ||||||
|  |         project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||||||
|  |         config_path = os.path.join(project_root, config_file) | ||||||
|  |          | ||||||
|  |         # 加载配置文件 | ||||||
|  |         with open(config_path, 'r', encoding='utf-8') as f: | ||||||
|  |             self._config = yaml.safe_load(f) | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def simulation_enabled(self): | ||||||
|  |         """获取模拟模式是否启用""" | ||||||
|  |         return self._config.get('simulation', {}).get('enabled', False) | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def simulation_controllers(self): | ||||||
|  |         """获取模拟区域主控设备列表""" | ||||||
|  |         return self._config.get('simulation', {}).get('controllers', []) | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def simulation_devices(self): | ||||||
|  |         """获取模拟普通设备列表""" | ||||||
|  |         return self._config.get('simulation', {}).get('devices', []) | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def websocket_config(self): | ||||||
|  |         """获取WebSocket配置""" | ||||||
|  |         return self._config.get('websocket', {}) | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def websocket_address(self): | ||||||
|  |         """获取WebSocket服务器地址""" | ||||||
|  |         return self.websocket_config.get('address', '127.0.0.1') | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def websocket_port(self): | ||||||
|  |         """获取WebSocket服务器端口""" | ||||||
|  |         return self.websocket_config.get('port', 8080) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # 全局配置实例 | ||||||
|  | config = Config() | ||||||
							
								
								
									
										69
									
								
								config/config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								config/config.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | # 通信中继器配置文件 | ||||||
|  |  | ||||||
|  | # 中继器配置 | ||||||
|  | relay: | ||||||
|  |   # 中继设备唯一标识符,用于WebSocket连接时的身份标识 | ||||||
|  |   device_id: "1" | ||||||
|  |   # 中继器名称 | ||||||
|  |   name: "猪场1" | ||||||
|  |  | ||||||
|  | # WebSocket配置 | ||||||
|  | websocket: | ||||||
|  |   # WebSocket服务器地址 | ||||||
|  |   host: "localhost" | ||||||
|  |   # WebSocket端口 | ||||||
|  |   port: 8086 | ||||||
|  |   # WebSocket请求超时时间(秒) | ||||||
|  |   timeout: 5 | ||||||
|  |  | ||||||
|  | # 模拟模式配置 | ||||||
|  | simulation: | ||||||
|  |   # 是否开启模拟模式 | ||||||
|  |   enabled: true | ||||||
|  |   # 模拟区域主控设备列表(没有冒号的地址) | ||||||
|  |   controllers: | ||||||
|  |     - id: "2" | ||||||
|  |       name: "猪舍1" | ||||||
|  |       type: "pig_pen_controller" | ||||||
|  |       lora_address: "121" | ||||||
|  |       status: "running" | ||||||
|  |     - id: "5" | ||||||
|  |       name: "做料1" | ||||||
|  |       type: "feed_mill_controller" | ||||||
|  |       lora_address: "123" | ||||||
|  |       status: "stopped" | ||||||
|  |     - id: "8" | ||||||
|  |       name: "猪舍2" | ||||||
|  |       type: "pig_pen_controller" | ||||||
|  |       lora_address: "122" | ||||||
|  |       status: "running" | ||||||
|  |   # 模拟普通设备列表(带冒号的地址,格式为总线号:总线地址) | ||||||
|  |   devices: | ||||||
|  |     - id: "3" | ||||||
|  |       name: "风机1" | ||||||
|  |       type: "fan" | ||||||
|  |       rs485_bus: "1" | ||||||
|  |       rs485_address: "12" | ||||||
|  |       controller_id: "2" | ||||||
|  |       status: "stopped" | ||||||
|  |     - id: "9" | ||||||
|  |       name: "风机2" | ||||||
|  |       type: "fan" | ||||||
|  |       rs485_bus: "1" | ||||||
|  |       rs485_address: "11" | ||||||
|  |       controller_id: "2" | ||||||
|  |       status: "running" | ||||||
|  |     - id: "10" | ||||||
|  |       name: "水帘1" | ||||||
|  |       type: "water_curtain" | ||||||
|  |       rs485_bus: "1" | ||||||
|  |       rs485_address: "11" | ||||||
|  |       controller_id: "8" | ||||||
|  |       status: "stopped" | ||||||
|  |     - id: "11" | ||||||
|  |       name: "风机3" | ||||||
|  |       type: "fan" | ||||||
|  |       rs485_bus: "2" | ||||||
|  |       rs485_address: "21" | ||||||
|  |       controller_id: "2" | ||||||
|  |       status: "stopped" | ||||||
							
								
								
									
										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 | ||||||
							
								
								
									
										41
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  |  | ||||||
|  | """ | ||||||
|  | 通信中继器主程序入口 | ||||||
|  | 支持四级结构:平台->中继->区域主控->普通设备 | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import logging | ||||||
|  | import time | ||||||
|  |  | ||||||
|  | # 配置日志 | ||||||
|  | logging.basicConfig( | ||||||
|  |     level=logging.INFO, | ||||||
|  |     format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' | ||||||
|  | ) | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  | from internal.core import RelayService | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     """主函数""" | ||||||
|  |     logger.info("通信中继器启动") | ||||||
|  |      | ||||||
|  |     # 创建并初始化中继器服务 | ||||||
|  |     relay_service = RelayService() | ||||||
|  |     relay_service.initialize() | ||||||
|  |      | ||||||
|  |     try: | ||||||
|  |         # 启动中继器服务 | ||||||
|  |         relay_service.start() | ||||||
|  |     except KeyboardInterrupt: | ||||||
|  |         logger.info("收到中断信号,正在停止服务...") | ||||||
|  |         relay_service.stop() | ||||||
|  |     except Exception as e: | ||||||
|  |         logger.error(f"中继器服务发生错误: {e}") | ||||||
|  |         relay_service.stop() | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										3
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | # 项目依赖包 | ||||||
|  | PyYAML>=5.4.1 | ||||||
|  | websockets>=10.0,<15.0 | ||||||
							
								
								
									
										8
									
								
								scripts/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								scripts/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | # 脚本目录 | ||||||
|  |  | ||||||
|  | 该目录存放项目的各种脚本文件,包括: | ||||||
|  |  | ||||||
|  | 1. 启动脚本 | ||||||
|  | 2. 停止脚本 | ||||||
|  | 3. 部署脚本 | ||||||
|  | 4. 其他运维脚本 | ||||||
							
								
								
									
										2
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | # 测试文件目录 | ||||||
|  | # 存放项目的所有测试文件 | ||||||
							
								
								
									
										63
									
								
								tests/test_relay.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								tests/test_relay.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  |  | ||||||
|  | """ | ||||||
|  | 中继器测试脚本 | ||||||
|  | 用于模拟平台向中继器发送指令 | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import json | ||||||
|  | import time | ||||||
|  | import threading | ||||||
|  | from internal.core import RelayService | ||||||
|  |  | ||||||
|  | def test_relay_commands(): | ||||||
|  |     """测试中继器指令处理""" | ||||||
|  |     print("启动中继器测试") | ||||||
|  |      | ||||||
|  |     # 创建中继器服务实例(仅用于访问其方法,不启动完整服务) | ||||||
|  |     relay_service = RelayService() | ||||||
|  |     relay_service.initialize() | ||||||
|  |      | ||||||
|  |     # 模拟平台发送各种指令 | ||||||
|  |     test_commands = [ | ||||||
|  |         # 控制设备指令 | ||||||
|  |         { | ||||||
|  |             "type": "command", | ||||||
|  |             "command": "control_device", | ||||||
|  |             "data": { | ||||||
|  |                 "device_id": "3", | ||||||
|  |                 "action": "on" | ||||||
|  |             }, | ||||||
|  |             "timestamp": "2023-01-01T12:00:00Z" | ||||||
|  |         }, | ||||||
|  |          | ||||||
|  |         # 查询单个设备状态指令 | ||||||
|  |         { | ||||||
|  |             "type": "command", | ||||||
|  |             "command": "query_device_status", | ||||||
|  |             "data": { | ||||||
|  |                 "device_id": "3" | ||||||
|  |             }, | ||||||
|  |             "timestamp": "2023-01-01T12:00:05Z" | ||||||
|  |         }, | ||||||
|  |          | ||||||
|  |         # 查询所有设备状态指令 | ||||||
|  |         { | ||||||
|  |             "type": "command", | ||||||
|  |             "command": "query_all_device_status", | ||||||
|  |             "timestamp": "2023-01-01T12:00:10Z" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  |      | ||||||
|  |     print("开始发送测试指令...") | ||||||
|  |     for i, command in enumerate(test_commands): | ||||||
|  |         print(f"发送指令 {i+1}: {command['command']}") | ||||||
|  |         command_json = json.dumps(command) | ||||||
|  |         relay_service.handle_platform_command(command_json) | ||||||
|  |         time.sleep(1) | ||||||
|  |      | ||||||
|  |     print("测试指令发送完成") | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     test_relay_commands() | ||||||
							
								
								
									
										2
									
								
								utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | # 工具函数目录 | ||||||
|  | # 存放项目中使用的各种工具函数 | ||||||
		Reference in New Issue
	
	Block a user