Dostęp do urządzeń i ich metadanych

Do interfejsów API urządzeń można uzyskać dostęp za pomocą interfejsów API Home. Zaimportuj do aplikacji te pakiety:

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

Aby używać określonych typów urządzeń lub ich cech z interfejsami Device API, musisz je zaimportować osobno.

Aby na przykład używać atrybutu Matter Włączanie/wyłączanie i typu urządzenia Wtyczka, zaimportuj do aplikacji te pakiety:

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

Więcej informacji znajdziesz w artykule Model danych.

Obsługa błędów

Każda metoda w interfejsach API Home może wywołać błądHomeException, dlatego zalecamy użycie bloku try-catch, aby przechwytywać błądHomeException we wszystkich wywołaniach.

Podczas obsługi HomeException sprawdź pola codemessage, aby dowiedzieć się, co poszło nie tak.

Każdy nieobsługiwany wyjątek spowoduje awarię aplikacji.

Więcej informacji znajdziesz w artykule Postępowanie z błędami.

Przykładowo, aby wysłać polecenie do urządzenia, zobacz artykuł Wysyłanie polecenia do urządzenia.

Przykładowe rozmowy

Pobieranie listy urządzeń

Jeśli struktura jest dostępna, wywołanie devices() zwraca listę urządzeń Flow, do których masz dostęp w ramach tej struktury:

// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()

W tym miejscu można uzyskać dostęp do stanów poszczególnych urządzeń i wysłać do nich obsługiwane polecenia.

Czytanie stanu urządzenia

Zobaczmy przykład sprawdzania atrybutu OnOff z cechy Wł./wył. urządzenia. Korzystając z modelu danych cech interfejsów API Home, w którym ta cecha jest identyfikowana jako OnOff, możesz pobierać dane cech za pomocą klasy standardTraits typu urządzenia:

// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!

Aby dowiedzieć się więcej o funkcji przepływu w Kotlinie, zapoznaj się z artykułem distinctUntilChanged.

Unieważnianie stanu w subskrypcji cech

Interfejs TraitStateInvalidation umożliwia unieważnienie stanu wyodrębnionego za pomocą subskrypcji na urządzeniu docelowym w przypadku, gdy stan nie jest zgłaszany prawidłowo. Przykłady sytuacji, w których stan może nie być prawidłowo zgłaszany, to m.in. użycie atrybutów w cechach Matter o jakości „C” lub nieoczekiwane problemy spowodowane implementacją urządzenia.

Ten interfejs API wykonuje wymuszone odczytanie bieżącego stanu atrybutu i zwraca wynik za pomocą istniejących przepływów atrybutów.

Pobierz cechę, a potem uruchom na niej funkcję forceRead:

val generalDiagnosticsTrait = device.trait(GeneralDiagnostics).first()
generalDiagnosticsTrait.forceRead()

Pobieranie listy cech typu urządzenia

Typy urządzeń powinny być używane jako punkt wejścia do odczytu cech, ponieważ dzielą urządzenie na elementy funkcjonalne (np. punkty końcowe w Matter).

Uwzględniają one też kolizje cech w przypadku, gdy urządzenie ma 2 typy urządzeń, z których każdy może mieć tę samą cechę. Jeśli na przykład urządzenie jest jednocześnie głośnikiem i ściemnianym światłem, ma 2 cechy włączania/wyłączania i 2 cechy regulacji poziomu.

Aby uzyskać listę dostępnych cech dla typu urządzenia „Zgaś światło”:

// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()

Inny rodzaj kolizji cech może wystąpić, gdy urządzenie ma 2 cechy o tej samej nazwie. Na przykład onOff może odnosić się do standardowego atrybutu OnOff lub do atrybutu zdefiniowanego przez producenta OnOff. Aby uniknąć potencjalnych niejasności dotyczących tego, która cecha jest zamierzona, instancja Trait odwołująca się do urządzenia powinna być poprzedzona odpowiednią przestrzenią nazw. W przypadku standardowych cech, czyli takich, które są analogiczne do standardowych klastrów Matter, użyj standardTraits. W przypadku cech Google użyj googleTraits:

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

Aby uzyskać dostęp do cechy producenta, odwołuj się do niej bezpośrednio:

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

Pobieranie listy urządzeń z określonym atrybutem

Funkcji filter w Kotlinie można używać do dalszego dopracowywania wywołań interfejsu API. Aby na przykład uzyskać listę urządzeń w domu, które mają cechę włączania i wyłączania:

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

Pełna lista cech dostępnych w interfejsie Trait.

Pobieranie listy urządzeń o podobnych typach

Aby zobaczyć listę urządzeń odpowiadających wszystkim lampom w domu:

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

Interfejsy API Home obsługują kilka typów urządzeń, które mogą reprezentować podstawowy typ urządzenia. Na przykład nie ma typu urządzenia „Światło”. Zamiast tego, jak w poprzednim przykładzie, lampka może być reprezentowana przez 4 różne typy urządzeń. Aby uzyskać pełny obraz typu urządzenia na wyższym poziomie w domu, w przefiltrowanych przepływach danych musisz uwzględnić wiele typów urządzeń.

Pełną listę typów urządzeń dostępnych w interfejsie DeviceType znajdziesz w interfejsie API Home.

Pobieranie identyfikatora producenta lub identyfikatora produktu urządzenia

Cecha BasicInformation zawiera informacje takie jak identyfikator dostawcy, identyfikator produktu, nazwa produktu i numer seryjny urządzenia:

// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.productId}")

Identyfikowanie urządzeń w chmurze

Jeśli jesteś producentem urządzeń i tworzysz urządzenia Cloud-to-cloud, aby zidentyfikować swoje urządzenia Cloud-to-cloud za pomocą atrybutu BasicInformation, możesz uwzględnić te pola ciągu znaków w odpowiedzi SYNC:

  • Identyfikator dostawcy wydany przez Connectivity Standards Alliance (CSA): "matterOriginalVendorId": "0xfff1",

  • Identyfikator produktu, który jednoznacznie identyfikuje produkt danego sprzedawcy: "matterOriginalProductId": "0x1234",

  • Unikalny identyfikator urządzenia, który jest tworzony w sposób specyficzny dla producenta:"matterUniqueId": "matter-device-id",

Podczas wypełniania tych pól tekstowych użyj Matteridentyfikatorów sprzedawcy i produktu, jeśli je masz. Jeśli nie jesteś członkiem CSA i nie masz przypisanych tych identyfikatorów, możesz pozostawić pola matterOriginalVendorId i matterOriginalProductId puste i podać identyfikator matterUniqueId.

Przykładowa odpowiedź SYNC pokazuje użycie tych pól:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "456",
        "type": "action.devices.types.LIGHT",
        "traits": [
          "action.devices.traits.OnOff",
          "action.devices.traits.Brightness",
          "action.devices.traits.ColorSetting",
        ],
        "willReportState": true,
        "deviceInfo": { ... },
        "matterOriginalVendorId": "0xfff1",
        "matterOriginalProductId": "0x1234",
        "matterUniqueId": "matter-device-id",
        "otherDeviceIds": [
          {
            "deviceId": "local-device-id",
          }
        ]
      }
    ]
  }
}

Więcej informacji znajdziesz w dokumentacji Cloud-to-cloud SYNC.

Metadane urządzenia i cechy

Urządzenia i cechy w interfejsach Home API są powiązane z metadanymi, które mogą ułatwiać zarządzanie wrażeniami użytkownika w aplikacji.

Każda cecha w interfejsach API Home zawiera właściwość sourceConnectivity, która zawiera informacje o stanie online i lokalizacji cechy (przekierowanie lokalne lub zdalne).

Pobieranie głównego typu urządzenia

Niektóre urządzenia mogą wyświetlać wiele typów urządzeń za pomocą interfejsów API Home. Aby mieć pewność, że użytkownicy zobaczą odpowiednie opcje aplikacji (np. kontrolę urządzenia i sugerowane automatyzacje) na swoich urządzeniach, warto sprawdzić, jaki jest podstawowy typ urządzenia.

Najpierw pobierz typy urządzenia za pomocą elementu type(), a następnie określ, który z nich jest podstawowy:

val types = device.types().first()
val primaryType = types.first { it.metadata.isPrimaryType }

Sprawdzanie, czy cecha jest dostępna online

Aby sprawdzić łączność cechy, użyj metody connectivityState():

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

Niektóre cechy, zazwyczaj cechy Google smart home, mogą być wyświetlane w trybie offline, jeśli urządzenie nie ma połączenia z internetem. Dzieje się tak, ponieważ te cechy są oparte na chmurze i nie mają routingu lokalnego.

Sprawdzanie połączenia urządzenia

Łączność urządzenia jest sprawdzana na poziomie typu urządzenia, ponieważ niektóre urządzenia obsługują wiele typów urządzeń. Zwrócony stan to kombinacja stanów połączeń wszystkich cech na tym urządzeniu.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

Stan PARTIALLY_ONLINE może wystąpić w przypadku mieszanych typów urządzeń, gdy nie ma połączenia z internetem. Atrybuty standardu Matter mogą być nadal dostępne online z powodu routingu lokalnego, ale atrybuty oparte na chmurze będą offline.

Sprawdzanie kierowania sieciowego cechy

Lokalizacja atrybutu jest też dostępna w interfejsach API Home. dataSourceLocality wskazuje, czy cecha jest kierowana zdalnie (przez chmurę), lokalnie (przez lokalny koncentrator) czy peer-to-peer (bezpośrednio z urządzenia na urządzenie, bez koncentratora).

Wartość lokalizacji nieznanej UNSPECIFIED może wystąpić np. podczas uruchamiania aplikacji, która jeszcze nie połączyła się z hubem lub serwerem. Te urządzenia są niedostępne i nie będą reagować na żądania interakcji z poleceń ani zdarzeń. To klient decyduje, jak ma postępować z takimi urządzeniami.

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

Sprawdzanie trasowania sieci na urządzeniu

Podobnie jak w przypadku łączności, lokalizacja jest sprawdzana na poziomie typu urządzenia. Zwrócony stan to kombinacja lokalizacji wszystkich cech na danym urządzeniu.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Stan MIXED może być obserwowany w podobnym scenariuszu jak w przypadku łączności PARTIALLY_ONLINE: niektóre cechy są oparte na chmurze, a inne na lokalnych zasobach.

Lista interfejsów API

Po utworzeniu instancji interfejsu Home można korzystać z tych interfejsów API urządzenia:

Interfejs API Opis
devices() Uzyskaj dostęp do wszystkich urządzeń we wszystkich strukturach na koncie Google. Zwraca HomeObjectsFlow, który zawiera dalsze opcje wyszukiwania i filtrowania.

Gdy masz konto HomeDevice, możesz korzystać z tych interfejsów API:

Interfejs API Opis
allCandidates() Zwraca wszystkie kandydatury automatyzacji dla urządzenia i jego elementów podrzędnych.
candidates() Zwraca wszystkie kandydatury automatyzacji dla urządzenia.
connectivityStateChanged Ostatni czas zmiany stanu urządzenia.
events(event) Pobiera przepływ danych konkretnego zdarzenia.
events(trait) Pobiera przepływ wszystkich zdarzeń według tej cechy.
events(traits) Pobiera przepływ wszystkich zdarzeń według tych atrybutów.
getSourceConnectivity(trait) Pobiera metadane dotyczące określonej cechy. Zwraca wartość SourceConnectivity.
has(trait) Sprawdź, czy urządzenie obsługuje aktualnie żądaną cechę.
has(type) czy urządzenie obsługuje podany typ.
id Unikalny identyfikator systemu urządzenia.
isInRoom czy urządzenie znajduje się w pokoju.
isInStructure czy urządzenie znajduje się w strukturze.
isMatterDevice Jeśli urządzenie jest obsługiwane przez Matter.
name Nazwa urządzenia podana przez użytkownika.
room() Sala, do której jest przypisane urządzenie. Zwraca wartość Room.
roomId Identyfikator pokoju, do którego przypisana jest kamera. Zwraca wartość Id.
sourceConnectivity Łączność źródłowa urządzenia, która reprezentuje zbiorcze stany łączności i lokalizację sieciową cech urządzenia.
structure() Struktura, do której jest przypisane urządzenie. Zwraca wartość Structure.
structureId Identyfikator struktury, do której przypisany jest dany sprzęt. Zwraca wartość Id.
type(type) Pobierz definicję typu z wypełnionymi cechami (jeśli są dostępne) w celu uzyskania bezpośredniego dostępu. Zawsze zwraca aktualny zrzut cech.
types() wyświetlić listę wszystkich typów dostępnych na urządzeniu;