Scheduler (resolves #1)

This commit is contained in:
Артём Кокос
2026-02-18 22:47:57 +07:00
parent 298dcbc277
commit 7d30afe9a3
6 changed files with 100 additions and 0 deletions

48
main.py
View File

@@ -2,6 +2,7 @@ import asyncio
import logging
from contextlib import asynccontextmanager
from typing import Optional, List
from datetime import datetime, timedelta
from fastapi import FastAPI, HTTPException
from fastapi.staticfiles import StaticFiles
@@ -9,9 +10,11 @@ from sqlalchemy import select
from app.core.discovery import DiscoveryService
from app.core.state import state_manager
from app.core.scheduler import start_scheduler, scheduler, execute_lamp_command
from app.drivers.wiz import WizDriver
from app.core.database import init_db, async_session
from app.models.device import GroupModel, DeviceModel, GroupCreateSchema
from app.models.schedule import ScheduleTask
logging.basicConfig(
level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s"
@@ -29,6 +32,8 @@ async def lifespan(app: FastAPI):
await init_db()
logger.info("🗄️ База данных инициализирована")
await start_scheduler()
# 2. Загрузка групп из БД в память
async with async_session() as session:
result = await session.execute(select(GroupModel))
@@ -223,6 +228,49 @@ async def blink_device(device_id: str):
return {"status": "blink_sent"}
@app.post("/schedules/once")
async def add_once_task(device_id: str, minutes: int, state: bool):
device = state_manager.devices.get(device_id)
if not device:
raise HTTPException(status_code=404, detail="Лампа не найдена")
# Получаем TZ из самого шедулера, чтобы они были синхронны
run_time = datetime.now(scheduler.timezone) + timedelta(minutes=minutes)
job = scheduler.add_job(
execute_lamp_command,
"date",
run_date=run_time,
args=[device.ip, {"state": state}],
)
return {"status": "scheduled", "job_id": job.id, "run_at": run_time.isoformat()}
@app.get("/schedules/active")
async def get_active_jobs():
jobs = []
for job in scheduler.get_jobs():
jobs.append(
{
"id": job.id,
"next_run": job.next_run_time,
"func": job.func_ref,
"args": str(job.args),
}
)
return {"active_jobs": jobs}
@app.delete("/schedules/{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="Задача не найдена")
# --- МОНТИРОВАНИЕ СТАТИКИ (ДОЛЖНО БЫТЬ ПОСЛЕ ВСЕХ API МАРШРУТОВ) ---
app.mount("/", StaticFiles(directory="static", html=True), name="static")