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}, ] }