1. Прежде чем начать
Интеграция с системами «умного дома» позволяет Google Ассистенту управлять подключенными устройствами в домах пользователей. Для создания интеграции «облако-облако» необходимо предоставить конечную точку веб-перехватчика в облаке, способную обрабатывать намерения, связанные с «умным домом ». Например, когда пользователь говорит: «Привет, Google, включи свет», Ассистент отправляет команду в ваше облачное хранилище для обновления состояния устройства.
SDK Local Home расширяет возможности интеграции с системами умного дома, добавляя локальный путь для прямой передачи команд умного дома на устройство Google Home, что повышает надежность и снижает задержку при обработке пользовательских команд. Он позволяет писать и развертывать локальное приложение для выполнения команд на TypeScript или JavaScript, которое идентифицирует устройства и выполняет команды на любой умной колонке Google Home или умном дисплее Google Nest. Затем ваше приложение напрямую взаимодействует с существующими умными устройствами пользователей по локальной сети, используя существующие стандартные протоколы для выполнения команд.

Отладка интеграций между облачными сервисами — критически важный шаг для создания интеграций, соответствующих производственным стандартам, однако без информативных и простых в использовании инструментов для устранения неполадок и тестирования это может быть сложной и трудоемкой задачей. Для упрощения отладки интеграций между облачными сервисами доступны инструменты Google Cloud Platform (GCP) Metrics and Logging and Test Suite для умного дома, которые помогут вам выявить и устранить проблемы в ваших интеграциях.
Предварительные требования
- Создайте руководство для разработчиков по интеграции между облачными сервисами.
- Выполните практическое задание « Включение локального выполнения для облачных интеграций ».
Что вы построите
В этом практическом занятии вы создадите локальную среду выполнения для интеграции между облачными сервисами и подключите ее к Google Ассистенту, а затем отладите приложение «Локальный дом» с помощью набора тестов для анализа метрик и логирования умного дома и платформы Google Cloud Platform (GCP).
Что вы узнаете
- Как использовать метрики и логирование GCP для выявления и устранения проблем в производственной среде.
- Как использовать набор тестов для выявления функциональных проблем и проблем с API.
- Как использовать инструменты разработчика Chrome при разработке приложения «Локальный дом».
Что вам понадобится
- Последняя версия Google Chrome
- Устройство iOS или Android с установленным приложением Google Home.
- Умная колонка Google Home или умный дисплей Google Nest.
- Node.js версии 10.16 или более поздней.
- Аккаунт Google
- Платежный аккаунт Google Cloud
2. Запустите приложение для стиральной машины.
Получите исходный код
Чтобы загрузить пример этого практического задания на свой компьютер, перейдите по следующей ссылке:
...или вы можете клонировать репозиторий GitHub из командной строки:
$ git clone https://github.com/google-home/smarthome-debug-local.git
О проекте
Стартовое приложение содержит аналогичные подкаталоги и облачные функции, что и в практическом занятии по включению локального выполнения для интеграции «облако-облако» . Но вместо app-start у нас здесь app-faulty . Мы начнем с локального домашнего приложения, которое работает, но не очень хорошо.
Подключитесь к Firebase
Мы будем использовать тот же проект, который вы создали в практическом задании «Включение локального выполнения для облачных интеграций» , но мы развернем файлы, загруженные в этом задании.
Перейдите в каталог app-faulty , затем настройте Firebase CLI с вашим проектом интеграции, созданным в практическом задании «Включение локального выполнения для облачных интеграций» :
$ cd app-faulty $ firebase use <project-id>
Развернуть в Firebase
Перейдите в папку app-faulty/functions и установите все необходимые зависимости с помощью npm :
$ cd functions $ npm install
Примечание: Если вы видите сообщение ниже, можете проигнорировать его и продолжить. Предупреждение связано с некоторыми устаревшими зависимостями, более подробную информацию можно найти здесь .
found 5 high severity vulnerabilities run `npm audit fix` to fix them, or `npm audit` for details
Перейдите в каталог app-faulty/local/ и выполните следующие команды, чтобы загрузить компилятор TypeScript и скомпилировать приложение:
$ cd ../local $ npm install $ npm run build
Эта команда компилирует исходный код файла index.ts (TypeScript) и помещает следующее содержимое в каталог app-faulty/public/local-home/ :
-
bundle.js— Скомпилированный JavaScript-код, содержащий локальное приложение и зависимости. -
index.html— Локальная страница, используемая для размещения приложения и его тестирования на устройстве.
Теперь, когда вы установили зависимости и настроили свой проект, вы готовы запустить приложение в первый раз.
$ firebase deploy
Вот что вы должны увидеть в консоли:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<project-id>/overview Hosting URL: https://<projectcd -id>.web.app
Эта команда развертывает веб-приложение, а также несколько облачных функций для Firebase .
Обновить HomeGraph
Откройте URL-адрес хостинга в браузере ( https://<project-id>.web.app ), чтобы просмотреть веб-приложение. В веб-интерфейсе нажмите кнопку «Обновить».
Кнопка для обновления HomeGraph с использованием последних метаданных устройства из неисправного приложения стиральной машины с помощью функции Request Sync .

Откройте приложение Google Home и убедитесь, что вы видите свою стиральную машину под новым именем «Неисправная стиральная машина». Не забудьте назначить устройство комнате, в которой уже есть устройство Nest.

3. Запустите умную стиральную машину.
Если вы выполнили практическое задание « Включение локального выполнения для интеграции между облачными сервисами », виртуальная умная стиральная машина уже должна была запуститься. Если она остановлена, не забудьте перезапустить виртуальное устройство.
Запустите устройство
Перейдите в каталог virtual-device/ и запустите скрипт устройства, передав параметры конфигурации в качестве аргументов:
$ cd ../../virtual-device $ npm install $ npm start -- \ --deviceId=deviceid123 --projectId=<project-id> \ --discoveryPortOut=3311 --discoveryPacket=HelloLocalHomeSDK
Убедитесь, что скрипт для устройства выполняется с ожидаемыми параметрами:
(...): UDP Server listening on 3311 (...): Device listening on port 3388 (...): Report State successful
4. Протестируйте приложение «Локальный дом».
Отправляйте команды на устройство Google Home с помощью голосовых команд, например:
«Эй, Google, включи мою стиральную машину».
«Эй, Google, запусти мою стиральную машину».
«Эй, Google, принудительно выбери локальную сеть».
«Эй, Google, останови мою стиральную машину».
Вы заметите, что Google Ассистент отвечает: «Извините, похоже, неисправная стиральная машина сейчас недоступна», когда вы пытаетесь управлять стиральной машиной после команды «принудительно активировать локальную сеть».
Это означает, что устройство недоступно по локальному пути. До команды "Hey Google, force local" всё работало, потому что при недоступности устройства по локальному пути мы переключались на облачный путь. Однако после команды "force local" возможность переключения на облачный путь отключается.
Чтобы выяснить, в чем проблема, воспользуемся имеющимися у нас инструментами: средствами отслеживания и ведения журналов Google Cloud Platform (GCP) и инструментами разработчика Chrome.
5. Отладка приложения «Локальный дом»
В следующем разделе вы воспользуетесь инструментами Google, чтобы выяснить, почему устройство недоступно по локальному пути. Вы можете использовать инструменты разработчика Google Chrome для подключения к устройству Google Home, просмотра журналов консоли и отладки приложения Local Home. Вы также можете отправлять пользовательские журналы в Cloud Logging , чтобы быть в курсе наиболее распространенных ошибок, с которыми сталкиваются пользователи в вашем приложении Local Home.
Подключите инструменты разработчика Chrome
Чтобы подключить отладчик к локальному приложению для обработки заказов, выполните следующие действия:
- Убедитесь, что вы связали ваше устройство Google Home с пользователем, имеющим разрешение на доступ к проекту «Консоль разработчика» .
- Перезагрузите устройство Google Home, чтобы оно могло получить URL-адрес вашего HTML-кода, а также конфигурацию сканирования, которую вы указали в консоли разработчика.
- Запустите Chrome на своем компьютере для разработки.
- Откройте новую вкладку Chrome и введите
chrome://inspectв адресную строку, чтобы запустить инспектор.
На странице должен отобразиться список устройств, а URL-адрес вашего приложения должен появиться под названием вашего устройства Google Home.

Запустите инспектора
Нажмите «Проверить код элемента» под URL-адресом вашего приложения, чтобы запустить инструменты разработчика Chrome. Выберите вкладку «Консоль» и убедитесь, что вы видите содержимое намерения IDENTIFY , выводимого вашим приложением TypeScript.

Этот вывод означает, что обработчик IDENTIFY был успешно запущен, но verificationId , возвращенный в IdentifyResponse не соответствует ни одному из устройств в вашем HomeGraph. Давайте добавим пользовательские записи в лог, чтобы выяснить причину.
Добавить пользовательские журналы
Хотя SDK локального домашнего каталога выводит ошибку DEVICE_VERIFICATION_FAILED , это мало помогает в поиске первопричины. Давайте добавим несколько пользовательских логов, чтобы убедиться, что мы правильно считываем и обрабатываем данные сканирования, и отметим, что, если мы отклоняем промис с ошибкой, сообщение об ошибке также отправляется в Cloud Logging .
local/index.ts
identifyHandler(request: IntentFlow.IdentifyRequest):
Promise<IntentFlow.IdentifyResponse> {
console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));
const scanData = request.inputs[0].payload.device.udpScanData;
if (!scanData) {
const err = new IntentFlow.HandlerError(request.requestId,
'invalid_request', 'Invalid scan data');
return Promise.reject(err);
}
// In this codelab, the scan data contains only local device id.
// Is there something wrong here?
const localDeviceId = Buffer.from(scanData.data);
console.log(`IDENTIFY handler: received local device id
${localDeviceId}`);
// Add custom logs
if (!localDeviceId.toString().match(/^deviceid[0-9]{3}$/gi)) {
const err = new IntentFlow.HandlerError(request.requestId,
'invalid_device', 'Invalid device id from scan data ' +
localDeviceId);
return Promise.reject(err);
}
const response: IntentFlow.IdentifyResponse = {
intent: Intents.IDENTIFY,
requestId: request.requestId,
payload: {
device: {
id: 'washer',
verificationId: localDeviceId.toString(),
}
}
};
console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));
return Promise.resolve(response);
}
Кроме того, измените версию локального приложения Home, чтобы мы могли определить, используем ли мы правильную версию.
local/index.ts
const localHomeSdk = new App('1.0.1');
После добавления пользовательских логов необходимо повторно скомпилировать приложение и развернуть его в Firebase.
$ cd ../app-faulty/local $ npm run build $ firebase deploy --only hosting
Теперь перезагрузите устройство Google Home, чтобы оно могло загрузить обновленное локальное приложение «Дом». Вы можете проверить, использует ли устройство Google Home ожидаемую версию, посмотрев журналы консоли в инструментах разработчика Chrome.

Доступ к облачному журналированию
Давайте рассмотрим, как использовать Cloud Logging для поиска ошибок. Чтобы получить доступ к Cloud Logging для вашего проекта:
- В консоли облачной платформы перейдите на страницу «Проекты» .
- Выберите свой проект «умного дома».
- В разделе «Операции» выберите «Ведение журналов» > «Проводник журналов» .
Доступ к данным журналов управляется системой управления идентификацией и доступом (IAM) для пользователей вашего проекта интеграций. Более подробную информацию о ролях и разрешениях для доступа к данным журналов см. в разделе « Управление доступом к Cloud Logging».
Используйте расширенные фильтры
Мы знаем, что ошибки возникают в интенте IDENTIFY , поскольку локальный путь не работает, так как локальное устройство не удается идентифицировать. Однако мы хотим точно выяснить, в чем проблема, поэтому давайте сначала отфильтруем ошибки, возникающие в обработчике IDENTIFY .
Нажмите на переключатель «Показать запрос» , после чего он превратится в поле « Конструктор запросов» . Введите jsonPayload.intent="IDENTIFY" в поле «Конструктор запросов» и нажмите кнопку « Выполнить запрос» .

В результате вы получите все журналы ошибок, которые генерируются обработчиком IDENTIFY . Далее разверните последнюю ошибку. Вы найдете errorCode и debugString , которые вы только что установили при отклонении промиса в обработчике IDENTIFY .

Из debugString видно, что локальный идентификатор устройства имеет неожиданный формат. Приложение Local Home ожидает получить локальный идентификатор устройства в виде строки, начинающейся с deviceid и за которой следуют 3 цифры, но здесь локальный идентификатор устройства представляет собой шестнадцатеричную строку.
Исправьте ошибку.
Возвращаясь к исходному коду, где мы извлекаем локальный идентификатор устройства из данных сканирования, мы замечаем, что не указали кодировку при преобразовании строки в байты. Данные сканирования принимаются в виде шестнадцатеричной строки, поэтому передайте hex в качестве кодировки символов при вызове Buffer.from() .
local/index.ts
identifyHandler(request: IntentFlow.IdentifyRequest):
Promise<IntentFlow.IdentifyResponse> {
console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));
const scanData = request.inputs[0].payload.device.udpScanData;
if (!scanData) {
const err = new IntentFlow.HandlerError(request.requestId,
'invalid_request', 'Invalid scan data');
return Promise.reject(err);
}
// In this codelab, the scan data contains only local device id.
const localDeviceId = Buffer.from(scanData.data, 'hex');
console.log(`IDENTIFY handler: received local device id
${localDeviceId}`);
if (!localDeviceId.toString().match(/^deviceid[0-9]{3}$/gi)) {
const err = new IntentFlow.HandlerError(request.requestId,
'invalid_device', 'Invalid device id from scan data ' +
localDeviceId);
return Promise.reject(err);
}
const response: IntentFlow.IdentifyResponse = {
intent: Intents.IDENTIFY,
requestId: request.requestId,
payload: {
device: {
id: 'washer',
verificationId: localDeviceId.toString(),
}
}
};
console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));
return Promise.resolve(response);
}
Кроме того, измените версию локального приложения Home, чтобы мы могли определить, используем ли мы правильную версию.
local/index.ts
const localHomeSdk = new App('1.0.2');
После исправления ошибки скомпилируйте приложение и повторно разверните его в Firebase. В app-faulty/local выполните следующую команду:
$ npm run build $ firebase deploy --only hosting
Проверьте исправление.
После развертывания перезагрузите устройство Google Home, чтобы оно могло загрузить обновленное локальное приложение Home. Убедитесь, что версия локального приложения Home — 1.0.2, и на этот раз в консоли инструментов разработчика Chrome не должно быть ошибок.

Теперь вы можете снова попробовать отправить команды на ваше устройство.
«Эй, Google, принудительно выбери локальную сеть».
«Эй, Google, останови мою стиральную машину».
«Эй, Google, включи мою стиральную машину».
...
«Эй, Google, принудительно выбери значение по умолчанию».
6. Запустите набор тестов для умного дома.
После проверки вашего устройства с помощью сенсорного управления в приложении Google Home или голосовых команд вы можете использовать автоматизированный набор тестов для умного дома , чтобы проверить сценарии использования на основе типов и характеристик устройств, связанных с вашей интеграцией. Набор тестов запускает серию тестов для выявления проблем в вашей интеграции и отображает информативные сообщения о неудачных тестовых случаях, чтобы ускорить отладку, прежде чем углубляться в журналы событий.
Запустите набор тестов для умного дома.
Следуйте этим инструкциям, чтобы протестировать интеграцию между облачными сервисами с помощью набора тестов:
- Откройте в веб-браузере набор тестов для умного дома .
- Войдите в Google, используя кнопку в правом верхнем углу. Это позволит тестовому набору отправлять команды непосредственно в Google Ассистент.
- В поле «Идентификатор проекта» введите идентификатор проекта вашей интеграции «облако-облако». Затем нажмите «Далее» , чтобы продолжить.
- На этапе проверки настроек вы должны увидеть неисправную стиральную машину в разделе «Устройства и лотки» .
- Отключите параметр «Тестовый запрос синхронизации» , поскольку в тестовом приложении для стиральной машины отсутствует пользовательский интерфейс для добавления/удаления/переименования стиральной машины. В рабочей системе необходимо запускать запрос синхронизации всякий раз, когда пользователь добавляет/удаляет/переименовывает устройства.
- Оставьте опцию «Локальный домашний SDK» включенной, поскольку мы будем тестировать как локальные, так и облачные пути.
- Нажмите «Далее: Тестовая среда» , чтобы начать выполнение теста.

После завершения тестов вы заметите, что тесты приостановки/возобновления работы в локальной среде завершаются с ошибкой, в то время как тесты приостановки/возобновления работы в облачной среде проходят успешно.

Анализ сообщения об ошибке
Внимательно изучите сообщения об ошибках в неудачных тестовых случаях. Они показывают, какое состояние ожидалось для данного теста и какое состояние было фактическим. В данном случае, для теста "Приостановить стирку", ожидаемое состояние — isPaused: true , но в фактическом состоянии мы получили isPaused: false . Аналогично, для теста "Приостановить стирку" ожидаемое состояние — isPaused: true , но в фактическом состоянии мы получили isPaused: false .

Судя по сообщениям об ошибках, в локальной директории мы устанавливаем состояние isPaused в обратном порядке.
Выявите и устраните ошибку.
Давайте найдем исходный код, где приложение Local Home отправляет команду выполнения на устройство. Функция getDataCommand() вызывается функцией executeHandler() для установки payload в команде выполнения, отправляемой на устройство.
local/index.ts
getDataForCommand(command: string, params: IWasherParams): unknown {
switch (command) {
case 'action.devices.commands.OnOff':
return {
on: params.on ? true : false
};
case 'action.devices.commands.StartStop':
return {
isRunning: params.start ? true : false
};
case 'action.devices.commands.PauseUnpause':
return {
// Is there something wrong here?
isPaused: params.pause ? false : true
};
default:
console.error('Unknown command', command);
return {};
}
}
Мы действительно устанавливаем isPause в обратном состоянии: оно должно быть установлено в true когда params.pause равно true , и false в противном случае. Давайте это исправим.
local/index.ts
getDataForCommand(command: string, params: IWasherParams): unknown {
switch (command) {
case 'action.devices.commands.OnOff':
return {
on: params.on ? true : false
};
case 'action.devices.commands.StartStop':
return {
isRunning: params.start ? true : false
};
case 'action.devices.commands.PauseUnpause':
return {
isPaused: params.pause ? true : false
};
default:
console.error('Unknown command', command);
return {};
}
}
Измените версию локального приложения Home, чтобы мы могли определить, используем ли мы правильную версию.
local/index.ts
const localHomeSdk = new App('1.0.3');
Не забудьте перекомпилировать приложение и повторно развернуть его в Firebase. В app-faulty/local выполните следующую команду:
$ npm run build $ firebase deploy --only hosting
Теперь перезагрузите устройство Google Home, чтобы оно могло загрузить обновленное локальное приложение Home. Убедитесь, что версия локального приложения Home — 1.0.3.
Проверьте исправление.
Теперь повторно запустите набор тестов для умного дома с теми же настройками, и вы увидите, что все тестовые случаи пройдены успешно.

7. Поздравляем!

Поздравляем! Вы успешно освоили поиск и устранение неисправностей в приложении «Умный дом» с помощью набора тестов для умного дома и облачного логирования.
Узнать больше
Вот ещё несколько вариантов, которые вы можете попробовать:
- Добавьте к своему устройству больше поддерживаемых характеристик и протестируйте его с помощью Test Suite.
- Добавьте дополнительные пользовательские записи в каждый обработчик намерений и просматривайте их в Cloud Logging.
- Создавайте панели мониторинга , настраивайте оповещения и получайте доступ к данным метрик программным способом, чтобы получать полезные показатели использования вашей интеграции.
Вы также можете узнать больше о тестировании и отправке интеграции на проверку, включая процесс сертификации для публикации вашей интеграции для пользователей.