检查 trait 是否支持某个命令
您还可以查看 trait 命令是否受支持。此外,您还可以使用 trait 级 supports
函数检查特定设备是否支持某个命令。
例如,如需检查设备是否支持开/关 trait 的 toggle
命令,请执行以下操作:
// 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") }
向设备发送命令
发送命令类似于从 trait 读取状态属性。如需开启或关闭设备,请使用 OnOff
trait 的“切换”命令,该命令在 Google Home 生态系统数据模型中定义为 toggle()
。如果 onOff
为 true
,则此方法会将其更改为 false
;如果 onOff
为 false
,则会将其更改为 true
:
// Calling a command on a trait. try { onOffTrait.toggle() } catch (e: HomeException) { // Code for handling the exception }
所有 trait 命令都是 suspend
函数,只有在 API 返回响应(例如确认设备状态已更改)时才会完成。如果检测到执行流程存在问题,命令可能会返回异常。作为开发者,您应使用 try-catch
块妥善处理这些异常,并在错误可供用户采取行动时向用户显示详细信息。未处理的异常会停止应用运行时,并可能导致应用崩溃。
或者,使用 off()
或 on()
命令明确设置状态:
onOffTrait.off() onOffTrait.on()
发送用于更改状态的命令后,命令完成后,您可以按照读取设备状态中所述的方式读取状态,以便在应用中进行处理。或者,您也可以使用监控状态中所述的流程,这是首选方法。
发送带参数的命令
某些命令可能会使用参数,例如 OnOff
或 LevelControl
trait 中的参数:
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(), )
某些命令具有可选实参,这些实参位于必需实参之后。
例如,FanControl
trait 的 step
命令有两个可选参数:
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 }
检查 trait 是否支持属性
某些设备可能支持 Matter trait,但不支持特定属性。例如,映射到 Matter 的 Cloud-to-cloud 设备可能不支持所有 Matter 属性。如需处理此类情况,请使用 trait 级 supports
函数和 trait 的 Attribute
枚举来检查特定设备是否支持该属性。
例如,如需检查设备是否支持开/关 trait 的 onOff
属性,请执行以下操作:
// 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!") }
Matter 规范或 Cloud-to-cloud smart home 架构中的一些属性是可为 null 的。对于这些属性,您可以通过使用 isNullable
和 supports
,确定属性返回 null 是由于设备未报告该值,还是属性的值实际上为 null
:
// 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!") }
更新 trait 属性
如果您想更改给定属性的值,但 trait 的任何命令都无法执行此操作,则该属性可能支持显式设置其值。
属性的值能否更改取决于以下两个因素:
- 该属性是否可写入?
- 发送 trait 命令会导致属性值发生变化吗?
有关 trait 及其属性的参考文档提供了此类信息。
因此,决定属性值可能如何更改的属性组合如下:
只读,不受其他命令的影响。这意味着该属性的值不会发生变化。例如,
Switch
trait 的currentPosition
属性。只读,且会受其他命令影响。这意味着,属性值的唯一更改方式是发送命令。例如,
LevelControl
Matter trait 的currentLevel
属性是只读的,但其值可以通过moveToLevel
等命令进行更改。可写入,且不受其他命令的影响。这意味着,您可以使用 trait 的
update
函数直接更改属性的值,但没有任何命令会影响属性的值。例如,DoorLock
trait 的WrongCodeEntryLimit
属性。可写入,并受其他命令影响。这意味着,您可以使用 trait 的
update
函数直接更改属性的值,并且属性的值可能会因发送命令而发生变化。例如,可以写入Thermostat
trait 的occupiedCoolingSetpoint
属性,也可以使用setpointRaiseLower
命令更新该属性。
使用 update 函数更改属性值的示例
以下示例展示了如何显式设置 DoorLockTrait.WrongCodeEntryLimit
属性的值。
如需设置属性值,请调用 trait 的 update
函数,并向其传递用于设置新值的修饰符函数。
最好先验证 trait 是否支持属性。
例如:
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) } }