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

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

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

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

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

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

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

  • Пример холодильника с нативным представлением Matter и плоским рендерингом Home API

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

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

Многокомпонентное представление

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