In der folgenden Anleitung wird beschrieben, wie du mit verschiedenen DSL-Knoten für die Automatisierung eine Automatisierung erstellen kannst.
Die gesamte Automatisierungs-DSL wird in einem einzelnen automation-Knoten platziert. Der Knoten automation bildet die Grenze zwischen dem äußeren Kotlin-Sprachkontext und dem eingebetteten DSL-Kontext.
Sequenzieller Ablauf
Der sequenzielle Ablauf ist der Standardtyp für Automatisierungsabläufe.
Hier ist eine sehr einfache Automation DSL-Vorlage, die einen sequenziellen Ablauf mit einem Auslöser, einer Bedingung und einer Aktion verwendet:
import com.google.home.automation.action
import com.google.home.automation.automation
import com.google.home.automation.condition
import com.google.home.automation.sequential
import com.google.home.automation.starter
...
automation {
sequential {
starter<_>(...)
condition {...}
action {...}
}
}
Dies kann durch Hinzufügen weiterer Knoten verfeinert werden.
Starter
Auslöserknoten definieren die anfänglichen Umstände, die eine Automatisierung aktivieren. Beispiel: eine Änderung des Status oder Werts. Eine Automatisierung muss mindestens einen Auslöser haben, sonst schlägt die Validierung fehl. Wenn du einer Automatisierung mehr als einen Auslöser hinzufügen möchtest, musst du einen select-Knoten verwenden.
Auslöser basierend auf einem Attribut
Wenn du einen Starterknoten deklarierst, der auf einem Trait-Attribut basiert, gib Folgendes an:
- das Gerät
- den Gerätetyp, zu dem das Attribut gehört
- das Merkmal
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
Der Parameter „device_type“ ist erforderlich, da du damit angeben kannst, welchen Gerätetyp innerhalb eines Geräts die Automatisierung anspricht. Ein Gerät kann beispielsweise aus einem FanDevice und einem HeatingCoolingUnitDevice bestehen, die beide das Attribut OnOff enthalten. Wenn du den Gerätetyp angibst, ist eindeutig, welcher Teil des Geräts die Automatisierung auslöst.
Auslöser basierend auf Ereignis
Wenn du einen Starterknoten deklarierst, der auf einem Ereignis basiert, gib Folgendes an:
- das Gerät
- den Gerätetyp, zu dem das Attribut gehört
- die Veranstaltung
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)
Auslöser basierend auf einem Gebäude und Ereignis, mit Parametern
Einige Ereignisse können Parameter haben. Diese Parameter müssen dann auch im Starter enthalten sein.
In diesem Beispiel wird das ScheduledTimeEvent-Merkmal von Time verwendet, um die Automatisierung um 7:00 Uhr zu aktivieren:
val earlyMorning = starter<_>(structure, Time.ScheduledTimeEvent) {
parameter(Time.ScheduledTimeEvent.clockTime(
LocalTime.of(7, 0, 0, 0)))
}
Auslöser basierend auf dem Wetter
Du kannst aktuelle oder vorhergesagte Wetterbedingungen in einem Auslöser angeben, indem du das Attribut „Wetter“ verwendest:
val weatherState = starter<_>(structure, trait = Weather)
Weitere Informationen findest du auf der Seite Beispiele für automatisierte Abläufe unter Jalousien schließen, wenn es wahrscheinlich regnen wird.
Manueller Auslöser
Ein manueller Auslöser ist ein spezieller Auslöser, mit dem der Nutzer die Automatisierung manuell ausführen kann.
Wenn du einen manuellen Auslöser deklarierst:
- Gib kein Attribut und keinen Gerätetyp an.
- Stellen Sie ein UI-Element bereit, das
Automation.execute()aufruft.
Wenn du einen manuellen Auslöser zusammen mit einem anderen Auslöser in einem select-Ablauf platzierst, überschreibt der manuelle Auslöser den anderen Auslöser:
select {
manualStarter()
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
}
Beachte, dass alle condition-Knoten, die auf einen manuellen Auslöser folgen, ausgewertet werden und die Ausführung der Automatisierung je nach condition-Ausdruck blockieren können.
Eine Möglichkeit, deine Automatisierung so zu strukturieren, dass condition-Knoten eine Automatisierung, die mit einem manuellen Auslöser aktiviert wurde, nicht blockieren, besteht darin, den anderen Auslöser zusammen mit seinem condition in einen separaten sequenziellen Ablauf zu platzieren:
automation_graph {
sequential {
select {
sequential {
starter<_>(...)
condition {...}
}
sequential {
manualStarter()
}
}
action {...}
}
}
Auf den Wert eines Attributs verweisen
Wenn Sie den Wert eines Attributs in einem Ausdruck verwenden möchten, verwenden Sie die folgende Syntax.
Mit einem stateReader:
val time = stateReader<_>(structure, Structure, Time)
val currTime = time.currentTime
Mit einem starter:
val starterNode = starter<_>(device1, LaundryWasherDevice, OnOff)
condition() {
expression = starterNode.onOff equals true
}
Bedingungsknoten und -ausdrücke
Ein Bedingungsknoten stellt einen Entscheidungspunkt dar, der bestimmt, ob die Automatisierung fortgesetzt wird oder nicht. Eine Automatisierung kann mehrere condition-Knoten haben.
Wenn der Ausdruck eines condition-Knotens als false ausgewertet wird, wird die Ausführung der gesamten Automatisierung beendet.
In einem condition-Knoten können Sie mehrere Bedingungskriterien mit verschiedenen Operatoren kombinieren, solange der Ausdruck zu einem einzelnen booleschen Wert ausgewertet wird. Wenn der resultierende Wert true ist, ist die Bedingung erfüllt und die Automatisierung fährt mit der Ausführung des nächsten Knotens fort. Wenn der Wert false ist, wird die Ausführung der Automatisierung an dieser Stelle beendet.
Ausdrücke werden ähnlich wie Ausdrücke in Kotlin gebildet und können primitive Werte wie Zahlen, Zeichen, Strings und boolesche Werte sowie Enum-Werte enthalten. Wenn Sie Unterausdrücke mit Klammern gruppieren, können Sie die Reihenfolge steuern, in der sie ausgewertet werden.
Hier ist ein Beispiel für einen condition, der mehrere Unterausdrücke in einem einzigen Ausdruck kombiniert:
condition() {
val expr1 = starterNode.lockState equals DlLockState.Unlocked
val expr2 = stateReaderNode.lockState equals true
val expr3 = occupancySensingDevice.occupied notEquals 0
val expr4 = timeStateReaderNode
.currentTime
.between(
timeStateReaderNode.sunsetTime,
timeStateReaderNode.sunriseTime)
expression = (expr1 and expr2) or (expr3 and expr4)
}
Du kannst auf den Wert einer Eigenschaft verweisen, auf die über einen Auslöser zugegriffen wird:
val starterNode = starter<_>(device, OnOff)
condition() { expression = starterNode.onOff equals true }
stateReader
Die andere Möglichkeit, auf Attributwerte von Eigenschaften in einem condition-Knoten zu verweisen, ist ein stateReader-Knoten.
Erfassen Sie dazu zuerst den Attributwert „trait“ in einem stateReader-Knoten. Ein stateReader verwendet die structure und das Attribut als Argumente:
import com.google.home.automation.stateReader
...
val filterMonitoringState = stateReader<_>(structure, ActivatedCarbonFilterMonitoring)
Verweisen Sie dann im Knoten condition auf die stateReader:
condition() {
expression =
filterMonitoringState.changeIndication
.equals(ChangeIndicationEnum.Warning)
}
Mit Vergleichsoperatoren und logischen Operatoren können mehrere stateReaders in einem condition-Knoten verwendet werden:
val armState = stateReader<_>(doorLock, DoorLockDevice, ArmDisarm )
val doorLockState = stateReader<_>(doorLock, DoorLockDevice, DoorLock)
condition() {
expression =
(armState.armState equals true)
and
(doorLockState.lockState equals true)
}
Dauer der Bedingung
Zusätzlich zu einem booleschen Ausdruck in einer Bedingung kannst du einen Zeitraum angeben, in dem der Ausdruck wahr sein muss, damit die Automatisierung ausgeführt wird. Du kannst beispielsweise eine Bedingung definieren, die nur ausgelöst wird, wenn ein Licht zehn Minuten lang eingeschaltet war.
condition {
expression(lightStateReader.onOff == true)
forDuration(Duration.ofMinutes(10))
}
Die Dauer kann zwischen 5 Sekunden und 24 Stunden liegen.
Aktionsknoten
Im Aktionsknoten wird die Arbeit der Automatisierung ausgeführt.
In diesem Beispiel ruft die Aktion den Befehl broadcast() des Attributs AssistantBroadcast auf:
action(device, SpeakerDevice) {
command(AssistantBroadcast.broadcast("Intruder detected!"))
}
Importanweisungen
Bei der Entwicklung von Automatisierungen ist es nicht immer offensichtlich, wie verschiedene Elemente der Home APIs in den Code importiert werden.
Die Attribute des Traits werden aus dem Companion-Objekt des Traits importiert:
import com.google.home.matter.standard.OnOff.Companion.onOff
Datenstrukturen, die durch ein Merkmal definiert sind, werden aus der Merkmalsklasse importiert, deren Name auf „-Trait“ endet:
import com.google.home.matter.standard.MediaPlaybackTrait.PlaybackStateEnum
Trait-Befehle werden aus dem Companion-Objekt des Traits importiert:
import com.google.home.matter.standard.Thermostat.Companion.setTemperatureSetpointHold