複雑な自動化のための iOS DSL ガイド

Automation DSL を使用すると、 DSL ガイド - iOS での基本的な自動化で説明されているものよりも複雑な自動化を作成できます。

複数のアクションを順次実行する

複数のアクションを含む順次

自動化では複数の処理を行うことができます。たとえば、単一の action ノードの代わりに、複数の action ノードを配置して、順次実行できます。

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

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

}

複数の並列アクションを順次実行する

複数の並列アクションを含むシーケンシャル

複数の action ノードを parallel ノードに配置すると、アクションは同時に実行されます。

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

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

}

parallel ノードの後に sequential ノードに action ノードがある場合、parallel ノード内のすべてのノードの実行が完了するまで、実行は待機します。

条件付き実行

デフォルトでは、自動化はノードを順次または並行して実行します。実行時の条件に基づいて異なるアクションやパスを実行する条件付き分岐ロジックが必要な場合は、条件付き制御フロー DSL ブロック(ifThenelseIf、およびorElse)を使用して作成されたif-then-else ステートメントを使用します。

標準の condition ノードは自動化全体をゲートしますが(条件が false と評価されると、自動化はすぐに実行を終了します)、ifThen ブロックを使用すると、制御フローを分岐できます。

  • condition ノード: 式が false の場合、自動化全体(または現在の実行パス)の実行を停止します。
  • ifThen / elseIf / orElse: 条件を順番に評価します。条件が false の場合、実行は次の elseIf ブランチ、orElse フォールバック ブランチにフォールバックします。条件が満たされない場合は、自動化の後続のノードに進みます。

条件に基づいてアクションを実行する

ifThen ブロックは条件式を評価します。式が true と評価されると、ブロック内にネストされた DSL アクションまたはノードが実行されます。false と評価されると、アクションはスキップされ、自動化は順次フローの後続のノードに進みます。

自動化の後続のノードをブロックまたは終了せずに、条件付きでアクションを実行する場合にのみ、スタンドアロンの ifThen ブロックを使用できます。

// 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.")
  }
}

条件に基づいて異なるアクションを実行する

条件が true の場合は一連のアクションを実行し、false の場合は別の一連のアクションを実行するには、ifThen(...) { ... } の後にオプションの .orElse { ... } ブロックを連結します。

// 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!")
    }
  }
}

複数の条件を順番に連結する

1 つ以上のオプションの .elseIf(...) { ... } ブロックを連結して、複数の条件を順番に評価できます。条件が true と評価された最初のブランチが実行され、残りのブランチはすべてスキップされます。どの条件も true と評価されない場合は、オプションの .orElse { ... } ブロックが実行されます(指定されている場合)。

// 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()
    }
  }
}

条件付きフローのネスト

条件付きブロックは、他の ifThenelseIforElse ブロック内にネストできます。また、paralleldelay(for:)stateReader ノードと組み合わせることもできます。

ifThenelseIforElse ブロックは、その内容を順次フローとして実行します。各ブランチには、actionstateReaderparalleldelay(for:)、ネストされた ifThen ブロックなど、任意の順次ノードを配置できます。

処理の遅れ

自動化に一時停止を挿入するには、 delay(for:) メソッドを使用します。 このメソッドは、 Duration 実行を再開するまでの一時停止時間を表す引数を取ります。一時停止時間は、5 秒から 24 時間までです。

たとえば、ライトを 5 秒間隔で 4 回切り替えるには、次のようにします。

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() }
}

トリガーの抑制

トリガーの抑制は、最初のトリガー イベントが発生してから指定した期間、自動化が starter を無視できるようにする機能です。たとえば、自動化にモーション検知(機能)によってトリガーされる starter があり、トリガー抑制期間を 5 分に指定した場合、starter がトリガーされてから次の 5 分間はトリガーされません。これにより、自動化が何度もトリガーされるのを防ぐことができます。

自動化にトリガーの抑制を適用するには、 suppress(for:) キーワードを使用します。このキーワードには、後続のトリガーに応答するまでの待機時間を表す Duration 引数を指定します。抑制時間は、5 秒から 24 時間までです。

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() }
}

トリガーの抑制は、Suppression の前にある自動化のすべての starters に影響します。

実行回数を制限する

自動化の実行回数を制限できます。

たとえば、外出中に掃除機をかける 1 回限りの自動化を設定できます。

これを行うには、自動化の maxExecutionCount メタデータ フィールドを設定します。 次の例は、1 回だけ実行できる自動化です。

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

自動化は、最後の実行が完了して maxExecutionCount に達すると、すぐに削除されます。自動化の履歴エントリは、automation_id を含め、Google Home app (GHA) の [アクティビティ] タブに残ります。

アクションで特性属性を設定する

特性属性の値を設定するには:

  1. action ノード内に update ノードを作成し、関連するトレイトを update ノードの引数として含めます。
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
    
  2. update ノード内で、変更する属性ごとに、ミューテータ関数を使用し、新しい値を渡します。ミューテータ関数の名前を作成するには:
    1. 属性名を大文字にします。
    2. 接頭辞として「set」という単語を追加します。
    たとえば、defaultMoveRate という属性を更新するには、setDefaultMoveRate というミューテータ関数を使用します。

update ノードには複数のミューテータ関数を設定できます。次に、2 つの属性を更新する例を示します。

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

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