Para admitir la entrega local, debes compilar una app para controlar estos intents de casa inteligente:
IDENTIFY: Admite el descubrimiento de dispositivos inteligentes que se pueden controlar de forma local. El controlador de intents extrae los datos que devuelve tu dispositivo inteligente durante el descubrimiento y los envía en una respuesta a Google.EXECUTE: Admite la ejecución de comandos.QUERY: Admite la consulta del estado del dispositivo.REACHABLE_DEVICES: (Opcional) Admite el descubrimiento de dispositivos finales que se pueden controlar de forma local detrás de un dispositivo de hub (o puente).
Esta app se ejecuta en los dispositivos Google Home o Google Nest del usuario y conecta tu dispositivo inteligente a Asistente. Puedes crear la app con TypeScript (preferido) o JavaScript.
Se recomienda TypeScript porque puedes aprovechar las vinculaciones para garantizar de forma estática que los datos que devuelve tu app coincidan con los tipos que espera la plataforma.
Para obtener más detalles sobre la API, consulta la referencia de la API de Local Home SDK.
En los siguientes fragmentos, se muestra cómo puedes 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"); });
Crea tu proyecto
Para implementar tu app de entrega local, debes compilar un paquete de JavaScript para tu código y todas sus dependencias.
Usa el inicializador de proyectos de la app de entrega local para iniciar la estructura de proyecto adecuada con la configuración de paquete que prefieras.
Plantillas de proyectos
Para seleccionar la configuración de tu paquete, ejecuta el comando npm init como se muestra en los siguientes ejemplos:
TypeScript sin configuración de paquete:
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 paquete de webpack bundler configuración:
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 Rollup configuración de paquete:
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 Parcel configuración de paquete:
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 del proyecto
El proyecto generado admite las siguientes npm scripts:
cd project-directory/ npm run build
Esta secuencia de comandos compila la fuente de TypeScript y agrupa 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, lo compila sin producir ninguna salida en el subdirectorio dist/ y ejecuta pruebas automatizadas desde test.ts.
cd project-directory/ npm run start
Durante el desarrollo, esta secuencia de comandos entrega los paquetes de tu app para los entornos de ejecución de Chrome y Node.js de forma local.
Implementa el controlador IDENTIFY
El controlador IDENTIFY se activará cuando el dispositivo Google Home o dispositivo Google Nest se reinicie y vea dispositivos locales no verificados (incluidos los dispositivos finales conectados a una unidad central). La plataforma de Local Home buscará dispositivos locales con la información de configuración de análisis que especificaste anteriormente y llamará a tu controlador IDENTIFY con los resultados del análisis.
The
IdentifyRequest
de la plataforma de Local Home contiene los datos de análisis de una instancia de
LocalIdentifiedDevice. Solo se propagará 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 debe mostrar un
IdentifyResponsePayload
objeto, que incluye un objeto device con
metadatos de casa inteligente (como los tipos, los rasgos y el estado del informe).
Google establece una asociación de dispositivos 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 de dispositivos independientes y de hubs, 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 hub
Si Google identifica un dispositivo de hub, lo tratará como el conducto a los dispositivos finales conectados del hub y tratará de verificar esos dispositivos finales.
Para permitir que Google confirme que hay un dispositivo de hub, sigue estas instrucciones para tu controlador IDENTIFY:
- Si tu
SYNCrespuesta informa los IDs de los dispositivos finales locales conectados al hub, estableceisProxycomotrueen elIdentifyResponsePayload. - Si tu
SYNCrespuesta no informa tu dispositivo de hub, estableceisLocalOnlycomotrueen elIdentifyResponsePayload. - El campo
device.idcontiene el ID del dispositivo local para el dispositivo de hub.
Implementa el controlador REACHABLE_DEVICES (solo integraciones de hubs)
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 hub está en línea.
Implementas el controlador REACHABLE_DEVICES de manera similar al controlador IDENTIFY, excepto que tu controlador debe recopilar IDs de dispositivos adicionales a los que se puede acceder con el dispositivo proxy local (es decir, el hub). El campo device.verificationId contiene el ID del dispositivo local para un dispositivo final que está conectado al hub.
The
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.
Tu controlador REACHABLE_DEVICES debe mostrar un
ReachableDevicesPayload
objeto que incluya un devices objeto que contenga un array de
verificationId valores que representen los dispositivos finales que controla el hub. Los valores verificationId deben coincidir con uno de los otherDeviceIds de la respuesta SYNC.
En el siguiente fragmento, se muestra cómo puedes crear tu 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
Tu controlador EXECUTE en la app procesa los comandos del usuario y usa Local Home SDK 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 para el intent EXECUTE
a tu entrega en la nube. Del mismo modo, tu controlador EXECUTE muestra datos de salida en el mismo formato que el procesamiento del intent EXECUTE.
Para simplificar la creación de respuestas, puedes usar la
Execute.Response.Builder
clase que proporciona Local Home SDK.
Tu app no tiene acceso directo a la dirección IP del dispositivo. En su lugar,
usa la
CommandRequest
interfaz para crear comandos basados en uno de estos protocolos: UDP, TCP o HTTP. Luego, llama a la
deviceManager.send()
función para enviar los comandos.
Cuando orientes comandos a dispositivos, usa el ID del dispositivo (y los parámetros del
customData campo, si se incluye) de la SYNC respuesta para comunicarte
con el dispositivo.
Ejemplo
En el siguiente fragmento de código, se muestra cómo puedes crear tu 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
Tu controlador QUERY en la app procesa las solicitudes del usuario y usa Local Home SDK para informar el estado de tus dispositivos inteligentes.
La plataforma de Local Home pasa la misma carga útil de solicitud a la función del controlador "QUERY"
que para el QUERY
intent a tu entrega en la nube. Del mismo modo, tu controlador QUERY muestra datos en el mismo formato que el procesamiento del intent QUERY.
Envía comandos a dispositivos detrás de un hub
Para controlar los dispositivos finales detrás de un hub, es posible que debas proporcionar información adicional en la carga útil del comando específico del protocolo que se envía al hub para que este identifique a qué dispositivo está destinado el comando. En algunos casos, esto se puede inferir directamente del valor device.id, pero, cuando no es así, 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ódulos que prefieras para escribir tu código. Asegúrate de que el navegador Chrome admita tu objetivo.