访问 Android 设备和设备元数据

您可以通过适用于 Android 的 Home API 访问设备 API。 将以下软件包导入到您的应用中:

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

如需将特定设备类型或特征与设备 API 搭配使用,必须单独导入这些类型或特征。

例如,如需使用 Matter On/Off 特征和 On/Off 插件单元设备类型,请将以下软件包导入到您的应用中:

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 版中,您可以选择让 API 将每个多部分设备表示为单个设备,方法是将 devices() 方法的 enableMultipartDevices 参数设置为 true。如需了解详情,请参阅 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中的端点)。

它们还会考虑特征冲突,以防设备具有两种设备类型,而这两种设备类型可能具有相同的特征。例如,如果设备既是扬声器又是可调光灯,则它将具有两个 On/Off 特征和两个 Level Control 特征。

如需获取可调光灯设备类型的可用特征列表,请执行以下操作:

// 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 调用。例如,如需获取家中所有具有 On/Off 特征的设备列表,请执行以下操作:

// 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 设备, 为了通过 Cloud-to-cloud 设备标识您的 BasicInformation 特征,您可以在 其 SYNC 响应中添加以下字符串字段:

  • Connectivity Standards Alliance (Alliance) 发布的供应商 ID: "matterOriginalVendorId": "0xfff1",

  • 用于唯一标识供应商产品的商品标识符: "matterOriginalProductId": "0x1234",

  • 设备的唯一标识符,以 制造商特定的方式构建: "matterUniqueId": "matter-device-id",

输入这些字符串字段时,请使用您的 Matter 供应商 ID 和商品 ID(如果有)。如果您不是 Alliance 成员且未获分配这些 ID,则可以将 matterOriginalVendorIdmatterOriginalProductId 字段留空 并提供 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 标准特征可能仍处于在线状态,但基于云端的特征将处于离线状态。

获取设备的 IP 地址

如需查找设备的 IP 地址,请使用 networkInterfaces 属性,该属性属于 特征。GeneralDiagnostics地址以字节数组的形式返回,您可以将其格式化为标准 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 指示特征是远程路由(通过云端)、本地路由(通过本地 hub)还是对等路由(直接从设备到设备,没有 hub)。

可能会出现未知本地性值 UNSPECIFIED,例如,当应用正在启动且尚未连接到 hub 或服务器以进行设备连接时。这些设备无法访问,并且来自命令或事件的互动请求将失败。如何处理此类设备由客户端决定。

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

检查设备的网络路由

与连接一样,本地性是在设备类型级别进行检查的。返回的状态是该设备上所有特征的本地性的组合。

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

在与 PARTIALLY_ONLINE 连接类似的情况下,可能会观察到 MIXED 状态:某些特征基于云端,而另一些特征是本地特征。

更改设备的名称

调用 setName() 方法以更改设备的名称:

mixerDevice.setName("Grendel")

如果名称超过 60 个 Unicode 码位(字符)的限制,系统会截断名称,并且不会抛出任何错误。开发者负责处理长名称,例如,可以决定是否告知用户名称将被截断。