Dispositivos multipartes en Android

Algunos dispositivos Matter se componen de varios extremos con el mismo tipo de dispositivo. Otros dispositivos de Matter son jerárquicos, con extremos anidados dentro de otros extremos. En las APIs de Home, ambos tipos de dispositivos se denominan dispositivos de varias partes.

Representación plana

Antes de la versión 1.8 de las APIs de Home, las APIs de Home representan los dispositivos de varias partes como un conjunto de dispositivos independientes y no relacionados. Esto se conoce como la representación plana.

Por ejemplo, un solo dispositivo de panel de pared con cuatro interruptores aparece en las APIs de Home como cuatro dispositivos distintos y no relacionados. Y un dispositivo jerárquico de Matter, como un refrigerador, se puede representar en las APIs de Home como un conjunto de dispositivos, cada uno correspondiente a uno de los extremos.

  • Ejemplo de panel de pared con varios interruptores que muestra la representación nativa de Matter y la renderización plana de la API de Home

    Representación plana de un panel de pared de 4 interruptores.

  • Ejemplo de refrigerador que muestra la representación nativa de Matter y
          la renderización plana de la API de Home

    Representación plana de un refrigerador

Figura 1: Ejemplos de renderización plana

Representación de varias partes

A partir de la versión 1.8 de las APIs de Home, un dispositivo de varias partes se puede representar en la API como un solo dispositivo. Para habilitar este comportamiento, llama al método devices() en Structure, Room o HomeManager, y establece el parámetro enableMultipartDevices en true:

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

En los siguientes diagramas, se ilustra cómo la opción enableMultipartDevices afecta la representación de un dispositivo de varias partes en las APIs de Home:

  • Ejemplo de panel de pared con varios interruptores que muestra la representación nativa de Matter y la renderización de varias partes de la API de Home

    Representación de varias partes de un panel de pared.

  • Ejemplo de refrigerador que muestra la representación nativa de Matter y la renderización de varias partes de la API de Home

    Representación de varias partes de un refrigerador.

Figura 2: Ejemplos de renderización de varias partes

Siempre tienes la opción de obtener la representación plana omitiendo el parámetro enableMultipartDevices o configurándolo como false.

Dentro de un dispositivo de varias partes, cada instancia de componente de un tipo de dispositivo se denomina parte.

Se puede acceder a las partes directamente en el dispositivo superior o en una parte de manera jerárquica, con tipos de dispositivos o etiquetas semánticas Matter. Las etiquetas semánticas se implementan en las APIs de Home con DescriptorTrait.SemanticTagStruct.

La clase abstracta DeviceType implementa la interfaz HasParts, lo que permite que los desarrolladores naveguen por el árbol de dispositivos a través de la propiedad parts y el método part(). Cada instancia de parte también implementa la interfaz HasParts, de modo que, cuando se llama a parts() en una parte, se produce una lista de cero o más partes secundarias.

En el siguiente ejemplo, se muestra cómo acceder a las partes del dispositivo con varios interruptores:

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()

En el siguiente ejemplo, se muestra cómo acceder a las partes de un dispositivo de refrigerador:

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()