1. Hinweis
Die Google Home APIs bieten eine Reihe von Bibliotheken, mit denen Android-Entwickler das Google Home-Ökosystem nutzen können. Mit diesen neuen APIs können Entwickler Apps erstellen, mit denen Smart-Home-Geräte nahtlos in Betrieb genommen und gesteuert werden können.
Google stellt Entwicklern, die ein funktionierendes Beispiel für die Verwendung der Google Home APIs benötigen, eine Android-Beispiel-App zur Verfügung. Dieses Codelab basiert auf einem Branch der Beispiel-App, in dem Sie erfahren, wie Sie die Berechtigungs-, Inbetriebnahmen-, Geräte- und Struktur-APIs verwenden.
Vorbereitung
- Kenntnisse des Google Home-Ökosystems (Cloud-to-Cloud und Matter).
- Eine Workstation, auf der Android Studio (2024.3.1 Ladybug oder höher) installiert ist.
- Ein Android-Smartphone, das die Anforderungen der Home-APIs erfüllt (siehe Voraussetzungen), auf dem die Google Play-Dienste und die Google Home App installiert sind. Ein Emulator funktioniert nicht. Für die Beispiel-App werden nur physische Android-Smartphones unterstützt.
- Ein kompatibler Google Home Hub, der die Google Home APIs unterstützt.
- Optional: Ein Smart-Home-Gerät, das mit den Google Home-APIs kompatibel ist.
Lerninhalte
- So erstellen Sie eine Android-App mit den Google Home-APIs und Best Practices.
- So stellen Sie ein Smart Home mit den Geräte- und Gebäude-APIs dar und steuern es.
- Verwendung von Commissioning APIs zum Hinzufügen von Geräten zum Google Home-Ökosystem.
Optional: Zuhause einrichten
Bevor Sie die Google Home-APIs verwenden können, müssen Sie mit der Google Home App ein Zuhause in Ihrem Google-Konto einrichten und einige Geräte hinzufügen. In diesem Abschnitt wird beschrieben, wie Sie dies mit dem Google Home Playground tun können, der virtuelle Smart-Home-Geräte bereitstellt.
Öffne home-playground.withgoogle.com in deinem Webbrowser, melde dich mit deinem Google-Konto an und prüfe, ob die folgenden emulierten Geräte angezeigt werden:
- outlet1: Ein/Aus-Stecker
- light2: Dimmbares Licht
- light3: On/Off light (Licht 3: Licht an/aus)
- ac3: Klimaanlage
- blinds4: Window Covering
- washer5: Smart-Home-Waschmaschine
Öffnen Sie die Google Home App auf Ihrem Mobilgerät, tippen Sie auf die Schaltfläche Hinzufügen und wählen Sie Works with Google Home aus. Suchen Sie in der Liste nach „Playground“, wählen Sie das Projekt „Google Home Playground“ aus und tippen Sie auf Weiter.
Im Google Home Playground wird eine Seite zur Kontoautorisierung angezeigt. Tippen Sie auf Autorisieren oder Über Google anmelden. Alle Geräte, die Sie über die Web-App konfiguriert haben, werden in der mobilen App angezeigt.
Wähle alle Geräte aus und schließe die Einrichtung ab. Wenn Sie zur Startseite zurückkehren, werden alle verfügbaren Geräte angezeigt.
Die unterstützten Geräte in der Liste können jetzt mit den Google Home-APIs verwendet werden.
2. Projekt einrichten
Das folgende Diagramm veranschaulicht die Architektur einer Home APIs-App:
- App-Code:Der Hauptcode, an dem Entwickler arbeiten, um die Benutzeroberfläche der App und die Logik für die Interaktion mit dem Home APIs SDK zu erstellen.
- Home APIs SDK:Das von Google bereitgestellte Home APIs SDK funktioniert mit dem Home APIs-Dienst in GMSCore, um Smart-Home-Geräte zu steuern. Entwickler erstellen Apps, die mit den Home-APIs funktionieren, indem sie sie mit dem Home-APIs SDK bündeln.
- GMSCore unter Android:GMSCore, auch bekannt als Google Play-Dienste, ist eine Google-Plattform, die wichtige Systemdienste bereitstellt und wichtige Funktionen auf allen zertifizierten Android-Geräten ermöglicht. Das Home-Modul der Google Play-Dienste enthält die Dienste, die mit den Home APIs interagieren.
Home SDK einrichten
Folgen Sie der Anleitung unter SDK einrichten, um das aktuelle SDK zu erhalten.
Beispiel-App abrufen
Der Quellcode für die Beispiel-App ist auf GitHub verfügbar. In diesem Codelab werden die Beispiele aus dem codelab-branch-1
-Branch der Beispiel-App verwendet.
Gehen Sie zu dem Speicherort, an dem Sie das Projekt speichern möchten, und klonen Sie den codelab-branch-1
-Branch:
$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git
Beispielanwendung erstellen
Führen Sie die Schritte 1 bis 5 unter App erstellen aus.
Wenn die App auf Ihrem Smartphone ausgeführt wird, sehen Sie die Hauptseite der Beispiel-App. Sie können sich jedoch erst anmelden, wenn Sie die OAuth-Authentifizierung eingerichtet und die fehlenden Teile mit der Permission API implementiert haben.
3. Authentifizierung einrichten
Die Home APIs verwenden OAuth 2.0, um den Zugriff auf Geräte im Gebäude zu gewähren. Mit OAuth kann ein Nutzer einer App oder einem Dienst Berechtigungen erteilen, ohne seine Anmeldedaten weitergeben zu müssen.
Folgen Sie der Anleitung unter OAuth-Zustimmung einrichten, um den Zustimmungsbildschirm zu konfigurieren. Sie müssen mindestens ein Testkonto erstellen.
Folgen Sie dann der Anleitung unter OAuth-Anmeldedaten einrichten, um die Anmeldedaten für die App zu erstellen.
4. Berechtigungen für Initialisierung und Verarbeitung
In diesem Abschnitt erfahren Sie, wie Sie das SDK initialisieren und Nutzerberechtigungen mit der Permissions API verwalten.
Unterstützte Typen und Eigenschaften definieren
Bei der Entwicklung einer App müssen Sie explizit angeben, welche Gerätetypen und Merkmale die App unterstützt. In der Beispiel-App definieren wir dazu statische Listen im Companion-Objekt in HomeApp.kt
, auf die dann bei Bedarf in der gesamten App verwiesen werden kann:
companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
OnOffLightDevice,
DimmableLightDevice,
// ...
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
OnOff,
LevelControl,
// ...
)
}
Eine Liste aller unterstützten Gerätetypen und Funktionen finden Sie unter Unterstützte Gerätetypen und Funktionsindex unter Android.
Entfernen Sie die Kommentarzeichen für die Schritte 4.1.1 und 4.1.2 in der HomeApp.kt
-Quelldatei, um den Quellcode zu aktivieren, der die Berechtigung anfordert.
companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
// ContactSensorDevice,
// ColorTemperatureLightDevice,
// DimmableLightDevice,
// ExtendedColorLightDevice,
// GenericSwitchDevice,
// GoogleDisplayDevice,
// GoogleTVDevice,
// OccupancySensorDevice,
// OnOffLightDevice,
// OnOffLightSwitchDevice,
// OnOffPluginUnitDevice,
// OnOffSensorDevice,
// RootNodeDevice,
// SpeakerDevice,
// ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
// AreaAttendanceState,
// AreaPresenceState,
// Assistant,
// AssistantBroadcast,
// AssistantFulfillment,
// BasicInformation,
// BooleanState,
// OccupancySensing,
// OnOff,
// Notification,
// LevelControl,
// TemperatureControl,
// TemperatureMeasurement,
// Thermostat,
// Time,
// Volume,
)
}
HomeClient-Objekt initialisieren
Alle Apps, die die Home APIs verwenden, initialisieren ein HomeClient
-Objekt. Dies ist die Hauptschnittstelle für die Interaktion mit den APIs. Wir bereiten dieses Objekt im Initialisierer der Klasse HomeApp
(HomeApp.kt
) vor.
// Registry to record device types and traits used in this app:
val registry = FactoryRegistry(
types = supportedTypes,
traits = supportedTraits
)
// Configuration options for the HomeClient:
val config = HomeConfig(
coroutineContext = Dispatchers.IO,
factoryRegistry = registry
)
// Initialize the HomeClient, which is the primary object to use all Home APIs:
homeClient = Home.getClient(context = context, homeConfig = config)
Zuerst erstellen wir ein FactoryRegistry
mit den unterstützten Typen und Attributen, die wir zuvor definiert haben. Anschließend initialisieren wir mit dieser Registrierung ein HomeConfig
, das die Konfiguration enthält, die zum Ausführen der APIs erforderlich ist. Als Nächstes rufen wir Home.getClient(...)
auf, um die HomeClient
-Instanz abzurufen.
Unsere Interaktionen mit den Home-APIs erfolgen alle über dieses HomeClient
-Objekt.
Permissions API verwenden
Die Nutzerauthentifizierung für die Home APIs erfolgt über die Permissions API. Die PermissionsManager.kt
-Quelldatei der Beispiel-App enthält Code für die Nutzerauthentifizierung. Entfernen Sie die Auskommentierung des Inhalts der Funktionen checkPermissions(...)
und requestPermissions(...)
, um die Berechtigungen für die Beispiel-App zu aktivieren.
Registrierung:
homeClient.registerActivityResultCallerForPermissions(activity)
Wird eingeführt:
try {
val result: PermissionsResult
result = homeClient.requestPermissions(forceLaunch = true)
when (result.status) {
PermissionsResultStatus.SUCCESS -> // Success Case
PermissionsResultStatus.CANCELLED -> // User Cancelled
PermissionsResultStatus.ERROR -> // Some Error
else -> // Unsupported Case
}
}
catch (e: HomeException) { ... }
Wird geprüft:
try {
val state: PermissionsState
state = homeClient.hasPermissions().first { state ->
state != PermissionsState.PERMISSIONS_STATE_UNINITIALIZED
}
when (state) {
PermissionsState.GRANTED -> // Signed In
PermissionsState.NOT_GRANTED -> // Not Signed In
PermissionsState.PERMISSIONS_STATE_UNAVAILABLE -> // ...
PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> // ...
else -> // Unsupported case
}
}
catch (e: HomeException) { ... }
Abonnieren:
homeClient.hasPermissions().collect( { state ->
// Track the changes on state
} )
Entfernen Sie die Kommentarzeichen für Schritt 4.3.1 in PermissionsManager.kt
, um den Code zu aktivieren, mit dem die Berechtigungen angefordert werden:
fun requestPermissions() {
scope.launch {
try {
// TODO: 4.3.1 - Request the permissions from the Permissions API
// // Request permissions from the Permissions API and record the result:
// val result: PermissionsResult = client.requestPermissions(forceLaunch = true)
// // Adjust the sign-in status according to permission result:
// if (result.status == PermissionsResultStatus.SUCCESS)
// isSignedIn.emit(true)
// // Report the permission result:
// reportPermissionResult(result)
}
catch (e: HomeException) { MainActivity.showError(this, e.message.toString()) }
}
}
Führen Sie die App jetzt auf Ihrem Smartphone aus, folgen Sie der Anleitung und erteilen Sie die Berechtigungen. Sie sollten den folgenden Ablauf sehen:
Die Meldung „Wird geladen“ wird nicht geschlossen, da wir den Code, der die Struktur und die Geräte liest, noch nicht implementiert haben. Das machen wir im nächsten Abschnitt.
5. Informationen zum Datenmodell
In den Home-APIs besteht das Datenmodell aus:
Structure
steht für ein Zuhause mit Räumen und Geräten.Room
ist Teil einer Struktur und enthält Geräte.- Geräte (definiert als
HomeDevice
) können einer Struktur (oder einem Zuhause) oder einem Raum in einer Struktur zugewiesen werden. - Geräte bestehen aus einer oder mehreren
DeviceType
-Instanzen. DeviceType
besteht ausTrait
Instanzen.Trait
besteht ausAttribute
-Instanzen (zum Lesen/Schreiben),Command
-Instanzen (zum Steuern von Attributen) undEvent
-Instanzen (zum Lesen oder Abonnieren von Datensätzen mit vergangenen Änderungen).Automation
-Instanzen sind Teil einer Struktur und verwenden Metadaten und Geräte für das Zuhause, um Aufgaben im Zuhause zu automatisieren.
In diesem Abschnitt erfahren Sie, wie Sie den Quellcode entwickeln, um zu zeigen, wie Sie die Structure API verwenden, um Ihre Wohnstrukturen, Räume, Geräte usw. zu parsen und zu rendern.
Strukturen lesen
Das Design der Home APIs basiert auf Kotlin Flows, um die Datenmodellobjekte (z. B. Structure
, HomeDevice
usw.) zu streamen. Entwickler abonnieren ein Flow
, um alle im Objekt enthaltenen Objekte zu erhalten (z. B. ein Structure
, ein Room
usw.).
Rufen Sie die Funktion structures()
auf, um alle Strukturen abzurufen. Dadurch wird ein Stream von Strukturen zurückgegeben. Rufen Sie dann die Listenfunktion für den Ablauf auf, um alle Strukturen abzurufen, die dem Nutzer gehören.
// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
homeClient.structures() // HomeObjectsFlow<Structure>
.list() // Set<Structure>
Im Leitfaden zur App-Architektur wird dringend empfohlen, einen modernen reaktiven Programmieransatz zu verwenden, um den Datenfluss und das Statusmanagement der App zu verbessern.
So hält sich die Beispiel-App an den reaktiven Programmierstil:
- Ansichtsmodelle (z. B.
StructureViewModel
undDeviceViewModel
als State Holder) abonnieren die Flows aus dem Home APIs SDK, um Wertänderungen zu empfangen und die neuesten Status beizubehalten. - Views (wie
StructureView
undDeviceView
) abonnieren View-Modelle, um die Status zu empfangen und die Benutzeroberfläche entsprechend zu rendern. - Wenn ein Nutzer auf eine Schaltfläche in einer Ansicht klickt (z. B. die Schaltfläche „Ein“ eines Beleuchtungsgeräts), werden durch Ereignisse die Funktionen des Ansichtsmodells ausgelöst, die die entsprechenden Home-APIs-Funktionen aufrufen (z. B. den
On
-Befehl desOnOff
-Traits).
In Schritt 5.1.1 in HomeAppViewModel.kt
abonnieren wir Strukturänderungsereignisse, indem wir die Funktion collect()
aufrufen. Entfernen Sie die Auskommentierung des Abschnitts, in dem das structureSet
durchlaufen wird, das von der Structures API-Antwort zurückgegeben und im StructureViewModel's
StateFlow
bereitgestellt wird. Dadurch kann die App Änderungen des Strukturstatus überwachen:
private suspend fun subscribeToStructures() {
// TODO: 5.1.1 - Subscribe the structure data changes
// // Subscribe to structures returned by the Structures API:
// homeApp.homeClient.structures().collect { structureSet ->
// val structureVMList: MutableList<StructureViewModel> = mutableListOf()
// // Store structures in container ViewModels:
// for (structure in structureSet) {
// structureVMList.add(StructureViewModel(structure))
// }
// // Store the ViewModels:
// structureVMs.emit(structureVMList)
//
// // If a structure isn't selected yet, select the first structure from the list:
// if (selectedStructureVM.value == null && structureVMList.isNotEmpty())
// selectedStructureVM.emit(structureVMList.first())
//
// }
}
In DevicesView.kt
abonniert die App StructureViewModel'sStateFlow,
, wodurch die UI neu zusammengesetzt wird, wenn sich die Strukturdaten ändern. Entfernen Sie die Auskommentierung des Quellcodes in Schritt 5.1.2, um die Strukturliste als Drop-down-Menü zu rendern:
val structureVMs: List<StructureViewModel> = homeAppVM.structureVMs.collectAsState().value
...
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
// TODO: 5.1.2 - Show list of structures in DropdownMenu
// for (structure in structureVMs) {
// DropdownMenuItem(
// text = { Text(structure.name) },
// onClick = {
// scope.launch { homeAppVM.selectedStructureVM.emit(structure) }
// expanded = false
// }
// )
// }
}
...
Starten Sie die App noch einmal. Wenn Sie auf den Pfeil tippen, sollte das Menü angezeigt werden:
Struktur analysieren
Als Nächstes durchlaufen Sie die Home-Objekte in einer Struktur. Rufen Sie die Räume aus dem Gebäude ab:
val rooms: Set<Room>
rooms = structure.rooms().list()
Anschließend können Sie die Räume durchlaufen, um Geräte abzurufen:
val devices: Set<HomeDevice>
devices = room.devices().list()
Wichtig:Im Datenmodell der Home APIs kann ein Zuhause Geräte enthalten, die keinem Raum zugewiesen sind. Achten Sie also darauf, dass Sie auch die Geräte ohne Räume in Ihrer App erfassen:
val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()
for (device in structure.devices().list())
if (device.roomId == null)
devicesWithoutRooms.add(device)
Auch im vorhandenen Beispielcode abonnieren wir einen Flow, um die aktuelle Liste der Räume und Geräte zu erhalten. Sehen Sie sich den Code in den Schritten 5.2.1 und 5.2.2 in der Quelldatei StructureViewModel.kt
an und entfernen Sie die Kommentarzeichen, um das Abonnieren von Raumdaten zu aktivieren:
val roomVMs : MutableStateFlow<List<RoomViewModel>>
val deviceVMs : MutableStateFlow<List<DeviceViewModel>>
val deviceVMsWithoutRooms : MutableStateFlow<List<DeviceViewModel>>
private suspend fun subscribeToRooms() {
// TODO: 5.2.1 - Subscribe the room data changes
// // Subscribe to changes on rooms:
// structure.rooms().collect { roomSet ->
// val roomVMs = mutableListOf<RoomViewModel>()
// // Store rooms in container ViewModels:
// for (room in roomSet) {
// roomVMs.add(RoomViewModel(room))
// }
// // Store the ViewModels:
// this.roomVMs.emit(roomVMs)
// }
}
private suspend fun subscribeToDevices() {
// TODO: 5.2.2 - Subscribe the device data changes in a structure
// // Subscribe to changes on devices:
// structure.devices().collect { deviceSet ->
// val deviceVMs = mutableListOf<DeviceViewModel>()
// val deviceWithoutRoomVMs = mutableListOf<DeviceViewModel>()
// // Store devices in container ViewModels:
// for (device in deviceSet) {
// val deviceVM = DeviceViewModel(device)
// deviceVMs.add(deviceVM)
// // For any device that's not in a room, additionally keep track of a separate list:
// if (device.roomId == null)
// deviceWithoutRoomVMs.add(deviceVM)
// }
// // Store the ViewModels:
// this.deviceVMs.emit(deviceVMs)
// deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
// }
}
Entfernen Sie die Kommentarzeichen für die Schritte 5.2.3 und 5.2.4 in der Quelldatei DevicesView.kt
, um die Raumliste als Menü zu rendern:
val selectedRoomVMs: List<RoomViewModel> =
selectedStructureVM.roomVMs.collectAsState().value
...
for (roomVM in selectedRoomVMs) {
// TODO: 5.2.3 - Render the list of rooms
// RoomListItem(roomVM)
// TODO: 5.2.4 - Render the list of devices in a room
// val deviceVMsInRoom: List<DeviceViewModel> = roomVM.deviceVMs.collectAsState().value
//
// for (deviceVM in deviceVMsInRoom) {
// DeviceListItem(deviceVM, homeAppVM)
// }
}
Jetzt, da Sie die Geräte haben, erfahren Sie, wie Sie sie verwenden.
6. Mit Geräten arbeiten
Die Home APIs verwenden ein HomeDevice
-Objekt, um das Gerät und seine Funktionen zu erfassen. Entwickler können Geräteattribute abonnieren und damit Smart-Home-Geräte in ihren Apps darstellen.
Gerätestatus lesen
Das HomeDevice
-Objekt enthält eine Reihe statischer Werte, z. B. den Gerätenamen oder den Verbindungsstatus. Als Entwickler können Sie diese Informationen kurz nach Erhalt des Geräts über die APIs abrufen:
val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
device.sourceConnectivity.connectivityState
Um die Gerätefunktionen zu erhalten, müssen Sie die Typen und Merkmale aus HomeDevice
abrufen. Dazu können Sie den Gerätefluss so abonnieren und die Merkmale aus den Gerätetypen abrufen:
device.types().collect { typeSet ->
var primaryType : DeviceType = UnknownDeviceType()
for (typeInSet in typeSet)
if (typeInSet.metadata.isPrimaryType)
primaryType = typeInSet
val traits: List<Trait> = mutableListOf()
for (trait in primaryType.traits())
if (trait.factory in myTraits)
traits.add(trait)
for (trait in traits)
parseTrait(trait, primaryType)
}
Jedes Gerät enthält eine Reihe unterstützter DeviceType
(gebündelte Funktionen), die Sie mit device.types()
abrufen können. Diese Gerätetypen enthalten Merkmale, die mit type.traits()
abgerufen werden können. Jedes Gerät kennzeichnet einen seiner Typen als primären Typ (der mit type.metadata.isPrimaryType
geprüft werden kann), den Sie in Ihrer App darstellen sollten. Damit Nutzer die Funktionen vollständig nutzen können, empfehlen wir, alle zurückgegebenen Typen zu durchlaufen und alle verfügbaren Eigenschaften zu integrieren.
Nachdem Sie ein Merkmal abgerufen haben, können Sie es mit einer Funktion wie der folgenden parsen, um die Werte zu interpretieren:
fun <T : Trait?> parseTrait(trait : T, type: DeviceType) {
val status : String = when (trait) {
is OnOff -> { if (trait.onOff) "On" else "Off" }
is LevelControl -> { trait.currentLevel.toString() }
is BooleanState -> {
when (type.factory) {
ContactSensorDevice -> {
if (trait.stateValue) "Closed"
else "Open"
}
else -> ...
}
}
else -> ...
}
}
Je nach Gerätetyp, der ein Merkmal unterstützt (siehe BooleanState
im vorherigen Beispiel), kann es Unterschiede in der Bedeutung des Merkmals geben. Sie müssen also den Kontext jedes Gerätetyps kennen, um zu verstehen, was die Merkmale wirklich darstellen.
Entfernen Sie die Kommentarzeichen für die Schritte 6.1.1 und 6.1.2 in der Quelldatei DeviceViewModel.kt
, um die Status abzurufen:
private suspend fun subscribeToType() {
// Subscribe to changes on device type, and the traits/attributes within:
device.types().collect { typeSet ->
// Container for the primary type for this device:
var primaryType : DeviceType = UnknownDeviceType()
...
// TODO: 6.1.1 - Determine the primary type for this device
// // Among all the types returned for this device, find the primary one:
// for (typeInSet in typeSet)
// if (typeInSet.metadata.isPrimaryType)
// primaryType = typeInSet
//
// // Optional: For devices with a single type that did not define a primary:
// if (primaryType is UnknownDeviceType && typeSet.size == 1)
// primaryType = typeSet.first()
// Container for list of supported traits present on the primary device type:
val supportedTraits: List<Trait> = getSupportedTraits(primaryType.traits())
...
}
fun getSupportedTraits(traits: Set<Trait>) : List<Trait> {
val supportedTraits: MutableList<Trait> = mutableListOf()
// TODO: 6.1.2 - Get only the supported traits for this device
// for (trait in traits)
// if (trait.factory in HomeApp.supportedTraits)
// supportedTraits.add(trait)
return supportedTraits
}
Entfernen Sie die Kommentarzeichen für Schritt 6.1.3 in DeviceView.kt
, um ein OnOff-Trait mit seinem Namen und Status als String
zu rendern:
Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
// TODO: 6.1.3 - Render controls based on the trait type
// Column (Modifier.fillMaxWidth()) {
// Text(trait.factory.toString(), fontSize = 20.sp)
// Text(DeviceViewModel.getTraitStatus(trait, type), fontSize = 16.sp)
// }
...
}
is LevelControl -> {
...
}
is BooleanState -> {
...
}
is OccupancySensing -> {
...
}
...
}
Wenn Sie die App jetzt mit unterstützten Gerätetypen (z. B. einem Lichtgerät) ausführen, sollten die aktuellen Status für alle Geräte angezeigt werden.
Gerätebefehle ausgeben
Um Befehle an Geräte zu senden, bieten die Home APIs praktische Funktionen für Trait-Objekte wie trait.on()
oder trait.moveToLevel(...)
:
fun <T : Trait?> issueCommand(trait : T) {
when (trait) {
is OnOff -> {
// trait.on()
// trait.off()
}
is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
}
}
}
Tipp:Nachdem Sie den Typ des Attributs ermittelt haben, können Sie mit der Funktion zur automatischen Vervollständigung von Android Studio herausfinden, welche Aktionen für die Interaktion mit dem Attribut verfügbar sind.
Entfernen Sie die Auskommentierung von Schritt 6.2.1 in DeviceView.kt
, um der App funktionale Steuerelemente hinzuzufügen:
Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
....
// TODO: 6.2.1 - Render controls based on the trait type
// Switch (checked = (trait.onOff == true), modifier = Modifier.align(Alignment.CenterEnd),
// onCheckedChange = { state ->
// scope.launch { if (state) trait.on() else trait.off() }
// },
// enabled = isConnected
// )
}
Wenn Sie die App jetzt ausführen, sollten Sie damit physische Geräte steuern können.
Wenn du auf der Glühbirne auf die Ein/Aus-Steuerung tippst, sollte das Gerät jetzt eingeschaltet werden.
Weitere Informationen zum Steuern von Geräten finden Sie unter Geräte auf Android-Geräten steuern.
7. Geräte in Betrieb nehmen
Mit der Commissioning API können Entwickler Geräte dem Google Home-Ökosystem hinzufügen und sie über die Home APIs steuern. Es werden nur Matter-Geräte unterstützt. In diesem Abschnitt erfahren Sie, wie Sie die Geräteinbetriebnahme in Ihren Apps aktivieren können.
Bevor Sie mit diesem Abschnitt beginnen, sollten Sie prüfen, ob die folgenden Voraussetzungen erfüllt sind:
- Ein Google-Hub, der Matter unterstützt, wurde in der Google Home App hinzugefügt und befindet sich im selben Netzwerk wie Ihr Android-Smartphone.
- Sie haben in der Google Home Developer Console ein Entwicklerprojekt mit der VID
0xFFF1
und der PID0x8000
erstellt.
Wenn Sie ein physisches Matter-Gerät mit einem QR-Code für die Inbetriebnahme haben, können Sie direkt zum Abschnitt Inbetriebnahme-API aktivieren springen. Andernfalls fahren Sie mit dem nächsten Abschnitt fort, in dem wir erläutern, wie Sie mit der Matter Virtual Device App (MVD) in Betrieb zu nehmende virtuelle Geräte erstellen können.
Optional: Matter-kompatibles Gerät vorbereiten
Am einfachsten lässt sich ein Matter-kompatibles Gerät mit einem emulierten Gerät vorbereiten, das von der App Matter Virtual Device (MVD) bereitgestellt wird.
Führen Sie den MVD nach der Installation und Einrichtung der Firewall aus:
Erstellen Sie ein OnOff-Gerät. Es wurde noch nicht in Betrieb genommen. Das erfolgt später in diesem Codelab.
Commissioning API aktivieren
Die Commissioning API funktioniert außerhalb der Activity der App. Daher muss die Inbetriebnahme anders als bei den anderen Home APIs gehandhabt werden. Damit Ihre App für die Inbetriebnahme bereit ist, benötigen Sie zwei Variablen.
Eine Variable ist ActivityResultLauncher
, die zum Senden der Intention zur Inbetriebnahme und zum Verwalten des Ergebnis-Callbacks verwendet wird. Die andere Variable ist CommissioningResult
. Sie ist das Objekt, in dem das Ergebnis der Inbetriebnahme gespeichert wird. Im folgenden Beispiel sehen Sie, wie Sie die Inbetriebnahme einrichten:
var launcher: ActivityResultLauncher<IntentSenderRequest>
lateinit var commissioningResult: CommissioningResult?
launcher = activity.registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
commissioningResult = CommissioningResult.fromIntentSenderResult(
result.resultCode, result.data)
} catch (exception: ApiException) {
// Catch any issues
}
}
Nachdem Sie den Ablauf für die Inbetriebnahme eingerichtet haben, erstellen Sie den Intent für die Inbetriebnahme und starten ihn mit dem Launcher, den wir im vorherigen Beispiel erstellt haben. Wir empfehlen, die Intent- und Launcher-Elemente in einer dedizierten Funktion wie der folgenden zu platzieren. Eine bestimmte Funktion kann an ein UI-Element (z. B. die Schaltfläche +Gerät hinzufügen) gebunden und auf Nutzeranfrage aufgerufen werden:
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
scope.launch {
// Create a commissioning request to store the device in Google's Fabric:
val request = CommissioningRequest.builder()
.setStoreToGoogleFabric(true)
.setOnboardingPayload(payload)
.build()
// Initialize client and sender for commissioning intent:
val client: CommissioningClient = Matter.getCommissioningClient(context)
val sender: IntentSender = client.commissionDevice(request).await()
// Launch the commissioning intent on the launcher:
launcher.launch(IntentSenderRequest.Builder(sender).build())
}
}
Entfernen Sie die Auskommentierung von Schritt 7.1.1 in CommissioningManager.kt
, um die Inbetriebnahme zu aktivieren und die Schaltfläche + Gerät hinzufügen in der Beispiel-App zu aktivieren.
// Called by +Add Device button in DeviceView.kt
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
// TODO: 7.1.1 - Launch the commissioning intent
// scope.launch {
// // Create a commissioning request to store the device in Google's Fabric:
// val request = CommissioningRequest.builder()
// .setStoreToGoogleFabric(true)
// .setOnboardingPayload(payload)
// .build()
// // Initialize client and sender for commissioning intent:
// val client: CommissioningClient = Matter.getCommissioningClient(context)
// val sender: IntentSender = client.commissionDevice(request).await()
// // Launch the commissioning intent on the launcher:
// launcher.launch(IntentSenderRequest.Builder(sender).build())
// }
}
Wenn Sie diese Funktion ausführen, sollte der Ablauf zur Inbetriebnahme gestartet werden. Auf dem Bildschirm sollte dann Folgendes angezeigt werden:
Ablauf der Inbetriebnahme
Der Inbetriebnahmeprozess umfasst eine Reihe von Bildschirmen, die den Nutzer beim Hinzufügen eines Geräts zu seinem Google-Konto unterstützen:
Den Nutzern wird ein QR‑Code-Scanner angezeigt, mit dem sie die QR‑Codes von Matter-Geräten scannen können. Im weiteren Verlauf werden die Nutzungsbedingungen, die Gerätesuche und ‑inbetriebnahme sowie die Benennung des Geräts angezeigt. Sobald der Ablauf abgeschlossen ist, wird der Fokus wieder auf die App gerichtet und das Ergebnis der Inbetriebnahme wird in der Callback-Funktion übergeben, die wir im vorherigen Abschnitt erstellt haben.
Ein Vorteil der Commissioning APIs ist, dass der UX-Ablauf vom SDK übernommen wird, sodass Entwickler sehr schnell loslegen können. Außerdem wird so eine einheitliche Nutzererfahrung beim Hinzufügen von Geräten in verschiedenen Apps geschaffen.
Weitere Informationen zur Commissioning API finden Sie unter Commissioning API on Android.
8. Glückwunsch!
Glückwunsch! Sie haben erfolgreich eine Android-App mit den Google Home-APIs erstellt. In diesem Codelab haben Sie sich mit den APIs für Berechtigungen, Geräte, Gebäude und Inbetriebnahmen beschäftigt. Im nächsten Codelab, Erweiterte Automatisierungen mit den Home APIs unter Android erstellen, sehen wir uns die Automation und Discovery APIs an und schließen die App ab.
Wir hoffen, dass Sie viel Spaß beim Entwickeln von Apps haben, mit denen Geräte im Google Home-Ökosystem auf kreative Weise gesteuert werden können.
Nächste Schritte
- Setzen Sie Ihre Reise fort und lernen Sie die Home APIs auf Android kennen, indem Sie das zweite Codelab dieser Reihe durcharbeiten: Erweiterte automatisierte Abläufe mit den Home APIs auf Android erstellen.
- Sie können uns jederzeit Empfehlungen senden oder Probleme über die Problemverfolgung im Supportthema „Smart Home“ melden.