Files
ignis-core/app/api/routes/control.py
Артём Кокос fd0b9d4d81 WEB UI
2026-02-24 20:36:40 +07:00

140 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import asyncio
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from app.core.state import state_manager
from app.drivers.wiz import WizDriver
from app.api.deps import verify_token
router = APIRouter(dependencies=[Depends(verify_token)])
wiz = WizDriver()
@router.post("/device/{device_id}")
async def control_device(
device_id: str,
state: Optional[bool] = None,
brightness: Optional[int] = None,
scene: Optional[str] = None,
temp: Optional[int] = None,
r: Optional[int] = None,
g: Optional[int] = None,
b: Optional[int] = None,
):
device = state_manager.devices.get(device_id)
if not device:
raise HTTPException(status_code=404, detail="Лампа не в сети")
params = {}
if state is not None:
params["state"] = state
if brightness is not None:
params["dimming"] = brightness
if scene and scene in wiz.SCENES:
params["sceneId"] = wiz.SCENES[scene]
elif temp is not None:
params["temp"] = temp
elif any(v is not None for v in [r, g, b]):
params["r"], params["g"], params["b"] = r or 0, g or 0, b or 0
if not params:
raise HTTPException(status_code=400, detail="Никаких команд не передано")
result = await wiz.set_pilot(device.ip, params)
return {"device_id": device_id, "applied": params, "result": result}
@router.post("/group/{group_id}")
async def control_group(
group_id: str,
state: Optional[bool] = None,
brightness: Optional[int] = None,
scene: Optional[str] = None,
temp: Optional[int] = None,
r: Optional[int] = None,
g: Optional[int] = None,
b: Optional[int] = None,
):
ips = state_manager.get_group_ips(group_id)
if not ips:
raise HTTPException(status_code=404, detail="Группа не найдена или оффлайн")
params = {}
if state is not None:
params["state"] = state
if brightness is not None:
params["dimming"] = brightness
if scene and scene in wiz.SCENES:
params["sceneId"] = wiz.SCENES[scene]
elif temp is not None:
params["temp"] = temp
elif any(v is not None for v in [r, g, b]):
params["r"], params["g"], params["b"] = r or 0, g or 0, b or 0
tasks = [wiz.set_pilot(ip, params) for ip in ips]
await asyncio.gather(*tasks, return_exceptions=True)
return {"status": "ok", "applied": params, "sent_to": ips}
@router.post("/device/{device_id}/blink")
async def blink_device(device_id: str):
device = state_manager.devices.get(device_id)
if not device:
raise HTTPException(status_code=404, detail="Лампа оффлайн")
try:
# 1. Получаем текущее состояние
current = await wiz.get_pilot(device.ip)
# Если не удалось получить статус, считаем что она выключена (False)
original_state = current.get("result", {}).get("state", False)
# 2. Инвертируем состояние
await wiz.set_pilot(device.ip, {"state": not original_state})
await asyncio.sleep(0.5)
# 3. Возвращаем как было
await wiz.set_pilot(device.ip, {"state": original_state})
return {"status": "blink_done", "original": original_state}
except Exception as e:
logger.error(f"Blink error: {e}")
raise HTTPException(status_code=500, detail="Ошибка связи с лампой")
@router.get("/device/{device_id}/status")
async def get_device_status(device_id: str):
"""Опрос реального состояния конкретной лампы."""
device = state_manager.devices.get(device_id)
if not device:
raise HTTPException(status_code=404, detail="Лампа оффлайн или не найдена")
try:
status = await wiz.get_pilot(device.ip)
return {"device_id": device_id, "status": status.get("result", {})}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Ошибка опроса лампы: {e}")
@router.get("/group/{group_id}/status")
async def get_group_status(group_id: str):
"""Опрос состояния всей группы (возвращает список статусов)."""
ips = state_manager.get_group_ips(group_id)
if not ips:
raise HTTPException(status_code=404, detail="Группа не найдена или оффлайн")
# Опрашиваем все лампы группы параллельно
tasks = [wiz.get_pilot(ip) for ip in ips]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Формируем красивый ответ
status_report = []
for ip, res in zip(ips, results):
if isinstance(res, Exception):
status_report.append({"ip": ip, "error": str(res)})
else:
status_report.append({"ip": ip, "status": res.get("result", {})})
return {"group_id": group_id, "results": status_report}