Conecta dispositivos de casa inteligente a Asistente de Google

Como desarrollador de Internet de las cosas (IoT), puedes compilar Acciones para casa inteligente 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.

79266e5f45e6ae20.gif

Las Acciones de casa inteligente se basan en Home Graph, que brinda 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 sus ubicaciones 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.

d009cef0f903d284.jpeg

Requisitos previos

Qué compilarás

En este codelab, publicarás un servicio en la nube que administra una lavadora virtual y, luego, compilarás una Acción de casa inteligente y la conectarás a 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

Habilita los Controles de actividad

Habilita los siguientes Controles de actividad en la Cuenta de Google que planeas usar con Asistente:

  • Actividad web y de aplicaciones
  • Información del dispositivo
  • Actividad de voz y audio

Crea un proyecto de Acciones

  1. Ve a Actions on Google Developer Console.
  2. Haz clic en New Project, ingresa un nombre para el proyecto y haz clic en CREATE PROJECT.

AWXw5E1m9zVgvVeyeL3uxwCX6DtWOCK6LRSLmOATFzjMbmE5cSWBdSVhJZDFpEFH2azZTK2eMs6OYYdMJYiGb5bKqFEzxaLyRUYuwVGBlSjXzTyy8Z9CvwpXvRwP7xdycklETzFc7Q

Selecciona la app de casa inteligente

En la pantalla Overview de la Consola de Actions, selecciona Smart home.

36RsBUWBgbgsa5xZ7MJVMm1sIg07nXbfjv0mWCxXViaC5SlbL2gMigw9hgXsZQhNMHLLFOfiKdZsSTNXONFB1i47gksw3SBNpkVYl492WeryOlgxKjpVrLAvg-5cZqu1DI-s5kxM3g

Selecciona la tarjeta de experiencia Smart home y se te dirigirá a la consola de tu proyecto.

pzgHPsmc2LvLoeUvJfkjKQqD_BvO4v8JOPlcrxsmyptFkkjL4PP6LqrM9r5tNvEIfT9HmK-UKw3GWFPXTjqo4nUrhD2o5shUKHBE31OT8iIA69JZCev7_0_nh-lnL2oJHoxGfqqZ4w

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

A fin de autorizar Firebase CLI con tu Cuenta de Google, ejecuta el siguiente comando:

firebase login

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:

Descarga el código fuente

O bien, puedes clonar el repositorio de GitHub desde la línea de comandos.

git clone https://github.com/googlecodelabs/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.

Cómo conectarse a Firebase

Navega al directorio washer-start y configura Firebase CLI con tu proyecto de Acciones:

cd washer-start
firebase use <project-id>

Cómo implementar en Firebase

Ve a la carpeta functions y, luego, instala todas las dependencias necesarias mediante npm.

cd functions
npm install

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ías ver en la consola:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<project-id>/overview
Hosting URL: https://<project-id>.firebaseapp.com

Este comando implementa una app web, junto con varias Cloud Functions para Firebase.

Abre la URL de Hosting en tu navegador (https://<project-id>.firebaseapp.com) para ver la aplicación web. Verás la siguiente interfaz:

L60eA7MOnPmbBMl2XMipT9MdnP-RaVjyjf0Y93Y1b7mEyIsqZrrwczE7D3RQISRs-iusL1g4XbNmGhuA6-5sLcWefnczwNJEPfNLtwBsO4Tb9YvcAZBI6_rX19z8rxbik9Vq8F2fwg

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 Actions para conectar el servicio en la nube que implementaste en Asistente de Google.

Configura tu proyecto de la Consola de Actions

En Overview > Build your Action, selecciona Add Action(s). Ingresa la URL de tu Cloud Function que proporciona entregas para los intents de la casa inteligente y haz clic en Save.

https://us-central1-<project-id>.cloudfunctions.net/smarthome

Uso-o00XQXBHvOR9vQq9tmpYDYQJKsFEstsgRFnxPAJf7zJ2FxwhISiodo3dB1Tz49Okd6ivi66fjpo7rarS_GZelglGWCT1r9FzDGUl1r67ddIcIbQrxqN8jG9F9GAKOpk0Ckc-eA

En la pestaña Desarrollo > Invocación, agrega un nombre visible para tu acción y haz clic en Save. Este nombre aparecerá en la app de Google Home.

gvC-TvmKDy-D-xjwkeCjNt__9ErA7DL8hZWa1oH1yPJ9SpYOepDYjxx6WnJ56IG-t37fJ65kmHISQdh72Ot2G-0tu6Flxf4gom5kvx_3hlvFeMqYuFgXr_85pfWWn7VLFHtS55p1zw

s4yc1kOW4XtKUQN1EYegiDLU5oTqmxQ2PNbeaujm26OQmYKKpjug7j5FYmutLSAZ1zBd-ZkcZlL7zyTZqw4bge3_oOeWvJTsqJ-A08vfZwImYQrKiquLskLuTpmMqXEZD1xchhCWGQ

Para habilitar la vinculación de cuentas, selecciona la opción Develop > Account linking en el panel de navegación izquierdo. Usa la siguiente configuración de vinculación de la cuenta:

ID de cliente

ABC123

Secreto del cliente

DEF456

URL de autorización

https://us-central1-<project-id>.cloudfunctions.net/fakeauth

URL del token

https://us-central1-<project-id>.cloudfunctions.net/faketoken

rRyZTiBSTuPk3YtJtXjDK1pPftUxsaEhs9jzpvFtbHTD6bEwYxM8jV4MWxiljKA1bKVZrIRoO9O3jtBefLKf_OyMpukPjwIj8zGvyU3UwASzMrnRskl-hVAfAmQVi4sC_zAwgYwRXw

Haz clic en Save para guardar la configuración de vinculación de cuentas y, luego, haz clic en Test a fin de habilitar las pruebas en tu proyecto.

OgUvpQfXioygkRwPcaJpzjyNQDZy6enidUC8YMPaCOrZi0YeWCFsCJV9Gqg-_UfsqTnn4KEg--uE3Ymr0QuamDonF4RyYHtRKcULXABDuaEnj2hq8i20LYj1SrGP_1lQ_UsUB90pGw

Se te redireccionará al simulador. Verifica que se hayan habilitado las pruebas para tu proyecto. Para ello, mueve el mouse sobre el ícono de pruebas en el dispositivo (soCeBB1CkSIEqsBmDc8Cth6EjgcXUnrOHeOpLNlvMiiXM73Rmh8iBK1ZFLFd47kycYqIMq3Fm49ryAGUt79BXVPDyEB1IU3W0fgiL49iqTAVrpRszL10mmxzq_AQTJZVrXor-vne2w).

2zbfeYpG-wEd2SFP07Wc4mJzHakLX7YvrNw3IV0_0Kd-TonfsKIvvjKWlwvrmTm5jLj3XPWqCtcDd5J2z6gwn9fnchpYVraw1j_mE4M0LVppAl5WY5cK7g0uZyhZ3VFFS25yPmyksg

Ahora puedes comenzar a implementar los webhooks necesarios para conectar el estado del dispositivo con Asistente.

Ahora que configuraste la Acció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 procesar 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

Si deseas probar tu Acción para la casa inteligente, necesitas 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.

  1. 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.
  2. Ve a Asistente de Google > Configuración > Control del hogar (en Asistente).
  3. Selecciona el ícono del signo más en la esquina inferior derecha.
  4. Deberías ver tu app de prueba con el prefijo [test] y el nombre visible que estableciste.
  5. 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.

XcWmBVamBZtPfOFqtsr5I38stPWTqDcMfQwbBjetBgxt0FCjEs285pa9K3QXSASptw0KYN2G8yfkT0-xg664V4PjqMreDDs-HPegHjOc4EVtReYPu-WKZyygq9Xmkf8X8z9177nBjQ

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

El 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 procesa 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 = {isRunning: params.start};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
    case 'action.devices.commands.PauseUnpause':
      state = {isPaused: params.pause};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
  }

  return ref.update(state)
      .then(() => state);
};

Después de implementar los tres intents, puedes probar que si tu Acció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?".

También puedes ver estas consultas y comandos en los registros de Firebase console si haces clic en Develop > Functions > Logs en el menú de navegación.

ce02fb66fe2037dc.png

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 el 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 Google Cloud Console y habilitar la API de HomeGraph.

En Google Cloud Console, asegúrate de seleccionar el proyecto que coincida con tu <project-id>. de Acciones. Luego, en la pantalla Biblioteca de la API para la API de HomeGraph, haz clic en Enable.

5SVCzM8IZLi_9DV8M0nEklv16NXkpvM0bIzQK2hSyKyvnFHBxPOz90rbr72ayxzmxd5aNROOqC_Cp4outbdlwJdObDs0DIE_8vYzw6dovoVrP9IZWlWsZxDS7UHOi1jiRbDMG8MqUA

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 ae8d3b25777a5e30.png y asegúrate de ver una solicitud de sincronización en el registro de Firebase console.

5241d663238a8d04.png

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.

674c4f4392e98c1.png

¡Felicitaciones! Integraste correctamente Asistente con un servicio en la nube del dispositivo mediante Acciones de casa inteligente.

Más información

A continuación, te ofrecemos algunas ideas que puedes implementar para seguir experimentando:

También puedes obtener más información sobre cómo probar una Acción y enviarla a revisión, incluido el proceso de certificación para poner tu Acción a disponibilidad de los usuarios.