SWPF-JSON 文法ガイド

SWPF RULE_JSON 文法ガイド

SWPF-JSON 文法ガイド(初心者向け・サンプル付き)

このドキュメントは SWPF の `RULE_JSON`(条件分岐ルール) を、swpf_common / swpf_automation の実装(RuleEvaluator.php / SwpfAutomationContextBuilder.php など)に合わせて、迷わず新規作成できるようにまとめたものです。

1. RULE_JSON は「テンプレートIDを選ぶための JSON」

SWPF の RULE_JSON は、ざっくり言うと:

  • センサー生データ → PARAMS_JSON で PARAMS_MAP を作る
  • RULE_JSON が PARAMS_MAP を参照して if 条件を評価
  • then / else で「templateid(テンプレートID)」を選ぶ
  • 選ばれたテンプレート(TEMPLATE_JSON)が、最終的な コマンド式(EXPRESSION) を決めます
RULE_JSON 自体は「メール本文」や「コマンド」を直接持つものではなく、基本は どのテンプレートIDを使うか を決めるためのルールです
(ただし selectedNode として JSON を返すので、leaf に追加情報を入れること自体は可能です。実運用では templateid を中心に運用するのが安全です)

2. まず理解するべき登場人物

2.1 RAW(生データ)

例:IoTデバイスから来る JSON など(温度、湿度…)

{
  "temp": 28.4,
  "humid": 62,
  "device": {"id": "A-001"}
}

2.2 PARAMS_JSON(テンプレート側の設定)

「論理名 → 生データのパス」 の対応表です(ParamsMapBuilder.php で利用)。

{
  "TEMP": "temp",
  "HUMID": "humid",
  "DEVICE_ID": "device.id"
}

2.3 PARAMS_MAP(評価器が参照する実値マップ)

上の PARAMS_JSON に従い、RAWから抽出して作った値:

{
  "TEMP": 28.4,
  "HUMID": 62,
  "DEVICE_ID": "A-001"
}

RULE_JSON の `{ "var": "TEMP" }` は、この PARAMS_MAP のキーを参照します。


3. RULE_JSON の全体構造(最小形)

RULE_JSON は基本的に次の形です:

{
  "if":  { ...条件式... },
  "then": { ...実行したい templateid ... },
  "else": { ...実行したい templateid ... }
}
  • if:条件式(真偽を返すツリー)
  • then:条件が true のとき
  • else:条件が false のとき

4. if 条件式の文法(Bool式)

if の中は、次の4タイプのみをサポートしています:

1) and 2) or 3) not 4) op(比較)

4.0 AND / OR の基本(配列で書く)

andor は、条件式オブジェクトを配列で並べるのが基本です。

AND(すべて true で true)

配列内の条件が すべて true のとき true になります。途中で false になった時点で短絡評価(そこで終了)します。

{
  "and": [
    { "op": ">=", "a": { "var": "TEMP" }, "b": 20 },
    { "op": "<=", "a": { "var": "TEMP" }, "b": 30 }
  ]
}

OR(どれか 1 つ true で true)

配列内の条件のうち どれか 1 つでも true なら true になります。途中で true が出た時点で短絡評価(そこで終了)します。

{
  "or": [
    { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
    { "op": ">=", "a": { "var": "HUMID" }, "b": 80 }
  ]
}

※ SWPF実装では、and/or の配列要素は「オブジェクト(JSONの {})」が前提です。AND は不正要素があると false で終わりやすく、OR は errors に積みつつ継続します。


4.1 and(全部 true なら true)

{
  "and": [
    { "op": ">=", "a": { "var": "TEMP" }, "b": 20 },
    { "op": "<=", "a": { "var": "TEMP" }, "b": 30 }
  ]
}

意味:20 <= TEMP <= 30


4.2 or(どれか 1つ true なら true)

{
  "or": [
    { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
    { "op": ">=", "a": { "var": "HUMID" }, "b": 80 }
  ]
}

意味:TEMP >= 30 または HUMID >= 80


4.3 not(結果を反転)

{
  "not": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 }
}

意味:TEMP >= 30 ではない


4.4 op(比較ノード)

比較は次の op をサポートします:

  • > >= < <=(※ 両方 numeric のときだけ比較
  • == !=(PHP の緩い比較)

基本形:

{ "op": ">=", "a": { "var": "TEMP" }, "b": 30 }

5. 値ノード(a / b の書き方)

比較 opab に入れられる値は次のどちらかです。

5.1 変数参照ノード { "var": "KEY" }

{ "var": "TEMP" }
  • KEY は PARAMS_MAP のキー(例:TEMP

5.2 定数ノード { "value": ... }

定数は 直接数値を書く方法 と、明示的に { "value": ... } を使う方法があります。

{ "op": ">", "a": { "var": "TEMP" }, "b": 28 }

または

{ "op": ">", "a": { "var": "TEMP" }, "b": { "value": 28 } }

✅ どちらでもOKです(実装上は scalar をそのまま値として扱います)


6. then / else の書き方(templateid)

then/else では、最終的に `templateid` を指定します。

6.1 templateid が1つのとき(最もシンプル)

{
  "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
  "then": { "templateid": "HOT" },
  "else": { "templateid": "DEFAULT" }
}

6.2 templateid を複数にすると「順次実行」される

SwpfAutomationContextBuilder.php では、RULE_JSON から templateid を 複数収集して、 テンプレート(やプロファイル)の設定を 順に deep merge する仕様が維持されています。

{
  "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
  "then": { "templateid": ["HOT", "MAIL_ADMIN"] },
  "else": { "templateid": ["DEFAULT"] }
}

イメージ:

  • HOT を実行し、次に MAIL_ADMIN を実行する
  • 結果として「MAIL_ADMIN」の実行結果が返される
ただし2026/1/1時点の仕様では一番最後のTEMPLATE_ID以外は式の評価のみに限定されます。制御等のプラグインを含む処理を複数実施したい場合は、それぞれACTION_TEMPLATEエンティティに登録するようにしてください。

7. ネスト(入れ子) if の書き方

then/else の中に、さらに if/then/else を置けます。 RuleEvaluator.php は選択ノードを 最大 10 階層まで降りて最終ノードを決定します(無限ループ防止)。

{
  "if": { "op": "<=", "a": { "var": "TEMP" }, "b": 15 },
  "then": { "templateid": "COLD" },
  "else": {
    "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
    "then": { "templateid": "HOT" },
    "else": { "templateid": "DEFAULT" }
  }
}

8. 「else を何もしない(NOP)」にしたい場合

例えば「HOT のときだけ通知したい」など。

8.1 else を空にする(おすすめ)

{
  "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
  "then": { "templateid": "HOT" },
  "else": {}
}

または

{
  "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
  "then": { "templateid": "HOT" },
  "else": []
}

SWPF 側では templateid が空だと command が空になり NOP 扱いになりやすい設計です。

※ 実行系が「空の templateid をどう扱うか」は executor の実装に依存しますが、現在の設計では “command empty / NOP” に寄せています。

9. 実用サンプル集(コピペ用)

9.1 温度しきい値(3段階)

  • TEMP <= 15 → COLD
  • TEMP >= 30 → HOT
  • それ以外 → DEFAULT
{
  "if": { "op": "<=", "a": { "var": "TEMP" }, "b": 15 },
  "then": { "templateid": "COLD" },
  "else": {
    "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
    "then": { "templateid": "HOT" },
    "else": { "templateid": "DEFAULT" }
  }
}

9.2 温度 × 湿度(両方で警告)

  • TEMP >= 28 かつ HUMID >= 80 → ALERT_HOT_HUMID
  • それ以外 → DEFAULT
{
  "if": {
    "and": [
      { "op": ">=", "a": { "var": "TEMP" }, "b": 28 },
      { "op": ">=", "a": { "var": "HUMID" }, "b": 80 }
    ]
  },
  "then": { "templateid": "ALERT_HOT_HUMID" },
  "else": { "templateid": "DEFAULT" }
}

9.3 “範囲外” をまとめて検知(not + and)

  • 20〜30 の範囲外 → TEMP_OUT_OF_RANGE
  • 範囲内 → DEFAULT
{
  "if": {
    "not": {
      "and": [
        { "op": ">=", "a": { "var": "TEMP" }, "b": 20 },
        { "op": "<=", "a": { "var": "TEMP" }, "b": 30 }
      ]
    }
  },
  "then": { "templateid": "TEMP_OUT_OF_RANGE" },
  "else": { "templateid": "DEFAULT" }
}

9.4 どれかが危険(or)

  • TEMP >= 35 または HUMID >= 90 → DANGER
  • それ以外 → DEFAULT
{
  "if": {
    "or": [
      { "op": ">=", "a": { "var": "TEMP" }, "b": 35 },
      { "op": ">=", "a": { "var": "HUMID" }, "b": 90 }
    ]
  },
  "then": { "templateid": "DANGER" },
  "else": { "templateid": "DEFAULT" }
}

10. よくあるミスと対策

10.1 { "var": "TEMP" } が未定義(PARAMS_MAP に無い)

RuleEvaluator.phpUndefined var を errors に積み、値は null になりがちです。 その結果、> >= などの 数値比較は false になりやすいです(is_numeric が通らない)。

✅ 対策:

  • PARAMS_JSON に TEMP を定義しているか
  • RAW 側に temp が本当に来ているか
  • dot.path(例:device.id)の階層が合っているか

10.2 比較で文字列が混ざる

> >= < <=両方 numeric のときのみ動きます。 文字列 "28.4" でも is_numeric は true なので通りますが、"HIGH" などは比較できません。


10.3 書式ミス(and/or/not の中が配列になっていない等)

  • and / or は配列([])が必要です
  • not は単一の子ノードが必要です
  • opop/a/b の形が必要です

11. チートシート(最小パターン集)

if(比較)

{ "op": ">=", "a": { "var": "TEMP" }, "b": 30 }

and

{ "and": [ <expr>, <expr> ] }

or

{ "or": [ <expr>, <expr> ] }

not

{ "not": <expr> }

最小 RULE_JSON

{
  "if": { "op": ">=", "a": { "var": "TEMP" }, "b": 30 },
  "then": { "templateid": "HOT" },
  "else": { "templateid": "DEFAULT" }
}

12. 参考:実装上の“仕様メモ”(重要)

  • ネスト if の解決:最大 10 階層(無限ループ対策)
  • 比較:
  • > >= < <=両方 numeric のときのみ
  • == != は PHP の緩い比較
  • templateid の収集:
  • swpf_common 側は leaf の templateid を抽出(文字列/配列)
  • swpf_automation 側は templateid キーを再帰走査して拾う(収集用途)

付録:RULE_JSON を作るときの手順(おすすめ)

1) RAW の例を用意する(実際に来る JSON) 2) PARAMS_JSON を書く(論理名 → パス) 3) PARAMS_MAP を頭の中で作る(TEMP/HUMID が取れる状態にする) 4) RULE_JSON は最初は 最小形から作る(温度だけ) 5) 動いたら and/or/not を足していく 6) 最後に必要なら templateid を配列にして deep merge を使う


 

当サイトまたはIoTカスタムモジュール、開発支援に関するお問い合わせはこちらのメールフォームからお気軽にお問い合わせください。