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