1. Antes de comenzar
Las APIs de Google Home proporcionan un conjunto de bibliotecas para que los desarrolladores de Android aprovechen el ecosistema de Google Home. Con estas nuevas APIs, los desarrolladores pueden compilar apps que comisionen y controlen dispositivos de casa inteligente sin problemas.
Google proporciona una app de ejemplo para Android a los desarrolladores que quieran acceder a un ejemplo en funcionamiento con las APIs de Google Home. Este codelab se basa en una rama de la app de ejemplo que te muestra cómo usar las APIs de Permissions, Commissioning, Device y Structure.
Requisitos previos
- Conocimiento del ecosistema de Google Home (de nube a nube y Matter).
- Una estación de trabajo con Android Studio (Ladybug 2024.3.1 o una versión posterior) instalado
- Un teléfono Android que cumpla con los requisitos de las APIs de Home (consulta los Requisitos previos) con los Servicios de Google Play y la app de Google Home instalados
- Un Google Home Hub compatible que admita las APIs de Google Home
- Opcional: Un dispositivo de casa inteligente compatible con las APIs de Google Home.
Qué aprenderás
- Cómo compilar una app para Android con las APIs de Google Home y las prácticas recomendadas
- Cómo usar las APIs de Device y Structure para representar y controlar una casa inteligente
- Cómo usar las APIs de comisión para agregar dispositivos al ecosistema de Google Home
Opcional: Configura tu casa
Antes de usar las APIs de Google Home, deberás configurar una casa en tu Cuenta de Google con la app de Google Home y agregar algunos dispositivos. En esta sección, se explica cómo hacerlo con Google Home Playground, que proporciona dispositivos inteligentes del hogar virtuales.
Abre home-playground.withgoogle.com en tu navegador web, accede con tu Cuenta de Google y comprueba si aparecen los siguientes dispositivos emulados:
- outlet1: Enchufe de encendido/apagado
- light2: Luz regulable
- light3: Luz de encendido/apagado
- ac3: Aire acondicionado
- blinds4: Cobertura de ventana
- washer5: Lavadora inteligente
Abre la app de Google Home en tu dispositivo móvil, presiona el botón Agregar y selecciona Funciona con Google Home. Busca "playground" en la lista, selecciona el proyecto "Google Home Playground" y presiona Continuar.
En Google Home Playground, se te mostrará una página de autorización de la cuenta. Presiona Autorizar o Acceder con Google. Verás todos los dispositivos que configuraste desde la app web en la app para dispositivos móviles.
Selecciona todos los dispositivos y completa el proceso de configuración. Si vuelves a la página principal, verás todos los dispositivos disponibles.
Los dispositivos compatibles de la lista ahora están disponibles para usarse con las APIs de Google Home.
2. Configura tu proyecto
En el siguiente diagrama, se ilustra la arquitectura de una app de las APIs de Home:
- Código de la app: Es el código principal en el que trabajan los desarrolladores para compilar la interfaz de usuario de la app y la lógica para interactuar con el SDK de las APIs de Home.
- SDK de las APIs de Home: El SDK de las APIs de Home que proporciona Google funciona con el servicio de las APIs de Home en GMSCore para controlar dispositivos de casa inteligente. Los desarrolladores compilan apps que funcionan con las APIs de Home combinándolas con el SDK de las APIs de Home.
- GMSCore en Android: GMSCore, también conocido como Servicios de Google Play, es una plataforma de Google que proporciona servicios principales del sistema, lo que habilita funciones clave en todos los dispositivos Android certificados. El módulo principal de los Servicios de Google Play contiene los servicios que interactúan con las APIs de Home.
Configura el SDK de Home
Sigue los pasos que se describen en Configura el SDK para obtener el SDK más reciente.
Obtén la app de ejemplo
El código fuente de la app de ejemplo está disponible en GitHub. En este codelab, se usan los ejemplos de la rama codelab-branch-1
de la app de ejemplo.
Navega hasta donde quieras guardar el proyecto y clona la rama codelab-branch-1
:
$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git
Compila la app de ejemplo
Realiza los pasos del 1 al 5 en Compila la app.
Cuando la app se ejecute correctamente en tu teléfono, verás la página principal de la app de ejemplo. Sin embargo, no podrás acceder hasta que configures la autenticación de OAuth y, luego, implementes los elementos faltantes con la API de Permission.
3. Configura la autenticación
Las APIs de Home usan OAuth 2.0 para otorgar acceso a los dispositivos de la estructura. OAuth permite que un usuario otorgue permiso a una app o un servicio sin tener que exponer sus credenciales de acceso.
Sigue las instrucciones que se indican en Configura el consentimiento de OAuth para configurar la pantalla de consentimiento. Asegúrate de crear al menos una cuenta de prueba.
Luego, sigue las instrucciones que se indican en Configura credenciales de OAuth para crear las credenciales de la app.
4. Permisos de inicialización y manejo
En esta sección, aprenderás a inicializar el SDK y a controlar los permisos de los usuarios completando las piezas faltantes con la API de Permissions.
Define los tipos y atributos admitidos
Cuando desarrollas una app, debes tener en cuenta de forma explícita qué tipos de dispositivos y atributos admitirá. En la app de ejemplo, para ello, definimos listas estáticas en el objeto complementario en HomeApp.kt
, a las que se puede hacer referencia en toda la app según sea necesario:
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 Tipos de dispositivos compatibles y Índice de atributos en Android para ver todos los tipos de dispositivos y atributos compatibles.
Quita el comentario de los pasos 4.1.1 y 4.1.2 en el archivo fuente HomeApp.kt
para habilitar el código fuente que solicita el permiso.
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,
)
}
Cómo inicializar el objeto HomeClient
Todas las apps que usan las APIs de Home inicializan un objeto HomeClient
, que es la interfaz principal para interactuar con las APIs. Preparamos este objeto en el inicializador de la clase 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)
Primero, creamos un FactoryRegistry
con los tipos y atributos admitidos que definimos antes. Luego, con este registro, inicializamos un HomeConfig
, que contiene la configuración necesaria para ejecutar las APIs. A continuación, usamos la llamada Home.getClient(...)
para adquirir la instancia de HomeClient
.
Todas nuestras interacciones con las APIs de Home serán a través de este objeto HomeClient
.
Usa la API de Permissions
La autenticación de usuarios para las APIs de Home se realiza a través de la API de Permissions. El archivo fuente PermissionsManager.kt
de la app de ejemplo contiene código para la autenticación del usuario. Quita el comentario del contenido de las funciones checkPermissions(...)
y requestPermissions(...)
para habilitar los permisos de la app de ejemplo.
Registro:
homeClient.registerActivityResultCallerForPermissions(activity)
Lanzamiento:
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) { ... }
Verificación:
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) { ... }
Suscripción:
homeClient.hasPermissions().collect( { state ->
// Track the changes on state
} )
Quita el comentario del paso 4.3.1 en PermissionsManager.kt
para habilitar el código que solicita los permisos:
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()) }
}
}
Ahora, ejecuta la app en tu teléfono, sigue los pasos y permite los permisos. Deberías ver el siguiente flujo:
El mensaje “Cargando” nunca desaparece, pero esto se debe a que no implementamos el código que lee la estructura y los dispositivos. Lo haremos en la siguiente sección.
5. Obtén información sobre el modelo de datos
En las APIs de Home, el modelo de datos se compone de lo siguiente:
Structure
representa una casa que contiene habitaciones y dispositivos.Room
es parte de una estructura y contiene dispositivos.- Los dispositivos (definidos como
HomeDevice
) se pueden asignar a una estructura (o casa) o a una habitación de la estructura. - Los dispositivos se componen de una o más instancias de
DeviceType
. DeviceType
se compone de instancias deTrait
.Trait
se compone de instancias deAttribute
(para lectura y escritura), instancias deCommand
(para controlar atributos) e instancias deEvent
(para leer o suscribir registros de cambios anteriores).- Las instancias de
Automation
forman parte de una estructura y usan metadatos y dispositivos de la casa para automatizar tareas en ella.
En esta sección, aprenderás a desarrollar el código fuente para mostrar cómo usar la API de Structure para analizar y renderizar las estructuras, las habitaciones, los dispositivos de tu casa, etcétera.
Cómo leer estructuras
El diseño de las APIs de Home se basa en Flujos de Kotlin para transmitir los objetos del modelo de datos (por ejemplo, Structure
, HomeDevice
, etcétera). Los desarrolladores se suscriben a un Flow
para obtener todos los objetos que contiene (por ejemplo, un Structure
, un Room
, etcétera).
Para recuperar todas las estructuras, llama a la función structures()
, que muestra un flujo de estructuras. Luego, llama a la función de lista en el flujo para obtener todas las estructuras que posee el usuario.
// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
homeClient.structures() // HomeObjectsFlow<Structure>
.list() // Set<Structure>
En la Guía de arquitectura de apps, se recomienda adoptar un enfoque de programación reactiva moderno para mejorar el flujo de datos y la administración de estado de la app.
A continuación, se muestra cómo la app de ejemplo se adhiere al estilo de codificación reactivo:
- Los modelos de vista (como
StructureViewModel
yDeviceViewModel
, como el contenedor de estado) se suscriben a los flujos del SDK de las APIs de Home para recibir cambios de valor y mantener los estados más recientes. - Las vistas (como
StructureView
yDeviceView
) se suscriben a los modelos de vista para recibir los estados y renderizar la IU para reflejar esos cambios. - Cuando un usuario hace clic en un botón de una vista (por ejemplo, el botón "On" de un dispositivo de luz), los eventos activan las funciones del modelo de vista, que llaman a las funciones de las APIs de Home que responden (por ejemplo, el comando
On
del atributoOnOff
).
En el paso 5.1.1 de HomeAppViewModel.kt
, nos suscribimos a eventos de cambio de estructura llamando a la función collect()
. Quita el comentario de la sección que atraviesa el structureSet
que muestra la respuesta de la API de Structures y se entrega en el StructureViewModel's
StateFlow
. Esto permite que la app supervise los cambios de estado de la estructura:
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())
//
// }
}
En DevicesView.kt
, la app se suscribe a StructureViewModel'sStateFlow,
, que activa la recomposición de la IU cuando cambian los datos de la estructura. Quita el comentario del código fuente en el paso 5.1.2 para renderizar la lista de estructuras como un menú desplegable:
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
// }
// )
// }
}
...
Vuelve a ejecutar la app. Deberías ver el menú cuando presiones la flecha:
Analiza la estructura
El siguiente paso es recorrer los objetos de la casa en una estructura. Recupera las salas de la estructura:
val rooms: Set<Room>
rooms = structure.rooms().list()
Luego, puedes recorrer las salas para recuperar dispositivos:
val devices: Set<HomeDevice>
devices = room.devices().list()
Importante: En el modelo de datos de las APIs de Home, una estructura puede contener dispositivos que no están asignados a una habitación, así que asegúrate de capturar también los dispositivos sin habitaciones en tu app:
val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()
for (device in structure.devices().list())
if (!device.isInRoom)
devicesWithoutRooms.add(device)
Una vez más, en el código de muestra existente, nos suscribimos a un flujo para obtener la lista más reciente de habitaciones y dispositivos. Verifica el código en los pasos 5.2.1 y 5.2.2 del archivo fuente StructureViewModel.kt
y quita el comentario para habilitar la suscripción a los datos de la habitación:
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.isInRoom)
// deviceWithoutRoomVMs.add(deviceVM)
// }
// // Store the ViewModels:
// this.deviceVMs.emit(deviceVMs)
// deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
// }
}
Quita los comentarios de los pasos 5.2.3 y 5.2.4 en el archivo fuente DevicesView.kt
para renderizar la lista de salas como un menú:
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)
// }
}
Ahora que tienes los dispositivos, aprenderemos a trabajar con ellos.
6. Cómo trabajar con dispositivos
Las APIs de Home usan un objeto HomeDevice
para capturar el dispositivo y sus capacidades. Los desarrolladores pueden suscribirse a los atributos del dispositivo y usarlos para representar dispositivos de casa inteligente en sus apps.
Cómo leer los estados del dispositivo
El objeto HomeDevice
presenta un conjunto de valores estáticos, como el nombre del dispositivo o el estado de conectividad. Como desarrollador, puedes recuperarlos poco después de obtener el dispositivo de las APIs:
val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
device.sourceConnectivity.connectivityState
Para obtener las capacidades del dispositivo, debes recuperar los tipos y atributos de HomeDevice
. Para ello, puedes suscribirte al flujo de tipo de dispositivo de la siguiente manera y recuperar los atributos de los tipos de dispositivos:
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)
}
Cada dispositivo contiene un conjunto de DeviceType
compatibles (funciones agrupadas), que puedes recuperar con device.types()
. Estos tipos de dispositivos contienen atributos que se pueden recuperar con type.traits()
. Cada dispositivo marca uno de sus tipos como el principal (que se puede verificar con type.metadata.isPrimaryType
) que debes representar en tu app. Para proporcionar una experiencia completa a los usuarios, te recomendamos que recorras todos los tipos que se muestran y que integres todos los atributos disponibles.
Una vez que recuperes un atributo, puedes analizarlo con una función como la siguiente para interpretar los valores:
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 -> ...
}
}
Ten en cuenta que puede haber variaciones en lo que representa un atributo, según el tipo de dispositivo que lo incluya (consulta BooleanState
en el ejemplo anterior), por lo que debes tener en cuenta el contexto de cada tipo de dispositivo para comprender qué representan realmente sus atributos.
Quita los comentarios de los pasos 6.1.1 y 6.1.2 en el archivo fuente DeviceViewModel.kt
para recuperar los estados:
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
}
Quita el comentario del paso 6.1.3 en DeviceView.kt
para renderizar un atributo OnOff, incluido su nombre y estado, como un 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 -> {
...
}
...
}
Si ejecutas la app ahora con los tipos de dispositivos compatibles (por ejemplo, un dispositivo Light), debería mostrar los estados actualizados de todos los dispositivos.
Cómo emitir comandos del dispositivo
Para enviar comandos a los dispositivos, las APIs de Home proporcionan funciones de conveniencia en objetos de Trait, como 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(...)
}
}
}
Nota: Una vez que determines el tipo del atributo, usa la función de autocompletar de Android Studio para ver qué tipo de acciones están disponibles para interactuar con él.
Quita el comentario del paso 6.2.1 en DeviceView.kt
para agregar controles funcionales en la 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
// )
}
Si ejecutas la app ahora, debería permitirte controlar dispositivos físicos reales.
Si presionas el control de encendido y apagado de la bombilla, el dispositivo debería encenderse.
Para obtener más información sobre cómo controlar dispositivos, consulta Cómo controlar dispositivos en Android.
7. Cómo comisionar dispositivos
La API de Commissioning permite a los desarrolladores agregar dispositivos al ecosistema de Google Home y ponerlos a disposición para controlarlos con las APIs de Home. Solo se admiten dispositivos Matter. En esta sección, exploraremos cómo puedes habilitar la comisión de dispositivos en tus apps.
Antes de comenzar esta sección, asegúrate de que se cumplan los siguientes requisitos:
- Se agregó un Google Hub compatible con Matter a la misma red que tu teléfono Android en la app de Google Home.
- Creaste un proyecto de desarrollador en la consola para desarrolladores de Google Home con el VID
0xFFF1
y el PID0x8000
.
Si tienes un dispositivo Matter físico con un código QR para la comisión, puedes avanzar al paso Habilita la API de comisión. De lo contrario, continúa con la siguiente sección, en la que se explica cómo puedes usar la app de dispositivo virtual de Matter (MVD) para crear dispositivos virtuales comisionables.
Opcional: Prepara un dispositivo comisionable de Matter
La forma más sencilla de preparar un dispositivo comisionable de Matter es usar un dispositivo emulado que proporciona la app Matter Virtual Device (MVD).
Después de instalar el MVD y configurar el firewall, ejecútalo:
Crea un dispositivo OnOff. Ten en cuenta que aún no se encargó. Lo harás más adelante en este codelab.
Habilita la API de Commissioning
La API de Commissioning funciona fuera de la actividad de la app, por lo que la comisión se debe controlar de manera diferente a las otras APIs de Home. Para preparar tu app para la comisión, necesitas dos variables.
Una variable es ActivityResultLauncher
, que se usa para enviar el intent de comisión y administrar la devolución de llamada del resultado. La otra variable es CommissioningResult
, que es el objeto que se usa para almacenar el resultado de la comisión. Consulta el siguiente ejemplo para configurar la comisión:
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 vez que se configure tu flujo de comisión, compilarás tu intent de comisión y lo lanzarás con el selector que creamos en el ejemplo anterior. Te recomendamos que coloques el intent y el selector en una función dedicada como la siguiente. Una función dedicada se puede vincular a un elemento de la IU (como un botón +Agregar dispositivo) y se puede invocar según la solicitud del usuario:
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())
}
}
Quita el comentario del paso 7.1.1 en CommissioningManager.kt
para habilitar la función de comisión y hacer que el botón +Agregar dispositivo funcione en la app de ejemplo.
// 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())
// }
}
Si ejecutas esta función, se iniciará el flujo de comisión, que debería mostrar una pantalla similar a la siguiente captura de pantalla:
Comprende el flujo de la comisión
El flujo de comisión incluye un conjunto de pantallas que guían al usuario para agregar un dispositivo a su Cuenta de Google:
Los usuarios verán un escáner de códigos QR que pueden usar para escanear los códigos QR de los dispositivos Matter. Luego, el flujo mostrará el Acuerdo de Usuario, el descubrimiento y la puesta en marcha del dispositivo, y se le asignará un nombre. Una vez que se complete el flujo, este volverá a enfocarse en la app y pasará el resultado de la comisión en la función de devolución de llamada que redactamos en la sección anterior.
Una ventaja de las APIs de comisión es que el SDK controla el flujo de UX, por lo que los desarrolladores pueden comenzar a usarlas con rapidez. Esto también les brinda a los usuarios una experiencia coherente cuando agregan dispositivos en diferentes apps.
Para obtener más información sobre la API de comisión, consulta API de comisión en Android.
8. ¡Felicitaciones!
¡Felicitaciones! Creaste correctamente una app para Android con las APIs de Google Home. A lo largo de este codelab, exploraste las APIs de Permisos, Dispositivos, Estructuras y Comisión. En el siguiente codelab, Crea automatizaciones avanzadas con las APIs de Home en el codelab de Android, exploraremos las APIs de Automation y Discovery, y completaremos la app.
Esperamos que disfrutes de crear apps que controlen de forma creativa dispositivos dentro del ecosistema de Google Home.
Próximos pasos
- Para continuar con la siguiente parte de tu recorrido de aprendizaje de las APIs de Home en Android, completa el segundo codelab de esta serie: Cómo crear automatizaciones avanzadas con las APIs de Home en Android.
- Puedes comunicarte con nosotros para enviarnos recomendaciones o informarnos sobre cualquier problema a través del seguimiento de problemas, el tema de asistencia de la casa inteligente.