iOS DSL-Leitfaden für komplexe Automatisierungen

Mit der Automation DSL lassen sich komplexere automatisierte Abläufe erstellen als die in DSL-Leitfaden – grundlegende automatisierte Abläufe auf iOS beschriebenen.

Sequenziell mit mehreren Aktionen

Sequenziell mit mehreren Aktionen

Ein automatisierter Ablauf kann mehr als eine Aktion ausführen. Anstelle des einzelnen Knotens action können Sie beispielsweise mehrere Knoten action haben, die sequenziell ausgeführt werden:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  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.

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  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 einem automatisierten Ablauf 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 DSL-Blöcken für den bedingten Kontrollfluss erstellt werden: ifThen, elseIf, und orElse.

Während ein Standardknoten condition den gesamten automatisierten Ablauf steuert (wenn die Bedingung als false ausgewertet wird, wird die Ausführung des automatisierten Ablaufs sofort beendet), ermöglichen ifThen-Blöcke die Steuerung des Kontrollflusses durch Verzweigungen:

  • Knoten condition: Beendet die Ausführung des gesamten automatisierten Ablaufs (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 Fallback-Zweig orElse oder an nachfolgende Knoten im automatisierten Ablauf fortgesetzt, wenn keine Bedingung erfüllt ist.

Aktion basierend auf einer Bedingung ausführen

Der Block ifThen wertet einen bedingten Ausdruck aus. Wenn der Ausdruck als true ausgewertet wird, werden die DSL-Aktionen oder -Knoten ausgeführt, die im Block verschachtelt sind. Wenn er als false ausgewertet wird, werden die Aktionen übersprungen und der automatisierte Ablauf 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 im automatisierten Ablauf zu blockieren oder zu beenden:

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
typealias ContactSensorDevice = Matter.ContactSensorDeviceType
typealias BooleanStateTrait = Matter.BooleanStateTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let contactState = starter(
    contactSensor,
    ContactSensorDevice.self,
    BooleanStateTrait.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  contactState
  lightState

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

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

  // Continue executing subsequent actions in the sequential flow
  action(structure) {
    Google.AssistantBroadcastTrait.broadcast(msg: "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.
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLockTrait = Matter.DoorLockTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let doorLockEvent = starter(
    doorLock,
    DoorLockDevice.self,
    DoorLockTrait.LockOperationEvent.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  doorLockEvent
  lightState

  condition {
    doorLockEvent.lockOperationType.equals(.unlock)
  }

  ifThen(lightState.onOff.equals(false)) {
    action(light, DimmableLightDevice.self) {
      OnOffTrait.on()
    }
  }.orElse {
    action(structure) {
      Google.AssistantBroadcastTrait.broadcast(msg: "Welcome home!")
    }
  }
}

Mehrere Bedingungen sequenziell verketten

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

// Adjust climate controls based on room temperature changes.
typealias TemperatureSensorDeviceType = Matter.TemperatureSensorDeviceType
typealias TemperatureMeasurementTrait = Matter.TemperatureMeasurementTrait
typealias ThermostatDeviceType = Matter.ThermostatDeviceType
typealias SimplifiedThermostatTrait = Google.SimplifiedThermostatTrait
typealias FanDeviceType = Matter.FanDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let tempStarter = starter(
    tempSensor,
    TemperatureSensorDeviceType.self,
    TemperatureMeasurementTrait.self
  )
  tempStarter

  // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
  ifThen(tempStarter.measuredValue.greaterThanOrEquals(2800)) {
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .cool)
    }
  }.elseIf(tempStarter.measuredValue.lessThan(1800)) {
    // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .heat)
    }
  }.orElse {
    // Otherwise, turn on the fan
    action(fan, FanDeviceType.self) {
      OnOffTrait.on()
    }
  }
}

Verschachtelte bedingte Abläufe

Bedingte Blöcke können in anderen Blöcken ifThen, elseIf oder orElse verschachtelt sowie mit Knoten parallel, delay(for:) und stateReader kombiniert werden.

Die Blöcke ifThen, elseIf und orElse führen ihre Inhalte als sequenzielle Abläufe aus. Sie können beliebige sequenzielle Knoten in jedem Zweig platzieren, einschließlich action, stateReader, parallel, delay(for:) und verschachtelter Blöcke ifThen.

Verzögerungen

Mit der Methode delay(for:) können Sie Pausen in Ihre automatisierten Abläufe einfügen. Sie verwendet ein 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: Ein Licht viermal ein- und ausschalten, mit einer Pause von fünf Sekunden zwischen jedem Ein- und Ausschalten:

typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

sequential {
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

Triggerunterdrückung

Die Triggerunterdrückung ist eine Funktion, mit der Ihr automatisierter Ablauf einen starter für einen bestimmten Zeitraum nach dem ersten Auslöseereignis ignorieren kann. Wenn der automatisierte Ablauf 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 der automatisierte Ablauf schnell wiederholt ausgelöst wird.

Wenn Sie die Triggerunterdrückung auf Ihren automatisierten Ablauf anwenden möchten, verwenden Sie das suppress(for:) Schlüsselwort mit einem 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.

typealias OccupancySensorDevice = Matter.OccupancySensorDeviceType
typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias MotionDetectionTrait = Google.MotionDetectionTrait
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let starterNode = starter(device, OccupancySensorDevice.self, MotionDetectionTrait.self)
  starterNode
  suppress(for: .seconds(30 * 60)) // 30 minutes
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

Die Triggerunterdrückung wirkt sich auf alle starters in einem automatisierten Ablauf aus, die vor dem Suppression-Knoten stehen.

Anzahl der Ausführungen begrenzen

Sie können die Anzahl der Ausführungen eines automatisierten Ablaufs begrenzen.

Sie können beispielsweise einen einmaligen automatisierten Ablauf einrichten, der den Staubsauger laufen lässt, während Sie den ganzen Tag nicht zu Hause sind.

Dazu legen Sie das Metadatenfeld maxExecutionCount des automatisierten Ablaufs fest. Das folgende Beispiel zeigt einen automatisierten Ablauf, der nur einmal ausgeführt werden kann:

import GoogleHomeSDK
import GoogleHomeTypes

typealias RoboticVacuumCleanerDevice = Matter.RoboticVacuumCleanerDeviceType
typealias RvcRunModeTrait = Matter.RvcRunModeTrait
typealias AreaPresenceStateTrait = Google.AreaPresenceStateTrait

let draftAutomation = automation(
  name: "Vacuum home away",
  description: "Run the vacuum once when everyone is away.",
  maxExecutionCount: 1
) {
  let homeAwayState = starter(structure, AreaPresenceStateTrait.self)
  homeAwayState

  condition {
    homeAwayState.presenceState.equals(.presenceStateVacant)
  }

  action(vacuum, RoboticVacuumCleanerDevice.self) {
    RvcRunModeTrait.changeToMode(newMode: 1)
  }
}

Der automatisierte Ablauf wird sofort gelöscht, sobald er zum letzten Mal ausgeführt wurde und maxExecutionCount erreicht ist. Der Verlaufseintrag des automatisierten Ablaufs bleibt in der Google Home app (GHA) Aktivität 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 zum Knoten update hinzu:
    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 mit einem Großbuchstaben.
    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:

typealias FanDeviceType = Matter.FanDeviceType
typealias FanControlTrait = Matter.FanControlTrait

action(fan, FanDeviceType.self) {
  update(FanControlTrait.self) {
    $0.setFanMode(.on)
  }
}