Реализация управления IoT-устройствами голосом через мобильное приложение
Голосовое управление IoT-устройствами в мобильном приложении — это не просто «добавить SiriKit» или «интегрировать Google Assistant». Это отдельный слой логики: распознавание речи, извлечение намерений, маппинг на команды устройств, обратная связь. Каждый из этих шагов ломается по-своему.
Два принципиально разных подхода
Встроенные голосовые ассистенты (Siri Shortcuts, Google Assistant Actions) работают через облако и требуют явного разрешения пользователя. Siri Shortcuts на iOS доступны через INPlayMediaIntent и INSendMessageIntent, но для произвольных IoT-команд нужен AppIntent (iOS 16+) — Swift-фреймворк с описанием интентов. Пример: «Эй Siri, выключи свет на кухне» → Siri вызывает TurnOffLightIntent в вашем приложении, которое отправляет MQTT-команду. Задержка — 2–4 секунды через облако Apple, нет гарантий при отключённом интернете.
Локальное распознавание — другой уровень. На iOS это SFSpeechRecognizer с SFSpeechAudioBufferRecognitionRequest. С iOS 13 поддерживает on-device режим (requiresOnDeviceRecognition = true) без отправки аудио в облако. На Android — SpeechRecognizer API (через облако Google) или Vosk / Whisper.cpp для полностью офлайн-распознавания.
Для IoT-приложений, где важна работа в локальной сети без интернета, выбор очевиден — локальное распознавание + офлайн NLU.
NLU: от текста к команде устройства
Распознали «включи свет на кухне и подними температуру до двадцати двух» — теперь нужно извлечь:
- интент:
turn_on,set_temperature - сущности:
device_type=light,location=kitchen,device_type=thermostat,value=22
Для простых кейсов хватает rule-based подхода: словарь глаголов-намерений + словарь устройств и комнат из базы пользователя. Строим регулярки или simple intent matcher на тот же список устройств что уже есть в системе.
Для сложных сценариев — Rasa NLU (self-hosted) или Duckling для числовых значений. На Flutter интегрируем через HTTP-запрос к локальному серверу в домашней сети или через dart:ffi для встроенной модели.
Реальный пример: проект умной квартиры, 35 устройств, русский язык. Обучили простую модель на fastText с ~500 примерами команд, конвертировали в .tflite, запустили через tflite_flutter. Точность на бытовых командах — 94%. Промахи были на составных командах (два действия в одной фразе) — решили предобработкой через разбивку по союзам «и», «потом», «затем».
Обратная связь и edge cases
Push to talk vs always-on. Always-on на мобильном — убийца батареи. Рекомендуем push-to-talk кнопку в приложении + опциональное wake word через Porcupine SDK (PicoVoice). Porcupine работает локально, потребляет <5% CPU на idle.
Что делать, если устройство не распознано? Не молчать. Возвращаем голосовой ответ через AVSpeechSynthesizer (iOS) / TextToSpeech (Android), перечисляем что было понято, просим уточнить. Пользователь не видит экран — ему нужна аудиообратная связь.
На Flutter используем flutter_tts для синтеза и speech_to_text как unified API поверх платформенных движков. Важно: на Android 11+ SpeechRecognizer требует RECORD_AUDIO permission с явным объяснением в onRequestPermissionsResult. Без внятного rationale — Google Play консоль помечает как нарушение политики.
Интеграция с MQTT
Голосовая команда → NLU → команда устройства → публикация в MQTT-топик. Задержка от нажатия кнопки до отклика устройства: распознавание на устройстве ~300–800ms, NLU ~50ms, MQTT publish < 50ms при локальном брокере. Итого — ощущается как мгновенный отклик.
При облачном распознавании добавляем 1.5–3 секунды. На русском языке облачное Google Speech-to-Text работает хорошо, Apple Speech — хуже на специфичных IoT-терминах вроде «диммер», «ресивер», «реле».
Сроки
Push-to-talk с облачным распознаванием и простым маппингом команд — 2–3 недели. Офлайн-распознавание + NLU + wake word + TTS обратная связь — 6–10 недель. Стоимость зависит от языков, платформ и требований к офлайн-работе.







