from datetime import datetime, timedelta from typing import Optional from fastapi import APIRouter, Depends, HTTPException from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.date import DateTrigger from app.core.state import state_manager from app.core.scheduler import scheduler, execute_lamp_command from app.drivers.wiz import WizDriver from app.api.deps import verify_token router = APIRouter(dependencies=[Depends(verify_token)]) wiz = WizDriver() @router.post("/at") async def add_task_at_time( target_id: str, run_at: datetime, is_group: bool = False, state: Optional[bool] = None, brightness: Optional[int] = None, scene: Optional[str] = None, ): 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] ips = state_manager.get_group_ips(target_id) if is_group else [] if not is_group: dev = state_manager.devices.get(target_id) if dev: ips = [dev.ip] if not ips: raise HTTPException(status_code=404, detail="Цель не найдена") job_ids = [] for ip in ips: job = scheduler.add_job( execute_lamp_command, DateTrigger(run_date=run_at, timezone=scheduler.timezone), args=[ip, params], name=f"{'Group' if is_group else 'Device'}: {target_id} | {params}", ) job_ids.append(job.id) return {"status": "scheduled", "jobs": job_ids, "run_at": run_at} @router.post("/cron") async def add_cron_task( target_id: str, hour: str, minute: str, day_of_week: str = "*", is_group: bool = True, state: bool = True, ): ips = state_manager.get_group_ips(target_id) if is_group else [] if not is_group: dev = state_manager.devices.get(target_id) if dev: ips = [dev.ip] if not ips: raise HTTPException(status_code=404, detail="Цель не найдена") trigger = CronTrigger( hour=hour, minute=minute, day_of_week=day_of_week, timezone=scheduler.timezone ) job_ids = [] for ip in ips: job = scheduler.add_job( execute_lamp_command, trigger, args=[ip, {"state": state}], name=f"CRON: {target_id} | {hour}:{minute}", ) job_ids.append(job.id) return {"status": "cron_scheduled", "jobs": job_ids} @router.get("/tasks") async def get_all_tasks(): jobs = [] for job in scheduler.get_jobs(): # Разбираем строку типа "Group: bedroom | {'state': True}" # Вытаскиваем цель (bedroom) и состояние (True/False) name_parts = job.name.split("|") target = name_parts[0].replace("Group:", "").replace("Device:", "").strip() # Пытаемся понять, ВКЛ или ВЫКЛ задача is_on = "True" in job.name jobs.append( { "id": job.id, "target_id": target, "state": is_on, # Достаем время из триггера APScheduler "next_run": ( job.next_run_time.isoformat() if job.next_run_time else None ), # Вытаскиваем час и минуту прямо из настроек триггера для красоты "hour": ( str(job.trigger.fields[5]).zfill(2) if hasattr(job.trigger, "fields") else "??" ), "minute": ( str(job.trigger.fields[6]).zfill(2) if hasattr(job.trigger, "fields") else "??" ), } ) return {"tasks": jobs} @router.delete("/{job_id}") async def cancel_task(job_id: str): try: scheduler.remove_job(job_id) return {"status": "deleted"} except: raise HTTPException(status_code=404, detail="Задача не найдена")