Dispositivos multiparte no Android

Alguns Matter dispositivos são compostos por vários endpoints com o mesmo tipo de dispositivo. Outros Matter dispositivos são hierárquicos, com endpoints aninhados em outros endpoints. Nas APIs Home, os dois tipos de dispositivos são chamados de dispositivos multipartes.

Representação plana

Antes da versão 1.8 das APIs Home, os dispositivos multipartes eram representados pelas APIs Home como um conjunto de dispositivos separados e não relacionados. Isso é chamado de representação plana.

Por exemplo, um único dispositivo de painel de parede com quatro interruptores aparece nas APIs Home como quatro dispositivos distintos e não relacionados. E um dispositivo Matter hierárquico Matter como uma geladeira pode ser representado em nas APIs Home como um conjunto de dispositivos, cada um correspondente a um dos endpoints.

  • Exemplo de painel de parede com vários interruptores mostrando a representação nativa do Matter e a renderização plana da API Home

    Representação plana de um painel de parede de 4 interruptores.

  • Exemplo de geladeira mostrando a representação nativa do Matter e a renderização simples da API Home

    Representação plana de uma geladeira

Figura 1: exemplos de renderização plana

Representação multipartes

A partir da versão 1.8 das APIs Home, um dispositivo multipartes pode ser representado na API como um único dispositivo. Para ativar esse comportamento, chame o método devices() em Structure, Room ou HomeManager e defina o parâmetro enableMultipartDevices como 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)

Os diagramas a seguir ilustram como a opção enableMultipartDevices afeta a representação de um dispositivo multipartes nas APIs Home:

  • Exemplo de painel de parede com vários interruptores mostrando a representação nativa do Matter e a renderização multipart da API Home

    Representação multipartes de um painel de parede.

  • Exemplo de geladeira mostrando a representação nativa do Matter e a renderização em várias partes da API Home

    Representação multipartes de uma geladeira.

Figura 2: exemplos de renderização multipartes

Você sempre tem a opção de receber a representação plana omitindo o parâmetro enableMultipartDevices ou definindo-o como false.

Em um dispositivo multipartes, cada instância de componente de um tipo de dispositivo é chamada de parte.

As partes podem ser acessadas diretamente no dispositivo pai ou em uma parte de maneira hierárquica, usando tipos de dispositivos ou Matter tags semânticas. As tags semânticas são implementadas nas APIs Home com DescriptorTrait.SemanticTagStruct.

A classe abstrata DeviceType implementa a interface HasParts , permitindo que os desenvolvedores naveguem na árvore de dispositivos usando a propriedade parts e o método part(). Cada instância de parte também implementa a interface HasParts, de modo que chamar parts() em uma parte produz uma lista de zero ou mais subpartes.

O exemplo a seguir mostra como acessar as partes do dispositivo de vários 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()

O exemplo a seguir mostra como acessar as partes de um dispositivo de geladeira:

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