Устройства с несколькими частями на Android

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

Плоское представление

До выпуска 1.8 Home API составные устройства представлялись в Home API как набор отдельных, не связанных между собой устройств. Это называется плоским представлением.

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

  • Пример настенной панели с несколькими переключателями, показывающий нативное представление Matter и плоское представление Home API

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

  • Пример с холодильником, показывающий нативное представление Matter и плоское представление Home API

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

Рисунок 1. Примеры плоского рендеринга.

Составное представление

Начиная с версии 1.8 Home API, составное устройство может быть представлено в API как одно устройство. Чтобы включить эту функцию, вызовите метод devices() для Structure, Room или HomeManager и задайте для параметра enableMultipartDevices значение true:

var multipartDevice = structure.devices(enableMultipartDevices = multipartEnabled)
var multipartDevice = multipartDevices.list().filter{ device ->  device.has(PowerStrip)}

На следующих схемах показано, как параметр enableMultipartDevices влияет на представление составного устройства в Home API:

  • Пример настенной панели с несколькими переключателями, показывающий нативное представление Matter и составной рендеринг Home API.

    Составное представление настенной панели.

  • Пример холодильника, показывающий собственное представление Matter и составной рендеринг Home API.

    Составное представление холодильника.

Рисунок 2. Примеры отрисовки составных креативов

Вы всегда можете получить плоское представление, опустив параметр enableMultipartDevices или задав для него значение false.

Каждый экземпляр компонента в составном устройстве называется частью.

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