Для поддержки локального выполнения заказов вам необходимо создать приложение, которое будет обрабатывать следующие намерения умного дома:
-
IDENTIFY
: поддерживает обнаружение локально управляемых смарт-устройств. Обработчик намерений извлекает данные, возвращаемые вашим смарт-устройством во время обнаружения, и отправляет их в ответе Google. -
EXECUTE
: Поддерживает выполнение команд. -
QUERY
: Поддерживает запрос состояния устройства. -
REACHABLE_DEVICES
: (Необязательно) Поддерживает обнаружение локально управляемых конечных устройств за устройством-концентратором (или мостом).
Это приложение работает на устройствах Google Home или Google Nest и подключает ваше смарт-устройство к Ассистенту. Вы можете создать приложение с помощью TypeScript (предпочтительно) или JavaScript.
Рекомендуется использовать TypeScript, поскольку вы можете использовать привязки , чтобы статически гарантировать, что возвращаемые вашим приложением данные соответствуют типам, ожидаемым платформой.
Более подробную информацию об API см. в справочнике по API Local Home SDK .
В следующих фрагментах показано, как можно инициализировать локальное приложение для выполнения заказов и прикрепить обработчики.
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onReachableDevices(reachableDevicesHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
Создайте свой проект
Чтобы развернуть локальное приложение для выполнения заказов, вам необходимо создать пакет JavaScript для вашего кода и всех его зависимостей.
Используйте инициализатор проекта локального приложения выполнения заказов, чтобы загрузить соответствующую структуру проекта с предпочитаемой вами конфигурацией упаковщика.
Шаблоны проектов
Чтобы выбрать конфигурацию упаковщика, выполните команду npm init
как показано в следующих примерах:
TypeScript без конфигурации сборщика:
npm init @google/local-home-app project-directory/ --bundler none
Структура проекта:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
Замените project-directory на новый каталог, который будет содержать проект локального приложения для выполнения заказов.
TypeScript с конфигурацией сборщика Webpack :
npm init @google/local-home-app project-directory/ --bundler webpack
Структура проекта:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── webpack.config.web.js ├── webpack.config.node.js └── serve.js
Замените project-directory на новый каталог, который будет содержать проект локального приложения для выполнения заказов.
TypeScript с конфигурацией сборщика Rollup :
npm init @google/local-home-app project-directory/ --bundler rollup
Структура проекта:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── rollup.config.js └── serve.js
Замените project-directory на новый каталог, который будет содержать проект локального приложения для выполнения заказов.
TypeScript с конфигурацией Parcel bundler:
npm init @google/local-home-app project-directory/ --bundler parcel
Структура проекта:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
Замените project-directory на новый каталог, который будет содержать проект локального приложения для выполнения заказов.
Выполнять общие задачи на уровне проекта
Сгенерированный проект поддерживает следующие скрипты npm :
cd project-directory/ npm run build
Этот скрипт компилирует исходный код TypeScript и упаковывает ваше приложение с его зависимостями для среды выполнения Chrome в подкаталоге dist/web
и среды выполнения Node.js в подкаталоге dist/node
.
cd project-directory/ npm run lint npm run compile npm test
Этот скрипт проверяет синтаксис вашего кода TypeScript, компилирует его, не создавая никаких выходных данных в подкаталоге dist/
, и запускает автоматизированные тесты из test.ts
cd project-directory/ npm run start
Во время разработки этот скрипт локально обслуживает ваши пакеты приложений для сред выполнения Chrome и Node.js.
Реализовать обработчик IDENTIFY
Обработчик IDENTIFY
сработает при перезагрузке устройства Google Home или Google Nest и обнаружении непроверенных локальных устройств (включая конечные устройства, подключенные к концентратору). Платформа Local Home выполнит поиск локальных устройств, используя указанную вами ранее конфигурацию сканирования, и вызовет обработчик IDENTIFY
с результатами сканирования.
Запрос IdentifyRequest
от платформы Local Home содержит данные сканирования экземпляра LocalIdentifiedDevice
. Заполняется только один экземпляр device
на основе конфигурации сканирования, которая обнаружила устройство.
Если результаты сканирования соответствуют вашему устройству, ваш обработчик IDENTIFY
должен вернуть объект IdentifyResponsePayload
, который включает объект device
с метаданными умного дома (такими как типы, характеристики и состояние отчета).
Google устанавливает связь с устройством, если значение verificationId
из ответа IDENTIFY
совпадает с одним из значений otherDeviceIds
, возвращаемых ответом SYNC
.
Пример
В следующих фрагментах показано, как можно создать обработчики IDENTIFY
для интеграции автономных устройств и концентраторов соответственно.
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const verificationId = "local-device-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: device.id || "", verificationId, // Must match otherDeviceIds in SYNC response }, }, }; return response; };
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const proxyDeviceId = "local-hub-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: proxyDeviceId, isProxy: true, // Device can control other local devices isLocalOnly: true, // Device not present in `SYNC` response }, }, }; return response; };
Определите устройства за концентратором
Если Google обнаружит устройство-концентратор, он будет рассматривать концентратор как канал связи с подключенными к концентратору конечными устройствами и попытается проверить эти конечные устройства.
Чтобы Google мог подтвердить наличие концентратора, следуйте этим инструкциям для вашего обработчика IDENTIFY
:
- Если ваш ответ
SYNC
сообщает идентификаторы локальных конечных устройств, подключенных к концентратору, задайтеisProxy
значениеtrue
вIdentifyResponsePayload
. - Если ваш ответ
SYNC
не сообщает о вашем концентраторе, задайтеisLocalOnly
значениеtrue
вIdentifyResponsePayload
. - Поле
device.id
содержит локальный идентификатор устройства-концентратора.
Реализовать обработчик REACHABLE_DEVICES (только для интеграции с концентратором)
Намерение REACHABLE_DEVICES
отправляется Google для подтверждения того, какие конечные устройства можно контролировать локально. Это намерение срабатывает каждый раз, когда Google запускает сканирование (примерно раз в минуту), при условии, что концентратор находится в сети.
Обработчик REACHABLE_DEVICES
реализуется аналогично обработчику IDENTIFY
, за исключением того, что обработчику необходимо собирать дополнительные идентификаторы устройств, доступных локальному прокси-устройству (то есть концентратору). Поле device.verificationId
содержит локальный идентификатор конечного устройства, подключенного к концентратору.
Запрос ReachableDevicesRequest
от платформы Local Home содержит экземпляр LocalIdentifiedDevice
. С помощью этого экземпляра можно получить идентификатор прокси-устройства, а также данные из результатов сканирования.
Ваш обработчик REACHABLE_DEVICES
должен возвращать объект ReachableDevicesPayload
, включающий объект devices
, содержащий массив значений verificationId
, представляющих конечные устройства, управляемые концентратором. Значения verificationId
должны соответствовать одному из значений otherDeviceIds
из ответа SYNC
.
В следующем фрагменте показано, как можно создать обработчик REACHABLE_DEVICES
.
const reachableDevicesHandler = (request: IntentFlow.ReachableDevicesRequest): IntentFlow.ReachableDevicesResponse => { // Reference to the local proxy device const proxyDeviceId = request.inputs[0].payload.device.id; // Gather additional device ids reachable by local proxy device // ... const reachableDevices = [ // Each verificationId must match one of the otherDeviceIds // in the SYNC response { verificationId: "local-device-id-1" }, { verificationId: "local-device-id-2" }, ]; // Return a response const response: IntentFlow.ReachableDevicesResponse = { intent: Intents.REACHABLE_DEVICES, requestId: request.requestId, payload: { devices: reachableDevices, }, }; return response; };
Реализовать обработчик EXECUTE
Ваш обработчик EXECUTE
в приложении обрабатывает пользовательские команды и использует Local Home SDK для доступа к вашим смарт-устройствам через существующий протокол.
Платформа Local Home передаёт функции-обработчику EXECUTE
те же входные данные, что и для намерения EXECUTE
в вашем облачном исполнении. Аналогично, ваш обработчик EXECUTE
возвращает выходные данные в том же формате, что и при обработке намерения EXECUTE
. Для упрощения создания ответа можно использовать класс Execute.Response.Builder
из Local Home SDK.
У вашего приложения нет прямого доступа к IP-адресу устройства. Вместо этого используйте интерфейс CommandRequest
для создания команд на основе одного из следующих протоколов: UDP, TCP или HTTP. Затем вызовите функцию deviceManager.send()
для отправки команд.
При отправке команд на устройства используйте идентификатор устройства (и параметры из поля customData
, если они включены) из ответа SYNC
для связи с устройством.
Пример
В следующем фрагменте кода показано, как можно создать обработчик EXECUTE
.
const executeHandler = (request: IntentFlow.ExecuteRequest): Promise<IntentFlow.ExecuteResponse> => { // Extract command(s) and device target(s) from request const command = request.inputs[0].payload.commands[0]; const execution = command.execution[0]; const response = new Execute.Response.Builder() .setRequestId(request.requestId); const result = command.devices.map((device) => { // Target id of the device provided in the SYNC response const deviceId = device.id; // Metadata for the device provided in the SYNC response // Use customData to provide additional required execution parameters const customData: any = device.customData; // Convert execution command into payload for local device let devicePayload: string; // ... // Construct a local device command over TCP const deviceCommand = new DataFlow.TcpRequestData(); deviceCommand.requestId = request.requestId; deviceCommand.deviceId = deviceId; deviceCommand.data = devicePayload; deviceCommand.port = customData.port; deviceCommand.operation = Constants.TcpOperation.WRITE; // Send command to the local device return localHomeApp.getDeviceManager() .send(deviceCommand) .then((result) => { response.setSuccessState(result.deviceId, state); }) .catch((err: IntentFlow.HandlerError) => { err.errorCode = err.errorCode || IntentFlow.ErrorCode.INVALID_REQUEST; response.setErrorState(device.id, err.errorCode); }); }); // Respond once all commands complete return Promise.all(result) .then(() => response.build()); };
Реализовать обработчик QUERY
Обработчик QUERY
в приложении обрабатывает запросы пользователей и использует Local Home SDK для сообщения о состоянии ваших смарт-устройств.
Платформа Local Home передаёт в функцию-обработчик запроса QUERY ту же полезную нагрузку, что и для намерения QUERY
в вашем облачном исполнении. Аналогично, ваш обработчик QUERY
возвращает данные в том же формате, что и при обработке намерения QUERY
.
Отправка команд устройствам за концентратором
Для управления конечными устройствами, находящимися за концентратором, может потребоваться предоставить дополнительную информацию в полезной нагрузке команды, специфичной для протокола, отправляемой концентратору, чтобы концентратор мог определить, какому устройству предназначена команда. В некоторых случаях это можно определить непосредственно по значению device.id
, но в других случаях следует включить эти дополнительные данные в поле customData
.
Если вы создали приложение на TypeScript, не забудьте скомпилировать его в JavaScript. Вы можете использовать любую модульную систему для написания кода. Убедитесь, что ваш целевой проект поддерживается браузером Chrome.