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

Device API には、iOS 向けの Home API からアクセスできます。次のパッケージをアプリにインポートします。

import GoogleHomeSDK
import GoogleHomeTypes

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

エラー処理

Home API の一部の関数は HomeError をスローするため、do-catch ブロックを使用して、これらの呼び出しで HomeError をキャッチすることをおすすめします。

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

処理されないエラーがあると、アプリがクラッシュします。

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

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

通話の例

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

Home オブジェクトへの参照を使用して devices() を呼び出し、アクセス可能なデバイスの Query を取得します。Querybatched() メソッドを呼び出します。このメソッドは、デバイスのメタデータが変更されるたびに、家の現在の状態を反映した Set を出力します。または、Query.list() を呼び出して、使用可能なデバイスのスナップショットを取得します。これは、batched() ストリームにサブスクライブし、最初に出力された値を返す便利なメソッドです。Query.stream() は、デバイスのメタデータ(名前、部屋、構造など)が変更されたときに新しい値を出力するストリームを生成します。内部では、batched() を使用して変更されたプロパティのみを出力します。

// Get a list of all devices accessible to the user
let homeDevices = try await self.home.devices().list()

そこから、各デバイスの状態にアクセスし、対応するコマンドをデバイスに送信できます。

デバイスの種類を取得する

デバイスに関連付けられているデバイスタイプを取得するには、デバイスの types プロパティを読み取ります。これにより、DeviceTypeController が返されます。

DeviceTypeController.subscribe(_:) を呼び出して、特定のデバイスタイプのアップデートを定期購入します。

let devices = try await self.home.devices().list()
if let device = devices.first(where: { $0.id == myDeviceId }) {
  var receivedUpdate1 = false
  var receivedUpdate2 = false
  device.types.subscribe(OnOffLightDeviceType.self)
    .assertNoFailure()
    .sink { device in
      if !receivedUpdate1 {
        receivedUpdate1 = true
        Task {
          try await device.matterTraits.onOffTrait?.on()
        }
        return
      }
      if !receivedUpdate2 {
        receivedUpdate2 = true
        return
      }
      fatalError("Received unexpected update")
    }
}

デバイスが指定されたデバイスタイプをサポートしていない場合、Empty Publisher が返され、すぐに完了します。

デバイスが特定のデバイスタイプをサポートしている場合は、get() を呼び出してそのタイプのハンドルを取得できます。

if let device = devices.first(where: { $0.id == myDeviceId }) {
  let deviceType = await device.types.get(OnOffLightDeviceType.self)
}

デバイスが指定されたタイプをサポートしていない場合、nil を返します。

DeviceTypeController.subscribeAll() を呼び出して、DeviceTypeCollectionPublisher を取得します。このクラスを使用すると、デバイスに特定のデバイスタイプがあるかどうかを確認できます。

if let device = devices.first(where: { $0.id == myDeviceId }) {
  device.types.subscribeAll()
    .assertNoFailure()
    .sink { types in
      let lightDeviceType = types[OnOffLightDeviceType.self]
      let fanDeviceType = types[FanDeviceType.self]
    }
}

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

デバイスタイプは、デバイスを機能的な部分(Matter のエンドポイントなど)に分解するため、トレイトの読み取りのエントリ ポイントです。

また、デバイスに 2 つのデバイスタイプがあり、どちらも同じトレイトを持つ可能性がある場合のトレイト コリジョンも考慮されます。たとえば、デバイスがスピーカーと調光可能なライトの両方である場合、2 つのオン/オフ トレイトと 2 つのレベル コントロール トレイトがあります。

別の種類のトレイト競合は、デバイスに同じ名前の 2 つのトレイトがある場合に発生する可能性があります。たとえば、onOff は標準の OnOff トレイトのインスタンスを参照することも、メーカー定義の OnOff トレイトのインスタンスを参照することもできます。どのトレイトが意図されているかについて曖昧さを回避するには、各デバイスタイプで 2 つのトレイト コレクションのいずれかを使用してトレイトを参照します。

標準特性(Matter 標準クラスタに類似する特性)の場合は、matterTraits を使用します。たとえば、Dimmable Light デバイスタイプの特定の特徴を取得するには:

if let dimmableLightDeviceType =
  await device.types.get(DimmableLightDeviceType.self)
{
  // Accessing standard trait on the type.
  let levelControlTrait =
    dimmableLightDeviceType.matterTraits.levelControlTrait.self
}

Google の特徴の場合は、googleTraits を使用します。

if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) {
  // Accessing Google trait on the type.
  let doorbellPressTrait =
    doorbellDeviceType.googleTraits.doorbellPressTrait.self
}

メーカー固有の特性には、traits プロパティでアクセスしますが、その前にメーカーのパッケージ名を指定します。

let deviceType = await device1?.types.get(OnOffLightDeviceType.self)
// Accessing custom trait on the type.
if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] {
  let rpmVal = spinnerTrait.attributes.rpm
}

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

デバイスのオン/オフ トレイトから OnOff 属性を確認する例を次に示します。

let lightDevices = devices.filter {
  $0.types.contains(OnOffLightDeviceType.self)
}
let light1 = lightDevices.first
let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self)
if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait {
  let onOffVal = onOffTrait.attributes.onOff
}

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

特定のトレイトを持つデバイスのリストを取得するには、デバイス、各デバイスのデバイスタイプ、各デバイスタイプのトレイトを反復処理する必要があります。たとえば、オン/オフの特徴を持つ家のデバイスのリストを取得するには、次のコマンドを実行します。

// Get all light devices that support levelControl
var levelControlDevices: [HomeDevice] = []
var allDevices = try await home.devices().list()
for device in allDevices {
  if let deviceType = await device.types.get(OnOffLightDeviceType.self) {
    if deviceType.traits.contains(Matter.LevelControlTrait.self) {
      levelControlDevices.append(device)
    }
  }
}

Home API で使用可能な特徴の一覧については、iOS の特徴インデックスをご覧ください。

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

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

// Get a list of devices with similar device types (lights)
let lightDevices =
  try await self.home.devices().list().compactMap {
    $0.types.contains(DimmableLightDeviceType.self)
      || $0.types.contains(OnOffLightDeviceType.self)
      || $0.types.contains(ColorTemperatureLightDeviceType.self)
      || $0.types.contains(ExtendedColorLightDeviceType.self)
  }

Home API には、コア デバイスタイプを表す複数のデバイスタイプがあります。たとえば、「ライト」というデバイスタイプはありません。代わりに、上の例に示すように、照明を表すデバイスタイプは 4 種類あります。そのため、家にあるデバイスのより上位の種類を包括的に把握するには、複数のデバイスタイプを含める必要があります。

Home API で使用できるデバイスタイプとそのトレイトの完全なリストについては、iOS でサポートされているデバイスタイプをご覧ください。

デバイスのベンダー名、ベンダー ID、製品 ID を取得する

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

guard
  let vendorName =
    basicInfoTrait.attributes.vendorName
else {
  fatalError("Failed to get vendorName")
}
guard
  let vendorID =
    basicInfoTrait.attributes.vendorID
else {
  fatalError("Failed to get vendorID")
}
guard
  let productID =
    basicInfoTrait.attributes.productID
else {
  fatalError("Failed to get productID")
}

Cloud-to-Cloud デバイスを特定する

デバイス メーカーが Cloud-to-cloud デバイスをビルドする場合、BasicInformationTraitCloud-to-cloud デバイスを識別するには、SYNC レスポンスに次の文字列フィールドを含めます。

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

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

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

これらの文字列フィールドに入力する際は、Matter ベンダー ID と商品 ID(該当する場合)を使用します。CSA メンバーでない場合、またはこれらの 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 を介して複数のデバイスタイプを提示する場合があります。デバイスに適したオプション(デバイスの操作や自動化の候補など)がアプリに表示されるようにするには、デバイスタイプがデバイスのメインタイプかどうかを確認すると便利です。

if let deviceType =
  await device?.types.get(HumiditySensorDeviceType.self)
{
  if deviceType.metadata.isPrimaryType {
    print("Humidity Sensor is the primary type on this device.")
  } else {
    print("Humidity Sensor isn't the primary type on this device.")
  }
}

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

connectivityState プロパティを読み取って、トレイトの接続を確認します。

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

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

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

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

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

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

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

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

不明なローカリティー値 unspecified は、アプリの起動中にデバイス接続用のハブまたはサーバーにまだ到達していない場合などに使用できます。これらのデバイスには到達できないため、コマンドまたはイベントからのインタラクション リクエストは失敗します。このようなデバイスの処理方法は、クライアントが決定します。

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

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

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

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

mixed の状態は、partiallyOnline 接続の場合と同様の状況で観察されることがあります。一部の特徴はクラウドベースで、他の特徴はローカルです。

API リスト

Home のインスタンスを作成すると、次の Device API にアクセスできるようになります。

API 説明
device(id:) 指定したデバイスの Publisher を返します。この Publisher は、デバイスの状態が変化するたびにエミットします。
devices() Google アカウントのすべての構造内のすべてのデバイスを取得します。詳細な取得とフィルタリング オプションを提供する Query<HomeDevice> を返します。

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

API 説明
id デバイスの一意のシステム ID。
name ユーザーが指定したデバイスの名前。
structureID デバイスが割り当てられている構造物の ID。String? を返します。
roomID デバイスが割り当てられている部屋の ID。String? を返します。
types デバイスで利用可能な特定のタイプまたはすべてのタイプを取得します。
isMatterDevice デバイスが Matter でバッキングされている場合。
sourceConnectivity デバイスのソース接続。デバイスの特徴の集約された接続状態とネットワーク ローカリティーを表します。