Cómo acceder a dispositivos y metadatos de dispositivos para iOS

Se puede acceder a las APIs de dispositivos a través de las APIs de Home para iOS. Importa los siguientes paquetes a tu app:

import GoogleHomeSDK
import GoogleHomeTypes

Para obtener más información, consulta Modelo de datos en iOS.

Manejo de errores

Algunos métodos de las APIs de Home arrojan una HomeError, por lo que te recomendamos que uses un bloque do-catch para capturar HomeError en esas llamadas.

Cuando controles HomeError, revisa sus campos code y message para saber qué salió mal.

Cualquier error no controlado hará que tu app falle.

Para obtener más información, consulta Manejo de errores.

Consulta Cómo enviar un comando a un dispositivo para ver un ejemplo.

Llamadas de muestra

Cómo obtener una lista de dispositivos

Con una referencia al objeto Home, invoca devices() para obtener un Query de dispositivos accesibles. Llama al método batched() de Query, que emite un conjunto que refleja el estado actual de la casa con cada cambio de metadatos del dispositivo. También puedes llamar a Query.list() para obtener un resumen de los dispositivos disponibles. Este es un método de conveniencia que se suscribe al flujo batched() y muestra el primer valor emitido. Query.stream() produce un flujo que emite valores nuevos en los cambios de metadatos del dispositivo, como su nombre, habitación o estructura. De forma interna, usa batched() y solo emite las propiedades cambiadas.

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

Desde allí, se puede acceder a los estados de cada dispositivo y se pueden enviar comandos compatibles al dispositivo.

Obtén los tipos de dispositivos

Para obtener los tipos de dispositivos asociados con un dispositivo, lee la propiedad types del dispositivo, que muestra un DeviceTypeController.

Llama a DeviceTypeController.subscribe(_:) para suscribirte a las actualizaciones de un tipo de dispositivo en particular:

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")
    }
}

Si el dispositivo no es compatible con el tipo de dispositivo especificado, muestra un Empty Publisher que se completa de inmediato.

Si el dispositivo admite un tipo específico, puedes obtener un identificador para ese tipo llamando a get():

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

Si el dispositivo no admite el tipo especificado, muestra nil.

Llama a DeviceTypeController.subscribeAll() para obtener un Publisher de DeviceTypeCollection. Esta clase te permite verificar si el dispositivo tiene un tipo de dispositivo en particular:

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]
    }
}

Cómo obtener un atributo de tipo de dispositivo

Los tipos de dispositivos son el punto de entrada para leer atributos, ya que descomponen un dispositivo en sus partes funcionales (como los extremos en Matter).

También tienen en cuenta las colisiones de atributos en caso de que un dispositivo tenga dos tipos de dispositivos, ambos con el mismo atributo. Por ejemplo, si un dispositivo es una bocina y una luz regulable, tendrá dos atributos de encendido/apagado y dos de control de nivel.

Otro tipo de colisión de atributos puede ocurrir cuando un dispositivo tiene dos atributos con el mismo nombre. Por ejemplo, onOff podría hacer referencia a una instancia del atributo OnOff estándar o a una instancia de un atributo OnOff definido por el fabricante. Para eliminar cualquier ambigüedad sobre el atributo que se pretende, haz referencia a un atributo a través de una de las dos colecciones de atributos en cada tipo de dispositivo.

Para los atributos estándar, es decir, aquellos que son análogos a los clústeres estándar de Matter, usa matterTraits. Por ejemplo, para obtener un atributo específico para el tipo de dispositivo de luz regulable, haz lo siguiente:

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

Para los atributos de Google, usa googleTraits:

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

Para acceder a un atributo específico del fabricante, haz referencia a él a través de la propiedad traits, pero anteplágalo con el nombre del paquete del fabricante:

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
}

Cómo leer el estado de un dispositivo

Observa este ejemplo de cómo verificar el atributo OnOff del atributo On/Off del dispositivo:

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
}

Cómo obtener una lista de dispositivos con una característica específica

Para obtener una lista de dispositivos que tienen una característica específica, debes iterar sobre los dispositivos, los tipos de dispositivos de cada dispositivo y las características de cada tipo de dispositivo. Por ejemplo, para obtener una lista de los dispositivos de la casa que tienen el atributo Encendido/apagado, haz lo siguiente:

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

Consulta el índice de atributos en iOS para obtener una lista completa de los atributos disponibles en las APIs de Home.

Cómo obtener una lista de dispositivos con tipos de dispositivos similares

Para obtener una lista de los dispositivos que representan todas las luces de una casa, haz lo siguiente:

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

Hay varios tipos de dispositivos en las APIs de Home que podrían representar un tipo de dispositivo principal. Por ejemplo, no hay un tipo de dispositivo "Lámpara". En su lugar, hay cuatro tipos de dispositivos diferentes que podrían representar una luz, como se muestra en el ejemplo anterior. Por lo tanto, para obtener una vista integral del tipo de dispositivo de nivel superior en una casa, se deben incluir varios tipos de dispositivos.

Consulta Tipos de dispositivos compatibles en iOS para obtener una lista completa de los tipos de dispositivos y sus atributos disponibles en las APIs de Home.

Cómo obtener el nombre, el ID o el ID de producto del proveedor de un dispositivo

El atributo BasicInformationTrait incluye información como el ID del proveedor, el ID del producto, el nombre del producto y el número de serie de un dispositivo:

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")
}

Identificación de dispositivos de nube a nube para fabricantes de dispositivos

Si eres fabricante de dispositivos y compilas dispositivos Cloud-to-cloud, para identificar tus dispositivos Cloud-to-cloud a través del atributo BasicInformation, puedes incluir estos campos de cadena en su respuesta SYNC:

  • ID del proveedor emitido por la Connectivity Standards Alliance (CSA): "matterOriginalVendorId": "0xfff1",

  • Un identificador de producto que identifica de forma única un producto de un proveedor: "matterOriginalProductId": "0x1234",

  • Es un identificador único para el dispositivo, que se construye de una manera específica del fabricante: "matterUniqueId": "matter-device-id",

Cuando ingreses estos campos de cadena, usa los IDs de proveedor y producto de Matter si los tienes. Si no eres miembro de CSA y no se te asignaron estos IDs, puedes dejar los campos matterOriginalVendorId y matterOriginalProductId en blanco y proporcionar matterUniqueId como identificador.

En la respuesta de ejemplo de SYNC, se muestra el uso de estos campos:

{
  "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",
          }
        ]
      }
    ]
  }
}

Para obtener más información, consulta la documentación de SYNC de Cloud-to-cloud.

Metadatos de dispositivos y atributos

Los dispositivos y las características de las APIs de Home tienen metadatos asociados que pueden ayudar a administrar la experiencia del usuario en una app.

Cada atributo de las APIs de Home contiene una propiedad sourceConnectivity, que tiene información sobre el estado en línea y la localidad de un atributo (enrutamiento local o remoto).

Cómo obtener el tipo principal de un dispositivo

Algunos dispositivos pueden presentar varios tipos de dispositivos a través de las APIs de Home. Para garantizar que a los usuarios se les presenten las opciones adecuadas en una app (como el control de dispositivos y las automatizaciones sugeridas) para sus dispositivos, es útil verificar si un tipo de dispositivo es el principal.

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.")
  }
}

Cómo comprobar si un atributo está en línea

Lee la propiedad connectivityState para verificar la conectividad de un atributo:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Es posible que algunos atributos, por lo general, los de smart home de Google, aparezcan sin conexión si el dispositivo no tiene conectividad a Internet. Esto se debe a que estos atributos se basan en la nube y no tienen enrutamiento local.

Cómo verificar la conectividad de un dispositivo

La conectividad de un dispositivo se verifica a nivel del tipo de dispositivo porque algunos dispositivos admiten varios tipos de dispositivos. El estado que se muestra es una combinación de los estados de conectividad de todos los atributos de ese dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Se puede observar un estado de partiallyOnline en el caso de tipos de dispositivos mixtos cuando no hay conectividad a Internet. Es posible que los atributos estándar de Matter aún estén en línea debido al enrutamiento local, pero los atributos basados en la nube estarán sin conexión.

Cómo comprobar el enrutamiento de red de un atributo

La localidad de un atributo también está disponible en las APIs de Home. dataSourceLocality indica si el atributo se enruta de forma remota (a través de la nube), de forma local (a través de un concentrador local) o de igual a igual (directamente de dispositivo a dispositivo, sin concentrador).

El valor de localidad desconocida unspecified es posible, por ejemplo, mientras se inicia una app y aún no se ha conectado a un concentrador o servidor para la conectividad del dispositivo. No se puede acceder a estos dispositivos, y las solicitudes de interacción de comandos o eventos fallarán. Depende del cliente determinar cómo controlar esos dispositivos.

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

Cómo verificar el enrutamiento de red de un dispositivo

Al igual que la conectividad, la localidad se verifica a nivel del tipo de dispositivo. El estado que se muestra es una combinación de la localidad de todos los atributos de ese dispositivo.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

Se puede observar un estado de mixed en una situación similar a la de la conectividad partiallyOnline: algunos atributos se basan en la nube, mientras que otros son locales.

Lista de APIs

Una vez que se crea una instancia de Home, se puede acceder a las siguientes APIs de dispositivos a través de ella:

API Descripción
device(id:) Devuelve un Publisher para el dispositivo especificado que emite el estado del dispositivo cada vez que cambia.
devices() Obtén todos los dispositivos de todas las estructuras de la Cuenta de Google. Devuelve un Query<HomeDevice> que proporciona más opciones de recuperación y filtrado.

Una vez que tengas un HomeDevice, podrás acceder a las siguientes APIs a través de él:

API Descripción
id El ID de sistema único del dispositivo.
name Es el nombre del dispositivo que proporcionó el usuario.
structureID Es el ID de la estructura a la que está asignado el dispositivo. Muestra un objeto String?.
roomID Es el ID de la sala a la que está asignado el dispositivo. Muestra un objeto String?.
types Obtén un tipo específico o todos los tipos disponibles en el dispositivo.
isMatterDevice Si el dispositivo tiene una copia de seguridad de Matter.
sourceConnectivity La conectividad de origen del dispositivo, que representa los estados de conectividad agregados y la localidad de red de los atributos del dispositivo.