feat: add RGB/color temp control and enhance error handling for groups
This commit is contained in:
93
main.py
93
main.py
@@ -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__":
|
||||
|
||||
Reference in New Issue
Block a user