A fin de admitir la entrega local, debes compilar una app para controlar estos intents de casa inteligente:
IDENTIFY
: Admite el descubrimiento de dispositivos inteligentes que se controlan localmente. El controlador del intent extrae los datos que muestra el dispositivo inteligente durante el descubrimiento y los envía en respuesta a Google.EXECUTE
: Admite la ejecución de comandos.QUERY
: Admite consultas de estado del dispositivo.REACHABLE_DEVICES
: Admite el descubrimiento de dispositivos finales controlables de forma local detrás de un dispositivo hub (o puente) (opcional).
Esta app se ejecuta en los dispositivos Google Home o Google Nest del usuario y conecta tu dispositivo inteligente a Asistente. Puedes crear la aplicación con TypeScript (método preferido) o JavaScript.
Se recomienda TypeScript porque puedes aprovechar las vinculaciones para asegurarte de que los datos que muestra tu app coincidan de forma estática con los tipos que la plataforma espera.
Para obtener más detalles sobre la API, consulta la referencia de la API del SDK de Local Home.
En los siguientes fragmentos, se muestra cómo inicializar la app de entrega local y adjuntar tus controladores.
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"); });
Crear tu proyecto
A fin de implementar tu app de entrega local, debes compilar un paquete de JavaScript para el código y todas sus dependencias.
Usa el inicializador del proyecto de la app de entrega local para iniciar la estructura del proyecto correspondiente con la configuración del empaquetador preferido.
Plantillas de proyectos
Para seleccionar la configuración del empaquetador, ejecuta el comando npm init
como se muestra en los siguientes ejemplos:
TypeScript sin configuración del agrupador:
npm init @google/local-home-app project-directory/ --bundler none
Estructura del proyecto:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
Reemplaza project-directory por un directorio nuevo que contendrá el proyecto de la app de entrega local.
TypeScript con la configuración del empaquetador webpack:
npm init @google/local-home-app project-directory/ --bundler webpack
Estructura del proyecto:
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
Reemplaza project-directory por un directorio nuevo que contendrá el proyecto de la app de entrega local.
TypeScript con la configuración del agrupador Rollup:
npm init @google/local-home-app project-directory/ --bundler rollup
Estructura del proyecto:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── rollup.config.js └── serve.js
Reemplaza project-directory por un directorio nuevo que contendrá el proyecto de la app de entrega local.
TypeScript con la configuración del agrupador Parcel:
npm init @google/local-home-app project-directory/ --bundler parcel
Estructura del proyecto:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
Reemplaza project-directory por un directorio nuevo que contendrá el proyecto de la app de entrega local.
Realiza tareas comunes a nivel de proyecto
El proyecto generado admite las siguientes secuencias de comandos de npm:
cd project-directory/ npm run build
Esta secuencia de comandos compila la fuente de TypeScript y une tu app con sus dependencias para el entorno de ejecución de Chrome en el subdirectorio dist/web
y el entorno de ejecución de Node.js en el subdirectorio dist/node
.
cd project-directory/ npm run lint npm run compile npm test
Esta secuencia de comandos verifica la sintaxis de tu código de TypeScript, la compila sin producir resultados en el subdirectorio dist/
y ejecuta pruebas automatizadas desde test.ts
.
cd project-directory/ npm run start
Durante la etapa de desarrollo, esta secuencia de comandos entrega tus paquetes de aplicaciones de forma local para los entornos de ejecución de Chrome y Node.js.
Implementa el controlador IDENTIFY
El controlador IDENTIFY
se activará cuando se reinicien los dispositivos Google Home o Google Nest, y verás dispositivos locales no verificados (incluidos los dispositivos finales conectados a un concentrador). La plataforma de Local Home buscará dispositivos locales con la información de configuración de análisis que especificaste antes y llamará a tu controlador IDENTIFY
con los resultados del análisis.
El IdentifyRequest
de la plataforma de Local Home contiene los datos de análisis de una instancia de LocalIdentifiedDevice
. Solo se propaga una instancia de device
, según la configuración de análisis que descubrió el dispositivo.
Si los resultados del análisis coinciden con tu dispositivo, el controlador IDENTIFY
debería mostrar un objeto IdentifyResponsePayload
, que incluye un objeto device
con metadatos de casa inteligente (como los tipos, las características y el estado del informe).
Google establece una asociación con un dispositivo si el verificationId
de la respuesta IDENTIFY
coincide con uno de los valores otherDeviceIds
que muestra la respuesta SYNC
.
Ejemplo
En los siguientes fragmentos, se muestra cómo puedes crear controladores IDENTIFY
para integraciones independientes de dispositivos y concentradores, respectivamente.
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; };
Identifica dispositivos detrás de un concentrador
Si Google identifica un dispositivo concentrador, lo tratará como el conducto para los dispositivos finales conectados del concentrador y tratará de verificar esos dispositivos.
A fin de permitir que Google confirme que hay un dispositivo concentrador, sigue estas instrucciones para tu controlador IDENTIFY
:
- Si la respuesta
SYNC
informa los ID de los dispositivos finales locales conectados al hub, configuraisProxy
comotrue
en elIdentifyResponsePayload
. - Si la respuesta
SYNC
no informa sobre el dispositivo hub, estableceisLocalOnly
comotrue
enIdentifyResponsePayload
. - El campo
device.id
contiene el ID de dispositivo local del dispositivo hub.
Implementa el controlador REACHABLE_DEVICES (solo integraciones de concentrador)
Google envía el intent REACHABLE_DEVICES
para confirmar qué dispositivos finales se pueden controlar de forma local. Este intent se activa cada vez que Google ejecuta un análisis de descubrimiento (aproximadamente una vez por minuto), siempre que se detecte que el concentrador está en línea.
Implementas el controlador REACHABLE_DEVICES
de manera similar al controlador IDENTIFY
, excepto que tu controlador debe recopilar ID de dispositivos adicionales accesibles por el proxy local (es decir, el concentrador). El campo device.verificationId
contiene el ID del dispositivo local para un dispositivo final que está conectado al concentrador.
El ReachableDevicesRequest
de la plataforma de Local Home contiene una instancia de LocalIdentifiedDevice
.
A través de esta instancia, puedes obtener el ID del dispositivo proxy, así como los datos de los resultados del análisis.
El controlador REACHABLE_DEVICES
debe mostrar un objeto ReachableDevicesPayload
que incluya un objeto devices
que contenga un array de valores verificationId
que representen los dispositivos finales que controla el concentrador. Los valores verificationId
deben coincidir con uno de los otherDeviceIds
de la respuesta SYNC
.
En el siguiente fragmento, se muestra cómo crear el controlador 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; };
Implementa el controlador EXECUTE
El controlador EXECUTE
de la app procesa comandos de usuario y usa el SDK de Local Home para acceder a tus dispositivos inteligentes a través de un protocolo existente.
La plataforma de Local Home pasa la misma carga útil de entrada a la función del controlador EXECUTE
que la intent EXECUTE
para la entrega en la nube. Del mismo modo, el controlador EXECUTE
muestra datos de salida en el mismo formato que procesa el intent EXECUTE
.
Para simplificar la creación de respuestas, puedes usar la clase Execute.Response.Builder
que proporciona el SDK de Local Home.
Tu app no tiene acceso directo a la dirección IP del dispositivo. En su lugar, usa la interfaz CommandRequest
para crear comandos basados en uno de estos protocolos: UDP, TCP o HTTP. Luego, llama a la función deviceManager.send()
para enviar los comandos.
Cuando orientes comandos a dispositivos, usa el ID de dispositivo (y los parámetros del campo customData
, si se incluyen) de la respuesta de SYNC
para comunicarte con el dispositivo.
Ejemplo
En el siguiente fragmento de código, se muestra cómo crear el controlador 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()); };
Implementa el controlador QUERY
El controlador QUERY
de la app procesa las solicitudes de los usuarios y usa el SDK de Local Home para informar el estado de tus dispositivos inteligentes.
La plataforma de Local Home pasa la misma carga útil de solicitudes a la función del controlador “QUERY” que la del intent QUERY
a la entrega en la nube. Del mismo modo, el controlador QUERY
muestra datos en el mismo formato que procesa el intent QUERY
.
Enviar comandos a dispositivos detrás de un concentrador
Para controlar los dispositivos finales de un concentrador, es posible que debas proporcionar información adicional en la carga útil del comando específica del protocolo que se envió al concentrador para que el centro identifique a qué dispositivo está dirigido el comando. En algunos casos, se puede inferir de forma directa desde el valor device.id
, pero cuando este no es el caso, debes incluir estos datos adicionales como parte del campo customData
.
Si creaste tu app con TypeScript, recuerda compilarla en JavaScript. Puedes usar el sistema de módulo que elijas para escribir tu código. Asegúrate de que el destino sea compatible con el navegador Chrome.