В данной статье речь пойдет о реализации мобильного клиента Flutter. Какого именно мобильного клиента? В предыдущей публикации описана система программных аксессуаров:
bobaoskit — аксессуары, dnssd и WebSocket. Аналог программного аксессуара — реальный объект. Лампочка, переключатель, cd/кассетный проигрыватель, радио плеер, термостат, датчик температуры, датчик движения и т.д… Набор аксессуаров определяется фантазией и программным кодом. Можно реализовать хоть шахматную доску. Для такой доски надо иметь поле управления(control) move, принимающее объект { from: "e2", to: "e4" } для примера и сервисные поля для сброса фигур и т.д… Скрипт аксессуара обработает запрос на управление полем move, примет решение можно ли перемещать фигуру, и вернет(или нет) статус с положением фигур на всем поле.  На текущий момент поддерживаемые типы аксессуаров с минимальным функционалом следующие: "switch", "temperature sensor", "thermostat", "radio player".  Про шахматы далее речи не пойдет. Если интересно и в таком случае, добро пожаловать под кат. Итак, bobaoskit.worker запущен. Объекты аксессуаров существуют в памяти компьютера, можно прочитать информацию о них, можно вручную отправить JSON запрос на WebSocket порт, видеть входящие события. Для управления я сделал простейшее мобильное приложение. Последнюю пару лет в голове активно жила идея изучить программирование под мобильные устройства. Поскольку пишу на JavaScript, изучал решения, позволяющие не изучать новый язык программирования.  Appcelerator. Начинал изучение с него. Если не изменяет память, SDK открыто, а вот IDE с различными тарифами.
NativeScript. Тут уже создал простое приложение, показывающее список с картинками. Дальше дело не пошло.
ReactNative. Самый длинный штурм из перечисленных до этого момента фреймворков. Самая большая сложность — начать. Посмотрел курс. Поначалу понятно, интересно, получается. А вот redux и после осилить не удалось. Потом регулярно пытался начать писать, но redux упорно не давал себя осилить. В итоге ни к какому решению я тогда(конец 2016го года) я не привязался. Возможно, потому что не было конкретной задачи, возможно по другим причинам. Ближе к осени прошлого(2018го) уже шла работа над sdk для программных аксессуаров. Естественно, нужно мобильное приложение. Все началось с mdns. Как-то в свободную минуту обновил ReactNative, нашел плагин react-native-zeroconf, создал приложение. По инструкции установил, сделал link, запустил. Запустилось приложение Expo для отладки, которое не поддерживает нативные модули, и, соответственно, плагин для mdns не работал. К этому моменту свободного времени не хватало на то, чтобы создать чистое(без expo) react-native приложение и протестировать с ним. Работа была отложена на пару месяцев. В это же время все больше и больше материалов появлялось про flutter в сети. Установил себе. Установка проста: git clone и добавить в PATH. Остальное — уже настройка Android SDK/Xcode(в моем случае Android SDK уже давно был настроен. Для iOS разрабатывать не могу, поскольку не являюсь пользователем macOS) и Dart SDK(можно установить отдельно, но не обязательно, поскольку есть в составе flutter). Входящие события — если аксессуар был удален, добавлен, обновил статус. Либо если все аксессуары удалены(clear accessories). Регистрируемые функции — для обновления списков, виджетов по этим событиям. Для каждого аксессуара создается объект AccessoryInfo: этот объект уже — модель. Изначально я писал везде StatefulWidget и setState() {}, но setState() {} работает только для виджета, внутри которого регистрировались слушатели. Но для детального управления аксессуаром я создавал изначально новые Stateful страницы, и заметил, что статус не обновляется. Как решение — использовал ScopedModel. После того как список аксессуаров получен, для каждого из них отправляем запрос на получение состояния и добавляем в список List <AccessoryInfo>. Вызываем setState() {}, таким образом добавляя поддерживаемый аксессуар в интерфейс. Поддерживаемые типы аксессуаров определены в ListView.builder и в ./lib/widgets/*.dart. Пока поддерживаются switch/temperature sensor/radio player/thermostat. Основная работа впереди — добавлять новые, улучшать существующие виджеты. Для аксессуара типа switch создается элемент в общем списке аксессуаров, при взаимодействии с которым(onTap) отправляется запрос на получение текущего значения, затем на переключение этого значения. ScopedModel позволяет перерисовать виджет при входящих обновлениях статуса. Для данного аксессуара не реализован обработчик длинного нажатия. Для радио проигрывателя оно выглядит так: Открывается страница AccRadioPlayerControl, которая также использует ScopedModel для управления состоянием. На этом весь описание алгоритма работы программы исчерпывается. Никаких дополнительных возможностей, таких как запоминание последнего хоста, сортировки аксессуаров по категориям/комнатам не реализовано. На текущий момент все просто. Опишу основную проблему, которая есть сейчас. Так и не понял как обнаружить разрыв WebSocket соединения. Использую: WebSocket class. При длительном нахождении приложения во сне/устройства в заблокированном режиме соединение разрывается. Приходится возвращаться на самую первую страницу и заново открывать обнаруженный сервис. С одной стороны, Flutter довольно быстр в изучении и разработке. ScopedModel для меня оказалось понятнее redux.
Dart оказался похожим на привычный JavaScript. Типизация + динамичные типы позволят каждому писать как удобно. Сложности при написании кода: большая вложенность виджетов. На всем известный callback hell после flutter-а смотришь уже по другому. Vim-mode и % будут полезны. Теперь немного мыслей насчет IoT. В последнее время все больше умных устройств/сервисов, которые требуют регистрации в облаке. Китайские розетки, для пользования которыми необходимо установить приложение, создать аккаунт, и лишь после этого можно пользоваться. Голосовые помощники. Алиса от Яндекса требует своего облака в которое отправляется распознанный текст. Alexa от Amazon работает похожим образом. Удачнее всего, по моему мнению, сделан Apple HomeKit в связке с Siri. Облако используется для распознавания текста. Взаимодействие с устройствами — в локальной сети.  Мое мнение состоит в том, что облако должно существовать для своей цели: удаленное управление, обновление, и т.д… Если устройством можно управлять в локальной сети, то надо так и делать.