实现数据接入层功能(REST API + WebSocket + 批量导入)

- 实现REST API服务器,支持IoT数据、手动录入和批量导入接口
- 实现WebSocket服务器,支持实时数据推送和连接管理
- 实现批量导入模块,支持CSV、Excel、JSON多种格式
- 实现数据处理工具,包含字段映射和单位转换功能
- 实现数据模型定义和数据验证机制
- 创建主程序入口和配置文件
- 添加详细的使用文档和API说明
This commit is contained in:
2026-06-15 11:59:00 +08:00
commit 5eae031679
8 changed files with 2071 additions and 0 deletions
+317
View File
@@ -0,0 +1,317 @@
"""
数据模型定义
定义水务管理系统的各种数据结构
"""
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()