import logging import asyncio import os from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from app.core.database import init_db, async_session from app.core.scheduler import start_scheduler from app.core.state import state_manager, discovery_service from sqlalchemy import select from app.models.device import GroupModel from app.api.routes import devices, control, schedules LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper() logging.basicConfig(level=LOG_LEVEL, format="%(asctime)s | %(levelname)s | %(message)s") logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): # 1. БД и Планировщик await init_db() await start_scheduler() # 2. Загрузка групп async with async_session() as session: result = await session.execute(select(GroupModel)) for g in result.scalars().all(): state_manager.groups[g.id] = g logger.info(f"📂 Загружена группа: {g.name}") # 3. Фоновый Discovery discovery_task = asyncio.create_task( discovery_service.start_background_discovery(state_manager) ) yield discovery_task.cancel() logger.info("🛑 Ignis Core остановлен") app = FastAPI(title="Ignis Core API", lifespan=lifespan) # Регистрация роутеров app.include_router(devices.router, prefix="/devices", tags=["Devices & Groups"]) app.include_router(control.router, prefix="/control", tags=["Control"]) app.include_router(schedules.router, prefix="/schedules", tags=["Schedules"]) # Статика # Мы убираем html=True из корня, чтобы 404-е ошибки API не превращались в загрузку index.html app.mount("/static", StaticFiles(directory="static"), name="static") @app.get("/") async def read_index(): from fastapi.responses import FileResponse return FileResponse("static/index.html") if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)