Prüfen, ob ein Merkmal einen Befehl unterstützt
Die Unterstützung kann auch für einen Merkmalsbefehl geprüft werden. Verwenden Sie außerdem die Funktion supports auf Merkmalsebene, um zu prüfen, ob ein Befehl für ein bestimmtes Gerät unterstützt wird.
So prüfen Sie beispielsweise, ob ein Gerät den Befehl des Merkmals „Ein/Aus“ unterstützt:
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") }
Befehl an Geräte senden
Das Senden eines Befehls ähnelt dem Lesen eines Statusattributs aus einem Merkmal. Verwenden Sie den
Befehl „Umschalten“ des
OnOff
Merkmals, der im Datenmodell des Google Home-Ökosystems als toggle() definiert ist, um das Gerät ein- oder auszuschalten. Mit dieser Methode wird onOff in false geändert, wenn es true ist, oder in true, wenn es false ist:
// Calling a command on a trait. try { onOffTrait.toggle() } catch (e: HomeException) { // Code for handling the exception }
Alle Merkmalsbefehle sind suspend Funktionen und werden erst abgeschlossen, wenn eine Antwort
von der API zurückgegeben wird (z. B. eine Bestätigung, dass sich der Gerätestatus geändert hat).
Befehle können eine Ausnahme zurückgeben, wenn ein Problem mit dem Ausführungsablauf festgestellt wird. Als Entwickler sollten Sie einen try-catch-Block verwenden, um diese Ausnahmen ordnungsgemäß zu verarbeiten und Nutzern detaillierte Informationen zu Fällen zu geben, in denen die Fehler behoben werden können. Nicht behandelte Ausnahmen beenden die Laufzeit der App und können zu Abstürzen in Ihrer App führen.
Alternativ können Sie die Befehle off() oder on() verwenden, um den Status explizit festzulegen:
onOffTrait.off() onOffTrait.on()
Nachdem Sie einen Befehl zum Ändern des Status gesendet haben, können Sie nach Abschluss den Status lesen, wie unter Gerätestatus lesen beschrieben, um ihn in Ihrer App zu verarbeiten. Alternativ können Sie Abläufe verwenden, wie unter Status beobachten beschrieben. Dies ist die bevorzugte Methode.
Befehl mit Parametern senden
Einige Befehle können Parameter verwenden, z. B. die Befehle der
OnOff oder
LevelControl
Merkmale:
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(), )
Einige Befehle haben optionale Argumente, die nach den erforderlichen Argumenten stehen.
Der Befehl step für das FanControl
Merkmal
hat beispielsweise zwei optionale Argumente:
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 }
Prüfen, ob ein Merkmal ein Attribut unterstützt
Einige Geräte unterstützen möglicherweise ein Matter Merkmal, aber nicht ein
bestimmtes Attribut. Ein Cloud-to-cloud Gerät, das
Matter zugeordnet wurde, unterstützt beispielsweise möglicherweise nicht alle
Matter Attribute. Verwenden Sie in solchen Fällen die Funktion supports auf Merkmalsebene und die Enumeration Attribute des Merkmals, um zu prüfen, ob das Attribut für ein bestimmtes Gerät unterstützt wird.
So prüfen Sie beispielsweise, ob ein Gerät das Attribut
onOff
des Merkmals „Ein/Aus“ unterstützt:
// 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!") }
Einige Attribute sind in der Matter Spezifikation oder
dem Cloud-to-cloud smart home Schema nullable. Für diese Attribute können Sie mit isNullable zusätzlich zu supports feststellen, ob ein null-Wert, der vom Attribut zurückgegeben wird, darauf zurückzuführen ist, dass das Gerät diesen Wert nicht meldet, oder ob der Wert des Attributs tatsächlich null ist:
// 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!") }
Merkmalsattribute aktualisieren
Wenn Sie den Wert eines bestimmten Attributs ändern möchten und keiner der Befehle des Merkmals dies tut, unterstützt das Attribut möglicherweise das explizite Festlegen des Werts.
Ob der Wert eines Attributs geändert werden kann, hängt von zwei Faktoren ab:
- Ist das Attribut beschreibbar?
- Kann sich der Wert des Attributs als Nebeneffekt des Sendens eines Merkmalsbefehls ändern?
Diese Informationen finden Sie in der Referenzdokumentation für Merkmale und ihre Attribute.
Daher sind die Kombinationen von Eigenschaften, die bestimmen, wie der Wert eines Attributs geändert werden kann, folgende:
Schreibgeschützt und nicht von anderen Befehlen betroffen. Das bedeutet, dass sich der Wert des Attributs nicht ändert. Beispiel: Das
currentPositionAttribut desSwitchMerkmals.Schreibgeschützt und von anderen Befehlen betroffen. Das bedeutet, dass sich der Wert des Attributs nur durch das Senden eines Befehls ändern kann. Das Attribut
currentLeveldesLevelControlMatter Merkmals ist beispielsweise schreibgeschützt, sein Wert kann aber durch Befehle wiemoveToLevelgeändert werden.Beschreibbar und nicht von anderen Befehlen betroffen. Das bedeutet, dass Sie den Wert des Attributs direkt mit der Funktion
updatedes Merkmals ändern können, aber es gibt keine Befehle, die sich auf den Wert des Attributs auswirken. Beispiel: DasWrongCodeEntryLimitAttribut desDoorLockMerkmals.Beschreibbar und von anderen Befehlen betroffen. Das bedeutet, dass Sie den Wert des Attributs direkt mit der Funktion
updatedes Merkmals ändern können und sich der Wert des Attributs durch das Senden eines Befehls ändern kann. DasspeedSettingAttribut desFanControlTraitkann beispielsweise direkt beschrieben werden, ist aber auch mit demstepBefehl änderbar.
Beispiel für die Verwendung der Funktion „update“ zum Ändern des Werts eines Attributs
In diesem Beispiel wird gezeigt, wie Sie den Wert des
DoorLockTrait.WrongCodeEntryLimit Attributs explizit festlegen.
Rufen Sie zum Festlegen eines Attributwerts die Funktion update des Merkmals auf und übergeben Sie ihr eine Mutator-Funktion, die den neuen Wert festlegt.
Es empfiehlt sich, zuerst
zu prüfen, ob das Merkmal ein Attribut unterstützt.
Beispiel:
val 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) } }
Mehrere Befehle gleichzeitig senden
Mit der Batching API kann ein Client mehrere Gerätebefehle der Home API in einer einzelnen Nutzlast senden. Die Befehle werden in einer einzelnen Nutzlast zusammengefasst und parallel ausgeführt, ähnlich wie bei der Erstellung einer Home API Automatisierung mit dem parallelen Knoten, z. B. im Beispiel Jalousien vor Sonnenaufgang öffnen . Die Batching API ermöglicht jedoch komplexere und ausgefeiltere Verhaltensweisen als die Automation API, z. B. die Möglichkeit, Geräte zur Laufzeit dynamisch nach beliebigen Kriterien auszuwählen.
Die Befehle in einem Batch können auf mehrere Merkmale auf mehreren Geräten in mehreren Räumen in mehreren Strukturen ausgerichtet sein.
Wenn Befehle in einem Batch gesendet werden, können Geräte Aktionen gleichzeitig ausführen. Das ist nicht möglich, wenn Befehle sequenziell in separaten Anfragen gesendet werden. Mit dem Verhalten, das mit Batch-Befehlen erzielt wird, kann der Entwickler den Status einer Gruppe von Geräten so festlegen, dass er einem vordefinierten aggregierten Status entspricht.
Batching API verwenden
Es gibt drei grundlegende Schritte zum Aufrufen von Befehlen über die Batching API:
- Rufen Sie die
Home.sendBatchedCommands()Methode auf. - Geben Sie im Text des Blocks
sendBatchedCommands()die Befehle an, die in den Batch aufgenommen werden sollen. - Prüfen Sie die Ergebnisse der gesendeten Befehle, um festzustellen, ob sie erfolgreich waren oder fehlgeschlagen sind.
Methode „sendBatchedCommands()“ aufrufen
Rufen Sie die
Home.sendBatchedCommands()
Methode auf. Im Hintergrund wird mit dieser Methode ein Lambda-Ausdruck in einem speziellen Batch-Kontext eingerichtet.
home.sendBatchedCommands() {
Batch-Befehle angeben
Füllen Sie im Text des Blocks sendBatchedCommands() die Batch-fähigen Befehle aus. Batch-fähige Befehle sind „Schattenversionen“ vorhandener Device API-Befehle, die in einem Batch-Kontext verwendet werden können. Sie werden mit dem zusätzlichen Suffix Batchable benannt. Der
LevelControl
des Merkmals
moveToLevel()
hat beispielsweise ein Gegenstück namens
moveToLevelBatchable().
Beispiel:
val response1 = add(command1)
val response2 = add(command2)
Der Batch wird automatisch gesendet, sobald alle Befehle dem Batch-Kontext hinzugefügt wurden und die Ausführung den Kontext verlassen hat.
Antworten werden in
DeferredResponse<T>
Objekten erfasst.
Die DeferredResponse<T>
Instanzen können in einem Objekt eines beliebigen Typs zusammengefasst werden, z. B. in einer
Collection, oder einer von Ihnen definierten Datenklasse. Der Typ des Objekts, das Sie
zum Zusammenstellen der Antworten auswählen, wird von
sendBatchedCommands() zurückgegeben. Der Batch-Kontext kann beispielsweise zwei
DeferredResponse Instanzen in einem Pair zurückgeben:
val (response1, response2) = homeClient.sendBatchedComamnds {
val response1 = add(someCommandBatched(...))
val response2 = add(someOtherCommandBatched(...))
Pair(response1, response2)
}
Alternativ kann der Batch-Kontext die DeferredResponse
Instanzen in einer benutzerdefinierten Datenklasse zurückgeben:
// Custom data class
data class SpecialResponseHolder(
val response1: DeferredResponse<String>,
val response2: DeferredResponse<Int>,
val other: OtherResponses
)
data class OtherResponses(...)
Jede Antwort prüfen
Prüfen Sie außerhalb des Blocks sendBatchedCommands() die Antworten, um festzustellen, ob der entsprechende Befehl erfolgreich war oder fehlgeschlagen ist. Rufen Sie dazu
DeferredResponse.getOrThrow() auf, das entweder:
- das Ergebnis des ausgeführten Befehls zurückgibt oder
- einen Fehler auslöst, wenn der Batch-Bereich nicht abgeschlossen wurde oder der Befehl
nicht erfolgreich war.
Sie sollten die Ergebnisse nur außerhalb des Lambda-Bereichs sendBatchedCommands() prüfen.
Beispiel
Angenommen, Sie möchten eine App entwickeln, die die Batching API verwendet, um eine „Gute Nacht“-Szene einzurichten, mit der alle Geräte im Zuhause für die Nacht konfiguriert werden, wenn alle schlafen. Diese App soll das Licht ausschalten und die Vorder- und Hintertür verriegeln.
So können Sie vorgehen:
val lightDevices: List<OnOffLightDevice>
val doorlockDevices: List<DoorLockDevice>
// Send all the commands
val responses: List<DeferredResponse<Unit>> = home.sendBatchedCommands {
// For each light device, send a Batchable command to turn it on
val lightResponses: List<DeferredResponse<Unit>> = lightDevices.map { lightDevice ->
add(lightDevice.standardTraits.onOff.onBatchable())
}
// For each doorlock device, send a Batchable command to lock it
val doorLockResponse: List<DeferredResponse<Unit>> = doorlockDevices.map { doorlockDevice ->
add(doorlockDevice.standardTraits.doorLock.lockDoorBatchable())
}
lightResponses + doorLockResponses
}
// Check that all responses were successful
for (response in responses) {
response.getOrThrow()
}