Android の構造化 API

Structure API には、Android 用 Home API を介してアクセスできます。次のパッケージをアプリにインポートします。

import com.google.home.Home
import com.google.home.Id
import com.google.home.Structure

エラー処理

Home API のメソッドは HomeException をスローする可能性があるため、すべての呼び出しで try-catch ブロックを使用して HomeException をキャッチすることをおすすめします。

HomeException を処理するときは、 error.code フィールドと error.message フィールドを確認して、何が問題だったかを把握します。サブエラーコードも存在する可能性があるため、 getSubErrorCodes() メソッドを呼び出して結果を確認してください。

処理されていない例外が発生すると、アプリがクラッシュします。

詳細については、 エラー処理をご覧ください。

呼び出しのサンプル

ストラクチャのリストを取得する

初期化すると、structures() 呼び出しは、アクセス可能なストラクチャの Flow を返します。

// Get a flow of all structures accessible to the user
val allStructuresFlow: HomeObjectsFlow<Structure> = home.structures()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allStructures: Set<Structure> = allStructuresFlow.list()

structures() API は、有効なストラクチャのリストをすぐに返さない可能性があるフローです。アプリがリアクティブで、そのフローをサブスクライブして UI を駆動している場合は、最終的に有効なストラクチャのリストが返されます。 ユーザーのスマートフォンが接続を失った場合や、ユーザーがアプリの権限を取り消した場合など、空のストラクチャ リストが返される可能性もあります。このようなケースはアプリで処理する必要があります。

リアクティブ プログラミングではなく命令型プログラミングが強く求められる場合は、ターミナル フロー オペレータを使用できます。

val everyStructure = withTimeout(5000) { home.structures().first { it.isNotEmpty() } }

この呼び出しは、有効なストラクチャのリストがフローを通過するまで待機し、アプリで指定されたタイムアウト時間内にリストが受信されない場合はタイムアウトします。

ストラクチャのプロパティを取得する

ストラクチャのリストを取得したら、そのプロパティにアクセスできます。

// Get a flow on a structure. Flow emits new values on structure metadata changes: name.
val structureFlow: Flow<Structure> = home.structures().itemFlow(myStructureId)

// Get a snapshot of the structure.
val structure: Structure = structureFlow.first()

// Get structure properties
println("id ${structure.id}")
println("name ${structure.name}")

名前でストラクチャを検索する

ストラクチャの名前がわかっている場合は、name プロパティを使用してアクセスすることもできます。

val myHome = home.structures().list().first { it.name == "My home" }

そこから、各ストラクチャのプロパティ、部屋、デバイスにアクセスできます。

複数のストラクチャを操作する

複数のストラクチャを使用するには、各ストラクチャへの参照を個別に取得します。

var structure1: Structure? = null
var structure2: Structure? = null

try {
  structure1 = home.structures().list().firstOrNull { it.name == "Main House" }
} catch (e: HomeException) {
  // Code for handling the exception
}
try {
  structure2 = home.structures().list().firstOrNull { it.name == "Guest Cottage" }
} catch (e: HomeException) {
  // Code for handling the exception
}

部屋のリストを取得する

ストラクチャを取得したら、部屋のリストを取得して、そのプロパティにアクセスできます。

val allRoomsFlow: HomeObjectsFlow<Room> = structure.rooms()
val allRooms: Set<Room> = allRoomsFlow.list()
val room: Room = allRooms.first()

println("id ${room.id}")
println("name ${room.name}")

部屋を作成する

新しい部屋を作成するには:

val testName = "Test Room Name"
val newRoom: Room = structure.createRoom(testName)

部屋を削除する

または、部屋を削除することもできます。

val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull()
    structure.deleteRoom(roomToDelete!!)

ID だけで部屋を削除することもできます。

val roomToDelete1 = allRooms.filter { it.id == testRoomId }.firstOrNull()
structure.deleteRoom(roomToDelete1!!)

デバイスがある部屋を削除しても、デバイスはストラクチャに残りますが、部屋に割り当てられなくなります。

デバイスを別の部屋に移動する

ストラクチャを取得したら、そのストラクチャ内の別の部屋にデバイスを移動できます。

val room2 = structure.rooms().get(Id("room_id_other_structure"))
    val device1 = structure.devices().get(Id("device_id1"))
    structure.moveDevicesToRoom(room2!!, listOf(device1!!))

デバイス ID と部屋 ID のみがある場合は、デバイスを移動することもできます。

structure.moveDevicesToRoom(Id("room_id_other_structure"), listOf(Id("device_id1")))

部屋の名前を変更する

setName() メソッドを呼び出して、部屋の名前を変更します。

livingRoom.setName("Living Room")

名前が 60 Unicode コードポイント(文字)の制限を超えると切り捨てられますが、エラーはスローされません。長い名前の処理はデベロッパーが行う必要があります。たとえば、名前が切り捨てられることをユーザーに通知するかどうかを決定できます。

Google Home エコシステムでは、ほとんどのデバイスタイプで、ユーザーはそのタイプのすべてのデバイスに対して一度に権限を付与できます。ロック、カメラ、ドアベルなど、機密性の高いデバイスタイプや制限付きのデバイスタイプについては、ユーザーが個別に権限を付与する必要があります。

ユーザーが機密性の高いデバイスタイプまたは制限付きのデバイスタイプへのアクセス権を付与しているかどうかを確認するには、ストラクチャ レベルの consentedDeviceTypes() 関数を使用します。

import com.google.home.Structure
import com.google.home.DeviceType
import com.google.home.DeviceTypeFactory
import com.google.home.consentedDeviceTypes // Extension function from the SDK
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
 * Example of how an app may monitor which device types have been granted access by a user.
 */
fun monitorDeviceConsent(structure: Structure, myScope: CoroutineScope) {
    // Obtain the flow of consented device type factories
    val consentedTypesFlow: Flow<Set<DeviceTypeFactory<out DeviceType>>> =
        structure.consentedDeviceTypes()

    myScope.launch {
        consentedTypesFlow.collect { consentedSet ->
            // Check if the user has consented to share a specific restricted
            // type, such as a Doorbell or Camera.
            val hasCameraAccess = consentedSet.any {
                it.toString() == "matter.google.type.GoogleDoorbellDevice"
            }

            if (hasCameraAccess) {
                // Enable features that require camera access
            } else {
                // Inform the user or disable camera-specific features
            }
        }
    }
}

自動化

Automation API のエントリ ポイントはストラクチャです。Home API の自動化について詳しくは、 Android の Automation API の概要をご覧ください。