Android で Home API を使用してモバイルアプリを作成する

1. 始める前に

Google Home API は、Android デベロッパーが Google Home エコシステムを活用するための一連のライブラリを提供します。これらの新しい API を使用すると、デベロッパーはスマートホーム デバイスをシームレスに設定して制御するアプリを構築できます。

Google Home API を使用したサンプルにアクセスしたいデベロッパー向けに、Android サンプルアプリが用意されています。この Codelab は、Permissions、Commissioning、Device、Structure API の使用方法を説明するサンプルアプリのブランチに基づいています。

前提条件

学習内容

  • Google Home API を使用して Android アプリを作成する方法とベスト プラクティス。
  • Device API と Structure API を使用してスマートホームを表現し、制御する方法。
  • Commissioning API を使用して Google Home エコシステムにデバイスを追加する方法。

省略可: 家をセットアップする

Google Home API を使用する前に、Google Home アプリを使用して Google アカウントで家をセットアップし、いくつかのデバイスを追加する必要があります。このセクションでは、仮想スマートホーム デバイスを提供する Google Home Playground を使用して、このテストを行う方法について説明します。

ウェブブラウザで home-playground.withgoogle.com を開き、Google アカウントでログインして、次のエミュレートされたデバイスが表示されるかどうかを確認します。

  • outlet1: オン/オフのプラグ
  • light2: 調光可能なライト
  • light3: ライトのオン/オフ
  • ac3: エアコン
  • blinds4: カーテン類
  • washer5: スマート洗濯機

914d23a42b72df8f.png

モバイル デバイスで Google Home アプリを開き、[追加] ボタンをタップして、[Google Home と連携させる] を選択します。リストで「playground」を検索し、[Google Home Playground] プロジェクトを選択して [続行] をタップします。

e9ec257b0d9b1ed2.png29fd7416e274d216.pngd974573af0611fd8.png

Google Home Playground にアカウントの承認ページが表示されます。[承認] または [Google でログイン] をタップします。ウェブアプリで設定したすべてのデバイスがモバイルアプリに表示されます。

13108a3a15440151.png8791a6d33748f7c8.png

すべてのデバイスを選択し、セットアップ プロセスを完了します。ホーム画面に戻ると、利用可能なすべてのデバイスが表示されます。

2b021202e6fd1750.png

リスト内のサポートされているデバイスは、Google Home API で使用できるようになりました。

2. プロジェクトをセットアップする

次の図は、Home APIs アプリのアーキテクチャを示しています。

Android アプリの Home API のアーキテクチャ

  • アプリコード: アプリのユーザー インターフェースと、Home APIs SDK を操作するロジックを構築するためにデベロッパーが作成するコアコード。
  • Home APIs SDK: Google が提供する Home APIs SDK は、GMSCore の Home APIs Service と連携してスマートホーム デバイスを制御します。デベロッパーは、Home APIs SDK とバンドルすることで、Home APIs と連携するアプリを構築します。
  • Android の GMSCore: GMSCore(Google Play 開発者サービス)は、コア システム サービスを提供する Google プラットフォームであり、認定済みのすべての Android デバイスで主要な機能を有効にします。Google Play 開発者サービスのホーム モジュールには、Home API とやり取りするサービスが含まれています。

Home SDK を設定する

SDK を設定するの手順に沿って、最新の SDK を入手します。

サンプルアプリを入手する

サンプルアプリのソースコードは GitHub で入手できます。この Codelab では、サンプルアプリの codelab-branch-1 ブランチのサンプルを使用します。

プロジェクトを保存する場所に移動し、codelab-branch-1 ブランチのクローンを作成します。

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

サンプルアプリを作成する

アプリをビルドするの手順 1 ~ 5 を実施します。

32f2b3c0cd80fcf1.png

アプリがスマートフォンで正常に実行されると、サンプルアプリのメインページが表示されます。ただし、OAuth 認証を設定し、Permission API を使用して不足している部分を実装するまで、ログインすることはできません。

3. Authentication を設定する

Home API は OAuth 2.0 を使用して、ストラクチャ内のデバイスへのアクセス権を付与します。OAuth を使用すると、ユーザーはログイン認証情報を公開することなく、アプリやサービスに権限を付与できます。

OAuth 同意を設定の手順に沿って、同意画面を構成します。少なくとも 1 つのテスト アカウントを作成してください。

次に、OAuth 認証情報を設定するの手順に沿って、アプリの認証情報を作成します。

4. 権限の初期化と処理

このセクションでは、Permissions API を使用して不足している部分を補完し、SDK を初期化してユーザー権限を処理する方法について説明します。

サポートされているタイプとトレイトを定義する

アプリを開発する際は、アプリがサポートするデバイスの種類とトレイトを明記する必要があります。サンプルアプリでは、HomeApp.kt のコンパニオン オブジェクトで静的リストを定義することで、必要に応じてアプリ全体で参照できるようにしています。

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

サポートされているすべてのデバイスタイプとトレイトについては、サポートされているデバイスの種類Android のトレイト インデックスをご覧ください。

HomeApp.kt ソースファイルのステップ 4.1.1 と 4.1.2 のコメントを解除して、権限をリクエストするソースコードを有効にします。

companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
//             ContactSensorDevice,
//             ColorTemperatureLightDevice,
//             DimmableLightDevice,
//             ExtendedColorLightDevice,
//             GenericSwitchDevice,
//             GoogleDisplayDevice,
//             GoogleTVDevice,
//             OccupancySensorDevice,
//             OnOffLightDevice,
//             OnOffLightSwitchDevice,
//             OnOffPluginUnitDevice,
//             OnOffSensorDevice,
//             RootNodeDevice,
//             SpeakerDevice,
//             ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
//             AreaAttendanceState,
//             AreaPresenceState,
//             Assistant,
//             AssistantBroadcast,
//             AssistantFulfillment,
//             BasicInformation,
//             BooleanState,
//             OccupancySensing,
//             OnOff,
//             Notification,
//             LevelControl,
//             TemperatureControl,
//             TemperatureMeasurement,
//             Thermostat,
//             Time,
//             Volume,
        )
}

HomeClient オブジェクトを初期化する

Home API を使用するすべてのアプリは、API を操作するためのメイン インターフェースである HomeClient オブジェクトを初期化します。このオブジェクトは、HomeAppHomeApp.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)

まず、前述で定義したサポートされている型と特性を使用して FactoryRegistry を作成します。次に、このレジストリを使用して HomeConfig を初期化します。これには、API の実行に必要な構成が含まれています。次に、Home.getClient(...) 呼び出しを使用して HomeClient インスタンスを取得します。

Home API とのやり取りはすべて、この HomeClient オブジェクトを介して行います。

Permissions API を使用する

Home API のユーザー認証は、Permissions API を介して行われます。サンプルアプリの PermissionsManager.kt ソースファイルには、ユーザー認証のコードが含まれています。サンプルアプリの権限を有効にするため、checkPermissions(...) 関数と requestPermissions(...) 関数の内容のコメント化を解除します。

登録:

homeClient.registerActivityResultCallerForPermissions(activity)

リリース:

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

確認:

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

登録:

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

PermissionsManager.kt のステップ 4.3.1 のコメントを解除して、権限をリクエストするコードを有効にします。

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

スマートフォンでアプリを実行し、手順に沿って権限を許可します。次のフローが表示されます。

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

[読み込み中] メッセージが消えないのは、構造とデバイスを読み取るコードが実装されていないためです。次のセクションで説明します。

5. データモデルについて理解する

Home API のデータモデルは、次の要素で構成されています。

  • Structure は、部屋とデバイスを含む家を表します。
  • Room はストラクチャの一部であり、デバイスが含まれています。
  • デバイス(HomeDevice として定義)は、ストラクチャ(家)またはストラクチャ内の部屋に割り当てることができます。
  • デバイスは 1 つ以上の DeviceType インスタンスで構成されます。
  • DeviceTypeTrait インスタンスで構成されています。
  • Trait は、Attribute インスタンス(読み取り/書き込み用)、Command インスタンス(属性の制御用)、Event インスタンス(過去の変更のレコードの読み取りまたはサブスクライブ用)で構成されています。
  • Automation インスタンスはストラクチャの一部であり、家のメタデータとデバイスを使用して家のタスクを自動化します。

76d35b44d5a8035e.png

このセクションでは、ソースコードを開発して、structure API を使用して家ストラクチャ、部屋、デバイスなどを解析してレンダリングする方法について説明します。

構造を読み取る

Home API の設計は Kotlin Flows に基づいており、データモデル オブジェクト(StructureHomeDevice など)をストリーミング出力します。デベロッパーは Flow をサブスクライブして、オブジェクトに含まれるすべてのオブジェクト(StructureRoom など)を取得します。

すべての構造体を取得するには、structures() 関数を呼び出します。この関数は、構造体のフローを返します。次に、フローに対して list 関数を呼び出して、ユーザーが所有するすべての構造体を取得します。

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

アプリ アーキテクチャ ガイドでは、最新のリアクティブ プログラミング アプローチを採用してアプリのデータフローや状態管理を改善することを強くおすすめしています。

サンプルアプリがリアクティブ コーディング スタイルに準拠している方法は次のとおりです。

  • ビューモデル(状態保持者としての StructureViewModelDeviceViewModel など)は、Home APIs SDK のフローをサブスクライブして値の変更を受け取り、最新の状態を維持します。
  • ビュー(StructureViewDeviceView など)はビューモデルをサブスクライブして状態を受け取ると、それらの変更を反映して UI をレンダリングします。
  • ユーザーがビュー上のボタン(照明デバイスの「オン」ボタンなど)をクリックすると、イベントによってビューモデルの関数がトリガーされ、対応する Home API 関数(OnOff トレイトの On コマンドなど)が呼び出されます。

HomeAppViewModel.kt のステップ 5.1.1 では、collect() 関数を呼び出して構造変更イベントをサブスクライブします。Structures API レスポンスで返され、StructureViewModel's StateFlow で配信される structureSet を走査するセクションのコメントを解除します。これにより、アプリは構造物の状態変化をモニタリングできます。

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

DevicesView.kt では、アプリが StructureViewModel'sStateFlow, をサブスクライブし、構造データが変更されたときに UI の再コンポーズをトリガーします。手順 5.1.2 のソースコードのコメントを解除して、構造リストをプルダウン メニューとしてレンダリングします。

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

アプリを再度実行すると、矢印をタップすると、メニューが表示されます。

f1fc2be1cb6436b6.png

構造を解析する

次のステップは、ストラクチャ内の家オブジェクトを走査することです。ストラクチャから部屋を取得します。

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

次に、部屋を走査してデバイスを取得します。

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

重要: Home APIs のデータモデルでは、構造に部屋に割り当てられていないデバイスを含めることができるため、アプリでも部屋のないデバイスをキャプチャしてください。

val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()

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

既存のサンプルコードでは、フローのサブスクリプションを使用して、最新の部屋とデバイスのリストを取得します。StructureViewModel.kt ソースファイルのステップ 5.2.1 と 5.2.2 のコードを確認し、コメント化を解除して、部屋データの定期購入を有効にします。

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

DevicesView.kt ソースファイルのステップ 5.2.3 と 5.2.4 のコメント化を解除して、会議室リストをメニューとしてレンダリングします。

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

デバイスが揃ったので、デバイスの操作方法を学びましょう。

e715ddda50e04839.png

6. デバイスを操作する

Home API は HomeDevice オブジェクトを使用して、デバイスとその機能をキャプチャします。デベロッパーはデバイス属性を定期購読し、それらを使用してアプリでスマートホーム デバイスを表すことができます。

デバイスの状態を読み取る

HomeDevice オブジェクトは、デバイス名や接続状態などの一連の静的値を表します。デベロッパーは、API からデバイスを取得した直後に、次の情報を取得できます。

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

デバイスの機能を取得するには、HomeDevice からタイプとトレイトを取得する必要があります。これを行うには、次のようにデバイスタイプ フローにサブスクライブし、デバイスタイプから特徴を取得します。

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

各デバイスには、サポートされている DeviceType(バンドル機能)のセットが含まれています。これは device.types() を使用して取得できます。これらのデバイスタイプには、type.traits() を使用して取得できるトレイトが含まれています。すべてのデバイスは、アプリで表現する必要があるプライマリ タイプとして、そのタイプの 1 つをマークします(これは type.metadata.isPrimaryType を使用して確認できます)。ユーザーに完全なエクスペリエンスを提供するには、返されたすべてのタイプを走査し、利用可能なすべての特性を統合することをおすすめします。

特徴を取得したら、次のような関数を使用して解析し、値を解釈できます。

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

トレイトが表す内容は、トレイトを備えたデバイスの種類によって異なる場合があります(上の例の BooleanState を参照)。そのため、トレイトが実際に表す内容を理解するには、各デバイスの種類のコンテキストを把握する必要があります。

DeviceViewModel.kt ソースファイルのステップ 6.1.1 と 6.1.2 のコメント化を解除して、状態を取得します。

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
}

DeviceView.kt のステップ 6.1.3 のコメントを解除して、名前とステータスを含む OnOff トレイトを 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 -> {
      ...
  }
  ...
}

サポートされているデバイスタイプ(ライト デバイスなど)でアプリを実行すると、すべてのデバイスの最新の状態が表示されます。

1bd8b3b2796c4c7a.png

デバイスのコマンドを発行する

デバイスにコマンドを送信するために、Home API には trait.on()trait.moveToLevel(...) などの Trait オブジェクトに対する便利な関数が用意されています。

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

ヒント: トレイトのタイプを特定したら、Android Studio の自動入力機能を使用して、トレイトを操作するために使用できるアクションを確認します。

DeviceView.kt のステップ 6.2.1 のコメントを解除して、アプリに機能制御を追加します。

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

アプリを実行すると、実際の物理デバイスを操作できるようになります。

電球のオン / オフ コントロールをタップすると、デバイスが点灯します。

c8ed3ecf5031546e.png

デバイスを制御する方法について詳しくは、Android でデバイスを制御するをご覧ください。

7. デバイスのコミッショニング

Commissioning API を使用すると、デベロッパーは Google Home エコシステムにデバイスを追加し、Home API を使用してデバイスを操作できるようになります。Matter デバイスのみがサポートされます。このセクションでは、アプリでデバイスの構成を有効にする方法について説明します。

このセクションを開始する前に、次の前提条件を満たしていることを確認してください。

物理的な Matter デバイスに構成用の QR コードがある場合は、構成 API を有効にするに進んでください。それ以外の場合は、次のセクションに進みます。ここでは、Matter Virtual Device アプリ(MVD)を使用して、委任可能な仮想デバイスを作成する方法について説明します。

省略可: Matter 対応デバイスを準備する

Matter の設定可能なデバイスを準備する最も簡単な方法は、Matter Virtual Device アプリ(MVD)で提供されるエミュレートされたデバイスを使用することです。

MVD をインストールしてファイアウォールを設定したら、MVD を実行します。

b20283893073ac1b.png

OnOff デバイスを作成します。まだコミッションされていません。この Codelab の後半でコミッションします。

5f4855b808312898.png

Commissioning API を有効にする

Commissioning API はアプリのアクティビティの外部で動作するため、他の Home API とは異なる方法で構成する必要があります。アプリを試運転する準備をするには、2 つの変数が必要です。

1 つの変数は ActivityResultLauncher で、コミッショニング インテントの送信と結果コールバックの管理に使用されます。もう一つの変数 CommissioningResult は、構成結果を格納するために使用されるオブジェクトです。コミッショニングを設定する方法については、次の例をご覧ください。

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

構成フローを設定した後、構成インテントを作成し、前述の例で作成したランチャーを使用して起動します。インテントとランチャーは、次のように専用の関数に配置することをおすすめします。専用の関数を UI 要素([+ デバイスを追加] ボタンなど)に関連付け、ユーザー リクエストに基づいて呼び出すことができます。

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

CommissioningManager.kt のステップ 7.1.1 のコメントを解除して、試用版アプリで設定機能を有効にし、[+ デバイスを追加] ボタンを機能させます。

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

この関数を実行すると、次のスクリーンショットに似た画面が表示され、設定フローが開始されます。

baae45588f460664.png

設置フローを理解する

設定フローには、デバイスを Google アカウントに追加する手順を案内する一連の画面が含まれています。

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

ユーザーには QR コード スキャナが表示され、Matter デバイスの QR コードをスキャンできます。その後、ユーザー契約の表示、デバイスの検出と設定、デバイスの名前の設定が順に実行されます。フローが完了すると、フローはフォーカスをアプリに戻し、前のセクションで下書きしたコールバック関数にコミッショニング結果を渡します。

コミッショニング API の利点の一つは、UX フローが SDK によって処理されるため、デベロッパーがすぐに運用を開始できることです。また、さまざまなアプリでデバイスを追加する際に、ユーザーに一貫したエクスペリエンスを提供できます。

コミッショニング API の詳細については、Android の Commissioning API をご覧ください。

8. 完了

これで、Google Home API を使用して Android アプリを作成できました。この Codelab では、Permissions、Devices、Structures、Commissioning API について学びました。次の Codelab「Android の Home API を使用して高度な自動化を作成する」では、Automation API と Discovery API を学び、アプリを完成させます。

Google Home エコシステム内のデバイスを創造的に操作するアプリをぜひ開発してください。

次のステップ