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

Se puede acceder a las APIs de dispositivos a través de las APIs de Home para Android. Importa estos paquetes a tu app:

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

Para usar tipos o rasgos de dispositivos específicos con las APIs de Device, se deben importar de forma individual.

Por ejemplo, para usar el rasgo Matter On/Off y el tipo de dispositivo On/Off Plug-in Unit, importa los siguientes paquetes a tu aplicación:

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

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

Manejo de errores

Cualquier método de las APIs de Home puede arrojar un HomeException, por lo que te recomendamos que uses un bloque try-catch para detectar HomeException en todas las llamadas.

Cuando manejes HomeException, verifica sus campos code y message para saber qué ocurrió.

Cualquier excepción no controlada provocará una falla en la app.

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

Consulta Enviar un comando a un dispositivo para ver un ejemplo.

Llamadas de muestra

Obtén una lista de dispositivos

Con la estructura disponible, una llamada a devices() devuelve un flujo de dispositivos a los que puedes acceder desde esa estructura:

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

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

Cómo leer el estado de un dispositivo

Veamos un ejemplo de cómo verificar el atributo OnOff del rasgo de encendido/apagado del dispositivo. Con el modelo de datos del rasgo de las APIs para la casa, en el que este rasgo se identifica como OnOff, puedes recuperar datos del rasgo a través de la clase standardTraits del tipo de dispositivo:

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

Consulta distinctUntilChanged para obtener más información sobre la función de flujo de Kotlin.

Invalida el estado en una suscripción a un rasgo

La interfaz TraitStateInvalidation permite invalidar un estado recuperado a través de suscripciones al dispositivo de destino en los casos en que el estado no se informa correctamente. Entre los ejemplos de situaciones en las que es posible que el estado no se informe correctamente, se incluyen el uso de atributos en rasgos de Matter con la calidad "C" o una implementación del dispositivo que causa el problema de forma inesperada.

Esta API emite una lectura forzada del estado actual del rasgo y devuelve el resultado a través de los flujos de rasgos existentes.

Obtén el rasgo y, luego, ejecuta un forceRead en el rasgo:

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

Obtén una lista de las características del tipo de dispositivo

Los tipos de dispositivos se deben usar como punto de entrada para leer rasgos, ya que descomponen un dispositivo en sus partes funcionales (como los extremos en Matter).

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

Para obtener la lista de rasgos disponibles para el tipo de dispositivo Luz regulable, haz lo siguiente:

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

Otro tipo de conflicto de rasgos puede ocurrir cuando un dispositivo tiene dos rasgos con el mismo nombre. Por ejemplo, onOff podría hacer referencia a una instancia del rasgo OnOff estándar o a una instancia de un rasgo OnOff definido por el fabricante. Para eliminar cualquier ambigüedad potencial sobre qué rasgo se pretende, una instancia de Trait a la que se hace referencia a través de un dispositivo debe estar precedida por un espacio de nombres calificador. Para los rasgos estándar, es decir, aquellos que son análogos a los clústeres estándar de Matter, usa standardTraits. Para los atributos de Google, usa googleTraits:

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

Para acceder a un rasgo específico del fabricante, haz referencia a él directamente:

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

Obtén una lista de dispositivos con un rasgo específico

La función filter en Kotlin se puede usar para refinar aún más las llamadas a la API. Por ejemplo, para obtener una lista de los dispositivos de la casa que tienen el rasgo de encendido/apagado, haz lo siguiente:

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

Consulta la interfaz de Trait para obtener una lista completa de los rasgos disponibles en las APIs para la casa.

Obtén 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)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

En las APIs de Home, hay varios tipos de dispositivos que podrían representar un tipo de dispositivo principal. Por ejemplo, no existe el tipo de dispositivo "Luz". 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 de los tipos de dispositivos de nivel superior en una casa, se deben incluir varios tipos de dispositivos en los flujos filtrados.

Consulta la interfaz de DeviceType para obtener una lista completa de los tipos de dispositivos disponibles en las APIs de Home.

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

El rasgo BasicInformation 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:

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

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 rasgo BasicInformation, puedes incluir estos campos de cadena en su respuesta SYNC:

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

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

En la respuesta de SYNC de ejemplo, 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 del dispositivo y del rasgo

Los dispositivos y los rasgos de las APIs de Home tienen metadatos asociados, lo que puede ayudar a administrar la experiencia del usuario en una app.

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

Obtiene 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 de dispositivos y las automatizaciones sugeridas) para sus dispositivos, es útil verificar cuál es el tipo de dispositivo principal.

Primero, obtén los tipos de dispositivo con type() y, luego, determina los tipos principales:

val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }

Cómo verificar si un rasgo está en línea

Usa el método connectivityState() para verificar la conectividad de un rasgo:

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

Algunos rasgos, por lo general, los rasgos de Google smart home, pueden mostrarse sin conexión si el dispositivo no tiene conectividad a Internet. Esto se debe a que estos rasgos son basados en la nube y no tienen enrutamiento local.

Cómo verificar la conectividad de un dispositivo

En realidad, la conectividad de un dispositivo se verifica a nivel del tipo de dispositivo, ya que algunos dispositivos admiten varios tipos. El estado que se devuelve es una combinación de los estados de conectividad de todas las características del dispositivo.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

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

Cómo verificar el enrutamiento de red de un rasgo

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

Por ejemplo, el valor de localidad desconocido UNSPECIFIED es posible mientras una app se inicia y aún no llega a un concentrador o 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. Depende del cliente determinar cómo controlar esos dispositivos.

val onOffLocality = onOffTrait?.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 devuelve es una combinación de la localidad de todos los rasgos del dispositivo.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

En una situación similar a la de la conectividad PARTIALLY_ONLINE, se puede observar un estado de MIXED: algunos rasgos se basan en la nube, mientras que otros son locales.

Cómo cambiar el nombre de un dispositivo

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

mixerDevice.setName("Grendel")

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.

Lista de APIs

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

API Descripción
devices() Obtiene todos los dispositivos en todas las estructuras de la Cuenta de Google. Devuelve un HomeObjectsFlow que proporciona más opciones de recuperación y filtrado.

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

API Descripción
allCandidates() Devuelve todos los candidatos de automatización para el dispositivo y sus elementos secundarios.
candidates() Devuelve todos los candidatos a la automatización para el dispositivo.
connectivityStateChanged Es la fecha y hora más reciente en la que cambió el estado del dispositivo.
events(event) Obtiene un flujo de un evento específico.
events(trait) Obtiene un flujo de todos los eventos de este rasgo.
events(traits) Obtiene un flujo de todos los eventos según estos rasgos.
getSourceConnectivity(trait) Obtiene los metadatos de un rasgo en particular. Muestra un objeto SourceConnectivity.
has(trait) Comprueba si el dispositivo admite el rasgo solicitado actual.
has(type) Indica si el dispositivo admite el tipo proporcionado.
id Es el ID único del sistema del dispositivo.
isMatterDevice Si el dispositivo está respaldado por Matter
name Es el nombre del dispositivo proporcionado por el usuario.
room() Es la habitación a la que está asignado el dispositivo. Muestra un objeto Room.
roomId Es el ID de la habitación a la que está asignado el dispositivo. Devuelve un Id.
sourceConnectivity Es la conectividad de origen del dispositivo, que representa los estados de conectividad agregados y la localidad de red de los rasgos del dispositivo.
structure() Es la estructura a la que se asigna el dispositivo. Muestra un objeto Structure.
structureId Es el ID de la estructura a la que está asignado el dispositivo. Devuelve un Id.
type(type) Obtén la definición del tipo con los rasgos completados (cuando estén disponibles) para el acceso directo. Siempre devuelve una instantánea actualizada de los rasgos.
types() Obtén una lista de todos los tipos disponibles en el dispositivo.