Некоторые устройства Matter состоят из нескольких конечных точек одного типа. Другие устройства Matter имеют иерархическую структуру, где конечные точки вложены друг в друга. В API Home оба типа устройств называются многокомпонентными устройствами .
Плоское изображение
До выпуска версии 1.8 API Home многокомпонентные устройства представлялись API Home как набор отдельных, не связанных между собой устройств. Это называется плоским представлением.
Например, одно настенное панельное устройство с четырьмя выключателями отображается в API Home как четыре отдельных и не связанных между собой устройства. А иерархическое устройство Matter , такое как холодильник, может быть представлено в API Home как набор устройств, каждое из которых соответствует одной из конечных точек.

Плоское изображение настенной панели с четырьмя выключателями.


Плоское изображение холодильника

Многокомпонентное представление
Начиная с версии 1.8 API Home, многокомпонентное устройство может быть представлено в API как одно устройство. Чтобы включить это поведение, вызовите метод devices() для Structure , Room или HomeManager и установите параметр 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 влияет на представление многокомпонентного устройства в API Home:

Многокомпонентное изображение стеновой панели.


Многокомпонентное изображение холодильника.

У вас всегда есть возможность получить плоское представление, либо опустив параметр enableMultipartDevices , либо установив его значение равным false .
Навигация по многокомпонентному устройству
В многокомпонентном устройстве каждый экземпляр компонента определенного типа называется частью .
Доступ к компонентам может осуществляться непосредственно либо на родительском устройстве, либо в иерархическом порядке с использованием типов устройств или семантических тегов Matter . Семантические теги реализованы в API Home с помощью DescriptorTrait.SemanticTagStruct .
Абстрактный класс 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()