Dispositivi multiparte su Android

Alcuni dispositivi Matter sono costituiti da più endpoint con lo stesso tipo di dispositivo. Gli altri dispositivi Matter sono gerarchici, con endpoint nidificati all'interno di altri endpoint. Nelle API Home, entrambi i tipi di dispositivi sono indicati come dispositivi multipart.

Rappresentazione piatta

Prima della release 1.8 delle API Home, i dispositivi multipart sono rappresentati dalle API Home come un insieme di dispositivi separati e non correlati. Questa è chiamata rappresentazione piatta.

Ad esempio, un unico dispositivo pannello a parete con quattro interruttori viene visualizzato nelle API Home come quattro dispositivi distinti e non correlati. Un dispositivo gerarchico Matter come un frigorifero può essere rappresentato nelle API Home come un insieme di dispositivi, ciascuno corrispondente a uno degli endpoint.

  • Esempio di pannello a parete con più interruttori che mostra la rappresentazione nativa di Matter
          e il rendering piatto dell'API Home

    Rappresentazione piatta di un pannello a parete con 4 interruttori.

  • Esempio di frigorifero che mostra la rappresentazione nativa di Matter e
          il rendering piatto dell'API Home

    Rappresentazione piatta di un frigorifero

Figura 1: esempi di rendering piatto

Rappresentazione multiparte

A partire dalla release 1.8 delle API Home, un dispositivo multipart può essere rappresentato nell'API come un unico dispositivo. Per attivare questo comportamento, chiama il metodo devices() su Structure, Room o HomeManager e imposta il parametro enableMultipartDevices su 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)

I seguenti diagrammi illustrano in che modo l'opzione enableMultipartDevices influisce sulla rappresentazione di un dispositivo multipart nelle API Home:

  • Esempio di pannello a parete con più interruttori che mostra la rappresentazione nativa di Matter
    e il rendering in più parti dell'API Home

    Rappresentazione in più parti di un pannello a parete.

  • Esempio di frigorifero che mostra la rappresentazione nativa di Matter e il rendering in più parti dell'API Home

    Rappresentazione in più parti di un frigorifero.

Figura 2: esempi di rendering in più parti

Hai sempre la possibilità di ottenere la rappresentazione piatta omettendo il parametro enableMultipartDevices o impostandolo su false.

All'interno di un dispositivo composto da più parti, ogni istanza componente di un tipo di dispositivo è chiamata parte.

È possibile accedere alle parti direttamente sul dispositivo genitore o a una parte in modo gerarchico, utilizzando i tipi di dispositivo o i tag semantici Matter. I tag semantici sono implementati nelle API Home con DescriptorTrait.SemanticTagStruct.

La classe astratta DeviceType implementa l'interfaccia HasParts, consentendo agli sviluppatori di navigare nel Device Tree tramite la proprietà parts e il metodo part(). Ogni istanza di parte implementa anche l'interfaccia HasParts, in modo che la chiamata di parts() su una parte produca un elenco di zero o più parti secondarie.

Il seguente esempio mostra come accedere alle parti del dispositivo multi-interruttore:

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

L'esempio successivo mostra come accedere alle parti di un frigorifero:

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