您可以通过 Home API for Android 访问 Structure API。将以下软件包导入您的应用:
import com.google.home.Home
import com.google.home.Id
import com.google.home.Structure
错误处理
Home API 中的任何方法都可能抛出
HomeException,因此我们建议您使用 try-catch 块在所有调用中捕获 HomeException。
处理 HomeException 时,请检查其
error.code 和
error.message 字段,了解具体出错情况。可能还存在子错误代码,因此请调用
getSubErrorCodes() 方法并检查结果。
任何未处理的异常都会导致应用崩溃。
如需了解详情,请参阅错误处理。
示例通话
获取结构列表
初始化后,structures() 调用会返回一个 Flow 结构,您可以访问该结构:
// Get a flow of all structures accessible to the user val allStructuresFlow: HomeObjectsFlow<Structure> = home.structures() // Calling list() on a HomeObjectsFlow returns the first Set of elements. val allStructures: Set<Structure> = allStructuresFlow.list()
structures() API 是一个数据流,可能不会立即返回有效的结构列表。如果您的应用是响应式的,并且订阅了该数据流来驱动界面,则最终应返回有效的结构列表。
在其他情况下,也可能会返回空结构列表,例如,用户的手机失去连接,或者用户撤消了对应用的权限。您应确保在应用中处理这些情况。
或者,如果强烈要求使用命令式编程而非响应式编程,则可以使用终端流运算符:
val everyStructure = withTimeout(5000) { home.structures().first { it.isNotEmpty() } }
此调用会等待通过数据流传入有效的结构列表,如果未在应用指定的超时时间内收到该列表,则会超时。
获取结构体属性
有了结构列表后,您就可以访问其属性:
// Get a flow on a structure. Flow emits new values on structure metadata changes: name. val structureFlow: Flow<Structure> = home.structures().itemFlow(myStructureId) // Get a snapshot of the structure. val structure: Structure = structureFlow.first() // Get structure properties println("id ${structure.id}") println("name ${structure.name}")
按名称查找结构体
如果您知道结构的名称,也可以使用 name 属性访问该结构:
val myHome = home.structures().list().first { it.name == "My home" }
从这里,您可以访问每个结构的属性、房间和设备。
使用多个结构
如需使用多个结构,请分别获取对每个结构的引用:
var structure1: Structure? = null var structure2: Structure? = null try { structure1 = home.structures().list().firstOrNull { it.name == "Main House" } } catch (e: HomeException) { // Code for handling the exception } try { structure2 = home.structures().list().firstOrNull { it.name == "Guest Cottage" } } catch (e: HomeException) { // Code for handling the exception }
获取聊天室列表
获得结构后,您可以获取房间列表并访问其属性:
val allRoomsFlow: HomeObjectsFlow<Room> = structure.rooms() val allRooms: Set<Room> = allRoomsFlow.list() val room: Room = allRooms.first() println("id ${room.id}") println("name ${room.name}")
创建聊天室
如需创建新聊天室,请执行以下操作:
val testName = "Test Room Name" val newRoom: Room = structure.createRoom(testName)
删除房间
或者,您也可以删除房间:
val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull() structure.deleteRoom(roomToDelete!!)
您也可以仅使用 ID 删除房间:
val roomToDelete1 = allRooms.filter { it.id == testRoomId }.firstOrNull() structure.deleteRoom(roomToDelete1!!)
如果删除包含设备的房间,这些设备仍会保留在结构中,但不再分配给任何房间。
将设备移至其他房间
创建结构后,您可以将设备移至该结构中的其他房间:
val room2 = structure.rooms().get(Id("room_id_other_structure")) val device1 = structure.devices().get(Id("device_id1")) structure.moveDevicesToRoom(room2!!, listOf(device1!!))
如果您只有设备 ID 和会议室 ID,也可以移动设备:
structure.moveDevicesToRoom(Id("room_id_other_structure"), listOf(Id("device_id1")))
更改房间名称
调用 setName() 方法来更改房间名称:
livingRoom.setName("Living Room")
如果名称超过 60 个 Unicode 码位(字符)限制,则会被截断,并且不会抛出任何错误。开发者负责处理长名称,例如,可以决定是否要告知用户名称将被截断。
查看用户已授予权限的设备类型
在 Google Home 生态系统中,对于大多数设备类型,用户可以一次性授予该类型所有设备的权限。对于敏感或受限的设备类型(例如门锁、摄像头或门铃),用户必须单独授予权限。
如需确定用户是否已授予访问敏感或受限设备类型的权限,请使用结构级 consentedDeviceTypes() 函数:
import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/**
* Example of how an app may monitor which device types have been granted access by a user.
*/
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
// Obtain the flow of consented device type factories
val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
structure.consentedDeviceTypes()
myScope.launch {
consentedTypesFlow.collect { consentedSet ->
// Check if the user has consented to share a specific restricted
// type, such as a Doorbell or Camera.
val hasCameraAccess = consentedSet.any {
it.toString() == "matter.google.type.GoogleDoorbellDevice"
}
if (hasCameraAccess) {
// Enable features that require camera access
} else {
// Inform the user or disable camera-specific features
}
}
}
}
设备组
设备组表示单个结构中由用户定义的一组设备。群组成员资格会保留在 Google 服务中,并且对住宅的其他成员以及有权访问住宅的其他应用可见。
与实体房间一样,设备组也属于单个结构。但与房间不同,设备组是逻辑分组。一个设备可以同时属于多个设备组。设备组最多可包含 100 台设备。
设备组由DeviceGroup 实体表示,该实体不同于 HomeDevice。如需查询设备组并与之互动,请在初始化 FactoryRegistry 时,将 DeviceGroup 包含在 entityTypes 列表中,同时包含 Group、GroupManagement 和 GroupMembership 特征。
您可以通过直接遍历群组中的成员设备(请参阅与群组成员设备互动)或定位到 DeviceGroup 上的设备类型部分(请参阅控制设备组)来与群组中的设备互动。
获取设备组列表
如需观察结构中的所有设备组,请调用 home.entities(DeviceGroup) 并按结构 ID 进行过滤:
home.entities(DeviceGroup).collect { allGroups ->
val structureGroups = allGroups.filter { it.structureId == structure.id }
for (group in structureGroups) {
val groupName = group.trait(Group)?.Name
println("Found group: $groupName with ID: ${group.id.id}")
}
}
与群组成员设备互动
使用 group.devices() 遍历群组的成员设备,您可以精细控制各个成员,在单个请求中批量执行命令,以及跨成员汇总或写入属性。
例如,如需发送单个批量请求,其中包含针对群组中所有兼容成员的特征的命令,请使用以下命令:
val members = group.devices(enableMultipartDevices = true).first()
val onOffTraits = members.mapNotNull { device ->
device.partOrNull(OnOffLightDevice).first()?.standardTraits?.onOff
}
val responses = home.sendBatchedCommands {
onOffTraits.map { onOff ->
add(onOff.onBatchable())
}
}
for (response in responses) {
response.getOrThrow()
}
您还可以更新组中所有匹配的成员设备上的属性(例如,在所有 DimmableLightDevice 成员上将 onTransitionTime 设置为 1u),并等待在截止日期前完成:
val members = group.devices(enableMultipartDevices = true).first()
withTimeout(5.seconds) {
members.map { device ->
async {
val light = device.partOrNull(DimmableLightDevice).first()
val levelControl = light?.standardTraits?.levelControl
if (
levelControl?.supports(
LevelControl.Attribute.onTransitionTime
) == true
) {
levelControl.update { setOnTransitionTime(1u) }
}
}
}.awaitAll()
}
如需汇总群组中各成员的属性,例如查找群组中所有色温灯的最小 colorTempPhysicalMaxMireds,请执行以下操作:
val members = group.devices(enableMultipartDevices = true).first()
val minMaxMireds: UShort? = members.mapNotNull { device ->
val light = device.partOrNull(ColorTemperatureLightDevice).first()
light?.standardTraits?.colorControl?.colorTempPhysicalMaxMireds
}.minOrNull()
创建设备组
对结构使用 GroupManagement 可创建设备组:
val groupManagement = structure.trait(GroupManagementTrait)
val response = groupManagement?.createUserDefinedGroup(
name = "Living room lights",
memberDeviceObjectIds = listOf(light1.id.id, light2.id.id)
)
管理群组成员资格
如需向现有群组添加成员,请执行以下操作:
structure.trait(GroupManagementTrait)?.addGroupMembers(
groupObjectId = group.id.id,
memberDeviceObjectIds = listOf(light3.id.id)
)
如需从群组中移除成员,请执行以下操作:
structure.trait(GroupManagementTrait)?.removeGroupMembers(
groupObjectId = group.id.id,
memberDeviceObjectIds = listOf(light1.id.id)
)
更改设备组的名称
如需重命名设备组,请更新该组的 GroupTrait 上的名称属性:
group.trait(GroupTrait)?.update {
name = "Movie corner"
}
删除设备组
如需从住宅中删除设备组,请执行以下操作:
structure.trait(GroupManagementTrait)?.deleteGroup(
groupObjectId = group.id.id
)
自动化操作
Automation API 的入口点是通过结构。如需详细了解 Home API 中的自动化操作,请参阅 Android 上的自动化操作 API 概览。