Ignis Core
ignis-core — локальный FastAPI-сервер для WiZ-ламп и домашней автоматики вокруг них.
Что есть сейчас
- discovery ламп по локальной сети с
startup,manualи background refresh; - управление отдельной лампой и группой;
- реальные
status-опросы иblinkдля идентификации; - группы в SQLite;
- one-shot и cron-расписания;
- persisted metadata расписаний поверх APScheduler;
- роли
master,admin,guest; - гостевые API-ключи с revoke/activate;
- event log и простая stats summary;
- встроенный локальный UI из
static/; - OpenAPI-экспорт в
openapi.json.
Архитектура
main.py— инициализация FastAPI, security headers, router wiring, startup lifecycle.app/api/routes/*— HTTP-маршруты.app/core/discovery.py— выбор подсетей и UDP discovery WiZ.app/core/state.py— in-memory runtime-state устройств и групп.app/core/scheduler.py— APScheduler, reconciliation и cleanup old events.app/models/*— SQLAlchemy-модели и Pydantic-схемы.static/— встроенный web UI без внешних CDN.
Запуск локально
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp deploy/ignis-core.env.example .env
uvicorn main:app --host 0.0.0.0 --port 8000
UI: http://<host>:8000/
Готовые файлы для systemd: deploy/README.md
Конфигурация
Минимальный набор:
IGNIS_API_KEY=change-me
IGNIS_INSTANCE_NAME=Home
APP_TIMEZONE=Asia/Novosibirsk
LOG_LEVEL=INFO
IGNIS_DATABASE_URL=sqlite+aiosqlite:///./ignis.db
IGNIS_SYNC_DATABASE_URL=sqlite:///./ignis.db
Параметры server metadata / versioning:
IGNIS_PUBLIC_BASE_URL=https://ignis.example.local
IGNIS_BUILD_VERSION=1.0.0
IGNIS_BUILD_DATE=2026-05-21T12:00:00Z
IGNIS_GIT_SHA=abc1234def56
IGNIS_INSTANCE_NAME— человекочитаемое имя инстанса, которое видно в UI иGET /system/info.IGNIS_PUBLIC_BASE_URL— внешний URL сервера, если он стоит за reverse proxy или доступен по доменному имени.IGNIS_BUILD_VERSION,IGNIS_BUILD_DATE,IGNIS_GIT_SHA— build metadata установленного сервера для диагностики и сверки версий.
Параметры discovery:
SCAN_NETWORK=192.168.0.0/24
DISCOVERY_INTERVAL_SECONDS=600
DISCOVERY_BACKGROUND_MISSING_THRESHOLD=2
DISCOVERY_ENV_MIN_PREFIX_LEN=16
DISCOVERY_AUTO_MIN_PREFIX_LEN=24
Параметры retention:
EVENT_LOG_RETENTION_DAYS=30
Как работает discovery
- Если
SCAN_NETWORKзадан, сервер сканирует только указанные подсети. - Если
SCAN_NETWORKпуст,DiscoveryServiceпытается выбрать private IPv4-сегменты обычных интерфейсов и избегаетdocker,tun,wg,tailscaleи похожих интерфейсов. - При старте выполняется
startup_refresh(). POST /devices/rescanделает ручной refresh и сразу удаляет оффлайн-устройства.- Background refresh работает циклически и удаляет устройство только после
DISCOVERY_BACKGROUND_MISSING_THRESHOLDподряд пропусков.
Для хостов с VPN, несколькими NIC или нетипичной маршрутизацией SCAN_NETWORK лучше задавать явно.
Авторизация и роли
Заголовок: X-API-Key
master— значениеIGNIS_API_KEY, полный доступ.admin— ключ из БД, доступ к группам, расписаниям, stats иrescan.guest— чтение и обычное управление светом.
Сервер работает в fail-closed: если IGNIS_API_KEY не задан, защищённые маршруты отвечают 503.
HTTP API
Основные маршруты:
GET /auth/meGET /devicesGET /devices/groupsGET /devices/scenesPOST /devices/groupsDELETE /devices/groups/{group_id}POST /devices/rescanPOST /control/device/{device_id}POST /control/group/{group_id}POST /control/device/{device_id}/blinkGET /control/device/{device_id}/statusGET /control/group/{group_id}/statusPOST /schedules/oncePOST /schedules/cronGET /schedules/tasksDELETE /schedules/{job_id}GET /api-keysPOST /api-keysPOST /api-keys/revokePOST /api-keys/activateGET /stats/summaryGET /stats/logGET /system/info
control/* и schedules/* принимают JSON body.
Поддерживаемые параметры команды:
statebrightnessscenetempr,g,b
Валидация:
brightness:10..100temp:2200..6500r/g/b:0..255scene,tempиrgbвзаимоисключаемыr,g,bнужно передавать полной тройкой- для
schedules/onceнужно передать ровно одно изrun_atилиhours_from_now
Пример:
curl -X POST http://127.0.0.1:8000/control/group/bedroom \
-H 'X-API-Key: change-me' \
-H 'Content-Type: application/json' \
-d '{"state":true,"brightness":60}'
Встроенный UI
- лежит в
static/index.html,static/app.js,static/ui.css; - использует только локальные ассеты;
- не использует
localStorage; - может хранить API-ключ только в
sessionStorageтекущей вкладки; - показывает build/server metadata текущего инстанса;
- умеет базовое управление группами, расписания, API-ключи, stats/log и быстрый таймер на 4 часа.
Хранилище
SQLite-таблицы:
groupsapi_keysevent_logschedulesapscheduler_jobsdevices
Важно: реальным runtime-источником истины для онлайн-устройств остаётся in-memory state_manager.devices. Таблица devices пока не используется как полноценный persistent source of truth.
OpenAPI
Актуальная схема хранится в openapi.json.
Перегенерация:
.venv/bin/python -c 'import json, os, pathlib; os.environ.setdefault("IGNIS_API_KEY", "openapi-export"); from main import app; pathlib.Path("openapi.json").write_text(json.dumps(app.openapi(), ensure_ascii=False, indent=2) + "\n", encoding="utf-8")'
Тесты
На 2026-05-21 в tests/ лежит 29 unittest-сценариев.
Покрыто:
- fail-closed auth и role checks;
- lifecycle API-ключей;
- control/status error handling и partial success;
- validation для scene, control body и schedules body;
- one-shot и cron-расписания;
- reconciliation и миграция legacy jobs;
- auto subnet selection для discovery;
- background offline cleanup threshold;
- manual rescan summary;
- server metadata endpoint и отсутствие утечки секретов в нём;
- security headers и локальные UI-ассеты;
- stats summary без двойного счёта
*_requested.
Команды:
.venv/bin/python -m compileall app tests main.py
timeout 120s .venv/bin/python -m unittest discover -s tests -v
Известные ограничения
- discovery по-прежнему основан на переборе IP в подсетях;
- миграций схемы БД нет, используется
Base.metadata.create_all(); - runtime-state устройств живёт в памяти процесса;
- встроенный UI остаётся монолитным файлом без отдельной frontend-сборки;
- stats — это audit/summary, а не полноценная аналитика.