BMS/backend/api/routes/alarms.py
2026-03-19 11:32:17 +00:00

82 lines
2.8 KiB
Python

from fastapi import APIRouter, Depends, Query, HTTPException
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from core.database import get_session
router = APIRouter()
@router.get("")
async def list_alarms(
site_id: str = Query(...),
state: str = Query("active", description="active | resolved | acknowledged | all"),
limit: int = Query(50, ge=1, le=200),
session: AsyncSession = Depends(get_session),
):
where = "WHERE site_id = :site_id"
if state != "all":
where += " AND state = :state"
result = await session.execute(text(f"""
SELECT id, sensor_id, site_id, room_id, rack_id,
severity, message, state, triggered_at,
acknowledged_at, resolved_at
FROM alarms
{where}
ORDER BY triggered_at DESC
LIMIT :limit
"""), {"site_id": site_id, "state": state, "limit": limit})
return [dict(r) for r in result.mappings().all()]
@router.post("/{alarm_id}/acknowledge")
async def acknowledge_alarm(
alarm_id: int,
session: AsyncSession = Depends(get_session),
):
result = await session.execute(text("""
UPDATE alarms
SET state = 'acknowledged', acknowledged_at = NOW()
WHERE id = :id AND state = 'active'
RETURNING id
"""), {"id": alarm_id})
await session.commit()
if not result.fetchone():
raise HTTPException(status_code=404, detail="Alarm not found or not active")
return {"id": alarm_id, "state": "acknowledged"}
@router.post("/{alarm_id}/resolve")
async def resolve_alarm(
alarm_id: int,
session: AsyncSession = Depends(get_session),
):
result = await session.execute(text("""
UPDATE alarms
SET state = 'resolved', resolved_at = NOW()
WHERE id = :id AND state IN ('active', 'acknowledged')
RETURNING id
"""), {"id": alarm_id})
await session.commit()
if not result.fetchone():
raise HTTPException(status_code=404, detail="Alarm not found or already resolved")
return {"id": alarm_id, "state": "resolved"}
@router.get("/stats")
async def alarm_stats(
site_id: str = Query(...),
session: AsyncSession = Depends(get_session),
):
result = await session.execute(text("""
SELECT
COUNT(*) FILTER (WHERE state = 'active') AS active,
COUNT(*) FILTER (WHERE state = 'acknowledged') AS acknowledged,
COUNT(*) FILTER (WHERE state = 'resolved') AS resolved,
COUNT(*) FILTER (WHERE state = 'active' AND severity = 'critical') AS critical,
COUNT(*) FILTER (WHERE state = 'active' AND severity = 'warning') AS warning
FROM alarms
WHERE site_id = :site_id
"""), {"site_id": site_id})
row = result.mappings().one()
return {k: int(v) for k, v in row.items()}