事件是异步的,并由 Google Cloud Pub/Sub 管理,每个 Project一个主题中。事件可为所有设备和结构提供更新,并能保证可以接收事件,前提是用户未撤消访问令牌且事件消息未过期。
允许显示活动
事件是 SDM API 的可选功能。请参阅 启用事件 ,了解如何为您的 Project启用这些事件。
Google Cloud Pub/Sub
请参阅 Google Cloud Pub/Sub 文档,详细了解 Pub/Sub 的工作原理。具体而言:
- 通过方法指南了解 Pub/Sub 的基础知识。
- 了解身份验证的工作原理。
- 选择提供的客户端库,或自行编写并使用 REST/HTTP 或 gRPC API surface。
事件订阅
为您的 Project启用事件后,系统会为您提供特定于该 Project ID 的主题,格式如下:
projects/sdm-prod/topics/enterprise-project-id
如需接收事件,请根据您的使用场景创建对该主题的pull或push订阅。支持对 SDM 主题进行多个订阅。如需了解详情,请参阅管理订阅。
发起活动
如需在创建 Pub/Sub 订阅后首次启动事件,请进行
devices.list
API 调用作为一次性触发器。所有结构和设备的事件都将在此调用后发布。
如需查看示例,请参阅快速入门指南中的授权页面。
事件顺序
Pub/Sub 不保证按顺序传送事件,并且事件的接收顺序可能与事件实际发生的顺序不相符。使用 timestamp
字段来帮助协调事件订单。事件还可能单独到达或合并为一条事件消息。
如需了解详情,请参阅为消息排序。
用户 ID
如果您的实现基于用户(而不是结构或设备),请使用事件载荷中的 userID
字段来关联资源和事件。此字段是代表特定用户的经过混淆处理的 ID。
userID
也可以在每个 API 调用的 HTTP 响应标头中找到。
关系事件
关系事件表示资源的关系更新。例如,当设备被添加到结构中或从结构中删除设备时。
关系事件有三种类型:
- 已创建
- DELETED
- 已更新
关系事件的载荷如下所示:
载荷
{ "eventId" : "eed9763a-8735-45d9-81d9-e0621c130eb1", "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
是触发事件的资源,subject
是 object
现在与其有关系的资源。在上面的示例中, user 已向 developer授予了对此特定设备的访问权限,并且 user的授权设备现在与其授权的结构相关,这会触发该事件。
subject
只能是房间或结构。如果 a developer 无权查看 user的结构,则 subject
始终为空。
字段
字段 | 说明 | 数据类型 |
---|---|---|
eventId |
事件的唯一标识符。 | string 示例:“1362476b-4ac4-4608-a8be-4c8cf4101426” |
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" }
DELETED
结构已删除
"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" : "5b98a768-6771-4d4d-836d-58cce3a62cca",
"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" : "3426d266-406b-48f3-9595-5192229a39a0",
"timestamp" : "2019-01-01T00:00:01Z",
"resourceUpdate" : { "name" : "enterprises/project-id/devices/device-id", "events" : { "sdm.devices.events.CameraMotion.Motion
" : { "eventSessionId" : "CjY5Y3VKaTZwR3o4Y19YbTVfMF...", "eventId" : "8XZ1cQ76Becovj551YfM9ZnuwB...", } } } "userId" : "AVPHwEuBfnPOnTqzVFT4IONX2Qqhu9EJ4ubO-bNnQ-yi",
"eventThreadId" : "d67cd3f7-86a7-425e-8bb3-462f92ec9f59",
"eventThreadState" : "STARTED",
"resourceGroup" : [ "enterprises/project-id/devices/device-id" ] }
这些类型的资源事件在特定特征中定义。例如,动作事件是在 CameraMotion 特征中定义的。请参阅每个特征的文档,了解这些类型资源事件的载荷格式。
字段
字段 | 说明 | 数据类型 |
---|---|---|
eventId |
事件的唯一标识符。 | string 示例:“3426d266-406b-48f3-9595-5192229a39a0” |
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 处理,随时可能会发生变化。 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 使用服务密钥请求访问令牌。
- developer 通过调用 API 来使用访问令牌。
如需详细了解 Google 2LO 及其设置方法,请参阅针对“服务器到服务器”应用使用 OAuth 2.0。
授权
该服务帐号应获得授权,可以与 Pub/Sub API 配合使用:
- 在 Google Cloud 中启用 Cloud Pub/Sub API。
- 按照创建服务帐号中的说明创建服务帐号和服务帐号密钥。我们建议仅为其授予 Pub/Sub Subscriber 角色。请务必将服务帐号密钥下载到将使用 Pub/Sub API 的机器上。
- 按照上一步中的说明向应用代码提供身份验证凭据(服务帐号密钥),或者如果您想快速测试 API 访问权限,请使用
oauth2l
手动获取访问令牌。 - 使用服务帐号凭据或访问令牌与 Pub/Sub
project.subscriptions
API 拉取和确认消息。
OAuth2L
Google oauth2l
是用 Go 编写的 OAuth 命令行工具。使用 Go 安装适用于 Mac 或 Linux 的 OAuth 命令行工具。
- 如果您的系统尚未安装 Go,请先下载并安装 Go。
- 安装 Go 后,安装
oauth2l
并将其位置添加到您的PATH
环境变量中:go install github.com/google/oauth2l@latest
export PATH=$PATH:~/go/bin
- 使用
oauth2l
通过适当的 OAuth 范围获取 API 的访问令牌:
。例如,如果您的服务密钥位于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
自述文件。
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 错误代码参考。