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: Alle zusätzlichen Einschränkungen, die nach der Aktivierung einer Automatisierung ausgewertet werden sollen. Der Ausdruck in einer Bedingung muss
true
ergeben, damit die Aktionen einer Automatisierung ausgeführt werden. - Aktion: Befehle oder Statusaktualisierungen, die ausgeführt werden, wenn alle Bedingungen erfüllt sind.
Vielleicht haben Sie einen automatisierten Ablauf, der das Licht in einem Raum dimmt, wenn der Fernseher in diesem Raum zwischen Sonnenuntergang und Sonnenaufgang eingeschaltet wird. In diesem Fall gilt Folgendes:
- Starter: Der Fernseher wurde eingeschaltet. Dies ist eine Statusänderung für ein TV-Attribut.
- Bedingung: Die aktuelle Uhrzeit für das Zuhause, in dem sich der Fernseher befindet, wird ausgewertet.
- Aktion: Die Beleuchtung im selben Raum wie der Fernseher wird gedimmt.
Die Automatisierung wird aktiviert, wenn der Fernseher im Raum eingeschaltet wird. Sie wird jedoch nur ausgeführt, wenn die Bedingung „Die Zeit liegt zwischen Sonnenuntergang und Sonnenaufgang“ erfüllt ist.
Zusätzlich zur grundlegenden Struktur enthalten Automatisierungen in den Home APIs auch Metadaten wie name und description, 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 das Verhalten von Entitäten 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 |
---|---|---|---|
Starter | Verhaltensbezogen |
StarterNodeDsl
|
Startet einen automatisierten Ablauf, 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 Trait-Befehle 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
|
Den Ausführungsablauf basierend auf der Auswertung logischer Ausdrücke bedingt ändern. Bedingungen können mit einem Auslöser verknüpft sein (auslöserspezifische Bedingungen) oder global sein (für alle Auslöser gelten). |
Auswählen | Ablauf der Ausführung |
SelectFlow
|
Ermöglicht, dass eine Automatisierung durch mehr als einen Auslöser aktiviert wird. |
Expression | Wert |
Expression
|
Kann der Wert eines Attributs eines Merkmals, eine Konstante oder ein Literalwert sein und muss zu einer Liste, einer Zahl, einem booleschen Wert oder einem String ausgewertet werden. |
Verhaltensbezogene Knoten
Knoten wie Auslöser und Aktionen sind Verhaltensknoten. Auslöser aktivieren einen automatisierten Ablauf basierend auf Änderungen von Geräteattributen. Mit Aktionen werden Gerätebefehle ausgegeben oder Attribute aktualisiert.
Verhaltens-Knoten sind in der Regel an Geräteattribute gebunden und geben den Attributstatus zur Verwendung als Eingabe in anderen Knoten aus.
Knoten für den Ausführungsablauf
Einige Knoten stellen Ausführungsabläufe dar, z. B. sequenziell und parallel. Jeder dieser Knoten enthält die Verhaltensweisen, 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 Lampen. 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.
Vielleicht haben Sie eine Automatisierung, die eine Aktion basierend darauf ausführt, ob es Nacht ist. In einem Bedingungsknoten wird die Tageszeit geprüft. Anschließend wird basierend auf dieser Prüfung der entsprechende Ausführungspfad verfolgt.
Ein Auswahlablauf ist nützlich, wenn Sie mehr als einen Starter haben möchten, der Ihre Automatisierung aktivieren kann. Wenn Sie zwei oder mehr Auslöser in einen select
-Ablauf einfügen, kann jeder von ihnen die Automatisierung aktivieren.
Sie können beispielsweise eine Automatisierung erstellen, die die Jalousien bei Sonnenuntergang herunterfährt, wenn die Temperatur einen bestimmten Schwellenwert überschreitet oder wenn die Helligkeit einen Schwellenwert überschreitet. Für jedes dieser Szenarien gibt es einen separaten Starter, die alle in einem select
-Ablauf zusammengefasst werden.
Verschachtelte Abläufe
In komplexen Automatisierungen können Ausführungsflussknoten auch verschachtelt werden. Beispielsweise kann ein sequenzieller Ablauf einen parallelen Ablauf ausführen.
DSL-Knoten können verschachtelt und auf verschiedene Weise kombiniert werden, um Ihren spezifischen Anforderungen zu entsprechen. Dabei müssen die Einschränkungen in der folgenden Tabelle berücksichtigt werden. Die Spalte „Builder“ enthält Links zur Kotlin-Dokumentation für typsichere Builder, in der beschrieben wird, was für die Verwendung in den einzelnen Knotentypen zulässig ist.
Knoten | Kann den folgenden Knotentyp und die folgenden Daten enthalten | Muss einer der folgenden Knotentypen sein |
---|---|---|
Starter | Ausdruck | „Auswählen“, „Sequenziell“ |
ManualStarter | „Auswählen“, „Sequenziell“ | |
StateReader | Ausdruck (besteht in der Regel aus einem Attributwert für ein Merkmal) | Aktion, Bedingung |
Aktion | Befehl, Einheit, Ausdruck | Parallel, Select, Sequential |
Sequenziell | Parallel, Select, Sequential | |
Parallel | Aktion | Sequenziell |
Bedingung | Ausdruck | Parallel, sequenziell |
Auswählen | Condition, Sequential, Starter, ManualStarter | Sequenziell und muss der erste Knoten im Ablauf sein |
Automatisierungs-DSL
In den Home APIs werden Automatisierungen mit der Automation DSL (Domain-Specific Language) definiert. Die Automation DSL ist als Kotlin DSL (domänenspezifische Sprache) implementiert. Dabei werden typsichere Kotlin-Builder verwendet. Sie wurde speziell für die Definition von Automatisierungsvorlagen entwickelt.
Wenn eine Automatisierung kompiliert wird, generieren Kotlin-Typsichere Builder Kotlin-Datenklassen, die dann in Protocol Buffer-JSON serialisiert werden. Dieses wird verwendet, um Aufrufe an die Automatisierungsdienste von Google zu senden.
Die Automatisierungs-DSL vereinfacht und optimiert den Prozess der Erstellung von Automatisierungen. Es verwendet nativ dasselbe Datenmodell mit Matter-Standardattributen und smart home-Attributen, das in der Geräte-API enthalten ist.
Die Automatisierungs-DSL definiert auch die Logik einer Automatisierung 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 Automation DSL geschriebene Automatisierung ist jedoch einfacher und prägnanter als dieselbe Automatisierung in reinem Kotlin.
Beispiel
Im Folgenden finden Sie ein Beispiel für eine Automatisierung, die ein Gerät einschaltet. Sie wurde mit der Automation 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.
Für die Automatisierung wird ein sequential
-Knoten verwendet, was bedeutet, dass die Knoten in sequenzieller Reihenfolge ausgeführt werden.
Der Knoten sequential
enthält Verhaltensweisen wie starter
, condition
und action
. Die Ausgabe des Knotens starter
wird einer Variablen zugewiesen, die im Knoten condition
verwendet wird.