某些 Matter 设备由多个具有 相同设备类型的端点组成。其他 Matter 设备采用 分层结构,端点嵌套在其他端点内。在 Home API 中,这两种设备都称为多部分设备 。
平面表示法
在 Home API 1.8 版发布之前,多部分设备在 Home API 中表示为一组单独且不相关的设备。这称为平面表示法 。
例如,一个带有四个开关的单壁面板设备在 Home API 中显示为四个不同的且不相关的设备。而冰箱等分层 Matter设备在 Home API 中可能表示为一组设备,每个设备对应一个端点。
4 开关壁面板的平面表示法。
冰箱的平面表示法
多部分表示法
从 Home API 1.8 版开始,多部分设备可以在 API 中表示为单个设备。如需启用此行为,请对 Structure、Room 或 HomeManager 调用 devices() 方法,并将 enableMultipartDevices 参数设置为 true:
let devices = try await self.home.devices(enableMultipartDevices: true).list() let device = try XCTUnwrap(devices.first { $0.id == powerstripID }) let outlets = try await device.types.getAll(of: OnOffPluginUnitDeviceType.self)
下图说明了 enableMultipartDevices 选项如何影响 Home API 中多部分设备的表示法:
壁面板的多部分表示法。
冰箱的多部分表示法。
您可以随时选择获取平面表示法,方法是省略 enableMultipartDevices 参数,或将其设置为 false。
浏览多部分设备
在多部分设备中,设备类型的每个组件实例称为一个部分 。
可以使用设备类型或 Matter 语义
标记,以
分层方式直接访问父设备或某个部分中的部分。语义标记在 Home API 中通过
DescriptorTrait.SemanticTagStruct实现。
The DeviceType 抽象类
实现了
HasParts 接口,
让开发者可以通过
parts 属性和
part()
方法浏览设备树。每个部分实例也实现了 HasParts 接口,因此对某个部分调用 parts() 会生成一个包含零个或多个子部分的列表。
以下示例展示了如何访问多开关设备的部分:
val device = homeManager .devices(enableMultipartDevices = true) .itemFlow(Id(MULTI_SWITCH_DEVICE)) .first() // Here at top-level, we are using the homeDevice.parts() API to access flow of // all the switches. Then we get the part ids. val partIds = device .parts() .map { parts -> parts.filter { it.has(Switch) }.mapNotNull { it.metadata.partId } } .first() .toSet()
下一个示例展示了如何访问冰箱设备的部分:
val rootDevice = homeManager.devices(true).itemFlow(Id("device@uuid1")) // On the top level, HomeDevice provides both plural (parts) // and singular (part) APIs. // The parts() API returns all the parts accessible from the top level, // including Endpoint 0 and its children. val childParts = rootDevice.parts().first() // childParts contain (EP0 as RootNode, EP1 as Refrigerator) // The singular part() API accepts DeviceType and tags (optional). val refrigerator = rootDevice.part(Refrigerator).first() // Get the refrigerator device which in this case is just device@uuid1 val refrigeratorDevice = homeManager.devices(false).itemFlow(refrigerator.metadata.partId.deviceId) // DeviceType uses a synchronous API for providing access to parts val cabinets = refrigerator.parts // [EP2, EP3] // Get the HomeDevice for these cabinets (device@uuid2 and device@uuid3) val cabinetDeviceIds = cabinets.map { it.metadata.partId } // Now use the devices API with enableMultipartDevices = false. val cabinetDevices = homeManager.devices(false) .map { devices -> devices.filter { it.id in cabinetDeviceIds } }.first()