实现数据接入层功能(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
+181
View File
@@ -0,0 +1,181 @@
"""
REST API 数据接入模块
支持 IoT 设备数据、手动录入和 API 批量导入
"""
from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Optional, Dict, Any
import uvicorn
import asyncio
import json
from datetime import datetime
# 创建FastAPI应用
app = FastAPI(title="Water Management System Data API", version="1.0.0")
# CORS配置
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 数据模型
class IoTData(BaseModel):
device_id: str
data_type: str # "LL", "YL", "SW", "ZD" 等
value: float
timestamp: datetime
location: str
class ManualInputData(BaseModel):
source: str
data_type: str
value: float
timestamp: datetime
operator: str
notes: Optional[str] = None
class BatchImportRequest(BaseModel):
batch_id: str
data_source: str
records: List[Dict[str, Any]]
# 数据存储(示例,实际应该用数据库)
data_store = []
@app.get("/")
async def root():
"""API根路径"""
return {"message": "Water Management System API", "version": "1.0.0"}
@app.post("/api/iot/data")
async def receive_iot_data(data: IoTData):
"""接收IoT设备数据"""
try:
data_dict = data.dict()
data_store.append({
**data_dict,
"id": len(data_store) + 1,
"type": "iot"
})
return {"status": "success", "id": len(data_store), "message": "IoT data received"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/manual/data")
async def receive_manual_data(data: ManualInputData):
"""接收手动录入数据"""
try:
data_dict = data.dict()
data_store.append({
**data_dict,
"id": len(data_store) + 1,
"type": "manual"
})
return {"status": "success", "id": len(data_store), "message": "Manual data received"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/batch/import")
async def batch_import(request: BatchImportRequest):
"""批量导入数据"""
try:
imported_count = 0
failed_count = 0
for record in request.records:
# 验证记录
if not all(k in record for k in ['device_id', 'data_type', 'value']):
failed_count += 1
continue
# 创建数据对象
data_record = {
"device_id": record['device_id'],
"data_type": record['data_type'],
"value": float(record['value']),
"timestamp": record.get('timestamp', datetime.now()),
"location": record.get('location', 'unknown'),
"batch_id": request.batch_id,
"source": request.data_source,
"id": len(data_store) + 1,
"type": "batch"
}
data_store.append(data_record)
imported_count += 1
return {
"status": "success",
"imported_count": imported_count,
"failed_count": failed_count,
"message": f"Batch import completed: {imported_count} records imported, {failed_count} failed"
}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/data/{data_type}")
async def get_data_by_type(data_type: str, limit: int = 100, offset: int = 0):
"""根据数据类型获取数据"""
filtered_data = [
item for item in data_store
if item.get('data_type') == data_type
]
return {
"data": filtered_data[offset:offset+limit],
"total": len(filtered_data),
"limit": limit,
"offset": offset
}
@app.get("/api/data/recent")
async def get_recent_data(hours: int = 24, limit: int = 100):
"""获取最近的数据"""
from datetime import timedelta
cutoff_time = datetime.now() - timedelta(hours=hours)
recent_data = [
item for item in data_store
if item.get('timestamp', datetime.now()) > cutoff_time
]
return {
"data": recent_data[-limit:],
"total": len(recent_data),
"hours": hours,
"limit": limit
}
@app.get("/api/stats")
async def get_statistics():
"""获取数据统计信息"""
stats = {
"total_records": len(data_store),
"by_type": {},
"by_device": {},
"by_hour": {}
}
for item in data_store:
data_type = item.get('data_type', 'unknown')
device_id = item.get('device_id', 'unknown')
hour = item.get('timestamp', datetime.now()).strftime('%Y-%m-%d %H:00:00')
stats['by_type'][data_type] = stats['by_type'].get(data_type, 0) + 1
stats['by_device'][device_id] = stats['by_device'].get(device_id, 0) + 1
stats['by_hour'][hour] = stats['by_hour'].get(hour, 0) + 1
return stats
@app.get("/health")
async def health_check():
"""健康检查"""
return {"status": "healthy", "timestamp": datetime.now()}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)