feat: add RGB/color temp control and enhance error handling for groups

This commit is contained in:
Артём Кокос
2026-02-12 22:52:05 +07:00
parent 738edd4db9
commit 3c52fcf4ec
4 changed files with 91 additions and 38 deletions

93
main.py
View File

@@ -33,11 +33,9 @@ async def lifespan(app: FastAPI):
result = await session.execute(select(GroupModel))
groups = result.scalars().all()
for g in groups:
# Превращаем модель БД в формат стейта (если нужно)
state_manager.groups[g.id] = g
logger.info(f"📂 Загружена группа: {g.name} (MACs: {g.device_ids})")
# 3. Задача для периодического сканирования сети
async def periodic_discovery():
logger.info("🚀 Запущена фоновая служба Discovery")
@@ -74,30 +72,17 @@ async def get_all_devices():
return state_manager.devices
@app.post("/control/device/{device_id}")
async def control_device(device_id: str, state: bool, brightness: Optional[int] = None):
"""Прямое управление лампой по MAC."""
device = state_manager.devices.get(device_id)
if not device:
raise HTTPException(status_code=404, detail="Лампа не в сети")
params = {"state": state}
if brightness:
params["dimming"] = brightness
result = await wiz.set_pilot(device.ip, params)
return {"device_id": device_id, "result": result}
# --- Эндпоинты Групп ---
@app.get("/groups")
async def get_groups():
"""Список всех созданных люстр/групп."""
return state_manager.groups
@app.get("/scenes")
async def get_scenes():
return wiz.SCENES
@app.post("/groups")
async def create_group(data: GroupCreateSchema):
async with async_session() as session:
@@ -115,37 +100,77 @@ async def create_group(data: GroupCreateSchema):
return {"status": "created", "group": data.name}
@app.post("/control/group/{group_id}")
async def control_group(
group_id: str,
@app.post("/control/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,
):
"""Управление всей люстрой сразу."""
ips = state_manager.get_group_ips(group_id)
if not ips:
raise HTTPException(
status_code=404, detail="Группа не найдена или лампы оффлайн"
)
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 r is not None or g is not None or b is not None:
params["r"], params["g"], params["b"] = r or 0, g or 0, b or 0
if not params:
raise HTTPException(status_code=400, detail="Никаких команд не передано")
# Параллельная отправка всем лампам группы
tasks = [wiz.set_pilot(ip, params) for ip in ips]
await asyncio.gather(*tasks)
result = await wiz.set_pilot(device.ip, params)
return {"device_id": device_id, "applied": params, "result": result}
return {"status": "ok", "group": group_id, "sent_to": ips}
@app.post("/control/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 r is not None or g is not None or b is not None:
params["r"], params["g"], params["b"] = r or 0, g or 0, b or 0
if not params:
raise HTTPException(status_code=400, detail="Никаких команд не передано")
# Используем return_exceptions=True, чтобы ошибки одной лампы не ломали всё
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}
if __name__ == "__main__":