Для поддержки локального выполнения заказов вам необходимо создать приложение, которое будет обрабатывать следующие намерения умного дома:
-
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.