存取 iOS 裝置和裝置中繼資料

您可以透過 iOS 版 Home API 存取裝置 API。將下列套件匯入應用程式:

import GoogleHomeSDK
import GoogleHomeTypes

詳情請參閱「iOS 資料模型」一文。

處理錯誤

Home API 中的某些方法會擲回 HomeError,因此建議您使用 do-catch 區塊,在這些呼叫中擷取 HomeError

處理 HomeError 時,請檢查 codemessage 欄位,瞭解發生錯誤的原因。

任何未處理的錯誤都會導致應用程式當機。

詳情請參閱「錯誤處理」一節。

如需範例,請參閱「將指令傳送至裝置」。

呼叫範例

取得裝置清單

取得 Home 物件的參照後,請叫用 devices() 取得可存取裝置的 Query。呼叫 Querybatched() 方法,每次裝置中繼資料變更時,都會發出反映 Home 目前狀態的 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() 取得 PublisherDeviceTypeCollection。這個類別可讓您檢查裝置是否屬於特定裝置類型:

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 中的端點)。

如果裝置有兩種裝置類型,且這兩種裝置類型可能具有相同特徵,系統也會將特徵衝突納入考量。舉例來說,如果裝置同時是音箱和可調光燈具,就會有兩個開/關和兩個層級控制特徵。

如果裝置有兩個名稱相同的特徵,也可能發生特徵衝突。舉例來說,onOff 可以參照標準 OnOff 特徵的例項,也可以參照製造商定義的 OnOff 特徵例項。為避免可能出現的特徵不明確情況,請透過各裝置類型上的其中一個特徵集合參照特徵。

如果是標準特徵 (即與 Matter 標準叢集類似的特徵),請使用 matterTraits。舉例來說,如要取得可調光燈具裝置類型的特定特徵:

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
}

讀取裝置狀態

請參閱以下範例,瞭解如何從裝置的 On/Off 特徵檢查 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 中有多種裝置類型,可代表核心裝置類型。舉例來說,沒有「燈具」裝置類型。如上述範例所示,燈光有四種不同的裝置類型。因此,如要全面瞭解住家中的高階裝置類型,必須納入多種裝置類型。

如需 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 裝置,如要透過 BasicInformation 特徵識別 Cloud-to-cloud 裝置,可以在 SYNC 回應中加入下列字串欄位:

  • Connectivity Standards Alliance (CSA) 已核發供應商 ID: "matterOriginalVendorId": "0xfff1",

  • 可專屬識別供應商產品的產品 ID: "matterOriginalProductId": "0x1234",

  • 裝置的專屬 ID,以製造商專屬方式建構: "matterUniqueId": "matter-device-id",

輸入這些字串欄位時,請使用供應商和產品 ID (如有)。Matter如果不是 CSA 成員,且未獲派這些 ID,請將 matterOriginalVendorIdmatterOriginalProductId 欄位留空,並提供 matterUniqueId 做為 ID。

範例 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 說明文件

裝置和特徵中繼資料

Google 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

在類似 partiallyOnline 連線的案例中,可能會出現 mixed 狀態:部分特徵以雲端為基礎,其他特徵則為本機。

變更裝置名稱

呼叫 setName(_:) 方法來變更裝置名稱:

let updatedDevice = try await theDevice.setName("new device name")

變更裝置名稱時,原始 HomeDevice 結構體會保持不變,變更會反映在傳回的更新 HomeDevice 物件中。

如果名稱超過 60 個 Unicode 碼點 (字元) 的限制,系統會截斷名稱,且不會擲回錯誤。開發人員有責任處理長名稱,例如決定是否要通知使用者名稱會遭到截斷。

API 清單

建立 Home 執行個體後,即可透過該執行個體存取下列裝置 API:

API 說明
device(id:) 針對指定裝置傳回 Publisher,每當裝置狀態變更時,就會發出該狀態。
devices() 取得 Google 帳戶中所有結構的所有裝置。傳回 Query<HomeDevice>,提供進一步的擷取和篩選選項。

取得 HomeDevice 後,您就可以透過該權杖存取下列 API:

API 說明
id 裝置的專屬系統 ID。
name 使用者提供的裝置名稱。
structureID 裝置所屬的結構體 ID。傳回 String?
roomID 裝置所屬房間的 ID。傳回 String?
types 取得裝置上的特定類型或所有可用類型。
isMatterDevice 如果裝置有 Matter 支援。
sourceConnectivity 裝置的來源連線,代表裝置特徵的匯總連線狀態和網路位置。