Files
water-management-system/src/models/models.py
T
bot_dev1 5eae031679 实现数据接入层功能(REST API + WebSocket + 批量导入)
- 实现REST API服务器,支持IoT数据、手动录入和批量导入接口
- 实现WebSocket服务器,支持实时数据推送和连接管理
- 实现批量导入模块,支持CSV、Excel、JSON多种格式
- 实现数据处理工具,包含字段映射和单位转换功能
- 实现数据模型定义和数据验证机制
- 创建主程序入口和配置文件
- 添加详细的使用文档和API说明
2026-06-15 11:59:00 +08:00

317 lines
10 KiB
Python

"""
数据模型定义
定义水务管理系统的各种数据结构
"""
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any
from datetime import datetime
from enum import Enum
class DataType(Enum):
"""数据类型枚举"""
LL = "LL" # 流量
YL = "YL" # 压力
SW = "SW" # 水位
ZD = "ZD" # 浊度
PH = "PH" # pH值
WD = "WD" # 温度
DD = "DD" # 电导率
YD = "YD" # 硬度
class AlertLevel(Enum):
"""警报级别枚举"""
INFO = "info"
WARNING = "warning"
ERROR = "error"
CRITICAL = "critical"
@dataclass
class Device:
"""设备模型"""
id: str
name: str
device_type: str
location: str
description: Optional[str] = None
install_date: Optional[datetime] = None
status: str = "active" # active, inactive, maintenance
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class SensorData:
"""传感器数据模型"""
id: str
device_id: str
data_type: DataType
value: float
unit: str
timestamp: datetime
location: str
quality_score: float = 1.0
metadata: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"id": self.id,
"device_id": self.device_id,
"data_type": self.data_type.value,
"value": self.value,
"unit": self.unit,
"timestamp": self.timestamp.isoformat(),
"location": self.location,
"quality_score": self.quality_score,
"metadata": self.metadata
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'SensorData':
"""从字典创建对象"""
return cls(
id=data["id"],
device_id=data["device_id"],
data_type=DataType(data["data_type"]),
value=float(data["value"]),
unit=data.get("unit", ""),
timestamp=datetime.fromisoformat(data["timestamp"]),
location=data.get("location", ""),
quality_score=float(data.get("quality_score", 1.0)),
metadata=data.get("metadata", {})
)
@dataclass
class Alert:
"""警报模型"""
id: str
device_id: str
alert_type: str
level: AlertLevel
message: str
timestamp: datetime
resolved: bool = False
resolved_by: Optional[str] = None
resolved_at: Optional[datetime] = None
metadata: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"id": self.id,
"device_id": self.device_id,
"alert_type": self.alert_type,
"level": self.level.value,
"message": self.message,
"timestamp": self.timestamp.isoformat(),
"resolved": self.resolved,
"resolved_by": self.resolved_by,
"resolved_at": self.resolved_at.isoformat() if self.resolved_at else None,
"metadata": self.metadata
}
@dataclass
class BatchImport:
"""批量导入记录模型"""
id: str
batch_id: str
data_source: str
total_records: int
successful_records: int
failed_records: int
status: str # pending, processing, completed, failed
file_name: Optional[str] = None
import_time: Optional[datetime] = None
completed_time: Optional[datetime] = None
error_messages: List[str] = field(default_factory=list)
metadata: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"id": self.id,
"batch_id": self.batch_id,
"data_source": self.data_source,
"total_records": self.total_records,
"successful_records": self.successful_records,
"failed_records": self.failed_records,
"status": self.status,
"file_name": self.file_name,
"import_time": self.import_time.isoformat() if self.import_time else None,
"completed_time": self.completed_time.isoformat() if self.completed_time else None,
"error_messages": self.error_messages,
"metadata": self.metadata
}
@dataclass
class APIRequest:
"""API请求模型"""
id: str
method: str
endpoint: str
params: Dict[str, Any]
headers: Dict[str, Any]
body: Optional[Any] = None
timestamp: datetime = field(default_factory=datetime.now)
response_code: Optional[int] = None
response_time_ms: Optional[float] = None
response_body: Optional[Any] = None
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"id": self.id,
"method": self.method,
"endpoint": self.endpoint,
"params": self.params,
"headers": self.headers,
"body": self.body,
"timestamp": self.timestamp.isoformat(),
"response_code": self.response_code,
"response_time_ms": self.response_time_ms,
"response_body": self.response_body
}
@dataclass
class WebSocketConnection:
"""WebSocket连接模型"""
id: str
client_ip: str
connected_at: datetime
disconnected_at: Optional[datetime] = None
subscriptions: List[str] = field(default_factory=list)
message_count: int = 0
last_message_at: Optional[datetime] = None
metadata: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"id": self.id,
"client_ip": self.client_ip,
"connected_at": self.connected_at.isoformat(),
"disconnected_at": self.disconnected_at.isoformat() if self.disconnected_at else None,
"subscriptions": self.subscriptions,
"message_count": self.message_count,
"last_message_at": self.last_message_at.isoformat() if self.last_message_at else None,
"metadata": self.metadata
}
@dataclass
class SystemStats:
"""系统统计模型"""
timestamp: datetime
total_records: int
total_devices: int
active_connections: int
api_requests_count: int
alerts_count: int
data_quality_score: float
memory_usage_mb: float
cpu_usage_percent: float
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"timestamp": self.timestamp.isoformat(),
"total_records": self.total_records,
"total_devices": self.total_devices,
"active_connections": self.active_connections,
"api_requests_count": self.api_requests_count,
"alerts_count": self.alerts_count,
"data_quality_score": self.data_quality_score,
"memory_usage_mb": self.memory_usage_mb,
"cpu_usage_percent": self.cpu_usage_percent
}
class DataValidator:
"""数据验证器"""
@staticmethod
def validate_sensor_data(data: Dict[str, Any]) -> List[str]:
"""验证传感器数据"""
errors = []
# 必需字段检查
required_fields = ["device_id", "data_type", "value", "location"]
for field in required_fields:
if field not in data:
errors.append(f"缺少必需字段: {field}")
# 数据类型验证
if "data_type" in data:
try:
DataType(data["data_type"])
except ValueError:
errors.append(f"无效的数据类型: {data['data_type']}")
# 数值验证
if "value" in data:
try:
value = float(data["value"])
# 根据数据类型进行数值范围检查
data_type = data.get("data_type")
if data_type == "LL" and value < 0:
errors.append("流量不能为负数")
elif data_type == "YL" and value < 0:
errors.append("压力不能为负数")
elif data_type == "SW" and value < 0:
errors.append("水位不能为负数")
except (ValueError, TypeError):
errors.append(f"无效的数值: {data['value']}")
# 时间戳验证
if "timestamp" in data:
try:
if isinstance(data["timestamp"], str):
datetime.fromisoformat(data["timestamp"])
except (ValueError, TypeError):
errors.append(f"无效的时间戳格式: {data['timestamp']}")
return errors
@staticmethod
def validate_device_data(data: Dict[str, Any]) -> List[str]:
"""验证设备数据"""
errors = []
# 必需字段检查
required_fields = ["id", "name", "device_type", "location"]
for field in required_fields:
if field not in data:
errors.append(f"缺少必需字段: {field}")
# 设备ID格式验证
if "id" in data:
device_id = data["id"]
if not isinstance(device_id, str) or not device_id.strip():
errors.append("设备ID不能为空")
elif len(device_id) > 50:
errors.append("设备ID长度不能超过50个字符")
# 状态验证
if "status" in data and data["status"] not in ["active", "inactive", "maintenance"]:
errors.append("设备状态必须是: active, inactive, maintenance")
return errors
@staticmethod
def validate_alert_data(data: Dict[str, Any]) -> List[str]:
"""验证警报数据"""
errors = []
# 必需字段检查
required_fields = ["device_id", "alert_type", "level", "message"]
for field in required_fields:
if field not in data:
errors.append(f"缺少必需字段: {field}")
# 警报级别验证
if "level" in data:
try:
AlertLevel(data["level"])
except ValueError:
errors.append(f"无效的警报级别: {data['level']}")
return errors
# 全局验证器实例
validator = DataValidator()