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 pongan en funcionamiento y controlen dispositivos inteligentes para la casa sin problemas.
Google proporciona una app de ejemplo para Android para los desarrolladores que desean acceder a un ejemplo funcional con las APIs de Google Home. Este codelab se basa en una rama de la app de ejemplo que te guía por el uso de 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 (2024.3.1 Ladybug o versiones posteriores) instalado
- Un teléfono Android que cumpla con los requisitos de las APIs de Home (consulta Requisitos previos) con los Servicios de Google Play y la app de Google Home instalados Un emulador no funcionará. Solo se admiten teléfonos Android físicos para la app de ejemplo.
- Un Google Home Hub compatible que admita las APIs de Google Home.
- Opcional: Un dispositivo inteligente para la casa 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 Commissioning 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 para la casa virtuales.
Abre home-playground.withgoogle.com en tu navegador web, accede con tu Cuenta de Google y verifica si aparecen los siguientes dispositivos emulados:
- outlet1: Enchufe de encendido/apagado
- light2: Luz regulable
- light3: Luz de encendido/apagado
- ac3: Aire acondicionado
- blinds4: Window Covering
- 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.
La zona de pruebas de Google Home 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. Cuando vuelvas 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 Home APIs: El SDK de Home APIs que proporciona Google funciona con el servicio de Home APIs en GMSCore para controlar dispositivos para la casa inteligente. Los desarrolladores compilan apps que funcionan con las APIs de Home incluyéndolas en 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 del sistema principales y 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 OAuth y, luego, implementes las partes faltantes con la API de Permissions.
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 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. Inicialización y control de permisos
En esta sección, aprenderás a inicializar el SDK y a controlar los permisos del usuario completando las partes faltantes con la API de Permissions.
Define los tipos y rasgos admitidos
Cuando desarrolles una app, deberás indicar explícitamente qué tipos y características de dispositivos admitirá. En la app de ejemplo, definimos listas estáticas en el objeto complementario en HomeApp.kt
, al que luego 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 el Índice de rasgos en Android para ver todos los tipos de dispositivos y rasgos compatibles.
Quita las marcas de 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,
)
}
Inicializa 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 rasgos admitidos que definimos anteriormente. 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 se realizará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 las marcas de 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 para la casa, el modelo de datos se compone de los siguientes elementos:
Structure
representa una casa que contiene habitaciones y dispositivos.Room
forma 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 instanciasTrait
.Trait
se compone de instancias deAttribute
(para lectura y escritura), instancias deCommand
(para controlar atributos) y instancias deEvent
(para leer o suscribirse a 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 tus estructuras, habitaciones, dispositivos, etcétera.
Estructuras de lectura
El diseño de las APIs de Home se basa en Kotlin Flows 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 devuelve 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>
La Guía de arquitectura de apps recomienda adoptar un enfoque moderno de programación reactiva para mejorar el flujo de datos y la administración de estados de la app.
A continuación, se muestra cómo la app de ejemplo se ajusta al estilo de programación reactiva:
- Los modelos de vistas (como
StructureViewModel
yDeviceViewModel
, como el titular del estado) se suscriben a los flujos del SDK de las APIs de Home para recibir cambios de valores y mantener los estados más recientes. - Las vistas (como
StructureView
yDeviceView
) se suscriben a los modelos de vistas para recibir los estados y renderizar la IU de modo que refleje esos cambios. - Cuando un usuario hace clic en un botón de una vista (por ejemplo, el botón "Encender" de un dispositivo de luz), los eventos activan las funciones del modelo de vista, que llaman a las funciones de las APIs de Home correspondientes (por ejemplo, el comando
On
del rasgoOnOff
).
En el paso 5.1.1 de HomeAppViewModel.kt
, nos suscribimos a los eventos de cambio de estructura llamando a la función collect()
. Quita las marcas de comentario de la sección que recorre el structureSet
que muestra la respuesta de la API de Structures y que 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,
, lo que activa la recomposición de la IU cuando cambian los datos de estructura. Quita la marca de 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 habitaciones de la estructura:
val rooms: Set<Room>
rooms = structure.rooms().list()
Luego, puedes recorrer las habitaciones 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, por lo que debes asegurarte de capturar también los dispositivos sin habitaciones en tu app:
val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()
for (device in structure.devices().list())
if (device.roomId == null)
devicesWithoutRooms.add(device)
Nuevamente, 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 las marcas de 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.roomId == null)
// 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 de los dispositivos y usarlos para representar dispositivos inteligentes para la casa en sus apps.
Leer estados de dispositivos
El objeto HomeDevice
presenta un conjunto de valores estáticos, como el nombre del dispositivo o el estado de conectividad. Como desarrollador, puedes recuperar estos datos 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 los rasgos del HomeDevice
. Para ello, puedes suscribirte al flujo del tipo de dispositivo de la siguiente manera y recuperar los rasgos 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 (capacidades incluidas), que puedes recuperar con device.types()
. Estos tipos de dispositivos contienen rasgos que se pueden recuperar con type.traits()
. Cada dispositivo marca uno de sus tipos como el tipo principal (que se puede verificar con type.metadata.isPrimaryType
) que debes representar en tu app. Para brindar una experiencia completa a los usuarios, te recomendamos que recorras todos los tipos que se devuelven y que integres todos los rasgos disponibles para ti.
Una vez que recuperes un rasgo, 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 rasgo, según el tipo de dispositivo que lo incluya (consulta BooleanState
en el ejemplo anterior), por lo que debes conocer el contexto de cada tipo de dispositivo para comprender lo que realmente representan sus rasgos.
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 la marca de comentario del paso 6.1.3 en DeviceView.kt
para renderizar un rasgo OnOff, incluidos 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 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 convenientes en objetos de rasgos, 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 de rasgo, usa la función de autocompletar de Android Studio para ver qué tipo de acciones están disponibles para interactuar con el rasgo.
Quita la marca de 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 de la vida real.
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. Puesta en marcha de dispositivos
La API de Commissioning permite a los desarrolladores agregar dispositivos al ecosistema de Google Home y hacer que estén disponibles para controlarlos con las APIs de Home. Solo se admiten dispositivos Matter. En esta sección, exploraremos cómo puedes habilitar la puesta en servicio de dispositivos en tus apps.
Antes de comenzar esta sección, asegúrate de que se cumplan los siguientes requisitos:
- Se agregó a tu app de Google Home una unidad central de Google compatible con Matter ubicada en la misma red que tu teléfono Android.
- Creaste un proyecto para desarrolladores 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 puesta en servicio, puedes avanzar a Habilita la API de puesta en servicio. De lo contrario, continúa con la siguiente sección, en la que analizaremos cómo puedes usar la app de Matter Virtual Device (MVD) para crear dispositivos virtuales aptos para la puesta en servicio.
Opcional: Prepara un dispositivo apto para la asignación de Matter
La forma más sencilla de preparar un dispositivo apto para la puesta en servicio de Matter es usar un dispositivo emulado que proporciona la app de Matter Virtual Device (MVD).
Después de instalar el MVD y configurar el firewall, ejecuta el MVD:
Crea un dispositivo OnOff. Observa 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 puesta en servicio debe controlarse 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 la intención de puesta en servicio 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 puesta en servicio. Consulta el siguiente ejemplo para saber cómo configurar la puesta en marcha:
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 configures el flujo de puesta en marcha, compilarás tu intent de puesta en marcha y lo iniciará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. Se puede vincular una función dedicada a un elemento de la IU (como un botón +Add Device) 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 la marca de comentario del paso 7.1.1 en CommissioningManager.kt
para habilitar la capacidad de puesta en servicio y hacer que funcione el botón +Add Device 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 debería iniciar el flujo de puesta en servicio, que debería mostrar una pantalla similar a la siguiente captura de pantalla:
Información sobre el flujo de puesta en marcha
El flujo de puesta en marcha 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 podrán usar para escanear los códigos QR de los dispositivos Matter. Luego, el flujo mostrará el Acuerdo del usuario, la detección y la puesta en servicio del dispositivo, y la asignación de un nombre al dispositivo. Una vez que se complete el flujo, el enfoque volverá a la app y pasará el resultado de la puesta en servicio en la función de devolución de llamada que creamos en la sección anterior.
Un beneficio de las APIs de Commissioning es que el SDK controla el flujo de UX, por lo que los desarrolladores pueden comenzar a trabajar muy rápidamente. 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 Commissioning, visita Commissioning API 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 Permissions, Devices, Structures y Commissioning. En el próximo codelab, Codelab sobre cómo crear automatizaciones avanzadas con las APIs de Home en Android, exploraremos las APIs de Automation y Discovery, y completaremos la app.
Esperamos que disfrutes crear apps que controlen dispositivos de forma creativa dentro del ecosistema de Google Home.
Próximos pasos
- Para continuar con la siguiente parte de tu recorrido de aprendizaje sobre las APIs de Home en Android, completa el segundo codelab de esta serie: Crea automatizaciones avanzadas con las APIs de Home en Android.
- Puedes comunicarte con nosotros para enviarnos recomendaciones o informar problemas a través del seguimiento de problemas, tema de asistencia para la casa inteligente.