# WiZ Provisioning Master Plan Статус: design / implementation brief Актуально на: 2026-05-16 Основной проект: `ignis_app` Связанный проект: `../ignis-core` ## Зачем нужен этот документ Этот документ нужен как рабочий implementation brief для добавления в `Ignis` мастера первичной посадки новых WiZ-ламп на домашний Wi-Fi без официального приложения WiZ. Цель документа: - быстро восстановить контекст через недели или месяцы без повторного ресерча; - понимать, что именно реализуем сначала, а что откладываем; - иметь точную карту действий по Flutter, Android native и интеграции с `ignis-core`; - заранее зафиксировать технические риски и места, где потребуются ручные проверки и апрувы. ## Краткий вывод Сделать это **реально**, но нужно разделять минимум два поколения/режима onboarding: - `SoftAP / manual setup`: лампа поднимает сеть вида `WiZConfig_xxxx`, телефон временно подключается к ней и передаёт домашние Wi-Fi credentials. - `BLE setup`: часть более новых устройств рекламируется и настраивается по Bluetooth. Дополнительно у части устройств есть `Matter`, но его не стоит брать как первый путь реализации внутри `Ignis`. ### Почему задача вообще выглядит решаемой Официальные материалы WiZ подтверждают: - есть режим `Manual setup` через Wi-Fi лампы `WiZConfig_xxxx`; - есть Bluetooth-based setup для новых устройств; - есть отдельный локальный commissioning-порт `UDP 18266`, который используется только во время ввода устройства в строй. Это означает, что задача не упирается в принципиальную закрытость экосистемы. Главная неизвестная не в том, можно ли это сделать, а в том, **какой именно payload нужно передать лампе при commissioning**. ## Границы задачи ### Что считаем целевым результатом Пользователь открывает `ignis_app`, запускает мастер, выбирает домашнюю Wi-Fi сеть, вводит пароль, переводит лампу в pairing mode, приложение временно подключается к лампе, передаёт credentials, ждёт появления лампы в домашней сети и затем вызывает `POST /devices/rescan` на локальном сервере `ignis-core`. ### Что не входит в первую фазу - полноценный iOS onboarding; - Matter commissioner внутри `Ignis`; - cloud-интеграции WiZ; - поддержка всех возможных поколений устройств одновременно; - идеальный cross-platform UX. ### Что делаем в первую очередь 1. Android-only onboarding. 2. Сначала `SoftAP`-ветка. 3. После неё `BLE`-ветка. 4. `Matter` рассматривать только как отдельный fallback/будущее расширение. ## Текущий статус реализации По состоянию на 2026-05-16 в `ignis_app` уже есть первая рабочая Android-first реализация мастера, но она закрывает только часть общей задачи. ### Что уже реализовано - отдельный экран мастера в `ignis_app`; - Android environment inspection через platform channel; - проверка Wi-Fi контекста, системных permissions и активного дома; - Android-first `smart pairing` flow на базе `esp_smartconfig`; - post-provision `POST /devices/rescan` через уже существующий backend `ignis-core`; - release build, `flutter analyze` и тесты проходят; - entrypoint мастера перенесён в `SettingsScreen`, в секцию `Дом и подключение`. ### Что это означает на практике Сейчас в проекте есть не "полноценный универсальный мастер WiZ", а первый технический клин в эту задачу: Android-only путь через smart pairing с последующим discovery в `Ignis`. ### Что критично ещё не реализовано - нет `SoftAP`-ветки через `WiZConfig_xxxx`; - нет reverse engineering и production-реализации commissioning-протокола `UDP 18266`; - нет `BLE`-ветки для новых ламп; - нет `Matter`-fallback; - нет iOS-реализации; - нет подтверждения на реальном железе, что текущий `smart pairing` путь покрывает нужные пользователю модели ламп. ### Честная оценка текущего состояния Тема не закрыта. Закрыт только первый этап. Если текущий `smart pairing` на реальных лампах пользователя не сработает, основной следующий шаг -- это не косметика и не polish, а возврат к базовому плану: 1. `SoftAP / WiZConfig_xxxx` 2. commissioning через `UDP 18266` 3. затем `BLE`-ветка ### Что ещё не добито по UX и диагностике - нет выбора provisioning mode (`smart pairing` / `WiZConfig_xxxx` / `BLE`); - нет явного fallback UX для ламп, которые не поддерживают текущий путь; - нет финального успешного сценария "создать группу / мигнуть лампой / открыть пульт"; - нет отдельного protocol notes файла с результатами reverse engineering; - нет полной ручной test matrix по реальным устройствам разных поколений. ## Почему основной объём живёт в `ignis_app` Onboarding должен жить в `ignis_app`, а не в `ignis-core`, потому что именно телефон: - видит nearby Wi-Fi/BLE устройства; - может временно переключаться на AP лампы; - может работать с Android Wi-Fi / Bluetooth API; - может запросить системные permissions и показать пользователю platform dialogs. `ignis-core` нужен только после успешного provisioning: - сделать `POST /devices/rescan`; - обнаружить лампу в домашней сети; - дальше работать обычным локальным API, который уже реализован. Связанные текущие точки в коде: - `ignis_app/lib/main.dart` - `ignis_app/lib/screens/homes_screen.dart` - `ignis_app/lib/screens/remote_screen.dart` - `ignis_app/android/app/src/main/kotlin/ru/akokos/ignis_app/MainActivity.kt` - `ignis_app/lib/services/api_client.dart` - `ignis-core/app/api/routes/devices.py` ## Подтверждённые факты из источников ### 1. У WiZ есть ручной setup через `WiZConfig_xxxx` Официальная legacy-справка WiZ говорит, что если обычное pairing не сработало, нужно идти в `Manual setup`, где телефон подключается напрямую к Wi-Fi сети лампы. Источник: - https://faq.wizconnected.com/hc/en/3-wiz-legacy/faq/138-adding-a-wiz-light-in-the-system/ Дополнительный важный нюанс: WiZ отдельно пишет, что у некоторых ламп сеть `WiZConfig_xxxx` может отсутствовать вообще. Это значит, что SoftAP-путь нельзя считать универсальным. Источник: - https://faq.wizconnected.com/hc/en/3-wiz-legacy/faq/147-can-t-find-wizconfig-xxxx-in-the-wi-fi-settings-during-manual-setup/ ### 2. У новых устройств есть Bluetooth-based setup Новая справка WiZ V2 указывает, что Bluetooth permission нужен для Bluetooth-enabled products и что приложение может автоматически находить такие лампы после включения питания. Источник: - https://faq.wizconnected.com/hc/en/7-wiz-v2/faq/767-smart-lighting---how-to-get-started/ Дополнительное косвенное подтверждение: в даташитах WiZ/WiZ Pro встречается `Wi-Fi + BLE` и явная фраза про setup via Bluetooth. Источники: - https://assets.wizconnected.com/datasheets/WiZ_Pro_A60_B22_TW_8W_230V_929002383771_DS1022.pdf - https://assets.wizconnected.com/datasheets/WiZ_Pro_A67_E27_RGBTW_13W_230V_929002449771_DS042023.pdf ### 3. У WiZ есть отдельный commissioning-порт `UDP 18266` Это ключевой технический сигнал. В официальном документе по сети WiZ указано, что порт `18266/UDP` используется локально и только во время commissioning. Источник: - https://assets.wizconnected.com/manuals/WiZ-Network-Configuration-v2-01162024.pdf Вывод: существует локальный commissioning-протокол, который, вероятно, и использует официальное приложение во время первичной посадки лампы в Wi-Fi. ### 4. Android официально поддерживает bootstrap к локальной Wi-Fi accessory network Для Android 10+ есть штатный путь для peer-to-peer Wi-Fi bootstrap через `WifiNetworkSpecifier`. Источник: - https://developer.android.com/develop/connectivity/wifi/wifi-bootstrap ### 5. iOS тоже поддерживает accessory Wi-Fi setup, но не это наш первый приоритет Для iOS есть `NEHotspotConfiguration` / `NEHotspotConfigurationManager`, а также accessory-oriented Wi-Fi configuration APIs. Это делает iOS-ветку возможной, но отдельной и более дорогой по времени. Источники: - https://developer.apple.com/documentation/networkextension/wi-fi_configuration - https://developer.apple.com/documentation/networkextension/nehotspotconfigurationmanager ### 6. Matter есть не на всех WiZ-устройствах WiZ пишет, что Matter поддерживают только lights/smart plugs, выпущенные после `Q2 2021`. Поэтому Matter нельзя использовать как универсальный onboarding-path. Источник: - https://faq.wizconnected.com/hc/en/7-wiz-v2/faq/531-do-all-wiz-devices-support-matter/ ## Принятая стратегия реализации ### Основной план 1. Реализовать Android-only `SoftAP onboarding`. 2. Через reverse engineering добыть локальный commissioning payload для `UDP 18266`. 3. Встроить это в `ignis_app` как отдельный мастер. 4. После успешного provisioning вызывать existing `rescanNetwork()` через текущий `IgnisApi`. 5. Затем добавить `BLE onboarding` как вторую ветку. ### Почему не начинать с BLE - SoftAP-path подтверждён официальной справкой WiZ. - Android Wi-Fi bootstrap API проще и стабильнее, чем reverse engineering GATT-профиля с нуля. - BLE вероятно потребуется для новых ламп, но SoftAP даст первый рабочий end-to-end flow быстрее. ### Почему не начинать с Matter - не все устройства его поддерживают; - внутри собственного Flutter-приложения Matter commissioner сильно увеличивает объём работ; - для цели `Ignis` нужен именно практичный локальный onboarding WiZ-лампы, а не параллельный smart-home стек. ## Архитектурное решение по проекту ## High-Level Flow ```text Flutter UI -> MethodChannel -> Android provisioning manager -> connect to WiZConfig_xxxx AP -> send commissioning payload to lamp over UDP 18266 -> wait for device to leave AP / join home Wi-Fi -> call ignis-core POST /devices/rescan -> show discovered device / success state ``` ## Что добавляем в `ignis_app` Новая feature-зона: - `lib/features/provisioning/models/` - `lib/features/provisioning/providers/` - `lib/features/provisioning/services/` Новый экран: - `lib/screens/wiz_provisioning_screen.dart` Новые Android native классы: - `android/app/src/main/kotlin/ru/akokos/ignis_app/WizProvisioningManager.kt` - `android/app/src/main/kotlin/ru/akokos/ignis_app/WizSoftApProvisioner.kt` - `android/app/src/main/kotlin/ru/akokos/ignis_app/WizUdpCommissioningClient.kt` - `android/app/src/main/kotlin/ru/akokos/ignis_app/WizProvisioningModels.kt` Вторая очередь, не первая: - `android/app/src/main/kotlin/ru/akokos/ignis_app/WizBleProvisioner.kt` ## Что не нужно делать в `ignis-core` Не нужно переносить туда onboarding-логику. Сервер не должен: - управлять Wi-Fi телефона; - принимать пароль от домашней сети как основную часть provisioning; - реализовывать platform-specific transport. В `ignis-core` достаточно использовать уже существующий: - `POST /devices/rescan` Текущая клиентская точка входа: - `ignis_app/lib/services/api_client.dart` -> `rescanNetwork()` ## Фактическая реализация против плана Изначальный план первой полноценной фазы предполагал старт с `SoftAP onboarding`. В коде сейчас первой реализованной веткой стал `smart pairing`. ### Почему это важно помнить - это ускорило появление первого рабочего мастера; - но это не доказывает, что задача "подключение любых новых WiZ-ламп без официального приложения" уже решена; - исходный `SoftAP + UDP 18266` путь по-прежнему остаётся вероятно более универсальным и по-прежнему нужен, если smart pairing не перекрывает нужные модели устройств. ## Предлагаемая модель состояния мастера Нужна явная state machine, а не набор bool-флагов. ### Состояния - `idle` - `checkingCapabilities` - `requestingPermissions` - `waitingForHomeSelection` - `waitingForPairingMode` - `scanningForSoftAp` - `connectingToLampAp` - `connectedToLampAp` - `commissioning` - `waitingForLampToJoinHome` - `rescanningIgnis` - `success` - `failure` - `cancelled` ### Данные состояния - `selectedHomeSsid` - `selectedHomePassphrase` - `selectedIgnisHomeId` - `lampApSsid` - `attempt` - `lastError` - `debugTimeline` - `startedAt` - `finishedAt` ### Почему нужен `debugTimeline` Provisioning без timeline очень трудно дебажить. Минимум нужен список событий: - permission granted/denied; - lamp AP discovered; - Wi-Fi request sent; - Wi-Fi request accepted/rejected; - UDP payload sent; - ack received / timeout; - device disappeared from AP; - `rescan` started/finished. ## UX-структура мастера ### Экран 1. Введение Показывает: - что мастер пока Android-only; - какие лампы могут не поддерживать SoftAP; - что телефон временно переключится на сеть лампы; - что нужен локальный сервер `Ignis` и доступный активный дом. ### Экран 2. Проверка контекста Проверки: - выбран ли активный `HomeConfig`; - доступен ли `auth/me` текущего дома; - есть ли Wi-Fi на телефоне; - есть ли необходимые Android permissions; - Android API level >= 29. ### Экран 3. Выбор домашней сети Варианты: - ручной ввод SSID и пароля; - позже, если потребуется, попытка показать текущий SSID как подсказку. Важно: не делать магии вокруг чтения текущего SSID как обязательного пути. На Android это permission-sensitive и OEM-dependent. ### Экран 4. Инструкция перевода лампы в pairing mode Нужно явно объяснить: - включить лампу; - если не находится, несколько раз выключить/включить до мигания; - если лампа не поднимает `WiZConfig_xxxx`, значит этот путь может не поддерживаться и нужен BLE-path. ### Экран 5. Подключение и provisioning Показывать по шагам: - поиск `WiZConfig_xxxx`; - подключение; - передача настроек; - ожидание возврата лампы в домашнюю сеть; - запрос `rescan`. ### Экран 6. Итог Успех: - показать, что лампа найдена; - предложить перейти к созданию группы или вернуться на пульт. Ошибка: - показать, на каком шаге упало; - дать actionable retry; - предлагать BLE-path только когда он будет реализован. ## Точки встраивания в текущее приложение Минимально логичное место входа: - `HomesScreen`: отдельная кнопка "Добавить лампу WiZ" - или `RemoteScreen` в overflow menu Рекомендуемый вариант первой версии: - вход из `HomesScreen`, потому что provisioning логически относится к конкретному дому/серверу. Причина: - мастер зависит от выбранного активного дома; - после provisioning всё равно нужен `rescan` именно этого дома; - onboarding новой лампы ближе по смыслу к инфраструктуре дома, чем к управлению существующими группами. ## Android implementation plan ## Phase 1: Platform Bridge Skeleton ### Цель Подготовить безопасный мост Flutter <-> Android без реальной provisioning-логики. ### Изменяемые файлы - `ignis_app/android/app/src/main/kotlin/ru/akokos/ignis_app/MainActivity.kt` - новые Kotlin-файлы из секции выше - новые Dart provider/service/screen файлы ### MethodChannel Использовать отдельный channel, не смешивать с geofence. Предлагаемое имя: - `ignis/wiz_provisioning` ### Методы канала v1 - `getProvisioningCapabilities` - `requestProvisioningPermissions` - `startSoftApProvisioning` - `cancelProvisioning` ### Формат `getProvisioningCapabilities` Возвращать map: - `platform`: `android` - `androidApiLevel` - `supportsWifiNetworkSpecifier` - `supportsBle` - `supportedModes`: `["softap"]` на первой фазе ### Формат `startSoftApProvisioning` Вход: - `homeSsid` - `homePassphrase` - `lampApPrefix` default `WiZConfig_` - `timeoutSeconds` - `activeHomeBaseUrl` - `activeHomeApiKey` На первой фазе `activeHomeBaseUrl` и `activeHomeApiKey` можно вообще не передавать в native и оставить `rescan` на Flutter-стороне. ## Phase 2: Android Wi-Fi Connect to Lamp AP ### Цель Научиться гарантированно подключать телефон к `WiZConfig_xxxx`. ### Android APIs - `WifiNetworkSpecifier` - `ConnectivityManager.requestNetwork()` - `NetworkCallback` Источник: - https://developer.android.com/develop/connectivity/wifi/wifi-bootstrap ### Требуемые permissions и manifest changes Проверить и добавить по необходимости: - `android.permission.NEARBY_WIFI_DEVICES` для Android 13+ - существующие location permissions уже частично есть Текущий manifest: - `ignis_app/android/app/src/main/AndroidManifest.xml` ### Что нужно реализовать - запрос permissions из Flutter; - поиск/выбор AP по префиксу `WiZConfig_`; - запрос на временное подключение; - ожидание `onAvailable()`; - bind сокетов к этой `Network`, если потребуется; - корректный release callback после завершения или отмены. ### Acceptance criteria - приложение может подключиться к реальной сети `WiZConfig_xxxx`; - есть надёжный таймаут и понятный error mapping; - повторный запуск после неудачи не оставляет висящих network requests. ## Phase 3: Reverse Engineering Commissioning Payload ### Это главный риск проекта Пока нет публичного официального описания payload для `UDP 18266`. Нужно добыть его экспериментально. ### Практический план reverse engineering 1. Взять лампу, которая точно поддерживает `WiZConfig_xxxx`. 2. Перевести лампу в pairing mode. 3. Запустить официальный WiZ app и пройти `Manual setup`. 4. Снять трафик между телефоном и лампой во время provisioning. 5. Отделить трафик к лампе от фонового шума. 6. Найти обмен по `UDP 18266`. 7. Зафиксировать: - формат payload; - есть ли ответ/ack; - есть ли checksum/nonce/session id; - передаётся ли SSID/пароль в открытом виде, JSON, protobuf, бинарнике и т.д. 8. Повторить пару раз с разными SSID/password, чтобы понять структуру. ### Что именно нужно получить в результате - пример сырого запроса; - пример сырого ответа; - описание полей; - минимальный payload, достаточный для посадки лампы; - список обязательных и необязательных параметров. ### Какие инструменты могут понадобиться - Android device + официальный WiZ app; - отдельная тестовая Wi-Fi сеть; - Wireshark / tcpdump / mitm на уровне точки доступа; - при необходимости второй Android с hotspot/sniffer схемой; - возможно `adb bugreport` / network diagnostics как вспомогательный путь. ### Решение по хранению результата После расшифровки протокола создать отдельный внутренний документ: - `ignis_app/docs/wiz_commissioning_protocol_notes.md` Если там будут чувствительные детали или сырые бинарные дампы, можно держать файл локально и не коммитить, но лучше иметь хотя бы структурированное описание в репозитории. ## Phase 4: Implement UDP Commissioning Client ### Цель Собрать Kotlin-клиент, который: - открывает UDP socket в сети лампы; - отправляет commissioning payload на `18266`; - ждёт подтверждение или фиксирует timeout; - отдаёт во Flutter понятный result object. ### Предлагаемый класс - `WizUdpCommissioningClient.kt` ### Предлагаемый API - `suspend fun sendCredentials(network: Network, targetIp: InetAddress, payload: ByteArray): CommissioningResult` ### Что нужно предусмотреть - bind сокета именно к `Network`, через которую подключились к AP лампы; - configurable timeout; - раздельные ошибки: - `socket_open_failed` - `payload_build_failed` - `send_failed` - `ack_timeout` - `malformed_ack` ## Phase 5: End-to-End Flutter Flow ### Цель Сделать законченный пользовательский мастер. ### Новые Dart сущности Предлагаемые файлы: - `lib/features/provisioning/models/wiz_provisioning_mode.dart` - `lib/features/provisioning/models/wiz_provisioning_state.dart` - `lib/features/provisioning/models/wiz_provisioning_failure.dart` - `lib/features/provisioning/services/wiz_provisioning_platform_service.dart` - `lib/features/provisioning/providers/wiz_provisioning_providers.dart` - `lib/screens/wiz_provisioning_screen.dart` ### Поведение после успешного provisioning 1. Flutter получает успех от native-слоя. 2. Flutter ждёт короткое окно на переподключение лампы к домашней сети. 3. Flutter вызывает текущий `IgnisApi.rescanNetwork()`. 4. Flutter обновляет список устройств/групп. 5. Flutter показывает success и, если возможно, имя/IP/MAC найденной лампы. Текущая клиентская точка: - `ignis_app/lib/services/api_client.dart` Текущий backend route: - `ignis-core/app/api/routes/devices.py` ## Phase 6: BLE Branch ### Когда переходить к BLE Только после того, как SoftAP-path уже рабочий end-to-end. ### Что нужно выяснить перед реализацией - advertise name/service UUID лампы в pairing mode; - GATT services/characteristics; - какой transport и payload используются для передачи Wi-Fi credentials; - есть ли там тот же commissioning payload, что и в SoftAP-path, или совсем другой протокол. ### Android tech stack для BLE - `BluetoothManager` - `BluetoothAdapter` - `BluetoothLeScanner` - `ScanCallback` - `BluetoothGatt` ### Дополнительные permissions - `android.permission.BLUETOOTH_SCAN` - `android.permission.BLUETOOTH_CONNECT` ### Важное ограничение Пока нет сведений, что BLE-path у WiZ можно поднять без reverse engineering. Официальные источники подтверждают наличие Bluetooth setup, но не описывают низкоуровневый протокол. ## Что менять в UI и навигации ### Первая версия Добавить в `HomesScreen` вторую FAB-entry или secondary action: - `Добавить дом` - `Добавить лампу WiZ` Если не хочется перегружать основной FAB, сделать extended bottom sheet / speed dial / отдельную кнопку в пустом состоянии. ### Более аккуратный вариант Добавить на `HomesScreen` card/banner: - "Новая лампа WiZ? Открыть мастер подключения" ### Что не делать - не прятать этот flow глубоко в `SettingsScreen`; - не запускать onboarding из `RemoteScreen` по умолчанию, если активный дом ещё не выбран и невалиден. ## Безопасность и хранение Wi-Fi credentials ### Минимальные правила - пароль домашней Wi-Fi сети не хранить в `SharedPreferences`; - не класть пароль в обычные debug-логи; - не записывать пароль в event log приложения; - держать пароль только в runtime memory на время onboarding-сессии; - по завершении или ошибке занулять/очищать state. ### Что можно хранить - только SSID как UX convenience, если это вообще нужно; - debug timeline без секретов; - machine-readable error codes. ## Тестовая стратегия ## Unit / Widget Tests Покрыть: - state machine; - error mapping native -> Flutter; - retry/cancel logic; - post-success переход к `rescan`. ### Предлагаемые test-файлы - `test/wiz_provisioning_state_test.dart` - `test/wiz_provisioning_notifier_test.dart` - `test/wiz_provisioning_screen_test.dart` ## Android Native Tests Минимум: - локальные unit tests на payload builder; - по возможности instrumentation tests на permission/result mapping. Но главное здесь всё равно manual verification на реальном устройстве. ## Manual Test Matrix Обязательные ручные сценарии: 1. Успешная посадка лампы через `WiZConfig_xxxx`. 2. Таймаут при отсутствии pairing mode. 3. Ошибочный пароль домашней сети. 4. Повторный запуск мастера сразу после ошибки. 5. Отмена пользователем system dialog подключения к Wi-Fi. 6. Потеря Wi-Fi во время provisioning. 7. Успешный `rescan` после provisioning. 8. Provisioning success, но `rescan` не находит лампу. 9. Лампа без `WiZConfig_xxxx` и корректный UX fallback. 10. Проверка на Android 13+ с новыми permission flows. ## Acceptance Criteria для первой поставляемой версии Первая версия считается завершённой, если: - мастер доступен из `ignis_app`; - Android 10+ устройство умеет подключиться к `WiZConfig_xxxx`; - приложение умеет отправить commissioning payload и получить воспроизводимый результат; - лампа уходит в домашнюю сеть; - `Ignis` после `rescan` видит лампу; - пользователь получает понятный success/failure UX; - чувствительные данные не остаются в persistent storage; - есть тесты на Dart state machine и минимум ручной regression checklist. ## Пошаговая карта действий ## Шаг 0. Подготовка перед кодом 1. Подтвердить наличие тестовой WiZ-лампы с `WiZConfig_xxxx`. 2. Подготовить Android-девайс для ручных прогонов. 3. Подготовить отдельную тестовую Wi-Fi сеть `2.4 GHz`. 4. Подготовить стенд с рабочим `ignis-core`. 5. Решить, где и как снимать provisioning traffic. ## Шаг 1. Скелет feature в `ignis_app` 1. Добавить `docs/` и этот план. 2. Создать feature-папки `lib/features/provisioning/*`. 3. Создать Dart-модели состояния. 4. Создать `WizProvisioningPlatformService`. 5. Создать новый `MethodChannel`. 6. Добавить пустой экран мастера и точку входа из `HomesScreen`. ## Шаг 2. Android bridge без реального provisioning 1. Добавить `WizProvisioningManager.kt`. 2. Подключить channel в `MainActivity.kt`. 3. Реализовать `getProvisioningCapabilities`. 4. Реализовать `requestProvisioningPermissions`. 5. Протянуть результат в UI и показать capability gate. ## Шаг 3. SoftAP connection layer 1. Добавить `WifiNetworkSpecifier` flow. 2. Сделать поиск/подключение к `WiZConfig_`. 3. Вернуть во Flutter structured result. 4. Обработать cancel/timeout. 5. Проверить ручным прогоном на тестовой точке доступа. ## Шаг 4. Reverse engineering commissioning payload 1. Снять трафик официального WiZ app. 2. Описать протокол. 3. Зафиксировать findings в отдельном notes-файле. 4. Только после этого писать production `WizUdpCommissioningClient`. ## Шаг 5. Реальный commissioning 1. Реализовать payload builder. 2. Реализовать отправку на `UDP 18266`. 3. Обработать ack/timeout. 4. Завести детальные internal error codes. ## Шаг 6. End-to-end flow с `Ignis` 1. После native success вызвать `rescanNetwork()`. 2. Дождаться ответа backend. 3. Показать найденное устройство или отдельную ошибку post-provision discovery. 4. Протестировать повторяемость. ## Шаг 7. Cleanup и hardening 1. Удалить лишние debug-логи. 2. Проверить, что пароль Wi-Fi нигде не сохраняется. 3. Добавить unit/widget tests. 4. Обновить `README.md`. ## Открытые вопросы ### Технические - Как именно выглядит payload для `UDP 18266`? - Нужен ли specific target IP на AP лампы или есть broadcast? - Есть ли обязательный ack и как он кодируется? - Нужен ли bind сокета к `Network` для всех Android OEM или только для части? - Как определить успешность до `rescan`: по ack или по исчезновению AP? ### Продуктовые - Где именно располагать entrypoint мастера в UI? - Нужен ли в первой версии ручной ввод SSID, или можно сразу только auto-fill + редактирование? - Нужен ли отдельный экран выбора provisioning mode, если BLE ещё не реализован? ### Операционные - Есть ли в наличии лампа старого поколения с `WiZConfig_xxxx`? - Нужны ли апрувы на Android permissions / реальные ручные прогоны / возможную установку вспомогательных инструментов для sniffing? ## Что проверять первым делом при возвращении к задаче Если вернулись к задаче через долгое время, стартовать так: 1. Перечитать этот документ целиком. 2. Проверить, не появились ли новые официальные WiZ материалы про local commissioning. 3. Проверить, не изменились ли Android Wi-Fi/BLE permission требования. 4. Уточнить, какая именно тестовая лампа есть на руках. 5. Решить, можно ли сразу идти в reverse engineering или сначала поднимать только bridge/UI skeleton. ## Рекомендуемый следующий practically useful шаг Когда будет время на апрувы и ручные проверки, не начинать сразу с большого рефактора. Самый выгодный порядок: 1. закоммитить UI skeleton и Android bridge; 2. проверить Wi-Fi connect к `WiZConfig_xxxx`; 3. только потом тратить время на reverse engineering `UDP 18266`. Это минимизирует риск закопаться в неизвестный протокол до того, как станет ясно, что platform plumbing вообще работает на конкретном устройстве. ## Источники ### WiZ - WiZ manual setup / `WiZConfig_xxxx`: https://faq.wizconnected.com/hc/en/3-wiz-legacy/faq/138-adding-a-wiz-light-in-the-system/ - WiZ: у части ламп `WiZConfig_xxxx` может отсутствовать: https://faq.wizconnected.com/hc/en/3-wiz-legacy/faq/147-can-t-find-wizconfig-xxxx-in-the-wi-fi-settings-during-manual-setup/ - WiZ V2 getting started / Bluetooth-enabled setup: https://faq.wizconnected.com/hc/en/7-wiz-v2/faq/767-smart-lighting---how-to-get-started/ - WiZ network configuration / commissioning port `UDP 18266`: https://assets.wizconnected.com/manuals/WiZ-Network-Configuration-v2-01162024.pdf - WiZ Matter support coverage: https://faq.wizconnected.com/hc/en/7-wiz-v2/faq/531-do-all-wiz-devices-support-matter/ - WiZ Pro A60 datasheet / `Wi-Fi + BLE`: https://assets.wizconnected.com/datasheets/WiZ_Pro_A60_B22_TW_8W_230V_929002383771_DS1022.pdf - WiZ Pro A67 datasheet / setup via Bluetooth: https://assets.wizconnected.com/datasheets/WiZ_Pro_A67_E27_RGBTW_13W_230V_929002449771_DS042023.pdf ### Android - Wi-Fi bootstrap / `WifiNetworkSpecifier`: https://developer.android.com/develop/connectivity/wifi/wifi-bootstrap - `WifiNetworkSpecifier.Builder` reference: https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier.Builder.html ### Apple - Wi-Fi configuration overview: https://developer.apple.com/documentation/networkextension/wi-fi_configuration - `NEHotspotConfigurationManager`: https://developer.apple.com/documentation/networkextension/nehotspotconfigurationmanager ## Связанные локальные файлы - `ignis_app/lib/main.dart` - `ignis_app/lib/screens/homes_screen.dart` - `ignis_app/lib/screens/remote_screen.dart` - `ignis_app/lib/services/api_client.dart` - `ignis_app/android/app/src/main/AndroidManifest.xml` - `ignis_app/android/app/src/main/kotlin/ru/akokos/ignis_app/MainActivity.kt` - `ignis-core/app/api/routes/devices.py` - `ignis-core/README.md`