Urządzenia wieloczęściowe na Androidzie

Niektóre urządzenia Matter składają się z wielu punktów końcowych tego samego typu. Inne urządzenia Matter mają strukturę hierarchiczną, a punkty końcowe są zagnieżdżone w innych punktach końcowych. W interfejsach API Google Home oba rodzaje urządzeń są określane jako urządzenia wieloczęściowe.

Reprezentacja płaska

Przed wersją 1.8 interfejsów API Google Home urządzenia wieloczęściowe były reprezentowane przez te interfejsy jako zestaw oddzielnych, niezwiązanych ze sobą urządzeń. Nazywa się to reprezentacją płaską.

Na przykład pojedynczy panel ścienny z 4 przełącznikami jest widoczny w interfejsach API Google Home jako 4 oddzielne i niezwiązane ze sobą urządzenia. Urządzenie Matter o strukturze hierarchicznej, takie jak lodówka, może być reprezentowane w interfejsach API Google Home jako zestaw urządzeń, z których każde odpowiada jednemu z punktów końcowych.

  • Przykład panelu ściennego z wieloma przełącznikami przedstawiający natywną reprezentację Matter i płaskie renderowanie interfejsu Home API

    Płaska reprezentacja panelu ściennego z 4 przełącznikami.

  • Przykład lodówki z natywną reprezentacją Matter i płaskim renderowaniem interfejsu Home API

    Płaska reprezentacja lodówki.

Rysunek 1. Przykłady renderowania płaskiego

Reprezentacja wieloczęściowa

Od wersji 1.8 interfejsów API Google Home urządzenie wieloczęściowe może być reprezentowane w interfejsie API jako pojedyncze urządzenie. Aby włączyć to działanie, wywołaj metodę devices() w przypadku Structure, Room lub HomeManager i ustaw parametr enableMultipartDevices na 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)

Ilustracje poniżej pokazują, jak opcja enableMultipartDevices wpływa na reprezentację urządzenia wieloczęściowego w interfejsach API Google Home:

  • Przykład panelu ściennego z wieloma przełącznikami przedstawiający natywną reprezentację Matter i renderowanie wieloczęściowe interfejsu Home API

    Reprezentacja wieloczęściowa panelu ściennego.

  • Przykład lodówki z natywną reprezentacją Matter i renderowaniem wieloczęściowym interfejsu Home API

    Reprezentacja wieloczęściowa lodówki.

Rysunek 2. Przykłady renderowania wieloczęściowego.

Zawsze możesz uzyskać reprezentację płaską, pomijając parametr enableMultipartDevices lub ustawiając go na false.

W urządzeniu wieloczęściowym każda instancja komponentu typu urządzenia jest nazywana częścią.

Do części można uzyskać dostęp bezpośrednio na urządzeniu nadrzędnym lub w sposób hierarchiczny, używając typów urządzeń lub Matter semantycznych tagów. Tagi semantyczne są implementowane w interfejsach API Google Home za pomocą DescriptorTrait.SemanticTagStruct.

Klasa abstrakcyjna DeviceType implementuje interfejs HasParts, co umożliwia programistom poruszanie się po drzewie urządzeń za pomocą właściwości parts i metody part(). Każda instancja części implementuje też interfejs HasParts, dzięki czemu wywołanie parts() w przypadku części powoduje utworzenie listy zawierającej 0 lub więcej podczęści.

Poniższy przykład pokazuje, jak uzyskać dostęp do części urządzenia z wieloma przełącznikami:

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

Następny przykład pokazuje, jak uzyskać dostęp do części urządzenia lodówki:

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