Android DSL のコンセプト

ここでは、Android の Automation DSL の基本コンセプトの概要について説明します。

自動化コンポーネント

自動化は、通常、次の基本コンポーネントで構成され、この順序で評価されます。

  1. 開始条件 - 特性の変更など、自動化を有効にする初期条件を定義します。自動化には開始条件が必要です。
  2. 条件 - 自動化が有効になった後に評価される追加の制約。自動化のアクションを続行するには、条件内の式が true と評価される必要があります。
  3. アクション - すべての条件が満たされたときに実行されるコマンドまたは状態の更新。

たとえば、日の入りから日の出までの間に部屋のテレビがオンになったときに、その部屋の照明を暗くする自動化があるとします。この例では、次のようになります。

  1. 開始条件 - テレビの電源がオンになった。これは、テレビのトレイトの状態の変化です。
  2. 条件 - テレビがある家の現在の時刻が評価されます。
  3. アクション - テレビと同じ部屋の照明が暗くなります。

この自動化は、部屋のテレビがオンになると有効になりますが、自動化が実行されるのは「日の入りから日の出までの時間」という条件が満たされた場合のみです。

基本構造に加えて、Home API の自動化には、名前や説明などのメタデータも含まれます。これらのメタデータは、デベロッパーやユーザーが自動化を識別するために使用できます。

ノード

Home API では、自動化の論理構造はノードで構成されます。ノードは、エンティティの動作または実行フローを表す抽象的な再利用可能なユニットです。各ノードには、入力変数と、他のノードで使用される出力変数があります。

表: 自動化ノードの種類
ノード ノードタイプ Kotlin の実装 説明
Starter 行動 StarterNodeDsl トレイトの状態(任意の属性)が変化したときに自動化を開始します。
StateReader 行動 StateReaderNodeDsl トレイト属性を読み取り、条件ノードで使用するためにその値をキャプチャできます。
操作 行動 ActionNodeDsl トレイト コマンドを呼び出します。
順次 実行フロー SequentialFlow ネストされたアクション ノードを順番に実行します。これはデフォルトの実行動作です。
並列 実行フロー ParallelFlow ネストされたアクション ノードを並列で実行します。
条件 実行フロー ConditionNodeDsl 論理式の評価に基づいて、実行フローを条件付きで変更します。条件は、開始条件に関連付けることも(開始条件固有の条件)、グローバルにすることも(すべての開始条件に適用)できます。
選択 実行フロー SelectFlow 複数の開始条件で自動化を有効にできます。
IfFlow 実行フロー IfFlowDsl どの条件(存在する場合)が true と評価されるかに基づいて、最大 1 つのアクション(またはブランチ)を実行します(if-then-else ステートメントと同様)。
Expression 値 Expression トレイトの属性の値、定数、リテラル値のいずれかです。リスト、数値、ブール値、文字列のいずれかに評価される必要があります。

行動ノード

開始条件やアクションなどのノードは、動作ノードです。開始条件は、デバイスの属性の変化に基づいて自動化を有効にします。アクションは、デバイス コマンドを発行するか、属性を更新します。

通常、動作ノードはデバイスのトレイトに関連付けられ、他のノードの入力として使用するトレイトの状態を出力します。

実行フローノード

一部のノードは、シーケンシャルや並列などの実行フローを表します。これらの各ノードには、自動化を定義する動作ノードが含まれています。

たとえば、シーケンシャル フローには、シーケンシャルな順序で実行されるノードが含まれる場合があります。通常、これらは開始条件、条件、アクションです。

順次実行フロー
図 1: 順次自動化フロー

並列フローでは、複数の照明を同時に点灯するなど、複数のアクション ノードを同時に実行できます。並列フローに続くノードは、並列フローのすべてのブランチが完了するまで実行されません。

並列実行フロー
図 2: 並列自動化フロー

別のタイプの実行フローは条件フローです。これは、式の評価に基づいて実行フローを変更できます。

たとえば、夜間かどうかに基づいてアクションを実行する自動化があるとします。条件ノードは時刻を確認し、その評価に基づいて適切な実行パスをたどります。

条件フロー
図 3: 条件フロー

選択フローは、自動化を有効にできる開始条件が複数ある場合に便利です。select フローに 2 つ以上の開始条件を囲むと、いずれかの開始条件で自動化を有効にできます。

たとえば、日没時、気温が特定のしきい値を超えた場合、または明るさがしきい値を超えた場合にブラインドを下げる自動化を作成できます。3 つの個別のスターターがこれらのシナリオを処理し、3 つすべてが select フローにラップされます。

フローを選択
図 4: フローを選択する

if-then-else フロー(IfFlow)を使用すると、自動化内で条件付き実行を分岐できます。条件が false の場合に自動化全体を停止する condition ノードとは異なり、if-then-else フローは、条件が true の場合に特定のアクションを条件付きで実行します。また、代替条件や代替アクションにフォールバックしたり、自動化の次のノードに進んだりすることもできます。詳細については、条件付き実行をご覧ください。

ネストされたフロー

複雑な自動化では、実行フローノードをネストすることもできます。たとえば、並列フローを実行するシーケンシャル フローを使用できます。

ネストされた実行フロー
図 5: ネストされた実行フロー

DSL ノードは、次の表に示す制約に従って、特定のニーズに合わせてさまざまな方法でネストして組み合わせることができます。[Builder] 列は、Kotlin のタイプセーフ ビルダーのドキュメントにリンクしています。このドキュメントには、各タイプのノードで使用できる内容が詳しく記載されています。

表: ノードの組み合わせ方法
ノード 次のノードタイプとデータが含まれる場合があります。 次のいずれかのノードタイプ内である必要があります
Starter 式 選択、順次
ManualStarter 選択、順次
StateReader 式(通常は特性属性値で構成される) IfFlow、Parallel、Sequential
操作 コマンド、エンティティ、式 IfFlow、Parallel、Select、Sequential
順次 IfFlow、Parallel、Select、Sequential
並列 アクション IfFlow、Sequential
条件 式 IfFlow、Parallel、Sequential
選択 Condition、Sequential、Starter、ManualStarter 順次。フローの最初のノードにする必要があります。
IfFlow Action、Condition、Delay、IfFlow、Parallel、Sequential、StateReader、Suppression 順次

自動化 DSL

Home API では、自動化は自動化 DSL(ドメイン固有言語)を使用して定義されます。自動化 DSL は、Kotlin のタイプセーフ ビルダーを使用して Kotlin DSL(ドメイン固有言語)として実装されており、自動化テンプレートを定義するために特別に設計されています。

自動化がコンパイルされると、Kotlin の型安全性ビルダーが Kotlin データクラスを生成します。このクラスは、プロトコル バッファ JSON にシリアル化され、Google の自動化サービスへの呼び出しに使用されます。

自動化 DSL を使用すると、自動化の構築プロセスを簡素化して効率化できます。Device API に搭載されている Matter 標準トレイトと smart home トレイトの同じデータモデルをネイティブで使用します。

また、Automation DSL は、ユーザーの家に設置されている特定のデバイス インスタンスではなく、抽象的なデバイスタイプに基づいて自動化のロジックを定義します。これにより、デベロッパーは、実行時に実際のデバイス インスタンスを指定するために使用される入力パラメータや、その他の重要なパラメータ値を指定できます。

DSL 構文は Kotlin の構文に似ており、同様に型安全ですが、Automation DSL で記述された自動化は、純粋な Kotlin で記述された同じ自動化よりもシンプルで簡潔です。

例

以下は、Automation DSL を使用して記述された、デバイスをオンにする自動化の例です。

val automation = automation {
  name = "MyFirstAutomation"
  description = "If light1 is on, turn on light2."
  isActive = true
  sequential {
    val onOffTrait = starter<_>(device1, OnOffLightDevice, OnOff)
    condition() { expression = onOffTrait.onOff equals true }
    action(device2, OnOffLightDevice) { command(OnOff.on()) }
  }
}

この自動化は非常に基本的なものです。device1(ライト)がオンになると(onOff 属性が true に変更される)、on() コマンドを送信して device2 をオンにします。

この自動化では sequential ノードを使用します。これは、ノードが順番に実行されることを示します。

sequential ノード内には、starter、condition、action などの動作ノードがあります。starter ノードの出力は、condition ノードで使用する変数に割り当てられます。