1. Antes de comenzar
Como desarrollador de Internet de las cosas (IoT), puedes compilar integraciones de nube a nube que permitan a los usuarios controlar sus dispositivos mediante los controles de tacto de la app de Google Home y los comandos por voz de Asistente.
Las integraciones de nube a nube se basan en Home Graph para proporcionar datos contextuales sobre la casa y sus dispositivos, de modo que se crea un mapa lógico de la casa. Ese contexto le permite a Asistente comprender con mayor naturalidad las solicitudes de los usuarios relacionadas con su ubicación en la casa. Por ejemplo, Home Graph puede almacenar el concepto de la sala de estar, que contiene varios tipos de dispositivos de distintos fabricantes, como un termostato, una lámpara, un ventilador y una aspiradora.
Requisitos previos
- Guía para desarrolladores de Cómo crear una integración de nube a nube
Qué compilarás
En este codelab, publicarás un servicio en la nube que administra una lavadora virtual y, luego, compilarás una integración de nube a nube y la conectarás al Asistente.
Qué aprenderás
- Cómo implementar un servicio de nube para casa inteligente
- Cómo conectar tu servicio a Asistente
- Cómo publicar cambios de estado del dispositivo en Google
Requisitos
- Un navegador web, como Google Chrome
- Un dispositivo iOS o Android con la app de Google Home instalada
- Node.js versión 10.16 o posterior
- Una cuenta de facturación de Google Cloud
2. Introducción
Habilita los Controles de actividad
Para usar Asistente de Google, debes compartir ciertos datos de actividad con Google. Asistente de Google necesita estos datos para funcionar correctamente. Sin embargo, el requisito de compartir datos no es específico del SDK. Para compartir estos datos, crea una Cuenta de Google si todavía no tienes una. Puedes usar cualquier Cuenta de Google, no es necesario que sea tu cuenta de desarrollador.
Abre la página Controles de actividad de la Cuenta de Google que quieres usar con Asistente.
Asegúrate de que los siguientes interruptores estén habilitados:
- Actividad web y de aplicaciones (además, recuerda seleccionar la casilla de verificación Incluir la actividad e historial de Chrome de sitios, apps y dispositivos que usan los servicios de Google)
- Información del dispositivo
- Actividad de voz y audio
Crea un proyecto de integración de nube a nube
- Ve a Developer Console.
- Haz clic en Create Project, ingresa un nombre para el proyecto y haz clic en Create Project.
Selecciona la integración de nube a nube.
En Página principal del proyecto en la Consola de Play, selecciona Agregar integración de nube a nube en Nube a nube.
Instala Firebase CLI
La interfaz de línea de comandos (CLI) de Firebase te permitirá publicar tus aplicaciones web a nivel local y, luego, implementar tu aplicación web en Firebase Hosting.
Para instalar la CLI, ejecuta el siguiente comando de npm desde la terminal:
npm install -g firebase-tools
Para verificar que la CLI se haya instalado de forma correcta, ejecuta el siguiente comando:
firebase --version
Ejecuta el siguiente comando para autorizar Firebase CLI con tu Cuenta de Google:
firebase login
3. Ejecuta la app de inicio
Ahora que ya configuraste tu entorno de desarrollo, puedes implementar el proyecto de inicio a fin de verificar que todo esté configurado de manera correcta.
Obtén el código fuente
Haz clic en el siguiente vínculo para descargar la muestra de este codelab en tu máquina de desarrollo:
También puedes clonar el repositorio de GitHub desde la línea de comandos:
git clone https://github.com/google-home/smarthome-washer.git
Acerca del proyecto
El proyecto inicial contiene los siguientes subdirectorios:
public:
Es una IU de frontend para controlar y supervisar el estado de la lavadora inteligente con facilidad.functions:
Es un servicio de nube completamente implementado que administra la lavadora inteligente con Cloud Functions para Firebase y Firebase Realtime Database.
Crea un proyecto de Firebase
- Ve a Firebase.
- Haz clic en Crear un proyecto y, luego, ingresa el nombre del proyecto.
- Marca la casilla de verificación del acuerdo y haz clic en Continuar. Si no hay una casilla de verificación de acuerdo, puedes omitir este paso.
- Una vez que crees tu proyecto de Firebase, busca el ID del proyecto. Ve a Descripción general del proyecto y haz clic en el ícono de configuración > Configuración del proyecto.
- Tu proyecto aparecerá en la pestaña General.
Cómo conectarse a Firebase
Navega al directorio washer-start
y configura Firebase CLI con tu proyecto de integración:
cd washer-start firebase use <firebase-project-id>
Configura un proyecto de Firebase
Inicializa un proyecto de Firebase.
firebase init
Selecciona las funciones de la CLI, Realtime Database, Functions y la función Hosting que incluye Firebase Hosting.
? Which Firebase CLI features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. ❯◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance ◯ Firestore: Configure security rules and indexes files for Firestore ◉ Functions: Configure a Cloud Functions directory and its files ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys ◯ Hosting: Set up GitHub Action deploys ◯ Storage: Configure a security rules file for Cloud Storage ◯ Emulators: Set up local emulators for Firebase products ◯ Remote Config: Configure a template file for Remote Config ◯ Extensions: Set up an empty Extensions manifest
De este modo, se inicializarán las APIs y las funciones necesarias para tu proyecto.
Cuando se te indique, inicializa Realtime Database. Puedes usar la ubicación predeterminada para la instancia de la base de datos.
? It seems like you haven't initialized Realtime Database in your project yet. Do you want to set it up? Yes ? Please choose the location for your default Realtime Database instance: us-central1
Dado que estás usando el código de proyecto inicial, elige el archivo predeterminado para las reglas de seguridad y asegúrate de no reemplazar el archivo de reglas de la base de datos existente.
? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for <project-ID>-default-rtdb from the Firebase Console? No
Si reinicializas tu proyecto, selecciona Reemplazar cuando se te pregunte si quieres inicializar o reemplazar una base de código.
? Would you like to initialize a new codebase, or overwrite an existing one? Overwrite
Cuando configures las Functions, debes usar los archivos predeterminados y asegurarte de no reemplazar los archivos existentes index.js y package.json en el ejemplo del proyecto.
? What language would you like to use to write Cloud Functions? JavaScript ? Do you want to use ESLint to catch probable bugs and enforce style? No ? File functions/package.json already exists. Overwrite? No ? File functions/index.js already exists. Overwrite? No
Si vuelves a inicializar tu proyecto, selecciona No cuando se te pregunte si quieres inicializar o reemplazar functions/.gitignore.
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
Por último, configura el Hosting para que use el directorio public
en el código del proyecto y usa el archivo index.html existente. Selecciona No cuando se te solicite usar ESLint.
? What do you want to use as your public directory? public ? Configure as a single-page app (rewrite all urls to /index.html)? Yes ? Set up automatic builds and deploys with GitHub? No ? File public/index.html already exists. Overwrite? No
Si ESLint se habilitó por accidente, hay dos métodos disponibles para inhabilitarlo:
- Con la GUI, ve a la carpeta
../functions
en el proyecto, selecciona el archivo oculto.eslintrc.js
y bórralo. No lo confundas con.eslintrc.json
, que tiene un nombre similar. - Con la línea de comandos:
cd functions rm .eslintrc.js
En el archivo washer-done/firebase.json
, completa el código con lo siguiente:
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
},
"headers": [{
"source" : "**/*.@(js|html)",
"headers" : [ {
"key" : "Cache-Control",
"value" : "max-age=0"
} ]
}],
"functions": [
{
"source": "functions",
"codebase": "default",
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log",
"*.local"
]
}
]
}
Cómo implementar en Firebase
Ahora que ya instalaste las dependencias y configuraste tu proyecto, tienes todo listo para ejecutar la app por primera vez.
firebase deploy
Este es el resultado que debería ver en la consola:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<firebase-project-id>/overview Hosting URL: https://<firebase-project-id>.web.app
Este comando implementa una app web, junto con varias Cloud Functions para Firebase.
Abre la URL de Hosting en tu navegador (https://
) para ver la aplicación web. Verás la siguiente interfaz:
Esta IU web representa una plataforma de terceros para ver o modificar los estados de los dispositivos. Haz clic en ACTUALIZAR a fin de comenzar a propagar tu base de datos con la información del dispositivo. No verás ningún cambio en la página, pero el estado actual de la lavadora se almacenará en la base de datos.
Es momento de usar la Consola de desarrolladores de Google Home para conectar el servicio en la nube que implementaste en Asistente de Google.
Configura tu proyecto de Play Console
En la pestaña Desarrollar, agrega un Nombre visible para tu interacción. Este nombre aparecerá en la app de Google Home.
En Desarrollo de la marca de la app, sube un archivo png
para el ícono de la app, con un tamaño de 144 × 144 px y el nombre
.
Para habilitar la vinculación de cuentas, usa esta configuración:
ID de cliente |
|
Secreto del cliente |
|
URL de autorización |
|
URL del token |
|
En URL de entrega en la nube, ingresa la URL de tu Cloud Function que proporciona entregas para los intents de la casa inteligente.
https://us-central1-
Haz clic en Guardar para guardar la configuración de tu proyecto y, luego, en Siguiente: Prueba para habilitar las pruebas en tu proyecto.
Ahora puedes comenzar a implementar los webhooks necesarios para conectar el estado del dispositivo con Asistente.
4. Crea una lavadora
Ahora que configuraste la integración, puedes agregar dispositivos y enviar datos. Tu servicio en la nube necesita procesar los siguientes intents:
- Se produce un intent
SYNC
cuando Asistente desea saber qué dispositivos conectó el usuario. Este se envía a tu servicio cuando el usuario vincula una cuenta. Deberías responder con una carga útil JSON de todos los dispositivos del usuario y sus capacidades. - Se produce un intent
QUERY
cuando el Asistente desea conocer el estado o el estado actual de un dispositivo. Deberías responder con una carga útil JSON con el estado de cada dispositivo solicitado. - Se produce un intent
EXECUTE
cuando el Asistente desea controlar un dispositivo en nombre de un usuario. Deberías responder con una carga útil JSON con el estado de ejecución de cada dispositivo solicitado. - Se produce un intent
DISCONNECT
cuando el usuario desvincula su cuenta del Asistente. Deberías dejar de enviar a Asistente eventos para el dispositivo de este usuario.
En las siguientes secciones, actualizarás las funciones que implementaste antes para controlar estos intents.
Actualiza la respuesta de SYNC
Abre functions/index.js
, que contiene el código para responder las solicitudes del Asistente.
Deberás controlar un intent SYNC
mostrando los metadatos y las capacidades del dispositivo. Actualiza el archivo JSON del array onSync
para incluir la información del dispositivo y los atributos recomendados para la lavadora de ropa.
index.js
app.onSync((body) => {
return {
requestId: body.requestId,
payload: {
agentUserId: USER_ID,
devices: [{
id: 'washer',
type: 'action.devices.types.WASHER',
traits: [
'action.devices.traits.OnOff',
'action.devices.traits.StartStop',
'action.devices.traits.RunCycle',
],
name: {
defaultNames: ['My Washer'],
name: 'Washer',
nicknames: ['Washer'],
},
deviceInfo: {
manufacturer: 'Acme Co',
model: 'acme-washer',
hwVersion: '1.0',
swVersion: '1.0.1',
},
willReportState: true,
attributes: {
pausable: true,
},
}],
},
};
});
Cómo implementar en Firebase
Implementa la entrega actualizada en la nube con Firebase CLI:
firebase deploy --only functions
Vínculo a Asistente de Google
Para probar tu integración de nube a nube, debes vincular tu proyecto con una Cuenta de Google. De esta manera, puedes realizar pruebas mediante las superficies de Asistente de Google y la app de Google Home que accedieron a la misma cuenta.
- En el teléfono, abre la configuración de Asistente de Google. Ten en cuenta que debes acceder con la misma cuenta que accediste a la consola.
- Ve a Asistente de Google > Configuración > Control del hogar (en Asistente).
- Haz clic en el ícono de búsqueda en la parte superior derecha.
- Busca tu app de prueba con el prefijo [test] para encontrar la app de prueba específica.
- Selecciona ese elemento. Luego, se autenticará Asistente de Google con el servicio y se enviará una solicitud
SYNC
para que el servicio le proporcione una lista de dispositivos.
Abre la app de Google Home y verifica que puedas ver el dispositivo de la lavadora.
5. Cómo procesar comandos y consultas
Ahora que tu servicio de nube informa correctamente la actividad de la lavadora a Google, debes agregar la capacidad de solicitar el estado del dispositivo y enviar comandos.
Cómo procesar el intent QUERY
Un intent QUERY
incluye un conjunto de dispositivos. Para cada dispositivo, debes responder con su estado actual.
En functions/index.js
, edita el controlador QUERY
para que procese la lista de dispositivos de destino incluidos en la solicitud de intent.
index.js
app.onQuery(async (body) => {
const {requestId} = body;
const payload = {
devices: {},
};
const queryPromises = [];
const intent = body.inputs[0];
for (const device of intent.payload.devices) {
const deviceId = device.id;
queryPromises.push(queryDevice(deviceId)
.then((data) => {
// Add response to device payload
payload.devices[deviceId] = data;
}
));
}
// Wait for all promises to resolve
await Promise.all(queryPromises);
return {
requestId: requestId,
payload: payload,
};
});
Para cada dispositivo incluido en la solicitud, muestra el estado actual almacenado en Realtime Database. Actualiza las funciones queryFirebase
y queryDevice
para mostrar los datos de estado de la lavadora.
index.js
const queryFirebase = async (deviceId) => {
const snapshot = await firebaseRef.child(deviceId).once('value');
const snapshotVal = snapshot.val();
return {
on: snapshotVal.OnOff.on,
isPaused: snapshotVal.StartStop.isPaused,
isRunning: snapshotVal.StartStop.isRunning,
};
};
const queryDevice = async (deviceId) => {
const data = await queryFirebase(deviceId);
return {
on: data.on,
isPaused: data.isPaused,
isRunning: data.isRunning,
currentRunCycle: [{
currentCycle: 'rinse',
nextCycle: 'spin',
lang: 'en',
}],
currentTotalRemainingTime: 1212,
currentCycleRemainingTime: 301,
};
};
Cómo procesar el intent EXECUTE
El intent EXECUTE
controla los comandos para actualizar el estado del dispositivo. La respuesta muestra el estado de cada comando (por ejemplo, SUCCESS
, ERROR
o PENDING
) y el estado del dispositivo nuevo.
En functions/index.js
, edita el controlador EXECUTE
para que procese la lista de características que necesitan actualizaciones y el conjunto de dispositivos de destino para cada comando:
index.js
app.onExecute(async (body) => {
const {requestId} = body;
// Execution results are grouped by status
const result = {
ids: [],
status: 'SUCCESS',
states: {
online: true,
},
};
const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
for (const device of command.devices) {
for (const execution of command.execution) {
executePromises.push(
updateDevice(execution, device.id)
.then((data) => {
result.ids.push(device.id);
Object.assign(result.states, data);
})
.catch(() => functions.logger.error('EXECUTE', device.id)));
}
}
}
await Promise.all(executePromises);
return {
requestId: requestId,
payload: {
commands: [result],
},
};
});
Para cada comando y dispositivo de destino, actualiza los valores de Realtime Database que corresponden a la ruta solicitada. Modifica la función updateDevice
para actualizar la referencia de Firebase adecuada y mostrar el estado actualizado del dispositivo.
index.js
const updateDevice = async (execution, deviceId) => {
const {params, command} = execution;
let state; let ref;
switch (command) {
case 'action.devices.commands.OnOff':
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
case 'action.devices.commands.StartStop':
state = params.start
? {isRunning: true, isPaused: false}
: {isRunning: false, isPaused: false};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
const data = await queryDevice(deviceId);
state = (data.isPaused === false && data.isRunning === false)
? {isRunning: false, isPaused: false}
: {isRunning: !params.pause, isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
}
return ref.update(state)
.then(() => state);
};
6. Prueba tu integración
Después de implementar los tres intents, puedes probar que si tu integración controla la lavadora.
Cómo implementar en Firebase
Implementa la entrega actualizada en la nube con Firebase CLI:
firebase deploy --only functions
Prueba la lavadora
Ahora puedes ver el cambio de valor cuando pruebas cualquiera de los siguientes comandos por voz en el teléfono:
"Hey Google, enciende la lavadora".
"Hey Google, pausa la lavadora".
"Hey Google, detén la lavadora".
También puedes hacer preguntas para consultar el estado actual de la lavadora.
"Hey Google, ¿la lavadora está encendida?".
"Hey Google, ¿la lavadora está funcionando?".
"Hey Google, ¿en qué ciclo está la lavadora?".
Puedes ver estas consultas y comandos en los registros que aparecen debajo de tu función en la sección Functions de Firebase console. Obtén más información sobre los registros de Firebase en Cómo escribir y ver registros.
También puedes encontrar estas consultas y comandos en la consola de Google Cloud. Para ello, navega a Registros > Explorador de registros. Obtén más información sobre el registro de Google Cloud en Cómo acceder a registros de eventos con Cloud Logging.
7. Informa sobre actualizaciones a Google
Integraste por completo tu servicio de nube con los intents de casa inteligente, lo que permite a los usuarios controlar y consultar sus estados actuales. Sin embargo, la implementación aún no permite que el servicio envíe información del evento de forma proactiva (como cambios en la presencia o el estado del dispositivo) a Asistente.
Con Request Sync, puedes activar una nueva solicitud de sincronización cuando los usuarios agreguen o quiten dispositivos, o cuando cambien las capacidades de sus dispositivos. Con Report State, tu servicio en la nube puede enviar de manera proactiva el estado de un dispositivo a Home Graph cuando los usuarios cambian físicamente el estado de un dispositivo (por ejemplo, cuando activar un interruptor de la luz) o cambian el estado con otro servicio.
En esta sección, agregarás código para llamar a estos métodos desde la aplicación web de frontend.
Habilita la API de HomeGraph
La API de HomeGraph permite almacenar y buscar dispositivos y sus estados en el Home Graph de un usuario. Para usar esta API, primero debes abrir la consola de Google Cloud y habilitar la API de HomeGraph.
En la consola de Google Cloud, asegúrate de seleccionar el proyecto que coincida con tu integración <project-id>.
Luego, en la pantalla Biblioteca de la API para la API de HomeGraph, haz clic en Habilitar.
Habilita la función de informe de estado
Las operaciones de escritura en Realtime Database activan la función reportstate
en el proyecto de inicio. Actualiza la función reportstate
en functions/index.js
para capturar los datos escritos en la base de datos y publicarlos en Home Graph mediante la función de informe de estado.
index.js
exports.reportstate = functions.database.ref('{deviceId}').onWrite(
async (change, context) => {
functions.logger.info('Firebase write event triggered Report State');
const snapshot = change.after.val();
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of our washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
},
},
},
},
};
const res = await homegraph.devices.reportStateAndNotification({
requestBody,
});
functions.logger.info('Report state response:', res.status, res.data);
});
Habilita la sincronización de solicitudes
Cuando se actualiza el ícono en la IU de la Web de frontend, se activa la función requestsync
en el proyecto de inicio. Implementa la función requestsync
en functions/index.js
para llamar a la API de HomeGraph.
index.js
exports.requestsync = functions.https.onRequest(async (request, response) => {
response.set('Access-Control-Allow-Origin', '*');
functions.logger.info(`Request SYNC for user ${USER_ID}`);
try {
const res = await homegraph.devices.requestSync({
requestBody: {
agentUserId: USER_ID,
},
});
functions.logger.info('Request sync response:', res.status, res.data);
response.json(res.data);
} catch (err) {
functions.logger.error(err);
response.status(500).send(`Error requesting sync: ${err}`);
}
});
Cómo implementar en Firebase
Implementa el código actualizado usando Firebase CLI:
firebase deploy --only functions
Prueba tu implementación
En la IU de la Web, haz clic en el botón Refresh y asegúrate de ver una solicitud de sincronización en el registro de Firebase console.
A continuación, ajusta los atributos de la lavadora en la IU de la Web de frontend y haz clic en Update. Verifica que puedas ver el cambio de estado que se informó a Google en tus registros de Firebase console.
8. Felicitaciones
¡Felicitaciones! Integraste correctamente Asistente con un servicio en la nube del dispositivo mediante integraciones de nube a nube.
Más información
A continuación, te ofrecemos algunas ideas que puedes implementar para seguir experimentando:
- Agrega modos y botones de activación a tu dispositivo.
- Agrega más características compatibles a tu dispositivo.
- Explora la ejecución local para la casa inteligente.
- Consulta nuestra muestra de GitHub para obtener más información.
También puedes obtener más información sobre cómo probar una integración y enviarla a revisión, incluido el proceso de certificación para publicar tu integración a los usuarios.