Для поддержки локального выполнения заказов вам необходимо разработать приложение, способное обрабатывать следующие запросы к системе умного дома:
-
IDENTIFY: Поддерживает обнаружение локально управляемых интеллектуальных устройств. Обработчик намерений извлекает данные, которые ваше интеллектуальное устройство возвращает во время обнаружения, и отправляет их в ответе в Google. -
EXECUTE: Поддерживает выполнение команд. -
QUERY: Поддерживает запрос состояния устройства. -
REACHABLE_DEVICES: (Необязательно) Поддерживает обнаружение локально управляемых конечных устройств, находящихся за концентратором (или мостом).
Это приложение работает на устройствах Google Home или Google Nest и подключает ваше умное устройство к Google Ассистенту. Вы можете создать приложение, используя TypeScript (предпочтительно) или JavaScript.
Рекомендуется использовать TypeScript, поскольку он позволяет использовать привязки для статической проверки соответствия возвращаемых приложением данных типам, ожидаемым платформой.
Для получения более подробной информации об API см. справочник по API 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 :
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.
Реализуйте обработчик IDENTIFIY.
Обработчик 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 , предоставляемый SDK Local Home.
Ваше приложение не имеет прямого доступа к 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 обрабатывает запросы пользователей и использует SDK Local Home для сообщения о состоянии ваших умных устройств.
Платформа Local Home передает функции обработчика запроса 'QUERY' те же данные запроса, что и для намерения QUERY в вашу облачную службу обработки запросов. Аналогично, ваш обработчик QUERY возвращает данные в том же формате, что и при обработке намерения QUERY .
Отправка команд устройствам, находящимся за хабом.
Для управления конечными устройствами, находящимися за концентратором, может потребоваться дополнительная информация в полезной нагрузке команды, отправляемой концентратору, чтобы он мог определить, какому устройству адресована команда. В некоторых случаях это можно определить непосредственно из значения device.id , но если это невозможно, следует включить эти дополнительные данные в поле customData .
Если вы создали приложение с использованием TypeScript, не забудьте скомпилировать его в JavaScript. Для написания кода вы можете использовать любую модульную систему по своему выбору. Убедитесь, что ваша целевая платформа поддерживается браузером Chrome.