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

您可以透過 Android 版 Home API 存取裝置 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,因此建議您使用 try-catch 區塊,在所有呼叫中擷取 HomeException。

處理 HomeException 時,請檢查其 error.code 和 error.message 欄位,瞭解發生什麼錯誤。此外,也可能會有子錯誤代碼,因此請呼叫 getSubErrorCodes() 方法並檢查結果。

任何未處理的例外狀況都會導致應用程式當機。

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

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

範例呼叫

取得裝置清單

取得 Structure 執行個體的參照後,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()

你可以在這裡查看每部裝置的狀態,並傳送指令給裝置。

在 Home API 1.8 版中,您可以將 devices() 方法的 enableMultipartDevices 參數設為 true,讓 API 將每個多部分裝置視為單一裝置。詳情請參閱「Android 上的多部分裝置」。

讀取裝置狀態

請參閱以下範例,瞭解如何檢查裝置 On/Off 特性的 OnOff 屬性。使用 Home API 特性資料模型時,這項特性會識別為 OnOff,您可以透過裝置類型的 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 介面可讓您撤銷透過訂閱目標裝置擷取的狀態。舉例來說,如果使用 Matter 特性中品質為「C」的屬性,或裝置實作方式意外導致問題,就可能無法正確回報狀態。

這個 API 會強制讀取目前的特徵狀態,並透過現有的特徵流程傳回結果。

取得特徵,然後對特徵執行 forceRead:

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

取得裝置類型特徵清單

裝置類型應做為讀取特性的進入點,因為裝置類型會將裝置分解為功能片段 (例如 Matter 中的端點)。

如果裝置具有兩種裝置類型,且兩者可能具有相同特性,則系統也會考量特性衝突。舉例來說,如果裝置同時是音箱和可調光燈具,就會有兩個「開/關」和兩個「亮度控制」特性。

如要取得可調光燈具裝置類型的可用特徵清單,請按照下列步驟操作:

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

如果裝置有兩個名稱相同的特徵,也可能發生另一種特徵衝突。舉例來說,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」裝置類型。如上述範例所示,有四種不同的裝置類型可以代表燈。因此,如要全面瞭解住家中較高層級的裝置類型,篩選流程中必須包含多種裝置類型。

如需 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 (Alliance) 核發的供應商 ID: "matterOriginalVendorId": "0xfff1",

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

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

輸入這些字串欄位時,請使用 Matter 供應商和產品 ID (如有)。如果您不是 Alliance 成員,且未獲派這些 ID,可以將 matterOriginalVendorId 和 matterOriginalProductId 欄位留空,並提供 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 說明文件。

裝置和特質中繼資料

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 標準特徵可能仍會上線,但雲端式特徵會離線。

取得裝置的 IP 位址

如要找出裝置的 IP 位址,請使用 GeneralDiagnostics 特性的 networkInterfaces 屬性。位址會以位元組陣列的形式傳回,您可以將其格式化為標準 IPv4 或 IPv6 字串:

val ipAddresses =
  trait.networkInterfaces?.flatMap { networkInterface ->
    (networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
      try {
        java.net.InetAddress.getByAddress(bytes).hostAddress
      } catch (e: java.net.UnknownHostException) {
        null
      }
    }
  } ?: emptyList()

檢查特性的網路轉送

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 碼點 (字元) 限制,系統會截斷名稱,且不會擲回任何錯誤。開發人員必須負責處理過長的名稱,例如決定是否要通知使用者名稱會遭到截斷。

查看裝置的群組成員資格

實體裝置可以屬於一或多個裝置群組。如要查看裝置屬於哪些群組,請檢查裝置的 GroupMembership 特性:

val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
  println("HomeAPI", "Device belongs to group: $groupId")
}

相反地,您可以在 DeviceGroup 上呼叫 devices() 流程,觀察屬於 DeviceGroup 的所有成員裝置:

group.devices(enableMultipartDevices = true).collect { members ->
  println("HomeAPI", "Group contains ${members.size} devices")
}

如要檢查 DeviceGroup 支援的裝置類型,並以單一實體的形式傳送指令給群組,請參閱「控制裝置群組」。