Files
ignis-core/app/api/routes/schedules.py
Артём Кокос c661e2450d Web-UI: Schedules support
2026-03-02 20:44:25 +07:00

134 lines
4.1 KiB
Python

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="Задача не найдена")