Improve sched

This commit is contained in:
Артём Кокос
2026-02-21 11:45:15 +07:00
parent ff0add2f58
commit 3fe2be5514
2 changed files with 109 additions and 1 deletions

View File

@@ -19,7 +19,10 @@ scheduler = AsyncIOScheduler(jobstores=jobstores, timezone=app_tz)
async def execute_lamp_command(ip: str, params: dict): async def execute_lamp_command(ip: str, params: dict):
"""Выполнение команды по расписанию""" """
Универсальное выполнение команды.
params может содержать: state, dimming, temp, sceneId, r, g, b
"""
driver = WizDriver() driver = WizDriver()
await driver.set_pilot(ip, params) await driver.set_pilot(ip, params)
logger.info(f"⏰ Сработало расписание для {ip}: {params}") logger.info(f"⏰ Сработало расписание для {ip}: {params}")

105
main.py
View File

@@ -16,6 +16,9 @@ from app.core.database import init_db, async_session
from app.models.device import GroupModel, DeviceModel, GroupCreateSchema from app.models.device import GroupModel, DeviceModel, GroupCreateSchema
from app.models.schedule import ScheduleTask from app.models.schedule import ScheduleTask
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.date import DateTrigger
logging.basicConfig( logging.basicConfig(
level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s" level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s"
) )
@@ -297,6 +300,108 @@ async def cancel_task(job_id: str):
raise HTTPException(status_code=404, detail="Задача не найдена") raise HTTPException(status_code=404, detail="Задача не найдена")
@app.post("/schedules/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,
):
"""Запуск команды в конкретную дату и время (ISO формат)"""
# Собираем параметры команды
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]
# Определяем список IP
ips = []
if is_group:
ips = state_manager.get_group_ips(target_id)
else:
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} | Action: {params}",
)
job_ids.append(job.id)
return {"status": "scheduled", "jobs": job_ids, "run_at": run_at}
@app.post("/schedules/cron")
async def add_cron_task(
target_id: str,
hour: str,
minute: str,
day_of_week: str = "*",
is_group: bool = True,
state: bool = True,
):
"""
Многоразовая задача (Cron).
Пример: hour="7", minute="30", day_of_week="mon-fri"
"""
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="Цель не найдена")
params = {"state": state}
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, params],
name=f"CRON: {target_id} | {hour}:{minute} | {day_of_week}",
)
job_ids.append(job.id)
return {"status": "cron_scheduled", "jobs": job_ids}
@app.get("/schedules/tasks")
async def get_all_tasks():
"""Тот самый расширенный список задач для бота или фронта"""
jobs = []
for job in scheduler.get_jobs():
jobs.append(
{
"id": job.id,
"name": job.name, # Мы сохранили описание в поле name выше
"next_run": (
job.next_run_time.isoformat() if job.next_run_time else None
),
"params": str(job.args[1]) if len(job.args) > 1 else None,
}
)
return {"tasks": jobs}
# --- МОНТИРОВАНИЕ СТАТИКИ (ДОЛЖНО БЫТЬ ПОСЛЕ ВСЕХ API МАРШРУТОВ) --- # --- МОНТИРОВАНИЕ СТАТИКИ (ДОЛЖНО БЫТЬ ПОСЛЕ ВСЕХ API МАРШРУТОВ) ---
app.mount("/", StaticFiles(directory="static", html=True), name="static") app.mount("/", StaticFiles(directory="static", html=True), name="static")