Créer une application mobile à l'aide des API Home sur Android

1. Avant de commencer

Les API Google Home fournissent un ensemble de bibliothèques permettant aux développeurs Android d'exploiter l'écosystème Google Home. Grâce à ces nouvelles API, les développeurs peuvent créer des applications qui mettent en service et contrôlent facilement les appareils connectés.

Google fournit une application exemple Android pour les développeurs qui souhaitent accéder à un exemple fonctionnel à l'aide des API Google Home. Cet atelier de programmation est basé sur une branche de l'application exemple qui vous explique comment utiliser les API Permissions, Commissioning, Device et Structure.

Prérequis

Points abordés

  • Créer une application Android à l'aide des API Google Home en suivant les bonnes pratiques
  • Utiliser les API Device et Structure pour représenter et contrôler une maison connectée
  • Utiliser les API de mise en service pour ajouter des appareils à l'écosystème Google Home

(Facultatif) Configurer votre maison

Avant d'utiliser les API Google Home, vous devez configurer une maison dans votre compte Google à l'aide de l'application Google Home, puis ajouter quelques appareils. Cette section explique comment procéder à l'aide du Google Home Playground, qui fournit des appareils de maison connectée virtuels.

Ouvrez home-playground.withgoogle.com dans votre navigateur Web, connectez-vous avec votre compte Google, puis vérifiez si les appareils émulés suivants s'affichent:

  • outlet1: prise marche/arrêt
  • light2: lumière réglable
  • light3: voyant Marche/Arrêt
  • ac3: climatiseur
  • blinds4: Window Covering
  • washer5: lave-linge connecté

914d23a42b72df8f.png

Ouvrez l'application Google Home sur votre appareil mobile, appuyez sur le bouton Ajouter, puis sélectionnez Fonctionne avec Google Home. Recherchez "playground" (terrain d'entraînement) dans la liste, puis sélectionnez le projet "Google Home Playground" (Google Home Playground), puis appuyez sur Continuer.

e9ec257b0d9b1ed2.png29fd7416e274d216.pngd974573af0611fd8.png

Google Home Playground affiche une page d'autorisation de compte. Appuyez sur Autoriser ou Se connecter avec Google. Tous les appareils que vous avez configurés depuis l'application Web s'affichent dans l'application mobile.

13108a3a15440151.png8791a6d33748f7c8.png

Sélectionnez tous les appareils et terminez le processus de configuration. Si vous revenez à la page d'accueil, tous les appareils disponibles s'affichent.

2b021202e6fd1750.png

Les appareils compatibles de la liste sont désormais disponibles avec les API Google Home.

2. Configurer votre projet

Le schéma suivant illustre l'architecture d'une application utilisant les API Home:

Architecture des API Home pour une application Android

  • Code de l'application:code principal sur lequel les développeurs travaillent pour créer l'interface utilisateur de l'application et la logique d'interaction avec le SDK des API Home.
  • SDK Home APIs:le SDK Home APIs fourni par Google fonctionne avec le service Home APIs de GMSCore pour contrôler les appareils de maison connectée. Les développeurs créent des applications compatibles avec les API Home en les regroupant avec le SDK des API Home.
  • GMSCore sur Android:GMSCore, également appelé services Google Play, est une plate-forme Google qui fournit des services système essentiels, ce qui permet de bénéficier de fonctionnalités clés sur tous les appareils Android certifiés. Le module d'accueil des services Google Play contient les services qui interagissent avec les API Home.

Configurer le SDK Home

Pour obtenir le dernier SDK, suivez la procédure décrite dans Configurer le SDK.

Obtenir l'application exemple

Le code source de l'application exemple est disponible sur GitHub. Cet atelier de programmation utilise les exemples de la branche codelab-branch-1 de l'application exemple.

Accédez à l'emplacement où vous souhaitez enregistrer le projet, puis clonez la branche codelab-branch-1:

$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git

Créer l'application exemple

Suivez les étapes 1 à 5 de la section Compiler l'application.

32f2b3c0cd80fcf1.png

Lorsque l'application s'exécute correctement sur votre téléphone, la page principale de l'application exemple s'affiche. Toutefois, vous ne pourrez pas vous connecter tant que vous n'aurez pas configuré l'authentification OAuth et implémenté les éléments manquants à l'aide de l'API Permission.

3. Configurer l'authentification

Les API Home utilisent OAuth 2.0 pour accorder l'accès aux appareils de la structure. OAuth permet à un utilisateur d'accorder une autorisation à une application ou à un service sans avoir à divulguer ses identifiants de connexion.

Suivez les instructions de la section Configurer le consentement OAuth pour configurer l'écran de consentement. Veillez à créer au moins un compte de test.

Suivez ensuite les instructions de la section Configurer des identifiants OAuth pour créer les identifiants de l'application.

4. Initialisation et gestion des autorisations

Dans cette section, vous allez apprendre à initialiser le SDK et à gérer les autorisations des utilisateurs en complétant les éléments manquants à l'aide de l'API Permissions.

Définir les types et les caractéristiques compatibles

Lorsque vous développez une application, vous devez indiquer explicitement les types d'appareils et les caractéristiques qu'elle prendra en charge. Dans l'application exemple, nous définissons des listes statiques dans l'objet associé dans HomeApp.kt, qui peuvent ensuite être référencées dans l'application selon les besoins:

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,
  // ...
  )
}

Consultez les pages Types d'appareils compatibles et Indice de traits sur Android pour connaître tous les types et traits d'appareils compatibles.

Décommentez les étapes 4.1.1 et 4.1.2 dans le fichier source HomeApp.kt pour activer le code source qui demande l'autorisation.

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,
        )
}

Initialiser l'objet HomeClient

Toutes les applications qui utilisent les API Home initialisent un objet HomeClient, qui est l'interface principale pour interagir avec les API. Nous préparons cet objet dans l'initialiseur de la 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)

Tout d'abord, nous créons un FactoryRegistry à l'aide des types et des traits compatibles que nous avons définis précédemment. Ensuite, à l'aide de ce Registre, nous initialisons un HomeConfig, qui contient la configuration nécessaire pour exécuter les API. Nous utilisons ensuite l'appel Home.getClient(...) pour acquérir l'instance HomeClient.

Toutes nos interactions avec les API Home se feront via cet objet HomeClient.

Utiliser l'API Permissions

L'authentification des utilisateurs pour les API Home s'effectue via l'API Permissions. Le fichier source PermissionsManager.kt de l'application exemple contient du code d'authentification des utilisateurs. Décommentez le contenu des fonctions checkPermissions(...) et requestPermissions(...) pour activer les autorisations de l'application exemple.

Enregistrement:

homeClient.registerActivityResultCallerForPermissions(activity)

Lancement:

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) { ... }

Vérifiez les points suivants:

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) { ... }

Abonnement:

       homeClient.hasPermissions().collect( { state ->
// Track the changes on state
        } )

Décommentez l'étape 4.3.1 dans PermissionsManager.kt pour activer le code qui demande les autorisations:

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()) }
    }
}

Exécutez maintenant l'application sur votre téléphone, en suivant les étapes et en autorisant les autorisations. Le flux suivant devrait s'afficher:

c263dcee4e945bf1.png f518cfd1fdb8a9d8.png 59937372f28c472f.png 383073ae57d2ced4.png 89f774a2ba6898ae.png

Le message "Chargement" ne disparaît jamais, mais cela est dû au fait que nous n'avons pas implémenté le code qui lit la structure et les appareils. Nous le ferons dans la section suivante.

5. Comprendre le modèle de données

Dans les API Home, le modèle de données est composé des éléments suivants:

  • Structure représente une maison contenant des pièces et des appareils.
  • Room fait partie d'une structure et contient des appareils.
  • Les appareils (définis comme HomeDevice) peuvent être attribués à une structure (ou maison) ou à une pièce de la structure.
  • Les appareils sont composés d'une ou plusieurs instances DeviceType.
  • DeviceType est composé d'instances Trait.
  • Trait se compose d'instances Attribute (pour la lecture/l'écriture), d'instances Command (pour contrôler les attributs) et d'instances Event (pour lire ou s'abonner aux enregistrements des modifications passées).
  • Les instances Automation font partie d'une structure et utilisent les métadonnées et les appareils de la maison pour automatiser des tâches.

76d35b44d5a8035e.png

Dans cette section, vous allez apprendre à développer le code source pour montrer comment utiliser l'API Structure afin d'analyser et d'afficher les structures, pièces, appareils, etc. de votre maison.

Lire les structures

La conception des API Home est basée sur les flux Kotlin pour diffuser les objets du modèle de données (par exemple, Structure, HomeDevice, etc.). Les développeurs s'abonnent à un Flow pour obtenir tous les objets qu'il contient (par exemple, un Structure, un Room, etc.).

Pour récupérer toutes les structures, appelez la fonction structures(), qui renvoie un flux de structures. Appelez ensuite la fonction de liste sur le flux pour obtenir toutes les structures appartenant à l'utilisateur.

// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
    homeClient.structures()   // HomeObjectsFlow<Structure>
    .list()                   // Set<Structure>

Le Guide de l'architecture des applications recommande vivement d'adopter une approche de programmation réactive moderne pour améliorer le flux de données et la gestion de l'état de l'application.

Voici comment l'application exemple respecte le style de codage réactif:

  • Les modèles de vue (comme StructureViewModel et DeviceViewModel, en tant que conteneur d'état) s'abonnent aux flux du SDK des API Home pour recevoir les modifications de valeur et conserver les derniers états.
  • Les vues (comme StructureView et DeviceView) s'abonnent aux modèles de vue pour recevoir les états et afficher l'UI afin de refléter ces modifications.
  • Lorsqu'un utilisateur clique sur un bouton d'une vue (par exemple, le bouton "Marche" d'un appareil d'éclairage), des événements déclenchent les fonctions du modèle de vue, qui appellent les fonctions des API Home correspondantes (par exemple, la commande On du trait OnOff).

À l'étape 5.1.1 de HomeAppViewModel.kt, nous nous abonnons aux événements de modification de structure en appelant la fonction collect(). Décommentez la section qui parcourt le structureSet renvoyé par la réponse de l'API Structures et transmis dans le StateFlow StructureViewModel's. Cela permet à l'application de surveiller les modifications de l'état de la structure:

   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())
//
// }
}

Dans DevicesView.kt, l'application s'abonne à StructureViewModel'sStateFlow,, qui déclenche la recomposition de l'UI lorsque les données de structure changent. Décommentez le code source à l'étape 5.1.2 pour afficher la liste de structures sous forme de menu déroulant:

   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
//          }
//      )
//  }
}
...

Exécutez à nouveau l'application. Le menu devrait s'afficher lorsque vous appuyez sur la flèche:

f1fc2be1cb6436b6.png

Analyser la structure

L'étape suivante consiste à parcourir les objets de la maison dans une structure. Récupérez les pièces de la structure:

val rooms: Set<Room>
rooms = structure.rooms().list()

Vous pouvez ensuite parcourir les pièces pour récupérer les appareils:

val devices: Set<HomeDevice>
devices = room.devices().list()

Important:Dans le modèle de données des API Home, une structure peut contenir des appareils qui ne sont pas attribués à une pièce. Veillez donc à capturer également les appareils sans pièce dans votre application:

val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()

for (device in structure.devices().list())
if (!device.isInRoom)
  devicesWithoutRooms.add(device)

Encore une fois, dans l'exemple de code existant, nous nous abonnons à un flux pour obtenir la dernière liste des pièces et des appareils. Vérifiez le code aux étapes 5.2.1 et 5.2.2 dans le fichier source StructureViewModel.kt, puis supprimez les commentaires pour activer l'abonnement aux données de la pièce:

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)
//   }
    }

Annulez la mise en commentaire des étapes 5.2.3 et 5.2.4 dans le fichier source DevicesView.kt pour afficher la liste des salles sous forme de 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)
//   }
}

Maintenant que vous avez les appareils, nous allons apprendre à les utiliser.

e715ddda50e04839.png

6. Utiliser des appareils

Les API Home utilisent un objet HomeDevice pour capturer l'appareil et ses fonctionnalités. Les développeurs peuvent s'abonner aux attributs de l'appareil et les utiliser pour représenter les appareils connectés dans leurs applications.

Lire les états des appareils

L'objet HomeDevice présente un ensemble de valeurs statiques, telles que le nom de l'appareil ou l'état de la connectivité. En tant que développeur, vous pouvez les récupérer peu de temps après avoir obtenu l'appareil à partir des API:

val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
    device.sourceConnectivity.connectivityState

Pour obtenir les fonctionnalités de l'appareil, vous devez récupérer les types et les traits de HomeDevice. Pour ce faire, vous pouvez vous abonner au flux de type d'appareil comme suit et récupérer les caractéristiques des types d'appareils:

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)
        }

Chaque appareil contient un ensemble de DeviceType (fonctionnalités groupées) compatibles, que vous pouvez récupérer à l'aide de device.types(). Ces types d'appareils contiennent des caractéristiques qui peuvent être récupérées à l'aide de type.traits(). Chaque appareil marque l'un de ses types comme type principal (que vous pouvez vérifier à l'aide de type.metadata.isPrimaryType) que vous devez représenter dans votre application. Pour offrir une expérience complète aux utilisateurs, nous vous recommandons d'examiner tous les types renvoyés et d'intégrer toutes les caractéristiques disponibles.

Une fois que vous avez récupéré un trait, vous pouvez l'analyser à l'aide d'une fonction telle que celle-ci pour interpréter les valeurs:

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 -> ...
    }
}

Notez que ce qu'un trait représente peut varier en fonction du type d'appareil qui l'inclut (voir BooleanState dans l'exemple précédent). Vous devez donc connaître le contexte de chaque type d'appareil pour comprendre ce que leurs traits représentent réellement.

Annulez la mise en commentaire des étapes 6.1.1 et 6.1.2 dans le fichier source DeviceViewModel.kt pour récupérer les états:

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
}

Décomentez l'étape 6.1.3 dans DeviceView.kt pour afficher une caractéristique OnOff, y compris son nom et son état, en tant que 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 vous exécutez l'application maintenant avec des types d'appareils compatibles (par exemple, un appareil Light), elle devrait afficher les états à jour de tous les appareils.

1bd8b3b2796c4c7a.png

Envoyer des commandes à l'appareil

Pour envoyer des commandes aux appareils, les API Home fournissent des fonctions pratiques sur les objets Trait tels que trait.on() ou trait.moveToLevel(...):

fun <T : Trait?> issueCommand(trait : T) {
     when (trait) {
         is OnOff -> {
// trait.on()
// trait.off()
   }
   is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
        }
    }
}

Conseil:Une fois que vous avez déterminé le type de la caractéristique, utilisez la fonctionnalité de saisie semi-automatique d'Android Studio pour voir les types d'actions disponibles pour interagir avec la caractéristique.

Décommentez l'étape 6.2.1 dans DeviceView.kt pour ajouter des commandes fonctionnelles dans l'application:

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 vous exécutez l'application maintenant, elle devrait vous permettre de contrôler des appareils physiques réels.

Si vous appuyez sur le bouton Marche/Arrêt de votre ampoule, l'appareil devrait s'allumer.

c8ed3ecf5031546e.png

Pour en savoir plus sur le contrôle des appareils, consultez Contrôler les appareils sur Android.

7. Mettre en service des appareils

L'API de mise en service permet aux développeurs d'ajouter des appareils à l'écosystème Google Home et de les rendre disponibles à la commande à l'aide des API Home. Seuls les appareils Matter sont compatibles. Dans cette section, nous allons voir comment activer la mise en service des appareils dans vos applications.

Avant de commencer cette section, assurez-vous que les conditions préalables suivantes sont remplies:

Si vous disposez d'un appareil Matter physique avec un code QR pour la mise en service, vous pouvez passer directement à la section Activer l'API de mise en service. Sinon, passez à la section suivante, qui explique comment utiliser l'application Matter Virtual Device (MVD) pour créer des appareils virtuels commissionnables.

Facultatif: Préparer un appareil pouvant être mis en service avec Matter

Le moyen le plus simple de préparer un appareil commissionnable Matter consiste à utiliser un appareil émulé fourni par l'application Matter Virtual Device (MVD).

Après avoir installé le MVD et configuré le pare-feu, exécutez-le:

b20283893073ac1b.png

Créez un appareil OnOff. Notez qu'il n'a pas encore été mis en service. Vous le mettrez en service plus tard dans cet atelier de programmation.

5f4855b808312898.png

Activer l'API de mise en service

L'API de mise en service fonctionne en dehors de l'activité de l'application. La mise en service doit donc être gérée différemment des autres API Home. Pour préparer votre application à la mise en service, vous avez besoin de deux variables.

L'une des variables est ActivityResultLauncher, qui permet d'envoyer l'intent de mise en service et de gérer le rappel de résultat. L'autre variable est CommissioningResult, qui est l'objet utilisé pour stocker le résultat de la mise en service. Pour savoir comment configurer la mise en service, consultez l'exemple suivant:

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
 }
}

Une fois le flux de mise en service configuré, vous allez créer votre intent de mise en service et le lancer à l'aide du lanceur que nous avons créé dans l'exemple précédent. Nous vous recommandons de placer l'intent et le lanceur dans une fonction dédiée, comme celle-ci. Une fonction dédiée peut être associée à un élément d'interface utilisateur (tel qu'un bouton + Ajouter un appareil) et appelée en fonction de la requête de l'utilisateur:

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())
  }
}

Décommentez l'étape 7.1.1 dans CommissioningManager.kt pour activer la fonctionnalité de mise en service et faire fonctionner le bouton + Add Device (Ajouter un appareil) dans l'application exemple.

// 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'exécution de cette fonction devrait lancer le parcours de mise en service, qui devrait afficher un écran semblable à la capture d'écran suivante:

baae45588f460664.png

Comprendre le processus de mise en service

Le flux de mise en service comprend un ensemble d'écrans qui guide l'utilisateur pour ajouter un appareil à son compte Google:

2fb0404820d4a035.png 3cbfa8ff9cfd5ee4.png a177c197ee7a67bf.png 3fdef24672c77c0.png dec8e599f9aa119.png

Les utilisateurs verront un lecteur de code QR qu'ils pourront utiliser pour scanner les codes QR des appareils Matter. Le parcours se poursuit ensuite avec l'affichage du contrat utilisateur, la découverte et la mise en service de l'appareil, puis le nommant. Une fois le flux terminé, il revient à l'application et transmet le résultat de la mise en service dans la fonction de rappel que nous avons rédigée dans la section précédente.

L'un des avantages des API de mise en service est que le flux d'expérience utilisateur est géré par le SDK, ce qui permet aux développeurs de se lancer très rapidement. Cela offre également aux utilisateurs une expérience cohérente lorsqu'ils ajoutent des appareils dans différentes applications.

Pour en savoir plus sur l'API de mise en service, consultez API de mise en service sur Android.

8. Félicitations !

Félicitations ! Vous avez créé une application Android à l'aide des API Google Home. Tout au long de cet atelier de programmation, vous avez exploré les autorisations, les appareils, les structures et les API de mise en service. Dans l'atelier de programmation suivant, Créer des automatisations avancées à l'aide des API Home sur Android, nous allons explorer les API Automation et Discovery, et terminer l'application.

Nous espérons que vous apprécierez de créer des applications qui contrôlent de manière créative les appareils de l'écosystème Google Home.

Étapes suivantes