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 atributos de dispositivos específicos con las APIs de Device, se deben importar de forma individual.
Por ejemplo, para usar el atributo On/Off de Matter 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 una
HomeException, por lo que te recomendamos que uses un bloque try-catch para detectar HomeException en todas las llamadas.
Cuando controles HomeException, verifica sus campos
error.code y
error.message para saber qué ocurrió. También puede haber códigos de error secundarios, por lo que debes llamar al método
getSubErrorCodes() y verificar el resultado.
Cualquier excepción no controlada hará que tu app falle.
Para obtener más información, consulta Manejo de errores.
Consulta Envía un comando a un dispositivo para ver un ejemplo.
Llamadas de muestra
Obtén una lista de dispositivos
Una vez que tengas una referencia a la instancia de Structure, una llamada a devices()
devolverá un Flow 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í, puedes acceder a los estados de cada dispositivo y enviarles comandos.
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 Android para obtener más
información.
Lee el estado de un dispositivo
Consulta un ejemplo de cómo verificar el atributo OnOff del rasgo de encendido o apagado del dispositivo. Con el modelo de datos de rasgos de las APIs de Home, en el que este rasgo se identifica como OnOff, puedes recuperar los datos de rasgos 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.
Estado de invalidación en una suscripción de atributo
La interfaz TraitStateInvalidation
proporciona la capacidad de 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 casos en los 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 debido a 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 él:
val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()
Obtén una lista de los atributos de tipo de dispositivo
Los tipos de dispositivos se deben usar como punto de entrada para leer los 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 caso de que un dispositivo tenga dos tipos de dispositivos, los cuales podrían tener el mismo rasgo. Por ejemplo, si un dispositivo es una bocina y una luz regulable, tendrá dos características 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 colisión 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 estándar OnOff o a una instancia de un rasgo OnOff definido por el fabricante. Para eliminar cualquier ambigüedad potencial en cuanto al atributo que 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 calificado. Para los rasgos estándar, es decir, aquellos que son análogos a
los clústeres estándar de Matter, usa standardTraits. Para los rasgos 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 atributo 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 atributo específico
La función filter en Kotlin se puede usar para definir mejor las llamadas a la API. Por ejemplo, para obtener una lista de los dispositivos de la casa que tienen el atributo On/Off, 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 atributos disponibles en las APIs de Home.
Obtén una lista de dispositivos con tipos 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) } }
Existen varios tipos de dispositivos en las APIs de Home 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 del tipo de dispositivo de nivel superior en una casa, se deben incluir varios tipos de dispositivos en los flujos filtrados.
Consulta la interfaz 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 del producto de un dispositivo
La característica 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 creas 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:
El ID de proveedor emitido por Connectivity Standards Alliance (Alliance):
"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 proveedor y de producto de Matter, si los tienes. Si no eres miembro de
Alliance y no se te asignaron estos IDs, puedes
dejar los campos matterOriginalVendorId y matterOriginalProductId en blanco
y proporcionar el matterUniqueId como identificador.
En el ejemplo de respuesta 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 Cloud-to-cloud de SYNC.
Metadatos de dispositivos y rasgos
Los dispositivos y los atributos 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).
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 de dispositivos y las automatizaciones sugeridas) para sus dispositivos, es útil verificar cuál es el tipo de dispositivo principal de un dispositivo.
Primero, obtén los tipos del dispositivo con
type()
y, luego, determina los tipos principales:
val types = device.types().first() val primaryTypes = types.filter { it.metadata.isPrimaryType }
Verifica si un rasgo está en línea
Usa el método connectivityState() para verificar la conectividad de un atributo:
val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState
Algunos atributos, por lo general, los de Google smart home, pueden mostrarse sin conexión si el dispositivo no tiene conectividad a Internet. Esto se debe a que estos rasgos se basan en la nube y no tienen enrutamiento local.
Verifica la conectividad de un dispositivo
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 todos los rasgos de ese 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 rasgos estándar de Matter sigan en línea debido al enrutamiento local, pero los rasgos basados en la nube estarán sin conexión.
Obtén la dirección IP del dispositivo
Para encontrar la dirección IP del dispositivo, usa el atributo networkInterfaces del atributo GeneralDiagnostics. Las direcciones se devuelven como arrays de bytes, a los que puedes dar formato de
strings IPv4 o IPv6 estándar:
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()
Verifica 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 par a par (directamente de un dispositivo a otro, sin concentrador).
El valor de localidad desconocido UNSPECIFIED es posible, por ejemplo, mientras se inicia una app
y aún no se conectó 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 manejar 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 de ese dispositivo.
val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality
Se puede observar un estado de MIXED en una situación similar
a la de la conectividad PARTIALLY_ONLINE: 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 arrojarán errores. Los desarrolladores son responsables de controlar los nombres largos y, por ejemplo, pueden decidir si quieren informar a los usuarios que se truncarán los nombres.
Cómo verificar la pertenencia a un grupo de un dispositivo
Un dispositivo físico puede pertenecer a uno o más grupos de dispositivos. Para ver a qué grupos pertenece un dispositivo, consulta el atributo GroupMembership en el dispositivo:
val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
println("HomeAPI", "Device belongs to group: $groupId")
}
Por el contrario, puedes observar todos los dispositivos miembros que pertenecen a un
DeviceGroup llamando al
flujo devices() en un DeviceGroup:
group.devices(enableMultipartDevices = true).collect { members ->
println("HomeAPI", "Group contains ${members.size} devices")
}
Para inspeccionar los tipos de dispositivos que admite un DeviceGroup y enviar comandos al
grupo como una sola entidad, consulta
Controla un grupo de dispositivos.