Eventos

Los eventos son asíncronos y los administra Google Cloud Pub/Sub, en un solo tema por Project. Los eventos proporcionan actualizaciones para todos los dispositivos y estructuras, y se garantiza la recepción de eventos siempre que el usuario no revoque el token de acceso y los mensajes de evento no hayan vencido.

Habilitar eventos

Los eventos son una función opcional de la API de SDM. Consulta Habilita eventos para obtener información sobre cómo habilitarlos para tu Project.

Google Cloud Pub/Sub

Consulta la documentación de Google Cloud Pub/Sub para obtener más información sobre cómo funciona Pub/Sub. En particular:

Suscripción al evento

Antes de enero de 2025, si los eventos estaban habilitados para tu Project, se te proporcionaba un tema alojado en Google específico para ese Project ID, con el siguiente formato:

projects/sdm-prod/topics/enterprise-project-id

Ahora, todos los proyectos deben alojar sus temas de Pub/Sub en su propio proyecto de Google Cloud (obligatorio para los proyectos nuevos desde enero de 2025 y para todos los proyectos existentes antes del 30 de noviembre de 2026), con el siguiente formato:

projects/gcp-project-name/subscriptions/topic-id

Si tu project ya usa un tema alojado de forma independiente en tu propio proyecto de Google Cloud, no es necesario que realices ninguna acción. La migración de la configuración de tu tema de Pub/Sub no invalida los tokens de acceso de usuario ni los permisos de OAuth existentes. Los temas y las suscripciones autoalojados están sujetos a los precios estándar de Google Cloud Pub/Sub (que incluyen un nivel gratuito de 10 GB por mes). Consulta Crea un tema para obtener más información.

Para recibir eventos, crea una suscripción de extracción o envío a ese tema, según tu caso de uso. Se admiten varias suscripciones al tema de SDM. Consulta Administra suscripciones para obtener más información.

Inicia eventos

Para iniciar eventos por primera vez una vez que se haya creado la suscripción a Pub/Sub, realiza una llamada a la API de devices.list como un activador único. Los eventos de todas las estructuras y dispositivos se publicarán después de esta llamada.

Para ver un ejemplo, consulta la página Autoriza en la guía de inicio rápido.

Orden de los eventos

Pub/Sub no garantiza la entrega ordenada de los eventos, y es posible que el orden de recepción de los eventos no corresponda al orden en que ocurrieron. Usa el campo timestamp para ayudar a conciliar el orden de los eventos. Los eventos también pueden llegar de forma individual o combinados en un solo mensaje de evento.

Para obtener más información, consulta Ordena mensajes.

IDs de usuario

Si tu implementación se basa en los usuarios (en lugar de la estructura o el dispositivo), usa el campo userID de la carga útil del evento para correlacionar los recursos y los eventos. Este campo es un ID ofuscado que representa a un usuario específico.

El userID también está disponible en el encabezado de respuesta HTTP de cada llamada a la API.

Eventos de relación

Los eventos de relación representan una actualización relacional de un recurso. Por ejemplo, cuando se agrega un dispositivo a una estructura o cuando se borra un dispositivo de una estructura.

Existen tres tipos de eventos de relación:

  • CREATED
  • ELIMINADO
  • ACTUALIZADA

La carga útil de un evento de relación es la siguiente:

Carga útil

{
  "eventId" : "1a2e13bc-c23c-4bc4-8366-6b5669607f0e",
  "timestamp" : "2019-01-01T00:00:01Z",
  "relationUpdate" : {
    "type" : "CREATED",
    "subject" : "enterprises/project-id/structures/structure-id",
    "object" : "enterprises/project-id/devices/device-id"
  },
  "userId": "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi"
}

En un evento de relación, el object es el recurso que activó el evento y el subject es el recurso con el que el object ahora tiene una relación. En el ejemplo anterior, un user otorgó acceso a este dispositivo específico a un developer, y el dispositivo autorizado del userahora está relacionado con su estructura autorizada, lo que activa el evento.

Un subject solo puede ser una habitación o una estructura. Si a developer no tiene permiso para ver la estructura de user, subject siempre está vacío.

Campos

Campo Descripción Tipo de datos
eventId Es el identificador único del evento. string
Ejemplo: "a121b435-e3bb-4ba1-9dea-945686b7dabf"
timestamp Es la hora en que se produjo el evento. string
Ejemplo: "2019-01-01T00:00:01Z"
relationUpdate Es un objeto que detalla información sobre la actualización de la relación. object
userId Es un identificador único y ofuscado que representa al usuario. string
Ejemplo: "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi"

Consulta Eventos para obtener más información sobre los diferentes tipos y cómo funcionan.

Ejemplos

Las cargas útiles de los eventos difieren para cada tipo de evento de relación:

CREATED

Se creó la estructura

"relationUpdate" : {
  "type" : "CREATED",
  "subject" : "",
  "object" : "enterprises/project-id/structures/structure-id"
}

Se creó el dispositivo

"relationUpdate" : {
  "type" : "CREATED",
  "subject" : "enterprises/project-id/structures/structure-id",
  "object" : "enterprises/project-id/devices/device-id"
}

Se creó el dispositivo

"relationUpdate" : {
  "type" : "CREATED",
  "subject" : "enterprises/project-id/structures/structure-id/rooms/room-id",
  "object" : "enterprises/project-id/devices/device-id"
}

ACTUALIZADA

Se movió el dispositivo

"relationUpdate" : {
  "type" : "UPDATED",
  "subject" : "enterprises/project-id/structures/structure-id/rooms/room-id",
  "object" : "enterprises/project-id/devices/device-id"
}

ELIMINADO

Se borró la estructura

"relationUpdate" : {
  "type" : "DELETED",
  "subject" : "",
  "object" : "enterprises/project-id/structures/structure-id"
}

Se borró el dispositivo

"relationUpdate" : {
  "type" : "DELETED",
  "subject" : "enterprises/project-id/structures/structure-id",
  "object" : "enterprises/project-id/devices/device-id"
}

Se borró el dispositivo

"relationUpdate" : {
  "type" : "DELETED",
  "subject" : "enterprises/project-id/structures/structure-id/rooms/room-id",
  "object" : "enterprises/project-id/devices/device-id"
}

Los eventos de relación no se envían en los siguientes casos:

  • Se borra una sala

Eventos de recursos

Un evento de recurso representa una actualización específica de un recurso. Puede ser en respuesta a un cambio en el valor de un campo de atributo, como cambiar el modo de un termostato. También puede representar una acción del dispositivo que no cambia un campo de atributo, como presionar un botón del dispositivo.

Un evento generado en respuesta a un cambio en el valor del campo de característica contiene un objeto traits, similar a una llamada GET de dispositivo:

Carga útil

{
  "eventId" : "caec1000-1cab-43d3-946f-bc3c5f8615c9",
  "timestamp" : "2019-01-01T00:00:01Z",
  "resourceUpdate" : {
    "name" : "enterprises/project-id/devices/device-id",
    "traits" : {
      "sdm.devices.traits.ThermostatMode" : {
        "mode" : "COOL"
      }
    }
  },
  "userId": "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi",
  "resourceGroup" : [
    "enterprises/project-id/devices/device-id"
  ]
}

Usa la documentación de rasgos individuales para comprender el formato de la carga útil de cualquier evento de recurso de cambio de campo de rasgo.

Un evento generado en respuesta a una acción del dispositivo que no cambia un campo de atributo también tiene una carga útil con un objeto resourceUpdate, pero con un objeto events en lugar de un objeto traits:

Carga útil

{
  "eventId" : "0111d3f2-5e7d-4ecf-88ed-8f3b0324f75c",
"timestamp" : "2019-01-01T00:00:01Z",
"resourceUpdate" : { "name" : "enterprises/project-id/devices/device-id", "events" : { "sdm.devices.events.CameraMotion.Motion" : { "eventSessionId" : "CjY5Y3VKaTZwR3o4Y19YbTVfMF...", "eventId" : "jOvQqNOSL76837k_JxTR4BJ6nw...", } } } "userId" : "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi",
"eventThreadId" : "d67cd3f7-86a7-425e-8bb3-462f92ec9f59",
"eventThreadState" : "STARTED",
"resourceGroup" : [ "enterprises/project-id/devices/device-id" ] }

Estos tipos de eventos de recursos se definen en rasgos específicos. Por ejemplo, el evento Motion se define en la característica CameraMotion . Consulta la documentación de cada atributo para comprender el formato de carga útil de estos tipos de eventos de recursos.

Campos

Campo Descripción Tipo de datos
eventId Es el identificador único del evento. string
Ejemplo: "0111d3f2-5e7d-4ecf-88ed-8f3b0324f75c"
timestamp Es la hora en que se produjo el evento. string
Ejemplo: "2019-01-01T00:00:01Z"
resourceUpdate Es un objeto que detalla información sobre la actualización del recurso. object
userId Es un identificador único y ofuscado que representa al usuario. string
Ejemplo: "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi"
eventThreadId Es el identificador único del subproceso del evento. string
Ejemplo: "d67cd3f7-86a7-425e-8bb3-462f92ec9f59"
eventThreadState Es el estado del subproceso del evento. string
Valores: "STARTED", "UPDATED", "ENDED"
resourceGroup Es un objeto que indica los recursos que podrían tener actualizaciones similares a este evento. El recurso del evento en sí (del objeto resourceUpdate) siempre estará presente en este objeto. object

Consulta Eventos para obtener más información sobre los diferentes tipos y cómo funcionan.

Notificaciones actualizables

Las notificaciones basadas en eventos de recursos se pueden implementar en una app, como para Android o iOS. Para reducir la cantidad de notificaciones enviadas, se puede implementar una función llamada notificaciones actualizables, en la que las notificaciones existentes se actualizan con información nueva basada en eventos posteriores en el mismo subproceso de eventos.

Selecciona la compatibilidad de la función de eventos con las notificaciones actualizables y etiquétalas como Actualizables  en la documentación. Estos eventos tienen un campo adicional llamado eventThreadId en sus cargas útiles. Usa este campo para vincular eventos individuales con el propósito de actualizar una notificación existente que se mostró a un usuario.

Un hilo de eventos no es lo mismo que una sesión de eventos. El subproceso del evento identifica un estado actualizado para un evento anterior en el mismo subproceso. La sesión de eventos identifica eventos separados que se relacionan entre sí, y puede haber varios subprocesos de eventos para una sesión de eventos determinada.

Para las notificaciones, los diferentes tipos de eventos se agrupan en distintos hilos.

Google controla esta lógica de agrupación y sincronización de hilos, que está sujeta a cambios en cualquier momento. Un developer debe actualizar las notificaciones según los hilos de eventos y las sesiones que proporciona la API de SDM.

Estado de subprocesos

Los eventos que admiten notificaciones actualizables también tienen un campo eventThreadState que indica el estado del subproceso del evento en ese momento. Este campo tiene los siguientes valores:

  • STARTED: Es el primer evento de un subproceso de eventos.
  • UPDATED: Es un evento en un subproceso de eventos en curso. Puede haber cero o más eventos con este estado en un solo subproceso.
  • ENDED: Es el último evento de un subproceso de eventos, que puede ser un duplicado del último evento UPDATED, según el tipo de subproceso.

Este campo se puede usar para hacer un seguimiento del progreso de un subproceso de evento y de cuándo finalizó.

Filtrado de eventos

En algunos casos, es posible que los eventos detectados por un dispositivo se filtren para que no se publiquen en un tema de Pub/Sub de SDM. Este comportamiento se denomina filtrado de eventos. El propósito del filtrado de eventos es evitar que se publiquen demasiados mensajes de eventos similares en un período breve.

Por ejemplo, se puede publicar un mensaje en un tema de SDM para un evento de movimiento inicial. Los demás mensajes de Motion que se envíen después de eso se filtrarán y no se publicarán hasta que transcurra un período determinado. Una vez que transcurre ese período, se puede volver a publicar un mensaje de evento para ese tipo de evento.

En la app de Google Home (GHA), los eventos que se filtraron seguirán apareciendo en el historial de eventos de user. Sin embargo, estos eventos no generan una notificación de la app (incluso si ese tipo de notificación está habilitado).

Cada tipo de evento tiene su propia lógica de filtrado de eventos, que define Google y está sujeta a cambios en cualquier momento. Esta lógica de filtrado de eventos es independiente de la lógica de subprocesos y sesiones de eventos.

Cuentas de servicio

Se recomiendan las cuentas de servicio para administrar las suscripciones y los mensajes de eventos de la API de SDM. Una cuenta de servicio la usa una aplicación o máquina virtual, no una persona, y tiene su propia clave de cuenta única.

La autorización de la cuenta de servicio para la API de Pub/Sub usa OAuth de dos segmentos (2LO).

En el flujo de autorización de 2LO, ocurre lo siguiente:

  • El developer solicita un token de acceso con una clave de servicio.
  • developer usa el token de acceso con llamadas a la API.

Para obtener más información sobre 2LO de Google y cómo configurarlo, consulta Usa OAuth 2.0 para aplicaciones de servidor a servidor.

Autorización

La cuenta de servicio debe estar autorizada para usarse con la API de Pub/Sub:

  1. Habilita la API de Cloud Pub/Sub en Google Cloud.
  2. Crea una cuenta de servicio y una clave de cuenta de servicio como se describe en Crea una cuenta de servicio. Te recomendamos que solo le otorgues el rol de suscriptor de Pub/Sub. Asegúrate de descargar la clave de la cuenta de servicio en la máquina que usará la API de Pub/Sub.
  3. Proporciona tus credenciales de autenticación (clave de cuenta de servicio) al código de la aplicación siguiendo las instrucciones de la página del paso anterior o, si quieres probar rápidamente el acceso a la API, obtén un token de acceso de forma manual con oauth2l.
  4. Usa las credenciales de cuenta de servicio o el token de acceso con la API de Pub/Sub project.subscriptions para extraer y confirmar mensajes.

oauth2l

Google oauth2l es una herramienta de línea de comandos para OAuth escrita en Go. Instálala para Mac o Linux con Go.

  1. Si no tienes Go en tu sistema, primero descárgalo y, luego, instálalo.
  2. Una vez que se haya instalado Go, instala oauth2l y agrega su ubicación a la variable de entorno PATH:
    go install github.com/google/oauth2l@latest
    export PATH=$PATH:~/go/bin
  3. Usa oauth2l para obtener un token de acceso para la API con los permisos de OAuth adecuados:
    oauth2l fetch --credentials path-to-service-key.json --scope https://www.googleapis.com/auth/pubsub
    https://www.googleapis.com/auth/cloud-platform
    Por ejemplo, si tu clave de servicio se encuentra en ~/myServiceKey-eb0a5f900ee3.json:
    oauth2l fetch --credentials ~/myServiceKey-eb0a5f900ee3.json --scope https://www.googleapis.com/auth/pubsub
    https://www.googleapis.com/auth/cloud-platform
    ya29.c.Elo4BmHXK5...

Consulta el archivo README de oauth2l para obtener más información de uso.

Bibliotecas cliente de la API de Google

Hay varias bibliotecas cliente disponibles para las APIs de Google que usan OAuth 2.0. Consulta las bibliotecas cliente de la API de Google para obtener más información sobre el lenguaje que elijas.

Cuando uses estas bibliotecas con Pub/Sub API, usa las siguientes cadenas de alcance:

https://www.googleapis.com/auth/pubsub
https://www.googleapis.com/auth/cloud-platform

Errores

Es posible que se muestren los siguientes códigos de error relacionados con esta guía:

Mensaje de error RPC Solución de problemas
La imagen de la cámara ya no está disponible para descargar. DEADLINE_EXCEEDED Las imágenes de eventos vencen 30 segundos después de que se publica el evento. Asegúrate de descargar la imagen antes de que venza.
El ID del evento no pertenece a la cámara. FAILED_PRECONDITION Usa el eventID correcto que devuelve el evento de la cámara.

Consulta la Referencia de códigos de error de la API para ver la lista completa de códigos de error.