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 generan un HomeError, por lo que te recomendamos que uses un do-catch para detectar HomeError en esas llamadas.

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

Cualquier error no controlado provocará que falle tu app.

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

Obtén una lista de dispositivos

Con una referencia al Home objeto, invoca devices() para obtener una Query de dispositivos accesibles. Llama al Query's batched() método, que emite un conjunto que refleja el estado actual de Home con cada cambio de metadatos del dispositivo. O bien, llama a Query.list() para obtener una instantánea de los dispositivos disponibles. Este es un método de conveniencia que se suscribe a la transmisión batched() y muestra el primer valor emitido. Query.stream() produce una transmisión que emite valores nuevos en los cambios de metadatos del dispositivo, como su nombre, habitación o estructura. Internamente, usa batched() y solo emite las propiedades modificadas.

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

Desde allí, puedes acceder a los estados de cada dispositivo y enviar comandos a los dispositivos.

Con la versión 1.8 de las APIs de Home, tienes la opción de que la API represente cada dispositivo de varias partes como un solo dispositivo configurando el parámetro enableMultipartDevices del método devices() en true. Consulta Dispositivos de varias partes en iOS para obtener más información.

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 admite el tipo de dispositivo especificado, muestra un Empty Publisher que se completa de inmediato.

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

if let device = devices.first(where: { $0.id == myDeviceId }) {
  let _ = 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]
    }
}

Obtén una característica de tipo de dispositivo

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

También tienen en cuenta las colisiones de características en caso de que un dispositivo tenga dos tipos de dispositivos, los cuales podrían tener la misma característica. Por ejemplo, si un dispositivo es un altavoz y una luz regulable, tendría dos características de encendido/apagado y dos de control de nivel.

Otro tipo de colisión de características puede ocurrir cuando un dispositivo tiene dos características con el mismo nombre. Por ejemplo, onOff podría hacer referencia a una instancia de la característica OnOff estándar o a una instancia de una característica OnOff definida por el fabricante. Para eliminar cualquier ambigüedad potencial en cuanto a qué característica se pretende, haz referencia a una característica a través de una de las dos colecciones de características en cada tipo de dispositivo.

Para las características estándar, es decir, aquellas que son análogas a Matter clústeres estándar, usa matterTraits. Por ejemplo, para obtener una característica específica 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 las características de Google, usa googleTraits:

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

Para acceder a una característica específica del fabricante, haz referencia a ella a través de la propiedad traits, pero anteponle 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
}

Lee el estado de un dispositivo

Observa este ejemplo para verificar el atributo OnOff de la característica de encendido/apagado 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
}

Obtén 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 dispositivos en la casa que tengan la característica de encendido/apagado, haz lo siguiente:

// Get all light devices that support levelControl
var levelControlDevices: [HomeDevice] = []
let 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 características en iOS para obtener una lista completa de las características disponibles en las APIs de Home.

Obtén una lista de dispositivos con tipos de dispositivos similares

Para obtener una lista de dispositivos que representen 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)
  }

Existen 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 "Light". En cambio, 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 los tipos de dispositivos compatibles en iOS para obtener una lista completa de los tipos de dispositivos y sus características que están disponibles en las APIs de Home.

Obtén el nombre del proveedor, el ID del proveedor o el ID del producto de un dispositivo

La BasicInformationTrait característica 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 Cloud-to-cloud dispositivos, para identificar tus Cloud-to-cloud dispositivos a través de la BasicInformation característica, puedes incluir estos campos de cadena en su respuesta SYNC:

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

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

  • 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 tus Matter IDs de proveedor y producto si los tienes. Si no eres miembro de Alliance y no se te asignaron estos IDs, puedes dejar en blanco los campos matterOriginalVendorId y matterOriginalProductId y proporcionar el matterUniqueId como identificador.

En el ejemplo de respuesta 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 Cloud-to-cloud SYNC.

Metadatos de dispositivos y características

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 característica de las APIs de Home contiene una sourceConnectivity propiedad, que tiene información sobre el estado en línea y la localidad de una característica (enrutamiento local o remoto).

Obtén 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 los usuarios vean las opciones adecuadas en una app (como el control del dispositivo y las automatizaciones sugeridas) para sus dispositivos, es útil verificar si un tipo de dispositivo es el tipo principal del dispositivo.

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

Verifica si una característica está en línea

Lee la propiedad connectivityState para verificar la conectividad de una característica:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Algunas características, por lo general, las características de smart home de Google, pueden mostrarse sin conexión si el dispositivo no tiene conectividad a Internet. Esto se debe a que estas características se basan en la nube y no tienen enrutamiento local.

Verifica la conectividad de un dispositivo

La conectividad de un dispositivo se verifica en el nivel del tipo de dispositivo, ya que algunos dispositivos admiten varios tipos de dispositivos. El estado que se muestra es una combinación de los estados de conectividad de todas las características 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. Matter Las características estándar de Matter pueden seguir en línea debido al enrutamiento local, pero las características basadas en la nube estarán sin conexión.

Verifica el enrutamiento de red de una característica

La localidad de una característica también está disponible en las APIs de Home. dataSourceLocality indica si la característica se enruta de forma remota (a través de la nube), localmente (a través de una unidad central local) o de par a par (directamente de dispositivo a dispositivo, sin unidad central).

Es posible que el valor de localidad desconocido unspecified esté disponible, por ejemplo, mientras se inicia una app y aún no llegó a una unidad central o un servidor para la conectividad del dispositivo. No se puede acceder a estos dispositivos y fallarán las solicitudes de interacción de comandos o eventos. Dependerá del cliente determinar cómo controlar esos dispositivos.

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

Verifica el enrutamiento de red de un dispositivo

Al igual que la conectividad, la localidad se verifica en el nivel del tipo de dispositivo. El estado que se muestra es una combinación de la localidad de todas las características 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: algunas características se basan en la nube, mientras que otras son locales.

Cambia el nombre de un dispositivo

Llama al setName(_:) método para cambiar el nombre de un dispositivo:

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

Cuando cambias el nombre de un dispositivo, la estructura HomeDevice original permanece igual, y el cambio se refleja en el objeto HomeDevice actualizado que se muestra.

Los nombres se truncarán si superan el límite de 60 puntos de código Unicode (caracteres) y no se generarán errores. Los desarrolladores son responsables de controlar los nombres largos y, por ejemplo, pueden decidir si quieren informar a los usuarios que los nombres se truncarán.