0fd64307b75496a440fa021cdf3733525e1e6942
Ignis Core
Локальный FastAPI-сервер для управления лампами WiZ.
Что есть
- discovery устройств в локальной сети
- группы устройств
- команды для device/group
- one-shot и cron расписания
- guest/admin/master API-ключи
- event log и базовая статистика
- встроенный UI в
static/index.html - встроенный UI без внешних CDN
Запуск
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
uvicorn main:app --host 0.0.0.0 --port 8000
UI: http://<host>:8000/
Готовые deployment-файлы для systemd: deploy/README.md
Конфигурация
Минимум:
IGNIS_API_KEY=change-me
APP_TIMEZONE=Asia/Novosibirsk
SCAN_NETWORK=
DISCOVERY_INTERVAL_SECONDS=600
DISCOVERY_BACKGROUND_MISSING_THRESHOLD=2
LOG_LEVEL=INFO
EVENT_LOG_RETENTION_DAYS=30
БД:
IGNIS_DATABASE_URL=sqlite+aiosqlite:///./ignis.db
IGNIS_SYNC_DATABASE_URL=sqlite:///./ignis.db
Замечание по discovery:
- если
SCAN_NETWORKне задан, сервер сам выбирает private IPv4-подсети обычных интерфейсов и старается не сканировать VPN / docker / tunnel-интерфейсы - если на хосте есть VPN или несколько интерфейсов, всё равно лучше явно задать
SCAN_NETWORK - формат:
192.168.0.0/24или список через запятую - startup scan выполняется до старта фонового цикла
- background refresh по умолчанию удаляет устройство только после двух подряд промахов discovery
- manual
POST /devices/rescanудаляет оффлайн-устройства сразу и возвращает summary (found,added,updated,removed_offline,pending_removal,online)
Авторизация
Заголовок: X-API-Key
Роли:
master: значение изIGNIS_API_KEY, полный доступadmin: ключ из БД, доступ к группам, расписаниям, stats и rescanguest: обычное управление и чтение
Сервер работает в fail-closed: если IGNIS_API_KEY не задан, защищённые маршруты недоступны.
Встроенный UI:
- использует только локальные статические ассеты
- по умолчанию не сохраняет API-ключ между перезагрузками
- может запомнить ключ только в рамках текущей вкладки браузера
API
Основные маршруты:
GET /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 /auth/me
control и schedules принимают JSON body.
Поддерживаемые параметры команд:
statebrightnessscenetempr,g,b
Примеры:
curl -X POST 'http://localhost:8000/control/device/dev-1' \
-H 'X-API-Key: change-me' \
-H 'Content-Type: application/json' \
-d '{"temp": 4200}'
curl -X POST 'http://localhost:8000/schedules/once' \
-H 'X-API-Key: change-me' \
-H 'Content-Type: application/json' \
-d '{"target_id":"bedroom","hours_from_now":2,"is_group":true,"temp":3200}'
Валидация:
brightness:10..100temp:2200..6500r/g/b:0..255scene,tempиrgbвзаимоисключаемыr,g,bнужно передавать только полной тройкой- для
schedules/onceнужно передать ровно одно изrun_atилиhours_from_now
API keys
- список ключей возвращает публичный
key/key_id - полный секрет возвращается только при создании
- маршруты
/api-keys/*доступны толькоmaster
Хранилище
Основные таблицы:
groupsapi_keysevent_logschedulesapscheduler_jobs
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")'
Тесты
Проверка синтаксиса:
.venv/bin/python -m compileall app tests main.py
Полный прогон:
timeout 120s .venv/bin/python -m unittest discover -s tests -v
Сейчас есть 27 тестов. Покрыты:
- auth и роли
- lifecycle API-ключей
- control/status ошибки и partial success
- валидация scene
- one-shot и cron расписания
- миграция legacy jobs
- auto-subnet selection для discovery
- background offline cleanup threshold
- manual rescan summary и immediate cleanup
- security headers и локальные UI-ассеты
- агрегация stats без двойного счёта
*_requested
Ограничения
- discovery всё ещё основан на переборе IP по подсетям
- UI остаётся монолитным файлом
- stats пока простые и не заменяют нормальную аналитику