Gebäude-APIs unter Android

Auf die Structure 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.Id
import com.google.home.Structure

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.

Beispielaufrufe

Liste der Gebäude abrufen

Nach der Initialisierung gibt ein structures()-Aufruf einen Ablauf von Strukturen zurück, auf die du zugreifen kannst:

// Get a flow of all structures accessible to the user
val allStructuresFlow: HomeObjectsFlow<Structure> = home.structures()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allStructures: Set<Structure> = allStructuresFlow.list()

Die structures() API ist ein Ablauf, der möglicherweise nicht sofort eine gültige Liste von Gebäuden zurückgibt. Wenn deine App reaktiv ist und diesen Ablauf abonniert, um die Benutzeroberfläche zu steuern, sollte schließlich eine gültige Liste von Gebäuden zurückgegeben werden. Es gibt weitere Situationen, in denen eine leere Gebäudeliste zurückgegeben werden kann, z. B. wenn das Smartphone des Nutzers die Verbindung verliert oder wenn der Nutzer die Berechtigungen für deine App widerrufen hat. Du solltest diese Fälle in deiner App berücksichtigen.

Wenn statt reaktiver Programmierung unbedingt imperative Programmierung erforderlich ist, kann alternativ ein Terminal-Flow-Operator verwendet werden:

val everyStructure = withTimeout(5000) { home.structures().first { it.isNotEmpty() } }

Dieser Aufruf wartet auf eine gültige Liste von Gebäuden, die über den Ablauf eingeht, und bricht ab, wenn die Liste nicht innerhalb eines von der App festgelegten Zeitlimits empfangen wird.

Gebäudeattribute abrufen

Anhand der Liste der Gebäude kannst du auf die zugehörigen Eigenschaften zugreifen:

// Get a flow on a structure. Flow emits new values on structure metadata changes: name.
val structureFlow: Flow<Structure> = home.structures().itemFlow(myStructureId)

// Get a snapshot of the structure.
val structure: Structure = structureFlow.first()

// Get structure properties
println("id ${structure.id}")
println("name ${structure.name}")

Gebäude anhand des Namens suchen

Wenn du den Namen eines Gebäudes kennst, kannst du auch über die Property name darauf zugreifen:

val myHome = home.structures().list().first { it.name == "My home" }

Von dort aus können Sie auf die Gebäude, Räume und Geräte für jedes Gebäude zugreifen.

Mit mehreren Gebäuden arbeiten

Wenn Sie mehrere Strukturen verwenden möchten, rufen Sie für jede Struktur eine separate Referenz ab:

var structure1: Structure? = null
var structure2: Structure? = null

try {
  structure1 = home.structures().list().firstOrNull { it.name == "Main House" }
} catch (e: HomeException) {
  // Code for handling the exception
}
try {
  structure2 = home.structures().list().firstOrNull { it.name == "Guest Cottage" }
} catch (e: HomeException) {
  // Code for handling the exception
}

Liste der Räume abrufen

Wenn du ein Gebäude hast, kannst du eine Liste der Räume abrufen und auf deren Eigenschaften zugreifen:

val allRoomsFlow: HomeObjectsFlow<Room> = structure.rooms()
val allRooms: Set<Room> = allRoomsFlow.list()
val room: Room = allRooms.first()

println("id ${room.id}")
println("name ${room.name}")

Chatroom erstellen

So erstellen Sie einen neuen Raum:

val testName = "Test Room Name"
val newRoom: Room = structure.createRoom(testName)

Raum löschen

Alternativ kannst du einen Raum löschen:

val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull()
    structure.deleteRoom(roomToDelete!!)

Sie können einen Raum auch nur mit einer ID löschen:

val roomToDelete1 = allRooms.filter { it.id == testRoomId }.firstOrNull()
structure.deleteRoom(roomToDelete1!!)

Wenn ein Raum mit Geräten gelöscht wird, bleiben die Geräte im Gebäude, sind aber keinem Raum mehr zugewiesen.

Geräte in einen anderen Raum verschieben

Sobald du ein Gebäude hast, kannst du Geräte in einen anderen Raum innerhalb dieses Gebäudes verschieben:

val room2 = structure.rooms().get(Id("room_id_other_structure"))
    val device1 = structure.devices().get(Id("device_id1"))
    structure.moveDevicesToRoom(room2!!, listOf(device1!!))

Wenn du nur Geräte- und Raum-IDs hast, kannst du Geräte auch so verschieben:

structure.moveDevicesToRoom(Id("room_id_other_structure"), listOf(Id("device_id1")))

Namen eines Raums ändern

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

livingRoom.setName("Living Room")

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.

In der Google Home-Umgebung können Nutzer für die meisten Gerätetypen Berechtigungen für alle Geräte dieses Typs gleichzeitig gewähren. Für sensible oder eingeschränkte Gerätetypen wie Schlösser, Kameras oder Türklingeln müssen Nutzer die Berechtigungen einzeln erteilen.

Mit der Funktion consentedDeviceTypes() auf Gebäudeebene kannst du feststellen, ob ein Nutzer die Berechtigung für den Zugriff auf einen sensiblen oder eingeschränkten Gerätetyp erteilt hat:

import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
 * Example of how an app may monitor which device types have been granted access by a user.
 */
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
    // Obtain the flow of consented device type factories
    val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
        structure.consentedDeviceTypes()

    myScope.launch {
        consentedTypesFlow.collect { consentedSet ->
            // Check if the user has consented to share a specific restricted
            // type, such as a Doorbell or Camera.
            val hasCameraAccess = consentedSet.any {
                it.toString() == "matter.google.type.GoogleDoorbellDevice"
            }

            if (hasCameraAccess) {
                // Enable features that require camera access
            } else {
                // Inform the user or disable camera-specific features
            }
        }
    }
}

Gerätegruppen

Eine Gerätegruppe ist eine benutzerdefinierte Sammlung von Geräten innerhalb eines einzelnen Gebäudes. Die Gruppenmitgliedschaft bleibt in Google-Diensten erhalten und ist für andere Mitglieder des Gebäudes und andere Apps mit Zugriff auf das Gebäude sichtbar.

Wie physische Räume gehören Gerätegruppen zu einem einzelnen Gebäude. Im Gegensatz zu Räumen sind Gerätegruppen jedoch logische Gruppierungen. Ein Gerät kann gleichzeitig mehreren Gerätegruppen angehören. Gerätegruppen können bis zu 100 Geräte enthalten.

Gerätegruppen werden durch die Entität DeviceGroup dargestellt, die sich von HomeDevice unterscheidet. Wenn du Gerätegruppen abfragen und mit ihnen interagieren möchtest, füge DeviceGroup in die entityTypes-Liste ein, wenn du deine FactoryRegistry initialisierst, zusammen mit den Attributen Group, GroupManagement und GroupMembership.

Du kannst mit den Geräten in einer Gruppe interagieren, indem du entweder direkt die Mitgliedsgeräte durchgehst (siehe Mit Mitgliedsgeräten einer Gruppe interagieren) oder einen Gerätetypteil auf dem DeviceGroup ansprichst (siehe Gerätegruppe steuern).

Liste der Gerätegruppen abrufen

Wenn du alle Gerätegruppen in einem Gebäude beobachten möchtest, rufe home.entities(DeviceGroup) auf und filtere nach der ID des Gebäudes:

home.entities(DeviceGroup).collect { allGroups ->
  val structureGroups = allGroups.filter { it.structureId == structure.id }
  for (group in structureGroups) {
    val groupName = group.trait(Group)?.Name
    println("Found group: $groupName with ID: ${group.id.id}")
  }
}

Mit Geräten von Gruppenmitgliedern interagieren

Wenn Sie mit group.devices() die Mitgliedsgeräte einer Gruppe durchlaufen, haben Sie eine detaillierte Kontrolle über einzelne Mitglieder, können Befehle in einer einzigen Anfrage zusammenfassen und Attribute für alle Mitglieder aggregieren oder schreiben.

So senden Sie beispielsweise eine einzelne Batchanfrage mit Befehlen für eine Eigenschaft für alle kompatiblen Mitglieder einer Gruppe:

val members = group.devices(enableMultipartDevices = true).first()
val onOffTraits = members.mapNotNull { device ->
  device.partOrNull(OnOffLightDevice).first()?.standardTraits?.onOff
}

val responses = home.sendBatchedCommands {
  onOffTraits.map { onOff ->
    add(onOff.onBatchable())
  }
}

for (response in responses) {
  response.getOrThrow()
}

Sie können ein Attribut auch für alle übereinstimmenden Mitgliedsgeräte in einer Gruppe aktualisieren (z. B. onTransitionTime auf 1u für alle DimmableLightDevice-Mitglieder festlegen) und auf den Abschluss innerhalb einer Frist warten:

val members = group.devices(enableMultipartDevices = true).first()

withTimeout(5.seconds) {
  members.map { device ->
    async {
      val light = device.partOrNull(DimmableLightDevice).first()
      val levelControl = light?.standardTraits?.levelControl
      if (
        levelControl?.supports(
          LevelControl.Attribute.onTransitionTime
        ) == true
      ) {
        levelControl.update { setOnTransitionTime(1u) }
      }
    }
  }.awaitAll()
}

So aggregierst du ein Attribut für die Mitglieder einer Gruppe, z. B. um den Mindestwert für colorTempPhysicalMaxMireds für alle Lampen mit Farbtemperatur in der Gruppe zu ermitteln:

val members = group.devices(enableMultipartDevices = true).first()
val minMaxMireds: UShort? = members.mapNotNull { device ->
  val light = device.partOrNull(ColorTemperatureLightDevice).first()
  light?.standardTraits?.colorControl?.colorTempPhysicalMaxMireds
}.minOrNull()

Gerätegruppe erstellen

Verwende GroupManagement für die Struktur, um eine Gerätegruppe zu erstellen:

val groupManagement = structure.trait(GroupManagementTrait)
val response = groupManagement?.createUserDefinedGroup(
  name = "Living room lights",
  memberDeviceObjectIds = listOf(light1.id.id, light2.id.id)
)

Gruppenmitgliedschaft verwalten

So fügen Sie einer bestehenden Gruppe Mitglieder hinzu:

structure.trait(GroupManagementTrait)?.addGroupMembers(
  groupObjectId = group.id.id,
  memberDeviceObjectIds = listOf(light3.id.id)
)

So entfernen Sie Mitglieder aus einer Gruppe:

structure.trait(GroupManagementTrait)?.removeGroupMembers(
  groupObjectId = group.id.id,
  memberDeviceObjectIds = listOf(light1.id.id)
)

Name einer Gerätegruppe ändern

Wenn Sie eine Gerätegruppe umbenennen möchten, aktualisieren Sie das Namensattribut im GroupTrait der Gruppe:

group.trait(GroupTrait)?.update {
  name = "Movie corner"
}

Gerätegruppe löschen

So löschst du eine Gerätegruppe aus einem Gebäude:

structure.trait(GroupManagementTrait)?.deleteGroup(
  groupObjectId = group.id.id
)

Automatisierungen

Der Einstiegspunkt für die Automation API ist ein Gebäude. Weitere Informationen zu automatisierten Abläufen in den Home APIs findest du unter Automation API für Android – Übersicht.