iOS DSL-Leitfaden für komplexe Automatisierungen

Mit der Automatisierungs-DSL können komplexere automatisierte Abläufe erstellt werden als die, die im DSL-Leitfaden – Grundlegende automatisierte Abläufe unter iOS beschrieben werden.

Sequenziell mit mehreren Aktionen

Sequenziell mit mehreren Aktionen

Eine Automatisierung kann mehrere Aktionen ausführen. Anstelle des einzelnen action-Knotens könnten Sie beispielsweise mehrere action-Knoten haben, die nacheinander 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 action-Knoten in einem parallel-Knoten platzieren, werden die Aktionen gleichzeitig ausgeführt.

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  starter(...)
  condition {...}
  parallel {
    action {...}
    action {...}
    action {...}
  }

}

Wenn im Knoten sequential nach dem Knoten parallel noch action Knoten vorhanden sind, wird mit deren Ausführung gewartet, bis alle Knoten im Knoten parallel ausgeführt wurden.

Bedingte Ausführung

Standardmäßig werden Knoten in einer Automatisierung nacheinander oder parallel ausgeführt. Wenn Sie eine bedingte Verzweigungslogik benötigen, um je nach Laufzeitbedingungen unterschiedliche Aktionen oder Pfade auszuführen, 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 Standard-condition-Knoten die gesamte Automatisierung blockiert (wenn die Bedingung als false ausgewertet wird, wird die Ausführung der Automatisierung sofort beendet), ermöglichen ifThen-Blöcke die Verzweigung des Kontrollflusses:

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

Aktion basierend auf einer Bedingung ausführen

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

Du kannst einen eigenständigen ifThen-Block verwenden, wenn du eine Aktion nur unter bestimmten Bedingungen ausführen möchtest, 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.
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.")
  }
}

Verschiedene Aktionen basierend auf einer Bedingung ausführen

Wenn Sie eine Reihe von Aktionen ausführen möchten, wenn eine Bedingung wahr ist, und eine alternative Reihe von Aktionen, wenn sie falsch ist, verketten Sie den optionalen .orElse { ... }-Block 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 nacheinander verketten

Sie können einen oder mehrere optionale .elseIf(...) { ... }-Blöcke verketten, um mehrere Bedingungen nacheinander 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 .orElse { ... }-Block 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 ifThen-, elseIf- oder orElse-Blöcken verschachtelt und mit parallel-, delay(for:)- und stateReader-Knoten kombiniert werden.

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

Verzögerungen

Mit der Methode delay(for:) kannst du Pausen in deine automatisierten Abläufe einfügen. Sie verwendet das Argument Duration, das angibt, wie lange die Pause dauern soll, bevor die Ausführung fortgesetzt wird. Die Pausendauer kann zwischen fünf Sekunden und 24 Stunden betragen.

Beispiel: Eine Lampe viermal mit einer Pause von fünf Sekunden zwischen den einzelnen Schaltvorgängen umschalten:

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

Mit der Triggerunterdrückung kann deine Automatisierung einen starter für einen bestimmten Zeitraum nach dem ersten auslösenden Ereignis ignorieren. Wenn die Automatisierung beispielsweise einen starter hat, der durch Bewegungserkennung ausgelöst wird, und du eine Dauer für die Auslöserunterdrückung von fünf Minuten festlegst, wird der starter nach dem Auslösen für die nächsten fünf Minuten nicht noch einmal ausgelöst. So wird verhindert, dass die Automatisierung schnell hintereinander ausgelöst wird.

Wenn du die Auslöserunterdrückung auf deine Automatisierung anwenden möchtest, verwende das Schlüsselwort suppress(for:) mit einem Duration-Argument, das angibt, wie lange gewartet werden soll, bevor auf nachfolgende Auslöser reagiert wird. Die Dauer der Unterdrückung kann zwischen fünf Sekunden und 24 Stunden betragen.

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 Auslöserunterdrückung wirkt sich auf alle starters in einer Automatisierung aus, die vor dem Suppression liegen.

Anzahl der Ausführungen begrenzen

Du kannst die Anzahl der Ausführungen einer Automatisierung begrenzen.

Du kannst beispielsweise eine einmalige Automatisierung einrichten, die den Staubsauger laufen lässt, während du tagsüber nicht zu Hause bist.

Legen Sie dazu das Metadatenfeld maxExecutionCount der Automatisierung fest. Das folgende Beispiel ist eine Automatisierung, die 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)
  }
}

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

Eigenschaftsattribute in einer Aktion festlegen

So legen Sie den Wert eines Attributs fest:

  1. Erstelle einen update-Knoten innerhalb eines action-Knotens und füge die relevante Eigenschaft als Argument für den update-Knoten hinzu:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
    
  2. Verwenden Sie im Knoten update für jedes zu ändernde Attribut eine Mutatorfunktion und übergeben Sie ihr den neuen Wert. So bilden Sie den Namen der Mutatorfunktion:
    1. Schreiben Sie den Namen des Attributs groß.
    2. Stellen Sie ihr das Wort set voran.
    Wenn Sie beispielsweise ein Attribut namens defaultMoveRate aktualisieren möchten, verwenden Sie eine Mutatorfunktion namens setDefaultMoveRate.

Ein update-Knoten kann mehrere Mutatorfunktionen haben. Hier ist 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)
  }
}