1. Prima di iniziare
Le API Google Home forniscono un insieme di librerie per consentire agli sviluppatori Android di accedere all'ecosistema Google Home. Con queste nuove API, gli sviluppatori possono creare app che eseguono il provisioning e controllano senza problemi i dispositivi per la smart home.
Google fornisce un'app di esempio per Android per gli sviluppatori che vogliono accedere a un esempio funzionante utilizzando le API Google Home. Questo codelab si basa su un ramo dell'app di esempio che ti guida nell'utilizzo delle API Permissions, Commissioning, Device e Structure.
Prerequisiti
- Conoscenza dell'ecosistema Google Home (cloud-to-cloud e Matter).
- Una workstation con Android Studio (2024.3.1 Ladybug o versioni successive) installato.
- Uno smartphone Android che soddisfi i requisiti delle API Home (vedi Prerequisiti) con Google Play Services e l'app Google Home installati. Un emulatore non funzionerà, solo gli smartphone Android fisici sono supportati per l'app di esempio.
- Un Google Nest Hub compatibile che supporti le API Google Home.
- Facoltativo: un dispositivo per la smart home compatibile con le API Google Home.
Obiettivi didattici
- Come creare un'app per Android utilizzando le API Google Home con le best practice.
- Come utilizzare le API Device e Structure per rappresentare e controllare una smart home.
- Come utilizzare le API di provisioning per aggiungere dispositivi all'ecosistema Google Home.
(Facoltativo) Configurare la casa
Prima di utilizzare le API Google Home, devi configurare una casa sul tuo Account Google utilizzando l'app Google Home e aggiungere alcuni dispositivi. Questa sezione spiega come farlo utilizzando Google Home Playground, che fornisce dispositivi per la smart home virtuali.
Apri home-playground.withgoogle.com nel browser web, accedi con il tuo Account Google e verifica se vengono visualizzati i seguenti dispositivi emulati:
- presa1: presa on/off
- light2: Luce dimmerabile
- light3: On/Off light
- ac3: Air conditioner
- blinds4: Window Covering
- washer5: Smart washer
Apri l'app Google Home sul dispositivo mobile, tocca il pulsante Aggiungi e seleziona Compatibile con Google Home. Cerca "playground" nell'elenco, seleziona il progetto "Google Home Playground" e tocca Continua.
Google Home Playground mostrerà una pagina di autorizzazione dell'account. Tocca Autorizza o Accedi con Google. Vedrai tutti i dispositivi che hai configurato dall'app web nell'app mobile.
Seleziona tutti i dispositivi e completa la procedura di configurazione. Tornando alla home page, vedrai tutti i dispositivi disponibili.
I dispositivi supportati nell'elenco sono ora disponibili per l'utilizzo con le API Google Home.
2. Configura il progetto
Il seguente diagramma illustra l'architettura di un'app Home APIs:
- Codice app:il codice principale su cui gli sviluppatori lavorano per creare l'interfaccia utente dell'app e la logica per interagire con l'SDK Home APIs.
- SDK Home APIs:l'SDK Home APIs fornito da Google funziona con il servizio Home APIs in GMSCore per controllare i dispositivi per la smart home. Gli sviluppatori creano app che funzionano con le API Home raggruppandole con l'SDK Home APIs.
- GMSCore su Android: GMSCore, noto anche come Google Play Services, è una piattaforma Google che fornisce servizi di sistema di base, consentendo funzionalità chiave su tutti i dispositivi Android certificati. Il modulo Home di Google Play Services contiene i servizi che interagiscono con le API Home.
Configura l'SDK Home
Per ottenere l'SDK più recente, segui i passaggi descritti in Configurare l'SDK.
Ottieni l'app di esempio
Il codice sorgente dell'app di esempio è disponibile su GitHub. Questo codelab utilizza gli esempi del ramo codelab-branch-1
dell'app di esempio.
Vai alla posizione in cui vuoi salvare il progetto e clona il ramo codelab-branch-1
:
$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git
Crea l'app di esempio
Esegui i passaggi 1-5 della sezione Crea l'app.
Quando l'app viene eseguita correttamente sullo smartphone, viene visualizzata la pagina principale dell'app di esempio. Tuttavia, non potrai accedere finché non configurerai l'autenticazione OAuth e implementerai i componenti mancanti utilizzando l'API Permissions.
3. Configurare l'autenticazione
Le API Home utilizzano OAuth 2.0 per concedere l'accesso ai dispositivi nella struttura. OAuth consente a un utente di concedere l'autorizzazione a un'app o a un servizio senza dover esporre le proprie credenziali di accesso.
Segui le istruzioni riportate in Configurare il consenso OAuth per configurare la schermata per il consenso. Assicurati di creare almeno un account di test.
Poi segui le istruzioni riportate in Configurare le credenziali OAuth per creare le credenziali per l'app.
4. Inizializzazione e gestione delle autorizzazioni
In questa sezione imparerai a inizializzare l'SDK e a gestire le autorizzazioni utente completando le parti mancanti utilizzando l'API Permissions.
Definisci i tipi e i tratti supportati
Quando sviluppi un'app, devi indicare esplicitamente quali tipi di dispositivi e caratteristiche supporterà. Nell'app di esempio, questa operazione viene eseguita definendo elenchi statici nell'oggetto complementare in HomeApp.kt
, a cui è possibile fare riferimento in tutta l'app in base alle esigenze:
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,
// ...
)
}
Consulta Tipi di dispositivi supportati e Indice delle caratteristiche su Android per visualizzare tutti i tipi di dispositivi e le caratteristiche supportati.
Rimuovi il commento dai passaggi 4.1.1 e 4.1.2 nel file di origine HomeApp.kt
per attivare il codice sorgente che richiede l'autorizzazione.
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,
)
}
Inizializza l'oggetto HomeClient
Tutte le app che utilizzano le API Home inizializzano un oggetto HomeClient
, che è l'interfaccia principale per interagire con le API. Prepariamo questo oggetto nell'inizializzatore della classe HomeApp
(HomeApp.kt
).
// 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)
Innanzitutto, creiamo un FactoryRegistry
utilizzando i tipi e i tratti supportati che abbiamo definito in precedenza. Poi, utilizzando questo registro, inizializziamo un HomeConfig
, che contiene la configurazione necessaria per eseguire le API. Successivamente, utilizziamo la chiamata Home.getClient(...)
per acquisire l'istanza HomeClient
.
Tutte le nostre interazioni con le API Home avverranno tramite questo oggetto HomeClient
.
Utilizzare l'API Permissions
L'autenticazione utente per le API Home viene eseguita tramite l'API Permissions. Il file di origine PermissionsManager.kt
dell'app di esempio contiene il codice per l'autenticazione utente. Rimuovi il commento dai contenuti delle funzioni checkPermissions(...)
e requestPermissions(...)
per attivare le autorizzazioni per l'app di esempio.
Registrazione in corso:
homeClient.registerActivityResultCallerForPermissions(activity)
Lancio:
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) { ... }
Controllo:
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) { ... }
Sottoscrizione in corso:
homeClient.hasPermissions().collect( { state ->
// Track the changes on state
} )
Rimuovi il commento dal passaggio 4.3.1 in PermissionsManager.kt
per attivare il codice che richiede le autorizzazioni:
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()) }
}
}
Ora esegui l'app sullo smartphone, seguendo i passaggi e consentendo le autorizzazioni. Dovresti vedere il seguente flusso:
Il messaggio "Caricamento" non scompare mai, ma questo perché non abbiamo implementato il codice che legge la struttura e i dispositivi. Lo faremo nella sezione successiva.
5. Informazioni sul modello dei dati
Nelle API Home, il modello dei dati è composto da:
Structure
rappresenta una casa che contiene stanze e dispositivi.Room
fa parte di una struttura e contiene dispositivi.- I dispositivi (definiti come
HomeDevice
) possono essere assegnati a una struttura (o casa) o a una stanza della struttura. - I dispositivi sono composti da una o più istanze
DeviceType
. DeviceType
è composto daTrait
istanze.Trait
è composto daAttribute
istanze (per la lettura/scrittura),Command
istanze (per il controllo degli attributi) eEvent
istanze (per la lettura o la sottoscrizione dei record delle modifiche passate).- Le istanze
Automation
fanno parte di una struttura e utilizzano i metadati e i dispositivi della casa per automatizzare le attività in casa.
In questa sezione imparerai a sviluppare il codice sorgente per mostrare come utilizzare l'API Structure per analizzare e visualizzare le strutture della casa, le stanze, i dispositivi e così via.
Strutture di lettura
La progettazione delle API Home si basa su Kotlin Flows per trasmettere in streaming gli oggetti del modello di dati (ad esempio Structure
, HomeDevice
e così via). Gli sviluppatori si abbonano a un Flow
per ottenere tutti gli oggetti contenuti nell'oggetto (ad esempio, un Structure
, un Room
e così via).
Per recuperare tutte le strutture, chiama la funzione structures()
, che restituisce un flusso di strutture. Quindi, chiama la funzione di elenco nel flusso per ottenere tutte le strutture di proprietà dell'utente.
// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
homeClient.structures() // HomeObjectsFlow<Structure>
.list() // Set<Structure>
La Guida all'architettura delle app consiglia vivamente di adottare un approccio di programmazione reattiva moderno per migliorare il flusso di dati e la gestione dello stato delle app.
Ecco come l'app di esempio rispetta lo stile di programmazione reattiva:
- Le visualizzazioni (come
StructureViewModel
eDeviceViewModel
, in qualità di titolari dello stato) si iscrivono ai flussi dell'SDK Home APIs per ricevere le modifiche dei valori e mantenere gli stati più recenti. - Le visualizzazioni (come
StructureView
eDeviceView
) si abbonano ai modelli di visualizzazione per ricevere gli stati e visualizzare l'interfaccia utente in modo da riflettere queste modifiche. - Quando un utente fa clic su un pulsante di una visualizzazione (ad esempio, il pulsante "On" di un dispositivo di illuminazione), gli eventi attivano le funzioni del modello di visualizzazione, che chiamano le funzioni delle API Home corrispondenti (ad esempio, il comando
On
del trattoOnOff
).
Nel passaggio 5.1.1 di HomeAppViewModel.kt
, ci abboniamo agli eventi di modifica della struttura chiamando la funzione collect()
. Rimuovi il commento dalla sezione che attraversa structureSet
restituito dalla risposta dell'API Structures e fornito in StructureViewModel's
StateFlow
. Ciò consente all'app di monitorare le modifiche allo stato della struttura:
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
, l'app si iscrive a StructureViewModel'sStateFlow,
, che attiva la ricomposizione dell'interfaccia utente quando cambiano i dati strutturati. Rimuovi il commento dal codice sorgente nel passaggio 5.1.2 per visualizzare l'elenco della struttura come menu a discesa:
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
// }
// )
// }
}
...
Esegui di nuovo l'app. Quando tocchi la freccia, dovresti vedere il menu:
Analizzare la struttura
Il passaggio successivo consiste nell'attraversare gli oggetti della casa in una struttura. Recupera le stanze dalla struttura:
val rooms: Set<Room>
rooms = structure.rooms().list()
Puoi quindi spostarti tra le stanze per recuperare i dispositivi:
val devices: Set<HomeDevice>
devices = room.devices().list()
Importante:nel modello di dati delle API Home, una struttura può contenere dispositivi non assegnati a una stanza, quindi assicurati di acquisire anche i dispositivi senza stanze nella tua app:
val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()
for (device in structure.devices().list())
if (device.roomId == null)
devicesWithoutRooms.add(device)
Anche in questo caso, nel codice campione esistente, ci abboniamo a un flusso per ottenere l'elenco più recente di stanze e dispositivi. Controlla il codice nei passaggi 5.2.1 e 5.2.2 del file di origine StructureViewModel.kt
e rimuovi il commento per attivare l'abbonamento ai dati della stanza:
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)
// }
}
Rimuovi il commento dai passaggi 5.2.3 e 5.2.4 nel file di origine DevicesView.kt
per visualizzare l'elenco delle stanze come menu:
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)
// }
}
Ora che hai i dispositivi, impareremo a utilizzarli.
6. Utilizzare i dispositivi
Le API Home utilizzano un oggetto HomeDevice
per acquisire il dispositivo e le sue funzionalità. Gli sviluppatori possono abbonarsi agli attributi dei dispositivi e utilizzarli per rappresentare i dispositivi per la smart home nelle loro app.
Lettura degli stati dei dispositivi
L'oggetto HomeDevice
presenta un insieme di valori statici, come il nome del dispositivo o lo stato della connettività. In qualità di sviluppatore, puoi recuperare questi dati dalle API subito dopo aver ricevuto il dispositivo:
val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
device.sourceConnectivity.connectivityState
Per ottenere le funzionalità del dispositivo, devi recuperare i tipi e i tratti da HomeDevice
. Per farlo, puoi abbonarti al flusso del tipo di dispositivo nel seguente modo e recuperare i tratti dai tipi di dispositivo:
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)
}
Ogni dispositivo contiene un insieme di DeviceType
supportate (funzionalità in bundle), che puoi recuperare utilizzando device.types()
. Questi tipi di dispositivi contengono caratteristiche che possono essere recuperate utilizzando type.traits()
. Ogni dispositivo contrassegna uno dei suoi tipi come tipo principale (che può essere controllato utilizzando type.metadata.isPrimaryType
) che devi rappresentare nella tua app. Per offrire un'esperienza completa agli utenti, ti consigliamo di attraversare tutti i tipi restituiti e integrare tutti i tratti a tua disposizione.
Una volta recuperato un tratto, puoi analizzarlo utilizzando una funzione come la seguente per interpretare i valori:
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 -> ...
}
}
Tieni presente che ciò che rappresenta un tratto può variare a seconda del tipo di dispositivo che lo include (vedi BooleanState
nell'esempio precedente), quindi devi conoscere il contesto di ogni tipo di dispositivo per capire cosa rappresentano realmente i suoi tratti.
Rimuovi il commento dai passaggi 6.1.1 e 6.1.2 nel file di origine DeviceViewModel.kt
per recuperare gli stati:
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
}
Rimuovi il commento dal passaggio 6.1.3 in DeviceView.kt
per eseguire il rendering di un tratto OnOff, inclusi nome e stato, come String
:
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 -> {
...
}
...
}
Se esegui l'app ora con i tipi di dispositivi supportati (ad esempio un dispositivo di illuminazione), dovresti visualizzare gli stati aggiornati di tutti i dispositivi.
Esegui comandi dispositivo
Per inviare comandi ai dispositivi, le API Home forniscono funzioni pratiche sugli oggetti tratto, ad esempio trait.on()
o trait.moveToLevel(...)
:
fun <T : Trait?> issueCommand(trait : T) {
when (trait) {
is OnOff -> {
// trait.on()
// trait.off()
}
is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
}
}
}
Suggerimento:una volta determinato il tipo di tratto, utilizza la funzionalità di completamento automatico di Android Studio per vedere quali tipi di azioni sono disponibili per interagire con il tratto.
Rimuovi il commento dal passaggio 6.2.1 in DeviceView.kt
per aggiungere controlli funzionali nell'app:
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
// )
}
Se esegui l'app ora, dovrebbe consentirti di controllare dispositivi fisici reali.
Se tocchi il controllo OnOff sulla lampadina, il dispositivo dovrebbe accendersi.
Per saperne di più su come controllare i dispositivi, vedi Controllare i dispositivi su Android.
7. Configurare i dispositivi
L'API Commissioning consente agli sviluppatori di aggiungere dispositivi all'ecosistema Google Home e di renderli disponibili per il controllo tramite le API Home. Sono supportati solo i dispositivi Matter. In questa sezione esploreremo come abilitare il provisioning dei dispositivi nelle tue app.
Prima di iniziare questa sezione, assicurati che siano soddisfatti i seguenti prerequisiti:
- Un Google Hub che supporta Matter si trova nella stessa rete del tuo smartphone Android ed è stato aggiunto all'app Google Home.
- Hai creato un progetto per sviluppatori nella console per sviluppatori Google Home con l'ID fornitore
0xFFF1
e l'ID prodotto0x8000
.
Se hai un dispositivo Matter fisico con un codice QR per il provisioning, puoi passare direttamente ad Abilitare l'API di provisioning. In caso contrario, continua con la sezione successiva, in cui viene illustrato come utilizzare l'app Matter Virtual Device (MVD) per creare dispositivi virtuali commissionabili.
(Facoltativo) Prepara un dispositivo commissionabile Matter
Il modo più semplice per preparare un dispositivo commissionabile Matter è utilizzare un dispositivo emulato fornito dall'app Matter Virtual Device (MVD).
Dopo aver installato MVD e configurato il firewall, esegui MVD:
Crea un dispositivo OnOff. Tieni presente che non è ancora stato commissionato. Lo farai più avanti in questo codelab.
Abilita l'API Commissioning
L'API Commissioning funziona al di fuori dell'attività dell'app, pertanto il provisioning deve essere gestito in modo diverso rispetto alle altre API Home. Per preparare l'app per la messa in servizio, sono necessarie due variabili.
Una variabile è ActivityResultLauncher
, che viene utilizzata per inviare l'intent di provisioning e per gestire il callback dei risultati. L'altra variabile è CommissioningResult
, ovvero l'oggetto utilizzato per archiviare il risultato del provisioning. Vedi l'esempio seguente per scoprire come configurare la commissione:
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
}
}
Una volta configurato il flusso di commissioning, creerai l'intent di commissioning e lo avvierai utilizzando il launcher creato nell'esempio precedente. Ti consigliamo di inserire l'intent e l'avvio in una funzione dedicata come la seguente. Una funzione dedicata può essere associata a un elemento dell'interfaccia utente (ad esempio un pulsante +Aggiungi dispositivo) e richiamata in base alla richiesta dell'utente:
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())
}
}
Rimuovi il commento dal passaggio 7.1.1 in CommissioningManager.kt
per attivare la funzionalità di provisioning e far funzionare il pulsante +Aggiungi dispositivo nell'app di esempio.
// 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())
// }
}
L'esecuzione di questa funzione dovrebbe avviare il flusso di provisioning, che dovrebbe mostrare una schermata simile allo screenshot seguente:
Informazioni sul flusso di commissioning
Il flusso di provisioning include una serie di schermate che guidano l'utente nell'aggiunta di un dispositivo al proprio Account Google:
Gli utenti visualizzeranno uno scanner di codici QR che possono utilizzare per scansionare i codici QR dei dispositivi Matter. Il flusso proseguirà con la visualizzazione del Contratto con l'utente, il rilevamento e il provisioning del dispositivo e l'assegnazione del nome al dispositivo. Al termine del flusso, il focus tornerà sull'app e il risultato della configurazione verrà passato alla funzione di callback che abbiamo creato nella sezione precedente.
Uno dei vantaggi delle API di provisioning è che il flusso UX viene gestito dall'SDK, quindi gli sviluppatori possono iniziare a lavorare molto rapidamente. In questo modo, gli utenti hanno un'esperienza coerente quando aggiungono dispositivi in app diverse.
Per saperne di più sull'API di provisioning, visita la pagina API di provisioning su Android.
8. Complimenti!
Complimenti! Hai creato correttamente un'app per Android utilizzando le API Google Home. Nel corso di questo codelab, hai esplorato le API Permissions, Devices, Structures e Commissioning. Nel prossimo codelab, Create advanced automations using the Home APIs on Android Codelab, esploreremo le API Automation e Discovery e completeremo l'app.
Ci auguriamo che ti divertirai a creare app che controllano in modo creativo i dispositivi all'interno dell'ecosistema Google Home.
Passaggi successivi
- Continua il tuo percorso di apprendimento delle API Home su Android completando il secondo codelab di questa serie: Crea automazioni avanzate utilizzando le API Home su Android.
- Puoi contattarci per eventuali consigli o segnalare problemi tramite Issue Tracker, l'argomento di assistenza per la smart home.