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

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

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

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

1 つの自動化で複数の処理を行うことができます。たとえば、1 つの action ノードの代わりに、複数の action ノードを順次実行できます。

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

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

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

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

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

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

条件付き実行

デフォルトでは、自動化はノードを順次または並列で実行します。条件付き分岐ロジック(実行時の条件に基づいて異なるアクションまたはパスを実行する)が必要な場合は、条件付き制御フロー DSL ブロック(ifThen、elseIf、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.
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."))
    }
  }
}

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

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

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

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

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

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

ネストされた条件付きフロー

条件付きブロックは、他の ifThen、elseIf、orElse ブロック内にネストしたり、parallel、delayFor、stateReader ノードと組み合わせたりできます。

ifThen、elseIf、orElse ブロックは、その内容をシーケンシャル フローとして実行します。各ブランチ内には、action、stateReader、parallel、delayFor、ネストされた ifThen ブロックなど、任意のシーケンシャル ノードを配置できます。

処理の遅れ

自動化に一時停止を導入するには、delayFor キーワードを使用します。このキーワードは、実行を再開するまでの一時停止時間を表す java.time.Duration 引数を取ります。一時停止の期間は、最短で 5 秒、最長で 24 時間です。

たとえば、ライトを 4 回切り替え、各切り替えの間に 5 秒間の一時停止を挿入するには、次のようにします。

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

トリガーの抑制

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

自動化にトリガーの抑制を適用するには、suppressFor キーワードと、後続のトリガーに応答するまでの待機時間を表す java.time.Duration 引数を使用します。抑制期間は、最短で 5 秒、最長で 24 時間です。

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

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

実行数を制限する

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

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

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

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

自動化は、最後の実行が完了して 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 つの属性が更新されています。

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