活动

事件是异步的,并由 Google Cloud Pub/Sub 在每个 Project主题中进行管理。事件可为所有设备和结构提供更新,只要用户未撤消访问令牌且事件消息未 过期,就可确保收到事件。

允许显示活动

事件是 SDM API 的可选功能。如需了解如何为 Project启用事件,请参阅允许显示活动

Google Cloud Pub/Sub

如需详细了解 Pub/Sub 的工作原理,请参阅Google Cloud Pub/Sub 文档。具体而言:

事件订阅

在 2025 年 1 月之前,如果为启用了事件,系统会以以下形式为您提供特定于该 ID 的主题: ProjectProject

projects/gcp-project-name/subscriptions/topic-id
在 2025 年 1 月之后创建的项目必须自行托管其 Pub/Sub 主题,并且您需要提供自己的主题 ID。如需了解详情,请参阅 创建主题

如需接收事件,请根据您的使用场景,为该主题创建拉取订阅或 推送订阅。支持对 SDM 主题进行多项订阅。如需了解详情,请参阅 管理订阅

启动事件

如需在创建 Pub/Sub 订阅后首次启动事件,请进行 devices.list API 调用作为一次性触发器。此调用后,所有结构和设备的事件都将发布。

如需查看示例,请参阅快速入门 指南中的 授权页面。

事件顺序

Pub/Sub 不保证事件的有序传递,并且事件的接收顺序可能不 与事件实际发生的顺序不符。使用 timestamp 字段有助于协调事件顺序。事件也可能单独到达,或者合并到单个事件消息中 。

如需了解详情,请参阅 对消息排序

用户 ID

如果您的实现基于用户(而非结构或设备),请使用事件载荷中的 userID 字段来关联资源和事件。此字段是 表示特定用户的混淆 ID。

您还可以在每个 API 调用的 HTTP 响应标头中找到 userID

关系事件

关系事件表示资源的关系更新。例如,将设备 添加到结构时,或从结构中删除设备时。

关系事件分为三种类型:

  • CREATED
  • 已删除
  • 已更新

关系事件的载荷如下所示:

载荷

{
  "eventId" : "465db104-bacc-41df-88ec-2a9b1888c998",
  "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"
}

在关系事件中,object 是触发事件的资源, subjectobject 现在与之建立关系的资源。在上面的 示例中,已向 user 授予对此特定设备的访问权限,并且 developer的授权设备现在与其授权 user结构相关联,从而触发事件。

subject 只能是房间或结构。如果 a developer 无权查看 的结构,则 subject 始终 为空。 user

字段

字段 说明 数据类型
eventId 事件的唯一标识符。 string
示例:"d31091a1-4e8a-4600-87e1-943f93ad5ad0"
timestamp 事件发生的时间。 string
示例:"2019-01-01T00:00:01Z"
relationUpdate 详细说明关系更新信息的对象。 object
userId 代表用户的唯一、经过混淆处理的标识符。 string
示例:"AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi"

如需详细了解不同类型的事件及其运作方式,请参阅事件

示例

每种类型的关系事件的事件载荷都不同:

创建时间

创建结构

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

创建设备

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

创建设备

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

已更新

设备已移动

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

已删除

已删除结构

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

已删除设备

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

已删除设备

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

在以下情况下,系统不会发送关系事件:

  • 房间被删除

资源事件

资源事件表示特定于资源的更新。它可能是对特性字段值更改的响应,例如更改温控器的模式。 它还可以表示不更改特性字段的设备操作,例如按设备按钮。

为响应特性字段值的更改而生成的事件包含一个 traits 对象,类似于设备 GET 调用:

载荷

{
  "eventId" : "98d6b069-a607-4fea-8512-ce78b8d61458",
  "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"
  ]
}

使用 各个 特性文档了解任何特性字段更改资源 事件的载荷格式。

为响应不更改特性字段的设备操作而生成的事件也有一个 包含 resourceUpdate 对象的载荷,但包含的是 events 对象 而不是 traits 对象:

载荷

{
  "eventId" : "50ae838d-42fd-48b7-b46b-4c24f97787a5",
"timestamp" : "2019-01-01T00:00:01Z",
"resourceUpdate" : { "name" : "enterprises/project-id/devices/device-id", "events" : { "sdm.devices.events.CameraMotion.Motion" : { "eventSessionId" : "CjY5Y3VKaTZwR3o4Y19YbTVfMF...", "eventId" : "fmLARdlpNMN9IiXyXjElNP1ZiI...", } } } "userId" : "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi",
"eventThreadId" : "d67cd3f7-86a7-425e-8bb3-462f92ec9f59",
"eventThreadState" : "STARTED",
"resourceGroup" : [ "enterprises/project-id/devices/device-id" ] }

这些类型的资源事件在特定特性中定义。例如, Motion 事件在 CameraMotion trait 中定义。如需了解这些类型的资源事件的载荷格式,请参阅每个特性的文档 。

字段

字段 说明 数据类型
eventId 事件的唯一标识符。 string
示例:"50ae838d-42fd-48b7-b46b-4c24f97787a5"
timestamp 事件发生的时间。 string
示例:"2019-01-01T00:00:01Z"
resourceUpdate 详细说明资源更新信息的对象。 object
userId 代表用户的唯一、经过混淆处理的标识符。 string
示例:"AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi"
eventThreadId 事件线程的唯一标识符。 string
示例:"d67cd3f7-86a7-425e-8bb3-462f92ec9f59"
eventThreadState 事件线程的状态。 string
值:"STARTED"、"UPDATED"、"ENDED"
resourceGroup 一个对象,用于指示可能与此事件有类似更新的资源。 事件本身的资源(来自 resourceUpdate 对象)将始终存在于此对象中。 object

如需详细了解不同类型的事件及其运作方式,请参阅事件

可更新的通知

基于资源事件的通知可以在应用(例如 Android 或 iOS 应用)中实现。为了减少发送的通知数量,可以实现一项名为可更新的通知 的功能,该功能会根据同一事件线程中的后续事件,使用新信息更新现有通知。

选择事件功能支持可更新的通知,并在文档中标记为 可更新  。这些事件的载荷中有一个名为 eventThreadId 的额外字段。使用此字段将各个事件关联在一起,以便更新已向用户显示的现有通知。

事件线程与事件会话不同。 事件线程 用于标识同一线程中先前事件的更新状态。事件会话 用于标识彼此相关的单独事件,并且给定事件会话可以有多个事件线程。

出于通知目的,不同类型的事件会分组到不同的线程中。

此线程分组和计时逻辑由 Google 处理,并且可能会随时更改。A developer 应根据 SDM API 提供的 事件线程和会话更新通知。

线程状态

支持可更新通知的事件还有一个 eventThreadState 字段,用于指示事件线程在当时的状态。此字段具有以下值:

  • STARTED - 事件线程中的第一个事件。
  • UPDATED - 正在进行的事件线程中的事件。单个线程中可以有零个或多个具有此状态的事件。
  • ENDED - 事件线程中的最后一个事件,它可能是最后一个 UPDATED 事件的重复项,具体取决于线程类型。

此字段可用于跟踪事件线程的进度以及事件线程何时结束。

事件过滤

在某些情况下,设备检测到的事件可能会被过滤掉,而无法发布到 SDM Pub/Sub 主题。这种行为称为事件过滤 。事件过滤的目的是避免在短时间内发布过多类似的事件消息。

例如,系统可能会针对初始动作事件向 SDM 主题发布消息。之后,其他 Motion 消息将被过滤掉,直到经过设定的时间段后才会发布。经过该时间段后,系统可能会再次发布该事件类型的事件消息。

在 Google Home 应用 (GHA) 中,过滤掉的事件仍会显示在 user的事件记录中。不过,此类事件不会生成应用通知(即使启用了该通知类型)。

每种类型的事件都有自己的事件过滤逻辑,该逻辑由 Google 定义,并且可能会随时更改。此事件过滤逻辑独立于事件线程和会话逻辑。

服务账号

建议使用服务账号来管理 SDM API 订阅和事件消息。服务账号由应用或虚拟机(而非个人)使用,并且有自己的唯一账号密钥。

Pub/Sub API 的服务账号授权使用二足式 OAuth (2LO)。

在 2LO 授权流程中:

  • 使用服务密钥请求访问令牌。 developer
  • 使用访问令牌调用 API。 developer

如需详细了解 Google 2LO 以及如何进行设置,请参阅 将 OAuth 2.0 用于服务器到服务器 应用

授权

服务账号应获得使用 Pub/Sub API 的授权:

  1. 在 Google Cloud 中启用 Cloud Pub/Sub API
  2. 按照 创建服务账号中的说明创建服务账号和服务账号密钥。 我们建议仅向其授予 Pub/Sub 订阅者 角色。请务必将服务账号密钥下载到将使用 Pub/Sub API 的机器。
  3. 按照上一步中的页面上的说明向您的应用代码提供您的身份验证凭据(服务账号密钥),或者如果您想快速测试 API 访问权限,请使用 oauth2l 手动获取访问令牌。
  4. 将服务账号凭据或访问令牌与 Pub/Sub project.subscriptions API 结合使用,以拉取和确认消息。

oauth2l

Google oauth2l 是一个用 Go 编写的 OAuth 命令行工具。使用 Go 为 Mac 或 Linux 安装它。

  1. 如果您的系统上没有 Go,请先下载并安装它
  2. 安装 Go 后,安装 oauth2l 并将其位置添加到 PATH 环境变量:
    go install github.com/google/oauth2l@latest
    export PATH=$PATH:~/go/bin
  3. 使用 oauth2l 获取 API 的访问令牌,使用适当的 OAuth 范围:
    oauth2l fetch --credentials path-to-service-key.json --scope https://www.googleapis.com/auth/pubsub
    https://www.googleapis.com/auth/cloud-platform
    例如,如果您的服务钥匙位于 ~/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...

如需了解更多使用 信息,请参阅 oauth2l README

Google API 客户端库

有多个客户端库可用于利用 OAuth 2.0 的 Google API。如需详细了解您选择的 语言,请参阅 Google API 客户端库

将这些库与 Pub/Sub API结合使用时,请使用以下范围字符串:

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

错误

可能会返回与本指南相关的以下错误代码:

错误消息 RPC 问题排查
无法再下载相机图片。 DEADLINE_EXCEEDED 事件图片会在事件发布 30 秒后过期。请务必在过期之前下载图片。
事件 ID 不属于相机。 FAILED_PRECONDITION 使用摄像头记录的事件返回的正确 eventID

如需查看完整的 API 错误代码列表,请参阅 API 错误代码参考文档