Auf Geräte und Gerätemetadaten für Android zugreifen

Auf Geräte-APIs kann über die Home APIs für Android zugegriffen werden. Importieren Sie diese Pakete in Ihre App:

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

Wenn du bestimmte Gerätetypen oder Attribute mit den Device APIs verwenden möchtest, musst du sie einzeln importieren.

Wenn du beispielsweise das Attribut Matter „An/Aus“ und den Gerätetyp „An/Aus-Steckdose“ verwenden möchtest, importiere die folgenden Pakete in deine Anwendung:

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

Weitere Informationen finden Sie unter Datenmodell unter Android.

Fehlerbehandlung

Jede Methode in den Home APIs kann eine HomeException auslösen. Wir empfehlen daher, bei allen Aufrufen einen try-catch-Block zu verwenden, um HomeException abzufangen.

Prüfen Sie beim Umgang mit HomeException die Felder error.code und error.message, um herauszufinden, was schiefgelaufen ist. Es kann auch Unterfehlercodes geben. Rufen Sie daher die Methode getSubErrorCodes() auf und prüfen Sie das Ergebnis.

Nicht behandelte Ausnahmen führen zum Absturz der App.

Weitere Informationen finden Sie unter Fehlerbehandlung.

Ein Beispiel finden Sie unter Befehl an ein Gerät senden.

Beispielaufrufe

Liste der Geräte abrufen

Sobald du eine Referenz zur Structure-Instanz hast, gibt ein devices()-Aufruf eine Flow der Geräte zurück, auf die du von diesem Gebäude aus zugreifen kannst:

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

Dort kannst du auf die Status der einzelnen Geräte zugreifen und Befehle an Geräte senden.

Mit Version 1.8 der Home APIs kannst du die API so konfigurieren, dass jedes mehrteilige Gerät als einzelnes Gerät dargestellt wird. Dazu musst du den Parameter enableMultipartDevices der Methode devices() auf true setzen. Weitere Informationen finden Sie unter Mehrteilige Geräte unter Android.

Gerätestatus lesen

Hier ist ein Beispiel für die Prüfung des Attributs OnOff des Gerätemerkmals „An/Aus“. Mit dem Trait-Datenmodell der Home APIs, in dem dieses Trait als OnOff identifiziert wird, kannst du Trait-Daten über die Klasse standardTraits des Gerätetyps abrufen:

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

Weitere Informationen zur Kotlin-Flow-Funktion finden Sie unter distinctUntilChanged.

Status in einem Attributabo ungültig machen

Die TraitStateInvalidation-Schnittstelle bietet die Möglichkeit, einen über Abos abgerufenen Status für das Zielgerät ungültig zu machen, wenn der Status nicht korrekt gemeldet wird. Beispiele für Fälle, in denen der Status möglicherweise nicht korrekt gemeldet wird, sind die Verwendung von Attributen in Matter-Eigenschaften mit der Qualität „C“ oder eine Geräteimplementierung, die das Problem unerwartet verursacht.

Diese API erzwingt das Lesen des aktuellen Attributstatus und gibt das Ergebnis über vorhandene Attributabläufe zurück.

Rufen Sie das Attribut ab und führen Sie dann einen forceRead für das Attribut aus:

val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()

Liste der Gerätetypattribute abrufen

Gerätetypen sollten als Einstiegspunkt für das Lesen von Attributen verwendet werden, da sie ein Gerät in seine funktionalen Teile zerlegen (wie Endpunkte in Matter).

Sie berücksichtigen auch Attributkonflikte, falls ein Gerät zwei Gerätetypen hat, die beide dasselbe Attribut haben können. Wenn ein Gerät beispielsweise sowohl ein Lautsprecher als auch eine dimmbare Lampe ist, hat es zwei „An/Aus“- und zwei „Helligkeitsregelung“-Attribute.

So rufen Sie die Liste der verfügbaren Eigenschaften für den Gerätetyp „Dimmable Light“ ab:

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

Eine andere Art von Attributkonflikt kann auftreten, wenn ein Gerät zwei Attribute mit demselben Namen hat. Beispielsweise könnte sich onOff auf eine Instanz des Standard-Attributs OnOff oder auf eine Instanz eines vom Hersteller definierten Attributs OnOff beziehen. Um Unklarheiten darüber zu vermeiden, welches Attribut gemeint ist, sollte einer Trait-Instanz, auf die über ein Gerät verwiesen wird, ein qualifizierender Namespace vorangestellt werden. Verwenden Sie für Standardmerkmale, d. h. Merkmale, die den Standardclustern von Matter entsprechen, standardTraits. Verwenden Sie für Google-Eigenschaften googleTraits:

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

Wenn Sie auf ein herstellerspezifisches Attribut zugreifen möchten, verweisen Sie direkt darauf:

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

Liste der Geräte mit einem bestimmten Attribut abrufen

Mit der Funktion filter in Kotlin können API-Aufrufe weiter verfeinert werden. So kannst du beispielsweise eine Liste der Geräte im Zuhause abrufen, die alle das Attribut „An/Aus“ haben:

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

Eine vollständige Liste der in den Home APIs verfügbaren Traits findest du in der Trait-Schnittstelle.

Liste der Geräte mit ähnlichen Gerätetypen abrufen

So rufen Sie eine Liste der Geräte ab, die alle Lampen in einem Zuhause darstellen:

// 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)
    }
  }

In den Home APIs gibt es mehrere Gerätetypen, die einen Hauptgerätetyp darstellen könnten. Es gibt beispielsweise keinen Gerätetyp „Licht“. Stattdessen gibt es vier verschiedene Gerätetypen, die eine Lampe darstellen können, wie im vorherigen Beispiel gezeigt. Um einen umfassenden Überblick über einen übergeordneten Gerätetyp in einem Zuhause zu erhalten, müssen daher mehrere Gerätetypen in gefilterte Abläufe einbezogen werden.

Eine vollständige Liste der in den Home APIs verfügbaren Gerätetypen findest du in der DeviceType-Schnittstelle.

Anbieter-ID oder Produkt-ID für ein Gerät abrufen

Das Attribut BasicInformation enthält Informationen wie die Anbieter-ID, die Produkt-ID, den Produktnamen und die Seriennummer eines Geräts:

// 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}")

Cloud-zu-Cloud-Geräteidentifikation für Gerätehersteller

Wenn du ein Gerätehersteller bist und Cloud-to-cloud-Geräte herstellst, kannst du diese Stringfelder in die SYNC-Antwort aufnehmen, um deine Cloud-to-cloud-Geräte über das Attribut BasicInformation zu identifizieren:

  • Die von Connectivity Standards Alliance (Alliance) ausgestellte Anbieter-ID: "matterOriginalVendorId": "0xfff1",

  • Eine Produktkennzeichnung, die ein Produkt eines Anbieters eindeutig identifiziert: "matterOriginalProductId": "0x1234",

  • Eine eindeutige Kennung für das Gerät, die herstellerspezifisch erstellt wird: "matterUniqueId": "matter-device-id",

Verwenden Sie bei der Eingabe dieser Stringfelder Ihre Matter-Anbieter- und Produkt-IDs, falls vorhanden. Wenn Sie kein Alliance-Mitglied sind und Ihnen diese IDs nicht zugewiesen wurden, können Sie die Felder matterOriginalVendorId und matterOriginalProductId leer lassen und die matterUniqueId als Kennung angeben.

Die Beispiel-SYNC-Antwort zeigt die Verwendung dieser Felder:

{
  "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",
          }
        ]
      }
    ]
  }
}

Weitere Informationen finden Sie in der Dokumentation zu Cloud-to-cloud SYNC.

Geräte- und Attributmetadaten

Geräte und Eigenschaften in den Home APIs sind mit Metadaten verknüpft, die bei der Verwaltung der Nutzererfahrung in einer App hilfreich sein können.

Jedes Attribut in den Home APIs enthält eine sourceConnectivity-Property, die Informationen zum Onlinestatus und zur Lokalität (lokales oder Remote-Routing) eines Attributs enthält.

Primären Typ eines Geräts abrufen

Einige Geräte können über die Home APIs mehrere Gerätetypen darstellen. Damit Nutzer in einer App die passenden Optionen für ihre Geräte sehen (z. B. Gerätesteuerung und vorgeschlagene automatisierte Abläufe), ist es hilfreich, den primären Gerätetyp für ein Gerät zu prüfen.

Rufe zuerst die Typen des Geräts mit type() ab und bestimme dann die primären Typen:

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

Prüfen, ob ein Merkmal online ist

Verwende die Methode connectivityState(), um die Verbindung eines Attributs zu prüfen:

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

Einige Eigenschaften, in der Regel Google smart home-Eigenschaften, werden möglicherweise als offline angezeigt, wenn das Gerät keine Internetverbindung hat. Das liegt daran, dass diese Attribute cloudbasiert sind und kein lokales Routing haben.

Verbindung eines Geräts prüfen

Die Konnektivität eines Geräts wird auf der Ebene des Gerätetyps geprüft, da einige Geräte mehrere Gerätetypen unterstützen. Der zurückgegebene Status ist eine Kombination der Verbindungsstatus aller Attribute auf diesem Gerät.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

Der Status PARTIALLY_ONLINE kann bei gemischten Gerätetypen auftreten, wenn keine Internetverbindung besteht. Matter-Standard-Traits sind aufgrund des lokalen Routings möglicherweise noch online, cloudbasierte Traits sind jedoch offline.

IP-Adresse des Geräts abrufen

Verwende das Attribut networkInterfaces des Attributs GeneralDiagnostics, um die IP-Adresse des Geräts zu ermitteln. Die Adressen werden als Byte-Arrays zurückgegeben, die Sie in Standard-IPv4- oder IPv6-Strings formatieren können:

val ipAddresses =
  trait.networkInterfaces?.flatMap { networkInterface ->
    (networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
      try {
        java.net.InetAddress.getByAddress(bytes).hostAddress
      } catch (e: java.net.UnknownHostException) {
        null
      }
    }
  } ?: emptyList()

Netzwerkrouting eines Merkmals prüfen

Die Lokalität für ein Trait ist auch in den Home APIs verfügbar. dataSourceLocality gibt an, ob das Attribut remote (über die Cloud), lokal (über einen lokalen Hub) oder Peer-to-Peer (direkt von Gerät zu Gerät, ohne Hub) weitergeleitet wird.

Der unbekannte Standortwert UNSPECIFIED ist beispielsweise möglich, während eine App gestartet wird und noch keinen Hub oder Server für die Geräteverbindung erreicht hat. Diese Geräte sind nicht erreichbar und Interaktionsanfragen von Befehlen oder Ereignissen schlagen fehl. Es liegt am Client, zu entscheiden, wie mit solchen Geräten umgegangen werden soll.

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

Netzwerkrouting für ein Gerät prüfen

Wie die Konnektivität wird auch die Lokalität auf Gerätetypebene geprüft. Der zurückgegebene Status ist eine Kombination aus der Lokalität für alle Attribute auf diesem Gerät.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Der Status MIXED kann in einem ähnlichen Szenario wie bei der PARTIALLY_ONLINE-Konnektivität beobachtet werden: Einige Merkmale sind cloudbasiert, andere lokal.

Gerätenamen ändern

Rufen Sie die Methode setName() auf, um den Namen eines Geräts zu ändern:

mixerDevice.setName("Grendel")

Namen werden abgeschnitten, wenn sie das Limit von 60 Unicode-Codepunkten (Zeichen) überschreiten. Es werden keine Fehler ausgegeben. Entwickler sind für den Umgang mit langen Nutzernamen verantwortlich und können beispielsweise entscheiden, ob sie Nutzer darüber informieren möchten, dass Nutzernamen gekürzt werden.

Gruppenmitgliedschaft für ein Gerät prüfen

Ein physisches Gerät kann zu einer oder mehreren Gerätegruppen gehören. Wenn du wissen möchtest, zu welchen Gruppen ein Gerät gehört, sieh dir das Attribut GroupMembership des Geräts an:

val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
  println("HomeAPI", "Device belongs to group: $groupId")
}

Umgekehrt kannst du alle Mitgliedsgeräte, die zu einem DeviceGroup gehören, beobachten, indem du den devices()-Ablauf für ein DeviceGroup aufrufst:

group.devices(enableMultipartDevices = true).collect { members ->
  println("HomeAPI", "Group contains ${members.size} devices")
}

Informationen dazu, wie du die von einer DeviceGroup unterstützten Gerätetypen prüfst und Befehle an die Gruppe als einzelne Entität sendest, findest du unter Gerätegruppe steuern.