Files

79 lines
3.2 KiB
Python
Raw Permalink Normal View History

from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_
from app.core.database import get_db
from app.core.deps import get_current_user
from app.models.device import Device
from app.models.energy import EnergyData
from app.models.user import User
router = APIRouter(prefix="/monitoring", tags=["实时监控"])
@router.get("/devices/{device_id}/realtime")
async def device_realtime(device_id: int, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
"""获取单台设备的最新实时数据"""
now = datetime.now(timezone.utc)
five_min_ago = now - timedelta(minutes=5)
result = await db.execute(
select(EnergyData).where(
and_(EnergyData.device_id == device_id, EnergyData.timestamp >= five_min_ago)
).order_by(EnergyData.timestamp.desc()).limit(20)
)
data_points = result.scalars().all()
latest = {}
for d in data_points:
if d.data_type not in latest:
latest[d.data_type] = {"value": d.value, "unit": d.unit, "timestamp": str(d.timestamp)}
device_q = await db.execute(select(Device).where(Device.id == device_id))
device = device_q.scalar_one_or_none()
return {
"device": {
"id": device.id, "name": device.name, "code": device.code,
"device_type": device.device_type, "status": device.status,
"model": device.model, "manufacturer": device.manufacturer,
} if device else None,
"data": latest,
}
@router.get("/energy-flow")
async def energy_flow(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
"""能流图数据 - 展示能量流向"""
now = datetime.now(timezone.utc)
five_min_ago = now - timedelta(minutes=5)
# 获取各类设备最新功率
result = await db.execute(
select(Device.device_type, func.sum(EnergyData.value))
.join(EnergyData, EnergyData.device_id == Device.id)
.where(and_(EnergyData.timestamp >= five_min_ago, EnergyData.data_type == "power"))
.group_by(Device.device_type)
)
power_by_type = {row[0]: round(row[1], 2) for row in result.all()}
pv_power = power_by_type.get("pv_inverter", 0)
hp_power = power_by_type.get("heat_pump", 0)
total_load = hp_power + power_by_type.get("meter", 0)
grid_import = max(0, total_load - pv_power)
grid_export = max(0, pv_power - total_load)
return {
"nodes": [
{"id": "pv", "name": "光伏发电", "power": pv_power, "unit": "kW"},
{"id": "grid", "name": "电网", "power": grid_import - grid_export, "unit": "kW"},
{"id": "heatpump", "name": "热泵系统", "power": hp_power, "unit": "kW"},
{"id": "building", "name": "建筑负荷", "power": total_load, "unit": "kW"},
],
"links": [
{"source": "pv", "target": "building", "value": min(pv_power, total_load)},
{"source": "pv", "target": "grid", "value": grid_export},
{"source": "grid", "target": "building", "value": grid_import},
{"source": "grid", "target": "heatpump", "value": hp_power},
]
}