Files
tianpu-ems/backend/app/api/v1/devices.py
Du Wenbo f53a610a19 Initial commit: Tianpu Zero-Carbon EMS Platform
Full-stack energy management system for Tianpu Daxing campus.
- Frontend: React 19 + TypeScript + Ant Design + ECharts
- Backend: FastAPI + SQLAlchemy + PostgreSQL/TimescaleDB
- Features: PV monitoring, heat pump management, carbon tracking, alarms, reports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:36:06 +08:00

123 lines
4.8 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from pydantic import BaseModel
from app.core.database import get_db
from app.core.deps import get_current_user, require_roles
from app.models.device import Device, DeviceType, DeviceGroup
from app.models.user import User
router = APIRouter(prefix="/devices", tags=["设备管理"])
class DeviceCreate(BaseModel):
name: str
code: str
device_type: str
group_id: int | None = None
model: str | None = None
manufacturer: str | None = None
serial_number: str | None = None
rated_power: float | None = None
location: str | None = None
protocol: str | None = None
connection_params: dict | None = None
collect_interval: int = 15
class DeviceUpdate(BaseModel):
name: str | None = None
group_id: int | None = None
location: str | None = None
protocol: str | None = None
connection_params: dict | None = None
collect_interval: int | None = None
status: str | None = None
is_active: bool | None = None
@router.get("")
async def list_devices(
device_type: str | None = None,
group_id: int | None = None,
status: str | None = None,
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
db: AsyncSession = Depends(get_db),
user: User = Depends(get_current_user),
):
query = select(Device).where(Device.is_active == True)
if device_type:
query = query.where(Device.device_type == device_type)
if group_id:
query = query.where(Device.group_id == group_id)
if status:
query = query.where(Device.status == status)
count_query = select(func.count()).select_from(query.subquery())
total = (await db.execute(count_query)).scalar()
query = query.offset((page - 1) * page_size).limit(page_size).order_by(Device.id)
result = await db.execute(query)
devices = result.scalars().all()
return {"total": total, "items": [_device_to_dict(d) for d in devices]}
@router.get("/types")
async def list_device_types(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
result = await db.execute(select(DeviceType).order_by(DeviceType.id))
return [{"id": t.id, "code": t.code, "name": t.name, "icon": t.icon} for t in result.scalars().all()]
@router.get("/groups")
async def list_device_groups(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
result = await db.execute(select(DeviceGroup).order_by(DeviceGroup.id))
return [{"id": g.id, "name": g.name, "parent_id": g.parent_id, "location": g.location} for g in result.scalars().all()]
@router.get("/stats")
async def device_stats(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
result = await db.execute(
select(Device.status, func.count(Device.id)).where(Device.is_active == True).group_by(Device.status)
)
stats = {row[0]: row[1] for row in result.all()}
return {"online": stats.get("online", 0), "offline": stats.get("offline", 0), "alarm": stats.get("alarm", 0), "maintenance": stats.get("maintenance", 0)}
@router.get("/{device_id}")
async def get_device(device_id: int, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)):
result = await db.execute(select(Device).where(Device.id == device_id))
device = result.scalar_one_or_none()
if not device:
raise HTTPException(status_code=404, detail="设备不存在")
return _device_to_dict(device)
@router.post("")
async def create_device(data: DeviceCreate, db: AsyncSession = Depends(get_db), user: User = Depends(require_roles("admin", "energy_manager"))):
device = Device(**data.model_dump())
db.add(device)
await db.flush()
return _device_to_dict(device)
@router.put("/{device_id}")
async def update_device(device_id: int, data: DeviceUpdate, db: AsyncSession = Depends(get_db), user: User = Depends(require_roles("admin", "energy_manager"))):
result = await db.execute(select(Device).where(Device.id == device_id))
device = result.scalar_one_or_none()
if not device:
raise HTTPException(status_code=404, detail="设备不存在")
for k, v in data.model_dump(exclude_unset=True).items():
setattr(device, k, v)
return _device_to_dict(device)
def _device_to_dict(d: Device) -> dict:
return {
"id": d.id, "name": d.name, "code": d.code, "device_type": d.device_type,
"group_id": d.group_id, "model": d.model, "manufacturer": d.manufacturer,
"serial_number": d.serial_number, "rated_power": d.rated_power,
"location": d.location, "protocol": d.protocol, "collect_interval": d.collect_interval,
"status": d.status, "is_active": d.is_active, "last_data_time": str(d.last_data_time) if d.last_data_time else None,
}