Для поддержки локального выполнения вам необходимо создать приложение для обработки этих намерений умного дома:
-
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 (только для интеграции с хабом)
Google отправляет намерение REACHABLE_DEVICES
, чтобы подтвердить, какие конечные устройства могут управляться локально. Это намерение срабатывает каждый раз, когда 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.