DSL-Leitfaden: Grundlegende Automatisierungen

In der folgenden Anleitung erfahren Sie, wie Sie verschiedene Automation DSL-Knoten zum Erstellen einer Automatisierung verwenden können.

Das gesamte Automation DSL wird in einem einzigen 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 den Ablauf der Automatisierung.

Beispiel für eine sequenzielle DSL

Hier ist eine sehr einfache Automation DSL-Vorlage mit einem sequenziellen Ablauf, der aus einem Auslöser, einer Bedingung und einer Aktion besteht:


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 optimiert werden.

Starter

Mit Auslöserknoten werden die anfänglichen Umstände definiert, die eine Automatisierung aktivieren. Zum Beispiel eine Status- oder Wertänderung. Eine Automatisierung muss mindestens einen Auslöser haben, da sie sonst nicht validiert werden kann. Wenn Sie einer Automatisierung mehrere Auslöser hinzufügen möchten, müssen Sie einen Auswahlknoten verwenden.

Auslöser basierend auf dem Merkmalattribut

Geben Sie beim Deklarieren eines Auslöserknotens, der auf einem Merkmalattribut basiert, Folgendes an:

  • das Gerät
  • den Gerätetyp, zu dem das Merkmal gehört
  • das Merkmal
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)

Der Parameter „device_type“ ist erforderlich, da Sie damit angeben können, welcher Gerätetyp innerhalb eines Geräts von der Automatisierung angesprochen werden soll. Ein Gerät kann beispielsweise aus einem FanDevice und einem HeatingCoolingUnitDevice bestehen, die beide das Merkmal OnOff enthalten. Wenn Sie den Gerätetyp angeben, ist klar, welcher Teil des Geräts die Automatisierung auslöst.

Auslöser basierend auf Ereignis

Geben Sie bei der Deklarierung eines Auslöserknotens, der auf einem Ereignis basiert, Folgendes an:

  • das Gerät
  • den Gerätetyp, zu dem das Merkmal gehört
  • das Ereignis
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)

Auslöser auf Grundlage einer Struktur und eines Ereignisses mit Parametern

Einige Ereignisse können Parameter haben. Diese Parameter müssen daher auch in den Auslöser aufgenommen werden.

In diesem Auslöser wird beispielsweise ScheduledTimeEvent des Attributs 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)))
}

Manueller Anlasser

Ein manueller Auslöser ist ein spezieller Auslöser, mit dem der Nutzer die Automatisierung manuell ausführen kann.

Wenn Sie einen manuellen Auslöser deklarieren:

  • Geben Sie keine Eigenschaft oder keinen Gerätetyp an.
  • Geben Sie ein UI-Element an, das Automation.execute() aufruft.

Wenn Sie einen manuellen Auslöser zusammen mit einem anderen Auslöser in einem select-Ablauf platzieren, wird der andere Auslöser vom manuellen Auslöser überschrieben:

select {
  manualStarter()
  starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
}

Hinweis: Alle condition-Knoten nach einem manuellen Auslöser werden ausgewertet und können je nach condition-Ausdruck die Ausführung der Automatisierung blockieren.

Manuellen Auslöser von einer Bedingung trennen

Eine Möglichkeit, Ihre 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 verschieben:

automation_graph {
  sequential {
    select {
      sequential {
        starter<_>(...)
        condition {...}
      }
      sequential {
        manualStarter()
      }
    }
    action {...}
  }
}

Verweis auf den Wert eines Attributs

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, an dem festgelegt wird, ob die Automatisierung fortgesetzt wird oder nicht. Eine Automatisierung kann mehrere condition-Knoten haben. Wenn der Ausdruck eines condition-Knotens false ergibt, wird die Ausführung der gesamten Automatisierung beendet.

Innerhalb eines condition-Knotens können Sie mehrere Bedingungskriterien mit verschiedenen Operatoren kombinieren, solange der Ausdruck zu einem einzelnen booleschen Wert führt. Wenn der resultierende Wert true ist, ist die Bedingung erfüllt und die Automatisierung führt die Ausführung des nächsten Knotens fort. Wenn es false ist, wird die Automatisierung an diesem Punkt beendet.

Ausdrücke werden ähnlich wie in Kotlin gebildet und können primitive Werte wie Zahlen, Zeichen, Strings und Boolesche Werte sowie Enum-Werte enthalten. Wenn Sie untergeordnete Ausdrücke in Klammern gruppieren, können Sie die Reihenfolge festlegen, in der sie ausgewertet werden.

Hier ein Beispiel für einen condition, der mehrere Teilausdrü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)
}

Sie können auf den Wert eines Merkmals verweisen, auf das über einen Auslöser zugegriffen wird:

val starterNode = starter<_>(device, OnOff)
condition() { expression = starterNode.onOff equals true }

stateReader

Eine weitere Möglichkeit, auf Werte von Merkmalattributen in einem condition-Knoten zu verweisen, ist ein stateReader-Knoten.

Dazu müssen Sie zuerst den Attributwert des Merkmals in einem stateReader-Knoten erfassen. Ein stateReader nimmt den structure und das Merkmal als Argumente an:

import com.google.home.automation.stateReader
...
val filterMonitoringState = stateReader<_>(structure, ActivatedCarbonFilterMonitoring)

Verweisen Sie dann auf stateReader im Knoten condition:

condition() {
  expression =
    filterMonitoringState.changeIndication
      .equals(ChangeIndicationEnum.Warning)
}

Mit Vergleichs- 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)
}

Bedingungsdauer

Neben einem booleschen Ausdruck in einer Bedingung können Sie einen Zeitraum angeben, in dem der Ausdruck wahr sein muss, damit die Automatisierung ausgeführt wird. Sie können beispielsweise eine Bedingung definieren, die nur ausgelöst wird, wenn eine Lampe zehn Minuten lang eingeschaltet war.

  condition {
    expression(lightStateReader.onOff == true)
    forDuration(Duration.ofMinutes(10))
  }

Die Dauer kann zwischen einer und 30 Minuten liegen.

Aktionsknoten

Im Aktionsknoten wird die 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

Beim Entwickeln von Automatisierungen ist es nicht immer offensichtlich, wie verschiedene Elemente der Home APIs in Ihren Code importiert werden.

Merkmalattribute werden aus dem Companion-Objekt des Merkmals 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

Merkmalbefehle werden aus dem Companion-Objekt des Merkmals importiert:

import com.google.home.matter.standard.Thermostat.Companion.setTemperatureSetpointHold