您可以通过适用于 iOS 的 Home API 访问设备 API。 将以下软件包导入您的应用:
import GoogleHomeSDK
import GoogleHomeTypes
如需了解详情,请参阅 iOS 上的数据模型。
错误处理
Home API 中的某些方法会抛出
HomeError,因此我们建议您使用 do-catch 块来捕获这些调用中的
HomeError。
处理 HomeError 时,请检查其 code 和 message
字段,了解具体出错情况。
任何未处理的错误都会导致应用崩溃。
如需了解详情,请参阅 错误处理。
如需查看示例,请参阅向设备发送命令 。
示例调用
获取设备列表
通过对 Home
对象的引用,调用
devices() 以获取可访问
设备的
Query。调用 Query's
batched()
方法,该方法会在每次
设备元数据更改时发出一个反映 Home 当前状态的 Set。或者,调用
Query.list() 以获取可用设备的
快照。这是一种便捷方法,用于订阅 batched() 流并返回第一个发出的值。
Query.stream()
会生成一个流,该流会在设备元数据(例如名称、房间或结构)发生更改时发出新值。在内部,此方法使用 batched(),并且仅发出已更改的属性。
// Get a list of all devices accessible to the user let homeDevices = try await self.home.devices().list()
这样一来,您便可以访问每个设备的状态并向设备发送命令。
借助 Home API 的 1.8 版,您可以选择将 API 设置为将每个多部分设备表示为单个设备,方法是将 devices() 方法的 enableMultipartDevices 参数设置为 true。如需了解详情,请参阅
iOS 上的多部分设备。
获取设备的类型
如需获取与设备关联的设备类型,请读取设备的
types
属性,该属性会返回
DeviceTypeController。
调用 DeviceTypeController.subscribe(_:) 以订阅特定设备类型的更新:
let devices = try await self.home.devices().list() if let device = devices.first(where: { $0.id == myDeviceId }) { var receivedUpdate1 = false var receivedUpdate2 = false device.types.subscribe(OnOffLightDeviceType.self) .assertNoFailure() .sink { device in if !receivedUpdate1 { receivedUpdate1 = true Task { try await device.matterTraits.onOffTrait?.on() } return } if !receivedUpdate2 { receivedUpdate2 = true return } fatalError("Received unexpected update") } }
如果设备不支持指定的设备类型,则会返回一个立即完成的 Empty
Publisher。
如果设备支持特定设备类型,您可以通过调用 get() 获取该类型的句柄:
if let device = devices.first(where: { $0.id == myDeviceId }) { let _ = await device.types.get(OnOffLightDeviceType.self) }
如果设备不支持指定的类型,则会返回 nil。
调用
DeviceTypeController.subscribeAll()
以获取 Publisher 的
DeviceTypeCollection。
借助此类,您可以检查设备是否具有特定设备类型:
if let device = devices.first(where: { $0.id == myDeviceId }) { device.types.subscribeAll() .assertNoFailure() .sink { types in let lightDeviceType = types[OnOffLightDeviceType.self] let fanDeviceType = types[FanDeviceType.self] } }
获取设备类型特征
设备类型是读取特征的入口点,因为它们会将设备分解为功能部件(例如 Matter 中的端点)。Matter
它们还会考虑特征冲突,以防设备具有两种设备类型,而这两种设备类型可能具有相同的特征。例如,如果设备既是扬声器又是可调光灯,则它将具有两个“开/关”特征和两个“级别控制”特征。
当设备具有两个名称相同的特征时,可能会发生另一种特征冲突。例如,onOff 可能指的是标准 OnOff 特征的实例,也可能指的是制造商定义的 OnOff 特征的实例。为了消除有关预期特征的任何潜在歧义,请通过每种设备类型上的两个特征集合之一引用特征。
对于标准特征(即与
Matter标准集群类似的特征),请使用matterTraits。例如,如需获取可调光灯设备类型的特定特征,请执行以下操作:
if let dimmableLightDeviceType = await device.types.get(DimmableLightDeviceType.self) { // Accessing standard trait on the type. let levelControlTrait = dimmableLightDeviceType.matterTraits.levelControlTrait.self }
对于 Google 特征,请使用 googleTraits:
if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) { // Accessing Google trait on the type. let doorbellPressTrait = doorbellDeviceType.traits[Google.DoorbellPressTrait.self] }
如需访问制造商特定的特征,请通过 traits 属性引用该特征,但请在前面加上制造商的软件包名称:
let deviceType = await device1?.types.get(OnOffLightDeviceType.self) // Accessing custom trait on the type. if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] { let rpmVal = spinnerTrait.attributes.rpm }
读取设备状态
请查看以下示例,了解如何检查设备“开/关”特征中的 OnOff 属性:
let lightDevices = devices.filter { $0.types.contains(OnOffLightDeviceType.self) } let light1 = lightDevices.first let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self) if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait { let onOffVal = onOffTrait.attributes.onOff }
获取具有特定特征的设备列表
如需获取具有特定特征的设备列表,您需要遍历设备、每个设备的设备类型以及每个设备类型的特征。 例如,如需获取家中所有具有“开/关”特征的设备列表,请执行以下操作:
// Get all light devices that support levelControl var levelControlDevices: [HomeDevice] = [] let allDevices = try await home.devices().list() for device in allDevices { if let deviceType = await device.types.get(OnOffLightDeviceType.self) { if deviceType.traits.contains(Matter.LevelControlTrait.self) { levelControlDevices.append(device) } } }
如需查看 Home API 中提供的特征的完整列表,请参阅 iOS 上的特征索引 。
获取具有类似设备类型的设备列表
如需获取表示家中所有灯具的设备列表,请执行以下操作:
// Get a list of devices with similar device types (lights) let lightDevices = try await self.home.devices().list().compactMap { $0.types.contains(DimmableLightDeviceType.self) || $0.types.contains(OnOffLightDeviceType.self) || $0.types.contains(ColorTemperatureLightDeviceType.self) || $0.types.contains(ExtendedColorLightDeviceType.self) }
Home API 中有多种设备类型可以表示核心设备类型。例如,没有“灯具”设备类型。相反,如上例所示,有四种不同的设备类型可以表示灯具。因此,如需全面了解家中的更高级别设备类型,必须包含多种设备类型。
如需查看 Home API 中提供的设备类型及其特征的完整列表,请参阅 iOS 上支持的设备类型 。
获取设备的供应商名称、供应商 ID 或商品 ID
BasicInformationTrait
特征包含供应商 ID、商品 ID、商品名称和
设备序列号等信息:
guard let vendorName = basicInfoTrait.attributes.vendorName else { fatalError("Failed to get vendorName") } guard let vendorID = basicInfoTrait.attributes.vendorID else { fatalError("Failed to get vendorID") } guard let productID = basicInfoTrait.attributes.productID else { fatalError("Failed to get productID") }
面向设备制造商的云到云设备标识
如果您是设备制造商并构建 Cloud-to-cloud 设备,
为了通过
Cloud-to-cloud 设备标识您的
BasicInformation 特征,您可以在
其 SYNC 响应中添加以下字符串字段:
Connectivity Standards Alliance (Alliance) 发布的供应商 ID:
"matterOriginalVendorId": "0xfff1",用于唯一标识供应商产品的商品标识符:
"matterOriginalProductId": "0x1234",设备的唯一标识符,以 制造商特定的方式构建:
"matterUniqueId": "matter-device-id",
输入这些字符串字段时,请使用您的 Matter
供应商 ID 和商品 ID(如果有)。如果您不是
Alliance成员且未获分配这些 ID,则可以
将 matterOriginalVendorId 和 matterOriginalProductId 字段留空
并提供 matterUniqueId 作为标识符。
示例 SYNC 响应展示了这些字段的用法:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"agentUserId": "1836.15267389",
"devices": [
{
"id": "456",
"type": "action.devices.types.LIGHT",
"traits": [
"action.devices.traits.OnOff",
"action.devices.traits.Brightness",
"action.devices.traits.ColorSetting",
],
"willReportState": true,
"deviceInfo": { ... },
"matterOriginalVendorId": "0xfff1",
"matterOriginalProductId": "0x1234",
"matterUniqueId": "matter-device-id",
"otherDeviceIds": [
{
"deviceId": "local-device-id",
}
]
}
]
}
}
如需了解详情,请参阅
Cloud-to-cloud SYNC 文档。
设备和特征元数据
Home API 中的设备和特征具有与其关联的元数据,这些元数据有助于管理应用中的用户体验。
Home API 中的每个特征都包含一个
sourceConnectivity
属性,其中包含有关特征的在线状态和本地性
(本地或远程路由)的信息。
获取设备的主要类型
某些设备可能会通过 Home API 显示多种设备类型。 为了确保在应用中向用户显示适合其设备的相关选项(例如设备控制和建议的自动化),检查设备类型是否为设备的主要类型非常有用。
if let deviceType = await device?.types.get(HumiditySensorDeviceType.self) { if deviceType.metadata.isPrimaryType { print("Humidity Sensor is the primary type on this device.") } else { print("Humidity Sensor isn't the primary type on this device.") } }
检查特征是否在线
读取 connectivityState 属性以检查特征的连接:
let levelControlConnectivity = levelControlTrait.metadata.sourceConnectivity .connectivityState
如果设备未连接到互联网,某些特征(通常是 Google smart home 特征)可能会显示 为离线。这是因为这些特征基于云,没有本地路由。
检查设备的连接
实际上,设备的连接是在设备类型级别进行检查的,因为某些设备支持多种设备类型。返回的状态是该设备上所有特征的连接状态的组合。
let lightConnectivity = dimmableLightDeviceType.metadata.sourceConnectivity .connectivityState
如果没有互联网连接,对于混合设备类型,可能会观察到 partiallyOnline 状态。Matter标准
特征可能仍处于在线状态,但基于云的特征将处于
离线状态。
获取设备的 IP 地址
如需查找设备的 IP 地址,请使用 networkInterfaces 属性
的
GeneralDiagnosticsTrait。
地址以 Data 对象的形式返回,您可以使用 Network 框架将其格式化为标准 IPv4 或 IPv6 字符串:
func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
let interfaces = trait.attributes.networkInterfaces ?? []
var ipAddresses: [String] = []
for interface in interfaces {
for data in interface.iPv4Addresses {
if let ipv4 = IPv4Address(data) {
ipAddresses.append(String(describing: ipv4))
}
}
for data in interface.iPv6Addresses {
if let ipv6 = IPv6Address(data) {
ipAddresses.append(String(describing: ipv6))
}
}
}
return ipAddresses
}
检查特征的网络路由
Home API 中还提供了特征的本地性。dataSourceLocality 指示特征是远程路由(通过云)、本地路由(通过本地 hub)还是对等路由(直接从设备到设备,没有 hub)。
未知本地性值 unspecified 是可能的,例如,当应用启动且尚未连接到 hub 或服务器以进行设备连接时。这些设备无法访问,并且来自命令或事件的互动请求将失败。客户端可以自行决定如何处理此类设备。
let levelControlLocality = levelControlTrait.metadata.sourceConnectivity .dataSourceLocality
检查设备的网络路由
与连接一样,本地性是在设备类型级别进行检查的。返回的状态是该设备上所有特征的本地性的组合。
let lightLocality = dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality
在与 partiallyOnline 连接类似的情况下,可能会观察到 mixed 状态:某些特征基于云,而另一些特征是本地特征。
更改设备的名称
调用
setName(_:)
方法以更改设备的名称:
let updatedDevice = try await theDevice.setName("new device name")
更改设备的名称时,原始 HomeDevice 结构体保持不变,并且更改会反映在返回的更新后的 HomeDevice 对象中。
如果名称超过 60 个 Unicode 码位(字符)的限制,系统会截断名称,并且不会抛出任何错误。开发者负责处理长名称,例如,可以决定是否告知用户名称将被截断。