# Ignis App Мобильное приложение для управления умными лампами WiZ через self-hosted сервер [Ignis Core](https://git.akokos.ru). ## Возможности - **Мульти-дом** -- поддержка нескольких серверов 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 -- локальные уведомления ## Структура проекта ```text 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 ``` ## Сборка ```bash # Зависимости 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-шаблона. Для личной установки на телефон этого достаточно, для настоящего релиза подпись нужно заменить. ## Проверки ```bash flutter analyze flutter test ``` Текущий baseline зелёный: `flutter analyze`, `flutter test` и release APK сборка проходят штатно. Дополнительно тестами уже прикрыты: - typed parsing/load-state для основных backend-ответов; - geofence distance/runtime логика; - чистая логика форм расписаний и групп; - provider-мутаторы для расписаний, таймера 4h и API-ключей; - widget-сценарии форм домов, групп, расписаний и API-ключей; - widget-сценарии `RemoteScreen`, `GroupCard` и error/retry-потоков. Сейчас baseline клиента закрывается примерно `60` тестами и уже ловит regressions не только в helper-логике, но и в основных пользовательских сценариях. ## Настройка При первом запуске приложение попросит добавить "дом" -- указать адрес сервера Ignis и API-ключ. После этого откроется пульт управления группами. Если задать координаты дома, экран домов начнёт показывать расстояние до активного дома. Если дополнительно включить автовыключение при уходе и выдать Android фоновые разрешения на геолокацию и уведомления, приложение сможет в фоне выключать свет при удалении от текущего активного дома. Для добавления второго дома: кнопка "домик" в левом верхнем углу пульта -> экран домов -> кнопка "+". API-ключи хранятся отдельно от конфигурации домов в `flutter_secure_storage`. Старые ключи из `SharedPreferences` мигрируются автоматически. ## API Приложение работает с [Ignis Core API](https://git.akokos.ru) -- self-hosted бэкенд на FastAPI (контракт OpenAPI 3.1.0). Авторизация происходит через заголовок `X-API-Key`. Доменный слой на стороне клиента полностью типизирован. ## Текущие ограничения - Целевая платформа сейчас Android. - Release APK пока подписывается debug-ключом из Flutter-шаблона. - Build info в APK показывает дату сборки и короткий git hash текущего `HEAD`. Если сборка делается поверх незакоммиченного рабочего дерева, hash будет от последнего коммита, а не от локальных незакоммиченных изменений. - Android-specific поведение реального background execution, уведомлений, runtime permissions и OEM battery restrictions пока подтверждается в основном ручными проверками на устройстве, а не automated integration-тестами. ## Лицензия Частный проект.