Android のデバイスとデバイスのメタデータにアクセスする

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

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

Device API で特定のデバイスタイプまたはトレイトを使用するには、それらを個別にインポートする必要があります。

たとえば、Matter のオン/オフ特性とオン/オフ プラグイン ユニットのデバイスタイプを使用するには、次のパッケージをアプリにインポートします。

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

詳細については、Android のデータモデルをご覧ください。

エラー処理

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

HomeException を処理するときは、code フィールドと message フィールドを確認して、何が問題だったかを把握します。

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

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

例については、デバイスにコマンドを送信するをご覧ください。

サンプル呼び出し

デバイスのリストを取得する

構造が利用可能な場合、devices() 呼び出しは、その構造からアクセス可能なデバイスの Flow を返します。

// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()

そこから、各デバイスの状態にアクセスし、サポートされているコマンドをデバイスに送信できます。

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

デバイスのオン/オフ特性から OnOff 属性を確認する例を見てみましょう。この特性が OnOff として識別される Home APIs 特性データモデルを使用して、デバイスタイプの standardTraits クラスから特性データを取得できます。

// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!

Kotlin フロー関数について詳しくは、distinctUntilChanged をご覧ください。

トレイト サブスクリプションの状態を無効にする

TraitStateInvalidation インターフェースは、状態が正しく報告されていない場合に、ターゲット デバイスへのサブスクリプションを通じて取得された状態を無効にする機能を提供します。状態が正しく報告されない例としては、品質が「C」の Matter トレイトで属性を使用している場合や、デバイスの実装が原因で予期せず問題が発生した場合などがあります。

この API は、現在のトレイトの状態の強制読み取りを発行し、既存のトレイト フローを介して結果を返します。

トレイトを取得し、トレイトに対して forceRead を実行します。

val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()

デバイスタイプのトレイトのリストを取得する

デバイスタイプは、デバイスを機能的な部分(Matter のエンドポイントなど)に分解するため、トレイトを読み取るためのエントリ ポイントとして使用する必要があります。

また、デバイスに 2 つのデバイスタイプがあり、両方に同じ特性がある場合に、特性の衝突を考慮します。たとえば、デバイスがスピーカーと調光可能なライトの両方である場合、OnOff トレイトと Level Control トレイトがそれぞれ 2 つずつ存在します。

調光可能な照明デバイスタイプで使用可能なトレイトのリストを取得するには:

// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()

デバイスに同じ名前の 2 つの特性がある場合、別の種類の特性の衝突が発生する可能性があります。たとえば、onOff は標準の OnOff トレイトのインスタンスを参照することも、メーカー定義の OnOff トレイトのインスタンスを参照することもできます。どのトレイトが意図されているかについての曖昧さを解消するため、デバイスを通じて参照される Trait インスタンスの前に、修飾名前空間を付加する必要があります。標準特性(Matter 標準クラスタに類似した特性)の場合は、standardTraits を使用します。Google トレイトの場合は、googleTraits を使用します。

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

メーカー固有のトレイトにアクセスするには、直接参照します。

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

特定の特性を持つデバイスのリストを取得する

Kotlin の filter 関数を使用すると、API 呼び出しをさらに絞り込むことができます。たとえば、オン/オフ特性を持つすべてのデバイスのリストを取得するには、次のようにします。

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

Home API で使用可能な特性の完全なリストについては、Trait インターフェースをご覧ください。

デバイスタイプが類似しているデバイスのリストを取得する

家にあるすべての照明を表すデバイスのリストを取得するには:

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

Home API には、コア デバイスタイプを表す可能性のあるデバイスタイプが複数あります。たとえば、「Light」というデバイスタイプはありません。代わりに、前の例に示すように、照明を表す 4 種類のデバイスタイプがあります。そのため、家にある上位レベルのデバイスの包括的なビューを取得するには、フィルタリングされたフローに複数のデバイスタイプを含める必要があります。

Home API で使用可能なデバイスタイプの完全なリストについては、DeviceType インターフェースをご覧ください。

デバイスのベンダー ID またはプロダクト ID を取得する

BasicInformation トレイトには、デバイスのベンダー ID、プロダクト ID、プロダクト名、シリアル番号などの情報が含まれます。

// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.productId}")

デバイス メーカー向けのクラウド間デバイス識別

デバイスメーカーが Cloud-to-cloud デバイスを構築する場合、BasicInformation トレイトで Cloud-to-cloud デバイスを識別するために、これらの文字列フィールドを SYNC レスポンスに含めることができます。

  • Connectivity Standards Alliance(CSA)が発行したベンダー ID: "matterOriginalVendorId": "0xfff1",

  • ベンダーの商品を一意に識別する商品 ID: "matterOriginalProductId": "0x1234",

  • デバイスの一意の識別子。メーカー固有の方法で構築されます。 "matterUniqueId": "matter-device-id",

これらの文字列フィールドを入力する際は、ベンダー ID とプロダクト ID がある場合はそれらを使用します。MatterCSA メンバーではなく、これらの ID が割り当てられていない場合は、matterOriginalVendorId フィールドと matterOriginalProductId フィールドを空白のままにして、識別子として matterUniqueId を指定できます。

次の SYNC レスポンスの例では、これらのフィールドの使用方法を示します。

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "456",
        "type": "action.devices.types.LIGHT",
        "traits": [
          "action.devices.traits.OnOff",
          "action.devices.traits.Brightness",
          "action.devices.traits.ColorSetting",
        ],
        "willReportState": true,
        "deviceInfo": { ... },
        "matterOriginalVendorId": "0xfff1",
        "matterOriginalProductId": "0x1234",
        "matterUniqueId": "matter-device-id",
        "otherDeviceIds": [
          {
            "deviceId": "local-device-id",
          }
        ]
      }
    ]
  }
}

詳細については、Cloud-to-cloud SYNC ドキュメントをご覧ください。

デバイスとトレイトのメタデータ

Home API のデバイスとトレイトにはメタデータが関連付けられており、アプリでのユーザー エクスペリエンスの管理に役立ちます。

Home API の各トレイトには、トレイトのオンライン ステータスとローカリティ(ローカル ルーティングまたはリモート ルーティング)に関する情報を含む sourceConnectivity プロパティが含まれています。

デバイスのプライマリ タイプを取得する

一部のデバイスは、Home API を通じて複数のデバイスタイプを表示する場合があります。デバイスの適切なオプション(デバイス制御や自動化の候補など)がアプリでユーザーに表示されるようにするには、デバイスのプライマリ デバイスタイプを確認することが役立ちます。

まず、type() を使用してデバイスのタイプを取得し、プライマリ タイプを特定します。

val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }

特性がオンラインかどうかを確認する

connectivityState() メソッドを使用して、特性の接続を確認します。

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

一部のトレイト(通常は Google smart home トレイト)は、デバイスがインターネットに接続されていない場合、オフラインと表示されることがあります。これは、これらの特性がクラウドベースであり、ローカル ルーティングがないためです。

デバイスの接続を確認する

デバイスの接続は、実際にはデバイスタイプ レベルでチェックされます。一部のデバイスは複数のデバイスタイプをサポートしているためです。返される状態は、そのデバイスのすべてのトレイトの接続状態の組み合わせです。

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

インターネット接続がない場合、デバイスタイプが混在していると PARTIALLY_ONLINE の状態になることがあります。Matter 標準トレイトはローカル ルーティングによりオンラインのままになる可能性がありますが、クラウドベースのトレイトはオフラインになります。

トレイトのネットワーク ルーティングを確認する

特性のローカリティは、Home API でも利用できます。dataSourceLocality は、トレイトがリモート(クラウド経由)、ローカル(ローカルハブ経由)、ピアツーピア(デバイスからデバイスへの直接接続、ハブなし)のいずれでルーティングされるかを示します。

不明な地域値 UNSPECIFIED は、たとえば、アプリの起動中にデバイス接続用のハブやサーバーにまだ到達していない場合に発生する可能性があります。これらのデバイスにはアクセスできず、コマンドやイベントからのインタラクション リクエストは失敗します。このようなデバイスの処理方法はクライアントが決定します。

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

デバイスのネットワーク ルーティングを確認する

接続と同様に、ローカリティはデバイスタイプ レベルでチェックされます。返される状態は、そのデバイスのすべてのトレイトのローカリティの組み合わせです。

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

PARTIALLY_ONLINE 接続と同様のシナリオで MIXED の状態が観測されることがあります。一部の特性はクラウドベースで、他の特性はローカルです。

デバイスの名前を変更する

setName() メソッドを呼び出して、デバイスの名前を変更します。

mixerDevice.setName("Grendel")

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

API リスト

Home のインスタンスが作成されると、次のデバイス API にアクセスできるようになります。

API 説明
devices() Google アカウントのすべての構造内のすべてのデバイスを取得します。取得とフィルタリングのオプションを提供する HomeObjectsFlow を返します。

HomeDevice を取得すると、次の API にアクセスできます。

API 説明
allCandidates() デバイスとその子デバイスのすべての自動化候補を返します。
candidates() デバイスのすべての自動化候補を返します。
connectivityStateChanged デバイスの状態が最後に変更された時刻。
events(event) 特定のイベントのフローを取得します。
events(trait) この Trait によるすべてのイベントのフローを取得します。
events(traits) これらの特性によるすべてのイベントのフローを取得します。
getSourceConnectivity(trait) 特定の特性のメタデータを取得します。SourceConnectivity を返します。
has(trait) 現在リクエストされているトレイトがデバイスでサポートされているかどうかを確認します。
has(type) デバイスが指定されたタイプをサポートしている場合。
id デバイスの一意のシステム ID。
isMatterDevice デバイスが Matter でバックアップされている場合。
name ユーザーが指定したデバイスの名前。
room() デバイスが割り当てられている部屋。Room を返します。
roomId デバイスが割り当てられている部屋の ID。Id を返します。
sourceConnectivity デバイスのソース接続。デバイスの特性の接続状態とネットワークのローカリティを集約した状態を表します。
structure() デバイスが割り当てられている構造。Structure を返します。
structureId デバイスが割り当てられている建物の ID。Id を返します。
type(type) 直接アクセス用に特性が入力された型定義を取得します(利用可能な場合)。常に最新の特性のスナップショットを返します。
types() デバイスで使用可能なすべてのタイプのリストを取得します。