Controla dispositivos

Cómo verificar si un atributo admite un comando

También se puede verificar la compatibilidad con un comando de rasgo. También usa la función supports a nivel de los atributos para verificar si un comando es compatible con un dispositivo en particular.

Por ejemplo, para verificar si un dispositivo admite el comando toggle del atributo de encendido/apagado, haz lo siguiente:

// Check if the OnOff trait supports the toggle command.
if (onOffTrait.supports(OnOff.Command.Toggle)) {
  println("onOffTrait supports toggle command")
} else {
  println("onOffTrait does not support stateful toggle command")
}

Enviar un comando a un dispositivo

Enviar un comando es similar a leer un atributo de estado de un rasgo. Para encender o apagar el dispositivo, usa el comando Toggle de la función OnOff, que se define en el modelo de datos del ecosistema de Google Home como toggle(). Este método cambia onOff a false si es true o a true si es false:

// Calling a command on a trait.
try {
  onOffTrait.toggle()
} catch (e: HomeException) {
  // Code for handling the exception
}

Todos los comandos de atributos son funciones suspend y solo se completan cuando la API muestra una respuesta (como confirmar que cambió el estado del dispositivo). Los comandos pueden mostrar una excepción si se detecta un problema con el flujo de ejecución. Como desarrollador, debes usar un bloque try-catch para controlar correctamente estas excepciones y mostrar información detallada a los usuarios en los casos en que los errores se puedan corregir. Las excepciones no controladas detendrán el entorno de ejecución de la app y pueden provocar fallas en ella.

Como alternativa, usa los comandos off() o on() para establecer el estado de forma explícita:

onOffTrait.off()
onOffTrait.on()

Después de enviar un comando para cambiar el estado, una vez que se complete, puedes leer el estado como se describe en Cómo leer el estado de un dispositivo para controlarlo en tu app. Como alternativa, usa los flujos como se describe en Cómo observar el estado, que es el método preferido.

Cómo enviar un comando con parámetros

Algunos comandos pueden usar parámetros, como los de los atributos OnOff o LevelControl:

offWithEffect

// Turn off the light using the DyingLight effect.
onOffTrait.offWithEffect(
  effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight,
  effectVariant = 0u,
)

moveToLevel

// Change the brightness of the light to 50%
levelControlTrait.moveToLevel(
  level = 127u.toUByte(),
  transitionTime = null,
  optionsMask = LevelControlTrait.OptionsBitmap(),
  optionsOverride = LevelControlTrait.OptionsBitmap(),
)

Algunos comandos tienen argumentos opcionales, que se colocan después de los argumentos obligatorios.

Por ejemplo, el comando step para el atributo FanControl tiene dos argumentos opcionales:

val fanControlTraitFlow: Flow<FanControl?> =
  device.type(FanDevice).map { it.standardTraits.fanControl }.distinctUntilChanged()

val fanControl = fanControlTraitFlow.firstOrNull()

// Calling a command with optional parameters not set.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase)

// Calling a command with optional parameters.
fanControl?.step(direction = FanControlTrait.StepDirectionEnum.Increase) { wrap = true }

Cómo verificar si un atributo admite un atributo

Es posible que algunos dispositivos admitan un atributo Matter, pero no un atributo específico. Por ejemplo, es posible que un dispositivo Cloud-to-cloud que se asignó a Matter no admita todos los atributos Matter. Para controlar casos como estos, usa la función supports a nivel del atributo y la enumeración Attribute del atributo para verificar si el atributo es compatible con un dispositivo en particular.

Por ejemplo, para verificar si un dispositivo admite el atributo onOff del atributo On/Off, haz lo siguiente:

// Check if the OnOff trait supports the onOff attribute.
if (onOffTrait.supports(OnOff.Attribute.onOff)) {
  println("onOffTrait supports onOff state")
} else {
  println("onOffTrait is for a command only device!")
}

Algunos atributos son nulos en la especificación Matter o en el esquema smart home Cloud-to-cloud. Para estos atributos, puedes determinar si un valor null que muestra el atributo se debe a que el dispositivo no informa ese valor o si el valor del atributo es null. Para ello, usa isNullable además de supports:

// Check if a nullable attribute is set or is not supported.
if (onOffTrait.supports(OnOff.Attribute.startUpOnOff)) {
  // The device supports startupOnOff, it is safe to expect this value in the trait.
  if (OnOff.Attribute.startUpOnOff.isNullable && onOffTrait.startUpOnOff == null) {
    // This value is nullable and set to null. Check the specification as to
    // what null in this case means
    println("onOffTrait supports startUpOnOff and it is null")
  } else {
    // This value is nullable and set to a value.
    println("onOffTrait supports startUpOnOff and it is set to ${onOffTrait.startUpOnOff}")
  }
} else {
  println("onOffTrait does not support startUpOnOff!")
}

Actualiza los atributos de los rasgos

Si quieres cambiar el valor de un atributo determinado y ninguno de los comandos del rasgo lo hace, es posible que el atributo admita que se establezca su valor de forma explícita.

La posibilidad de cambiar el valor de un atributo depende de dos factores:

  • ¿Se puede escribir en el atributo?
  • ¿Puede cambiar el valor del atributo como un efecto secundario de enviar un comando de rasgo?

La documentación de referencia de los atributos y sus atributos proporciona esta información.

Por lo tanto, las combinaciones de propiedades que determinan cómo se puede cambiar el valor de un atributo son las siguientes:

  • Es de solo lectura y no se ve afectado por otros comandos. Esto significa que el valor del atributo no cambia. Por ejemplo, el atributo currentPosition del rasgo Switch.

  • De solo lectura y afectado por otros comandos. Esto significa que la única forma en que puede cambiar el valor del atributo es como resultado del envío de un comando. Por ejemplo, el atributo currentLevel del rasgo Matter LevelControl es de solo lectura, pero su valor puede sufrir mutaciones con comandos como moveToLevel.

  • Se puede escribir en ellos y no se ven afectados por otros comandos. Esto significa que puedes cambiar directamente el valor del atributo con la función update del rasgo, pero no hay comandos que afecten el valor del atributo. Por ejemplo, el atributo WrongCodeEntryLimit del rasgo DoorLock.

  • Se puede escribir en ellos y otros comandos los afectan. Esto significa que puedes cambiar directamente el valor del atributo con la función update del atributo, y el valor del atributo puede cambiar como resultado de enviar un comando. Por ejemplo, se puede escribir en el atributo occupiedCoolingSetpoint del atributo Thermostat, pero también se puede actualizar con el comando setpointRaiseLower.

Ejemplo del uso de la función update para cambiar el valor de un atributo

En este ejemplo, se muestra cómo establecer de forma explícita el valor del atributo DoorLockTrait.WrongCodeEntryLimit.

Para establecer un valor de atributo, llama a la función update del atributo y pásale una función de mutador que establezca el valor nuevo. Te recomendamos que primero verifiques que el atributo admita un atributo.

Por ejemplo:

    var doorLockDevice = home.devices().list().first { device -> device.has(DoorLock) }

    val traitFlow: Flow<DoorLock?> =
      doorLockDevice.type(DoorLockDevice).map { it.standardTraits.doorLock }.distinctUntilChanged()

    val doorLockTrait: DoorLock = traitFlow.first()!!

    if (doorLockTrait.supports(DoorLock.Attribute.wrongCodeEntryLimit)) {
      val unused = doorLockTrait.update { setWrongCodeEntryLimit(3u) }
    }