创建项目及AI生成基本代码

This commit is contained in:
2025-09-08 22:12:42 +08:00
parent db6b887237
commit b96db8f5e3
26 changed files with 1866 additions and 0 deletions

1
internal/__init__.py Normal file
View File

@@ -0,0 +1 @@
# internal package

View File

@@ -0,0 +1,6 @@
# 核心业务逻辑模块
# 包含中继器的主要业务逻辑实现
from .relay import RelayService
__all__ = ['RelayService']

289
internal/core/relay.py Normal file
View 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}")

View File

@@ -0,0 +1,2 @@
# 协议处理模块
# 处理与各种通信协议相关的功能

57
internal/protocol/base.py Normal file
View 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

View File

@@ -0,0 +1,2 @@
# CoAP协议处理模块
# 处理受限应用协议轻量级的RESTful协议适用于资源受限设备

View File

@@ -0,0 +1,6 @@
# LoRa协议处理模块
# 处理LoRa物理层通信相关功能
from .handler import LoRaHandler
__all__ = ['LoRaHandler']

View 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}"
}

View File

@@ -0,0 +1,2 @@
# LoRaWAN协议处理模块
# 处理基于LoRa物理层的广域网协议功能包括设备认证、加密和网络管理

View File

@@ -0,0 +1,2 @@
# LwM2M协议处理模块
# 处理轻量级机器到机器协议,提供设备管理、固件更新等功能

View File

@@ -0,0 +1,2 @@
# SenML数据格式处理模块
# 处理传感器标记语言,标准化的传感器数据表示格式

View File

@@ -0,0 +1,6 @@
# WebSocket通信处理模块
# 处理与猪场主控的WebSocket通信
from .client import WebSocketClient
__all__ = ['WebSocketClient']

View 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

View File

@@ -0,0 +1,6 @@
# 模拟模块
# 用于在没有实际设备的情况下模拟场内子系统设备
from .device_interface import SimulatedDevice, DeviceManager, AreaController, NormalDevice
__all__ = ['SimulatedDevice', 'DeviceManager', 'AreaController', 'NormalDevice']

View 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

View 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

View 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