Android DSL-Leitfaden für komplexe Automatisierungen

Mit der Automation DSL können Sie komplexere Automatisierungen erstellen als die in DSL-Leitfaden – grundlegende Automatisierungen auf Androidbeschriebenen.

Sequenziell mit mehreren Aktionen

Sequenziell mit mehreren Aktionen

Eine Automatisierung kann mehr als eine Aufgabe ausführen. Anstelle des einzelnen Knotens action können Sie beispielsweise mehrere Knoten action haben, die in sequenzieller Reihenfolge ausgeführt werden:

automation {
  sequential {
    starter<_>(...)
    condition {...}
    action {...}
    action {...}
    action {...}
    }
}

Sequenziell mit mehreren parallelen Aktionen

Sequenziell mit mehreren parallelen Aktionen

Wenn Sie mehrere Knoten action in einem Knoten parallel platzieren, werden die Aktionen gleichzeitig ausgeführt.

automation {
  sequential {
    starter<_>(...)
    condition {...}
    parallel {
      action {...}
      action {...}
      action {...}
    }
  }
}

Wenn sich im Knoten sequential Knoten action befinden, die nach dem Knoten parallel kommen, warten sie mit der Ausführung, bis alle Knoten im Knoten parallel ausgeführt wurden.

Bedingte Ausführung

Standardmäßig werden Knoten in einer Automatisierung sequenziell oder parallel ausgeführt. Wenn Sie eine bedingte Verzweigungslogik benötigen, bei der je nach Laufzeitbedingungen unterschiedliche Aktionen oder Pfade ausgeführt werden, verwenden Sie if-then-else-Anweisungen, die mit den bedingten DSL-Blöcken für den Kontrollfluss erstellt werden: ifThen, elseIf, und orElse.

Während ein Standardknoten condition die gesamte Automatisierung steuert (wenn die Bedingung zu false ausgewertet wird, wird die Ausführung der Automatisierung sofort beendet), ermöglichen ifThen-Blöcke die Steuerung des Verzweigungsablaufs:

  • Knoten condition: Beendet die Ausführung der gesamten Automatisierung (oder des aktuellen Ausführungspfads), wenn der Ausdruck false ist.
  • ifThen / elseIf / orElse: Wertet Bedingungen in der Reihenfolge aus. Wenn eine Bedingung false ist, wird die Ausführung an den nächsten elseIf-Zweig, den orElse-Fallback-Zweig oder an nachfolgende Knoten in der Automatisierung weitergeleitet, wenn keine Bedingung erfüllt ist.

Aktion basierend auf einer Bedingung ausführen

Der Block ifThen wertet einen bedingten Ausdruck aus. Wenn der Ausdruck zu true ausgewertet wird, werden die im Block verschachtelten DSL-Aktionen oder -Knoten ausgeführt. Wenn er zu false ausgewertet wird, werden die Aktionen übersprungen und die Automatisierung wird mit den nachfolgenden Knoten im sequenziellen Ablauf fortgesetzt.

Sie können einen eigenständigen Block ifThen verwenden, wenn Sie eine Aktion nur bedingt ausführen möchten, ohne nachfolgende Knoten in der Automatisierung zu blockieren oder zu beenden:

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
automation {
  sequential {
    val contactState = starter<_>(
      contactSensor,
      ContactSensorDevice,
      BooleanState,
    )
    val lightState = stateReader<_>(
      light,
      DimmableLightDevice,
      OnOff,
    )

    condition {
      // Door opened (contact sensor open)
      expression = contactState.stateValue equals false
    }

    // Conditionally turn on the light if it's off
    ifThen(lightState.onOff equals false) {
      action(light, DimmableLightDevice) { command(OnOff.on()) }
    }

    // Continue executing subsequent actions in the sequential flow
    action(structure) {
      command(AssistantBroadcast.broadcast("The door was opened."))
    }
  }
}

Unterschiedliche Aktionen basierend auf einer Bedingung ausführen

Wenn Sie eine Reihe von Aktionen ausführen möchten, wenn eine Bedingung „true“ ist, und eine alternative Reihe von Aktionen, wenn sie „false“ ist, verketten Sie den optionalen Block .orElse { ... } nach ifThen(...) { ... }:

// When the door is unlocked, turn on the entryway light if it is off;
// otherwise, broadcast a welcome message.
automation {
  sequential {
    val doorLockEvent = starter<_>(
      doorLock,
      DoorLockDevice,
      LockOperationEvent,
    )
    val lightState = stateReader<_>(
      light,
      DimmableLightDevice,
      OnOff,
    )

    condition {
      expression =
        doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock
    }

    ifThen(lightState.onOff equals false) {
      action(light, DimmableLightDevice) { command(OnOff.on()) }
    }.orElse {
      action(structure) {
        command(AssistantBroadcast.broadcast("Welcome home!"))
      }
    }
  }
}

Mehrere Bedingungen in einer Sequenz verketten

Sie können einen oder mehrere optionale Blöcke .elseIf(...) { ... } verketten, um mehrere Bedingungen in einer Sequenz auszuwerten. Der erste Zweig, dessen Bedingung zu true ausgewertet wird, wird ausgeführt und alle verbleibenden Zweige werden übersprungen. Wenn keine der Bedingungen zu true ausgewertet wird, wird ein optionaler Block .orElse { ... } ausgeführt (falls angegeben):

// Adjust climate controls based on room temperature changes.
automation {
  sequential {
    val tempStarter = starter<_>(
      tempSensor,
      TemperatureSensorDevice,
      TemperatureMeasurement,
    )

    // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
    ifThen(tempStarter.measuredValue greaterThanOrEquals 2800) {
      action(thermostat, ThermostatDevice) {
        command(
          SimplifiedThermostat.setSystemMode(
            SimplifiedThermostatSystemModeEnum.Cool
          )
        )
      }
    }.elseIf(tempStarter.measuredValue lessThan 1800) {
      // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
      action(thermostat, ThermostatDevice) {
        command(
          SimplifiedThermostat.setSystemMode(
            SimplifiedThermostatSystemModeEnum.Heat
          )
        )
      }
    }.orElse {
      // Otherwise, turn on the fan
      action(fan, FanDevice) {
        command(OnOff.on())
      }
    }
  }
}

Verschachtelte bedingte Abläufe

Bedingte Blöcke können in anderen ifThen-, elseIf- oder orElse-Blöcken verschachtelt sowie mit Knoten parallel, delayFor und stateReader kombiniert werden.

In den Blöcken ifThen, elseIf und orElse werden die Inhalte als sequenzielle Abläufe ausgeführt. Sie können in jedem Zweig beliebige sequenzielle Knoten platzieren, einschließlich action, stateReader, parallel, delayFor und verschachtelter ifThen-Blöcke.

Verzögerungen

Mit dem delayFor Keyword können Sie Pausen in Ihre Automatisierungen einfügen. Es verwendet ein java.time.Duration Argument, das angibt, wie lange die Ausführung pausiert werden soll, bevor sie fortgesetzt wird. Die Pausendauer kann zwischen fünf Sekunden und 24 Stunden liegen.

Beispiel: Eine Lampe viermal ein- und ausschalten, mit einer Pause von fünf Sekunden zwischen jedem Ein- und Ausschalten:

sequential {
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
}

Triggerunterdrückung

Die Triggerunterdrückung ist eine Funktion, mit der Ihre Automatisierung einen starter für einen bestimmten Zeitraum nach dem ersten Auslöseereignis ignorieren kann. Wenn die Automatisierung beispielsweise einen starter hat, der durch die Bewegungserkennung ausgelöst wird, und Sie eine Dauer für die Triggerunterdrückung von fünf Minuten angeben, wird der starter nach dem Auslösen in den nächsten fünf Minuten nicht noch einmal ausgelöst. So wird verhindert, dass die Automatisierung schnell wiederholt ausgelöst wird.

Wenn Sie die Triggerunterdrückung auf Ihre Automatisierung anwenden möchten, verwenden Sie das suppressFor Keyword mit einem java.time.Duration Argument, das angibt, wie lange gewartet werden soll, bevor auf nachfolgende Trigger reagiert wird. Die Unterdrückungsdauer kann zwischen fünf Sekunden und 24 Stunden liegen.

automation {
  sequential {
    val starterNode = starter<_>(device, OccupancySensor, MotionDetection)
    suppressFor(Duration.ofMinutes(30))
    action(light, OnOffLightDevice) { command(OnOff.toggle()) }
}

Die Triggerunterdrückung wirkt sich auf alle starters in einer Automatisierung aus, die vor suppressFor stehen.

Anzahl der Ausführungen begrenzen

Sie können die Anzahl der Ausführungen einer Automatisierung begrenzen.

Sie können beispielsweise eine einmalige Automatisierung einrichten, die den Staubsauger laufen lässt, während Sie den Tag über nicht zu Hause sind.

Dazu legen Sie das maxExecutionCount Metadatenfeld der Automatisierung fest. Das folgende Beispiel zeigt eine Automatisierung, die nur einmal ausgeführt werden kann:

automation {
  // The automation can only be executed once.
  maxExecutionCount = 1
  // When the door lock state changes
  sequential {
    val doorLockEvent = starter<_>(doorLock, DoorLockDevice, LockOperationEvent)
    // if the door is unlocked
    condition() {
      expression = (doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock)
    }
    // turn the light on
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}

Die Automatisierung wird sofort gelöscht, sobald sie zum letzten Mal ausgeführt wurde und maxExecutionCount erreicht ist. Der Verlaufseintrag der Automatisierung bleibt in dem Google Home app (GHA) Aktivität Tab erhalten, einschließlich der automation_id.

Trait-Attribute in einer Aktion festlegen

So legen Sie den Wert eines Trait-Attributs fest:

  1. Erstellen Sie einen Knoten update in einem Knoten action, und fügen Sie das entsprechende Trait als Argument für den Knoten update ein:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
  2. Verwenden Sie im Knoten update für jedes zu ändernde Attribut eine Mutator-Funktion und übergeben Sie ihr den neuen Wert. So bilden Sie den Namen der Mutator-Funktion:
    1. Schreiben Sie den Namen des Attributs groß.
    2. Stellen Sie das Wort set voran.
    Wenn Sie beispielsweise ein Attribut mit dem Namen defaultMoveRate, aktualisieren möchten, verwenden Sie die Mutator-Funktion setDefaultMoveRate.

Ein Knoten update kann mehrere Mutator-Funktionen haben. Hier ein Beispiel, in dem zwei Attribute aktualisiert werden:

action(device, Fan) {
  update(FanControl) {
    setPercentSetting(50u)
    setRockSetting(FanControlCluster.RockBitmap.rockUpDown)
  }
}