Hier finden Sie eine Übersicht über die grundlegenden Konzepte der Automatisierungs-DSL auf Android.
Automatisierungskomponenten
Eine Automatisierung besteht aus den folgenden grundlegenden Komponenten, die in der Regel in dieser Reihenfolge ausgewertet werden:
- Auslöser : Definiert die Anfangsbedingungen, die die Automatisierung aktivieren, z. B. eine Änderung eines Merkmals. Eine Automatisierung muss einen Auslöser haben.
- Bedingung : Zusätzliche Einschränkungen, die nach der Aktivierung einer Automatisierung ausgewertet werden. Der Ausdruck in einer Bedingung muss
trueergeben, damit die Aktionen einer Automatisierung ausgeführt werden können. - Aktion : Befehle oder Statusaktualisierungen, die ausgeführt werden, wenn alle Bedingungen erfüllt sind.
Beispiel: Sie haben eine Automatisierung, die die Lichter in einem Raum dimmt, wenn der Fernseher in diesem Raum zwischen Sonnenuntergang und Sonnenaufgang eingeschaltet wird. In diesem Fall gilt Folgendes:
- Auslöser : Der Fernseher wurde eingeschaltet. Das ist eine Statusänderung für ein TV-Merkmal.
- Bedingung : Die aktuelle Uhrzeit für das Zuhause, in dem sich der Fernseher befindet, wird ausgewertet.
- Aktion : Die Lichter im selben Raum wie der Fernseher werden gedimmt.
Die Automatisierung wird aktiviert, wenn der Fernseher im Raum eingeschaltet wird. Sie wird jedoch nur ausgeführt, wenn die Bedingung „Uhrzeit liegt zwischen Sonnenuntergang und Sonnenaufgang“ erfüllt ist.
Neben der grundlegenden Struktur enthalten Automatisierungen in den Home APIs auch Metadaten wie Name und Beschreibung, mit denen sie für Entwickler und Nutzer identifiziert werden können.
Knoten
In den Home APIs besteht die logische Struktur einer Automatisierung aus Knoten. Knoten sind abstrakte, wiederverwendbare Einheiten, die Entitätsverhalten oder Ausführungsabläufe darstellen. Jeder Knoten kann Eingabevariablen sowie Ausgabevariablen haben, die von anderen Knoten verwendet werden können.
| Knoten | Knotentyp | Kotlin-Implementierung | Beschreibung |
|---|---|---|---|
| Auslöser | Verhaltensbezogen |
StarterNodeDsl
|
Startet eine Automatisierung, wenn sich der Status eines Merkmals (ein beliebiges Attribut) ändert. |
| StateReader | Verhaltensbezogen |
StateReaderNodeDsl
|
Liest ein Attribut eines Merkmals und ermöglicht es Ihnen, seinen Wert für die Verwendung in Bedingungsknoten zu erfassen. |
| Aktion | Verhaltensbezogen |
ActionNodeDsl
|
Ruft Merkmalsbefehle auf. |
| Sequenziell | Ablauf der Ausführung |
SequentialFlow
|
Führt verschachtelte Aktionsknoten nacheinander aus. Dies ist das Standardverhalten bei der Ausführung. |
| Parallel | Ablauf der Ausführung |
ParallelFlow
|
Führt verschachtelte Aktionsknoten parallel aus. |
| Bedingung | Ablauf der Ausführung |
ConditionNodeDsl
|
Ändert den Ablauf der Ausführung bedingt auf der Grundlage von Auswertungen logischer Ausdrücke. Bedingungen können mit einem Auslöser verknüpft sein (auslöserspezifische Bedingungen) oder global sein (gelten für alle Auslöser). |
| Auswählen | Ablauf der Ausführung |
SelectFlow
|
Ermöglicht es, dass mehr als ein Auslöser eine Automatisierung aktiviert. |
| Ausdruck | Wert |
Expression
|
Kann der Wert eines Attributs eines Merkmals, eine Konstante oder ein Literalwert sein, und muss eine Liste, eine Zahl, einen booleschen Wert oder einen String ergeben. |
Verhaltensbezogene Knoten
Knoten wie Auslöser und Aktionen sind verhaltensbezogene Knoten. Auslöser aktivieren eine Automatisierung basierend auf Änderungen von Geräteattributen. Aktionen geben Gerätebefehle aus oder aktualisieren Attribute.
Verhaltensbezogene Knoten sind in der Regel mit Geräteattributen verknüpft und geben den Status des Merkmals als Eingabe für andere Knoten aus.
Knoten für den Ablauf der Ausführung
Einige Knoten stellen Ausführungsabläufe dar, z. B. sequenziell und parallel. Jeder dieser Knoten enthält die verhaltensbezogenen Knoten, die die Automatisierung definieren.
Ein sequenzieller Ablauf kann beispielsweise Knoten enthalten, die in sequenzieller Reihenfolge ausgeführt werden. In der Regel sind das Auslöser, Bedingungen und Aktionen.
Ein paralleler Ablauf kann mehrere Aktionsknoten haben, die gleichzeitig ausgeführt werden, z. B. das gleichzeitige Einschalten mehrerer Lichter. Knoten, die einem parallelen Ablauf folgen, werden erst ausgeführt, wenn alle Zweige des parallelen Ablaufs abgeschlossen sind.
Eine weitere Art von Ausführungsablauf ist ein Bedingungsablauf, der den Ausführungsablauf basierend auf der Auswertung eines Ausdrucks ändern kann.
Beispiel: Sie haben eine Automatisierung, die eine Aktion ausführt, je nachdem, ob es Nacht ist. Ein Bedingungsknoten prüft die Tageszeit und folgt dann dem entsprechenden Ausführungspfad basierend auf dieser Auswertung.
Ein Auswahlablauf ist nützlich, wenn Sie mehr als einen Auslöser haben möchten, der Ihre Automatisierung aktivieren kann. Wenn Sie zwei oder mehr Auslöser in einen select-Ablauf einschließen, kann jeder der Auslöser die Automatisierung aktivieren.
Beispiel: Sie können eine Automatisierung schreiben, die die Jalousien bei Sonnenuntergang herunterlässt, wenn die Temperatur einen bestimmten Schwellenwert übersteigt oder wenn die Helligkeit einen Schwellenwert übersteigt. Drei separate Auslöser verarbeiten jedes dieser Szenarien und alle drei werden in einen select-Ablauf eingeschlossen.
Verschachtelte Abläufe
In komplexen Automatisierungen können auch Knoten für den Ablauf der Ausführung verschachtelt werden. Beispiel: Sie haben einen sequenziellen Ablauf, der einen parallelen Ablauf ausführt.
DSL-Knoten können auf verschiedene Weise verschachtelt und kombiniert werden, um Ihren spezifischen Anforderungen zu entsprechen. Dabei müssen die in der folgenden Tabelle aufgeführten Einschränkungen beachtet werden. Die Spalte „Builder“ enthält Links zur typsicheren Kotlin-Builder-Dokumentation, in der detailliert beschrieben wird, was in den einzelnen Knotentypen verwendet werden darf.
| Knoten | Kann den folgenden Knotentyp und die folgenden Daten enthalten | Muss in einem der folgenden Knotentypen enthalten sein |
|---|---|---|
| Auslöser | Ausdruck | Auswählen, Sequenziell |
| ManualStarter | Auswählen, Sequenziell | |
| StateReader | Ausdruck (besteht in der Regel aus einem Attributwert des Merkmals) | Aktion, Bedingung |
| Aktion | Befehl, Entität, Ausdruck | Parallel, Auswählen, Sequenziell |
| Sequenziell | Parallel, Auswählen, Sequenziell | |
| Parallel | Aktion | Sequenziell |
| Bedingung | Ausdruck | Parallel, Sequenziell |
| Auswählen | Bedingung, Sequenziell, Auslöser, ManualStarter | Sequenziell und muss der erste Knoten im Ablauf sein |
Automatisierungs-DSL
In den Home APIs werden Automatisierungen mit der Automatisierungs-DSL (Domain-Specific Language) definiert. Die Automatisierungs-DSL wird als Kotlin-DSL (Domain-Specific Language), implementiert. Dabei werden typsichere Kotlin-Builder verwendet und sie wurde speziell für die Definition von Automatisierungsvorlagen entwickelt.
Wenn eine Automatisierung kompiliert wird, generieren typsichere Kotlin-Builder Kotlin-Datenklassen, die dann in Protocol Buffer JSON serialisiert werden. Diese wird verwendet, um Aufrufe an die Automatisierungsdienste von Google zu senden.
Die Automatisierungs-DSL vereinfacht und optimiert den Prozess der Erstellung von Automatisierungen. Sie verwendet nativ dasselbe Datenmodell der Matter Standardmerkmale und smart home Merkmale die in der Device API enthalten sind.
Die Automatisierungs-DSL definiert die Logik einer Automatisierung auch in Bezug auf abstrakte Gerätetypen und nicht auf bestimmte Geräteinstanzen im Zuhause eines Nutzers. So kann der Entwickler Eingabeparameter bereitstellen, die zur Laufzeit verwendet werden können, um tatsächliche Geräteinstanzen sowie andere wichtige Parameterwerte anzugeben.
Die DSL-Syntax ähnelt der von Kotlin und ist ebenso typsicher. Eine in der Automatisierungs-DSL geschriebene Automatisierung ist jedoch einfacher und prägnanter als dieselbe Automatisierung, die in reinem Kotlin geschrieben wurde.
Beispiel
Im Folgenden finden Sie ein Beispiel für eine Automatisierung, die ein Gerät einschaltet. Sie wurde mit der Automatisierungs-DSL geschrieben:
val automation = automation {
name = "MyFirstAutomation"
description = "If light1 is on, turn on light2."
isActive = true
sequential {
val onOffTrait = starter<_>(device1, OnOffLightDevice, OnOff)
condition() { expression = onOffTrait.onOff equals true }
action(device2, OnOffLightDevice) { command(OnOff.on()) }
}
}
Diese Automatisierung ist sehr einfach: Wenn device1, eine Lampe, eingeschaltet wird (das Attribut onOff ändert sich zu true), wird der Befehl on() gesendet, um device2 einzuschalten.
Die Automatisierung verwendet einen sequential-Knoten, der angibt, dass die Knoten in sequenzieller Reihenfolge ausgeführt werden.
Innerhalb des sequential-Knotens befinden sich verhaltensbezogene Knoten wie starter, condition und action. Die Ausgabe des starter-Knotens wird einer Variablen zugewiesen, die im condition-Knoten verwendet wird.