Ignis App
Мобильное приложение для управления умными лампами WiZ через self-hosted сервер Ignis Core.
Возможности
- Мульти-дом -- поддержка нескольких серверов Ignis (квартира, дача, друзья). Каждый дом -- отдельный сервер со своим URL и API-ключом.
- Группы ламп -- создание, удаление и управление. При создании группы есть product-валидация, автогенерация
ID, предупреждение о конфликтах по устройствам и более честный перескан сети. - Управление освещением:
- Включение/выключение
- Яркость 10--100% с шагом 10%
- Цветовая температура 2700--6500K с шагом 100K
- RGB-цвет через HSV-пикер
- Сцены (загружаются с сервера, отображаются с человекочитаемыми названиями)
- Таймер "включить на 4 часа"
- Расписания -- одноразовые таймеры с выбором даты/времени и повторяющиеся задачи с выбором дней недели. Просмотр, создание, валидация и отмена активных задач.
- API-ключи -- просмотр, создание, отзыв и повторная активация гостевых ключей для администраторов с отдельным UX для только что созданного ключа.
- Статистика и лог событий -- просмотр сводки по группам и последних событий сервера.
- Геофенс и расстояния -- live-дистанция до дома в UI и опциональное автовыключение света при уходе. Геофенс работает для текущего активного дома, показывает диагностический статус и использует cooldown/re-arm поведение.
- Устойчивость к ошибкам -- гранулярные состояния загрузки (
LoadState), централизованная обработка сетевых сбоев, soft-ошибки при управлении ползунками без спама в UI.
Стек
- Flutter 3.x / Dart
- Riverpod -- управление состоянием
- Dio -- HTTP-клиент
- SharedPreferences -- локальное хранение несекретных настроек
- Flutter Secure Storage -- безопасное хранение API-ключей
- Geolocator -- геолокация
- Workmanager -- периодические фоновые задачи
- Flutter Local Notifications -- локальные уведомления
Структура проекта
lib/
├── app/
│ ├── app_bootstrap.dart -- bootstrap приложения и навигация
│ ├── build_info.dart -- метаданные сборки (дата, git hash)
│ ├── error_message.dart -- форматирование ошибок API и сети
│ └── load_state.dart -- универсальный стейт загрузки (idle/loading/data/error)
├── main.dart -- точка входа, тема, роутер
├── models/
│ ├── api_key_info.dart -- типизированная модель API-ключа
│ ├── auth_info.dart -- информация об авторизации
│ ├── event_log_item.dart -- лог событий
│ ├── home_config.dart -- несекретная конфигурация сервера
│ ├── ignis_device.dart -- устройство умного дома
│ ├── ignis_group.dart -- группа устройств и её состояние
│ ├── ignis_scene.dart -- сцена освещения
│ ├── schedule_task.dart -- задача расписания
│ └── stats_summary.dart -- статистика
├── services/
│ ├── api_client.dart -- HTTP-клиент к Ignis Core API
│ ├── credentials_storage.dart -- безопасное хранение ключей
│ ├── geofence_worker.dart -- фоновая логика геофенса
│ └── settings_service.dart -- хранение списка "домов"
├── features/
│ ├── api_keys/providers/ -- управление гостевыми API-ключами
│ ├── auth/providers/ -- auth/me и auth-state
│ ├── groups/ -- валидация и логика форм групп
│ ├── homes/ -- дома, геолокация, geofence sync/runtime
│ ├── remote/providers/ -- polling групп, устройства, сцены, control errors
│ ├── schedules/ -- логика и providers расписаний
│ ├── shared/providers/ -- базовые core providers
│ └── stats/providers/ -- статистика и лог событий
├── providers/
│ └── providers.dart -- compatibility barrel для публичных provider-экспортов
├── screens/
│ ├── api_keys_screen.dart -- экран гостевых API-ключей
│ ├── event_log_screen.dart -- последние события сервера
│ ├── homes_screen.dart -- список домов, distance/geofence статус
│ ├── home_edit_screen.dart -- создание и редактирование дома
│ ├── remote_screen.dart -- основной экран управления светом
│ ├── group_edit_screen.dart -- создание группы с выбором устройств
│ ├── schedules_screen.dart -- создание и просмотр расписаний
│ └── stats_screen.dart -- статистика по командам
└── widgets/
├── build_info_text.dart -- лейбл с версией сборки
├── group_card.dart
├── load_error_view.dart -- универсальный виджет ошибок и retry
└── color_picker.dart
Сборка
# Зависимости
flutter pub get
# Debug-запуск
flutter run
# Release APK (с пробросом build info)
flutter build apk --release --dart-define=IGNIS_BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" --dart-define=IGNIS_GIT_SHA="$(git rev-parse --short HEAD)"
APK: build/app/outputs/flutter-apk/app-release.apk
Сейчас release APK подписывается debug-ключом из Flutter-шаблона. Для личной установки на телефон этого достаточно, для настоящего релиза подпись нужно заменить.
Проверки
flutter analyze
flutter test
Текущий baseline зелёный: flutter analyze, flutter test и release APK сборка проходят штатно.
Дополнительно тестами уже прикрыты:
- typed parsing/load-state для основных backend-ответов;
- geofence distance/runtime логика;
- чистая логика форм расписаний и групп.
Настройка
При первом запуске приложение попросит добавить "дом" -- указать адрес сервера Ignis и API-ключ. После этого откроется пульт управления группами.
Если задать координаты дома, экран домов начнёт показывать расстояние до активного дома. Если дополнительно включить автовыключение при уходе и выдать Android фоновые разрешения на геолокацию и уведомления, приложение сможет в фоне выключать свет при удалении от текущего активного дома.
Для добавления второго дома: кнопка "домик" в левом верхнем углу пульта -> экран домов -> кнопка "+".
API-ключи хранятся отдельно от конфигурации домов в flutter_secure_storage. Старые ключи из SharedPreferences мигрируются автоматически.
API
Приложение работает с Ignis Core API -- self-hosted бэкенд на FastAPI (контракт OpenAPI 3.1.0).
Авторизация происходит через заголовок X-API-Key.
Доменный слой на стороне клиента полностью типизирован.
Текущие ограничения
- Целевая платформа сейчас Android.
- Release APK пока подписывается debug-ключом из Flutter-шаблона.
- Build info в APK показывает дату сборки и короткий git hash текущего
HEAD. Если сборка делается поверх незакоммиченного рабочего дерева, hash будет от последнего коммита, а не от локальных незакоммиченных изменений.
Лицензия
Частный проект.