コンテンツにスキップ

Functions

ページ: 設定 -> 機能

サポートされている機能の全一覧は、サポートされている機能を参照してください。

機能コントローラーは、入力や出力を使うタスクを実行することがよくあります。

Note

「最後」は、機能がデータベースから最後(最新)の測定値のみを取得することを意味します。「過去」は、機能が現在から設定した「最大経過時間(秒)」までさかのぼって、すべての測定値を取得することを意味します(たとえば、測定値が10秒ごとに収集され、最大経過時間が60秒に設定されている場合、平均して機能の処理対象として6個の測定値が返されます)。

目録から機能を探す~

ページ上部のドロップダウンは、機能を「制御・自動化」「トリガー」「カスタム機能」にグループ分けして表示します。検索ボックスは、表示名とモジュール名の両方に一致します。

カスタム機能~

AoTには、ユーザーが作成した機能をAoTシステム内で使用できるようにする、カスタム機能のインポート機能があります。カスタム機能は [歯車アイコン] -> 構成 -> カスタム機能 ページからアップロードできます。インポートすると、設定 -> 機能 ページで使用できるようになります。

動作するカスタム機能モジュールを開発した場合は、新しいGitHub Issueの作成やプルリクエストの送信を検討してください。そのモジュールが標準搭載セットに取り込まれる可能性があります。

きちんとフォーマットされた例を確認するには、ディレクトリ AoT/aot/functions にある標準搭載モジュールを開いてみてください。

また、ディレクトリ AoT/aot/functions/examples には、カスタム機能のサンプルが含まれています。

標準搭載セットには含まれていないカスタムモジュールを専門に扱う別のGitHubリポジトリが、aot-inc/AoT-custom にあります。

新しい測定値・単位を必要とする機能については、[歯車アイコン] -> 構成 -> 測定値 ページで追加できます。

PIDコントローラー~

比例・積分・微分(PID)コントローラーは、産業界全体でシステム制御に使われている制御ループのフィードバック機構です。温度のような測定可能な状態を目標の状態へ効率よく導き、オーバーシュートや振動を最小限に抑えながらその状態を維持します。うまく調整されたPIDコントローラーは設定値に素早く到達し、オーバーシュートを最小限にし、振動をほとんど起こさずに設定値を保ちます。

PIDの設定は、PIDが有効な状態のままでも変更でき、新しい設定はすぐに反映されます。コントローラーが一時停止している間に設定を変更した場合は、コントローラーが動作を再開したときに変更後の値が使われます。

PIDコントローラーの設定~

設定 説明
有効化/無効化 特定のPIDコントローラーをオン・オフします。
一時停止 一時停止中は制御変数が更新されず、PIDは関連する出力をオンにしません。現在のPID出力値を失うことなく設定を変更できます。
保持 保持中は制御変数は更新されませんが、PIDは関連する出力をオンにします。現在のPID出力値を失うことなく設定を変更できます。
再開 保持または一時停止の状態からPIDコントローラーを再開します。
方向 調整したい方向です。たとえば温度を上げるだけでよい場合は「上昇」に、上げ下げ両方が必要な場合は「両方」に設定します。
周期 PIDが測定値を取得し、更新して出力を調整する間隔です。
開始オフセット(秒) 最初の計算・測定を試みるまでに待機する時間です。
最大経過時間 センサーの測定値として許容される最大の経過時間(秒)です。測定値がこの時間より古い場合、その測定値は無視され、PIDは出力を作動させません。これはPIDが常に新しい測定値だけを使うようにするための安全機構です。
設定値 環境を調整したい具体的な値です。たとえば湿度を60%に調整したい場合は60と入力します。
バンド(±設定値) ヒステリシスのオプションです。0以外の値を設定すると、設定値が「バンド」になります。バンドの最大値は設定値+バンド、最小値は設定値-バンドです。上昇方向の場合、値がバンドの最大値を超えるとPIDは動作を待機し、条件がバンドの最小値を下回ると調整を再開します。下降方向の場合、値がバンドの最小値を下回るとPIDは動作を待機し、条件がバンドの最大値を上回ると調整を再開します。「両方」に設定した場合は、バンドの外側の最小値・最大値でのみ調整が行われ、バンドの内側では停止します。0に設定するとヒステリシスは無効になります。
下降アクションを負の値として保存 チェックすると、すべての出力変数(PIDおよび出力の継続時間/デューティサイクル)が測定値データベースに負の値として保存されます。これは、PIDが現在上昇方向・下降方向のどちらに動作しているかをグラフ上で示すのに役立ちます。無効にすると、すべての値が正の値として保存されます。
KPゲイン 比例係数(0以上)です。誤差の現在値を考慮します。たとえば誤差が大きく正の値であれば、制御出力も大きく正の値になります。
KIゲイン 積分係数(0以上)です。誤差の過去の値を考慮します。たとえば現在の出力が十分に強くない場合、誤差の積分は時間とともに蓄積され、コントローラーはより強い応答を返すようになります。
KDゲイン 微分係数(0以上)です。現在の変化率にもとづいて、誤差の将来の予測値を考慮します。
積分最小 Ki_totalを計算する際に積分項へ許容される最小値です。(Ki_total = Ki × 積分項;PID出力 = Kp_total + Ki_total + Kd_total)
積分最大 Ki_totalを計算する際に積分項へ許容される最大値です。(Ki_total = Ki × 積分項;PID出力 = Kp_total + Ki_total + Kd_total)
出力(上昇/下降) 特定の環境条件を上げ下げする出力です。たとえば温度を上げる場合、ヒーターパッドやヒーティングコイルがこれに当たります。
最小オン継続時間・デューティサイクル・または量(上昇/下降) 出力をオンにする前に、PID出力が到達していなければならない最小値です。PID出力がこの値を下回ると、継続時間で動く出力はオンにならず、PWM出力は「常に最小」が有効でない限りオフのままになります。
最大オン継続時間・デューティサイクル・または量(上昇/下降) 出力に設定できる継続時間・量・デューティサイクルの最大値です。PID出力がこの値を超える場合は、ここで設定した最大値が使われます。
最小オフ継続時間(上昇/下降) オン・オフ(継続時間)方式の出力について、再びオンにできるようになるまで出力をオフのままにしておく最小時間です。急な電源のオン・オフを繰り返すと壊れる恐れがある機器(たとえば冷蔵庫など)に有用です。
常に最小PWMで動作(上昇/下降) PWM出力にのみ適用されます。有効にすると、デューティサイクルが最小値を下回ることはありません。
設定値トラッキングメソッド 設定値を時間の経過とともに変化させるメソッドを設定します。

PID出力の計算~

PIDコントローラーは、継続時間・量・PWMデューティサイクルなど、さまざまな種類の出力を制御できます。ほとんどの出力タイプでは、PID出力(制御変数)は比例的に作用します(たとえば 出力の継続時間 = PID制御変数)。ただし、デューティサイクルを出力する場合は デューティサイクル = (制御変数 / 周期) * 100 として計算されます。

Note

制御変数 = P出力 + I出力 + D出力。デューティサイクルは0~100%の範囲、および設定された最小デューティサイクルと最大デューティサイクルの範囲内に収まります。出力の継続時間は設定された最小オン継続時間と最大オン継続時間の範囲内に、出力量も同様の範囲内に収まります。

PIDのチューニング~

PIDのチューニングは、使用する出力デバイスや、制御対象となる環境・システムによっては複雑な作業になることがあります。変動の大きいシステムは、安定したシステムより制御が難しくなります。同様に、適さない出力デバイスを使うと、PIDのチューニングが難しくなったり、不可能になったりすることがあります。PIDコントローラーの仕組みとチューニングの理論を学ぶことは、PIDコントローラーをうまく操作できるようになるだけでなく、システムの開発や出力デバイスの選定・実装にも役立ちます。

PIDチューニングの参考資料~

PID制御の理論~

PIDコントローラーは、単純なものから複雑なものまで幅広い制御課題に対応できるため、産業の現場でもっともよく使われている調節コントローラーです。PIDコントローラーには、比例・積分・微分という3つの経路があります。

P(比例)は、誤差に定数KPを掛けて出力値を生成します。誤差が大きいほど、比例出力も大きくなります。

I(積分)は、誤差にKIを掛けたうえで積分します(KI・1/s)。誤差が時間とともに変化するにつれ、積分は誤差を継続的に積算し、定数KIを掛け合わせます。積分は、制御システムに残り続ける誤差を取り除くために使われます。KPだけを使うと出力に持続的な誤差が生じる場合(つまりセンサーの測定値が設定値に到達しない場合)、積分は出力値を増やして誤差を減らし、設定値へ到達させます。

D(微分)は、誤差にKDを掛けたうえで微分します(KD・s)。誤差の変化率が時間とともに変わるにつれ、出力信号も変化します。誤差の変化が速いほど微分経路は大きくなり、出力の変化率を抑えます。これにより、設定値付近でのオーバーシュートとアンダーシュート(振動)が軽減されます。

KP、KI、KDのゲインは、P・I・D各変数が最終的なPID出力値にどれだけ影響するかを決めます。たとえばゲインが大きいほど、その変数の出力への影響も大きくなります。

PIDコントローラーの出力は、さまざまな用途に使えます。単純な使い方としては、この値を周期的な間隔(周期)の中で出力をオンにする秒数として使う方法があります。たとえば周期を30秒に設定した場合、PIDの式は望ましい測定値と実際の測定値を使って30秒ごとにPID出力を計算します。その周期の中で出力がオンになっている時間が長いほど、システムへの影響は大きくなります。たとえば30秒ごとに15秒間出力がオンになっている場合はデューティサイクル50%、30秒ごとに30秒間オンになっている場合はデューティサイクル100%で、システムへの影響は2倍になります。PIDコントローラーは、実際の測定値が望ましい測定値からどれだけ離れているか(誤差)にもとづいて出力を計算します。誤差が増えたり残り続けたりすると出力は大きくなり、周期内で出力がオンになる時間が長くなります。これによって測定される状態が変化し、誤差が一般的に小さくなります。誤差が小さくなると制御変数は小さくなり、出力がオンになる時間も短くなります。うまく調整されたPIDコントローラーの最終目標は、実際の測定値を素早く設定値へ導き、オーバーシュートを最小限にし、振動をほとんど起こさずに設定値を保つことです。

温度を例にすると、プロセス変数(PV)は測定された温度、設定値(SP)は望ましい温度、誤差(e)は測定温度と望ましい温度の差(つまり実際の温度がどれだけ高すぎる・低すぎるか)です。この誤差はPIDの3つの構成要素それぞれによって処理され、操作変数(MV)または制御変数(CV)と呼ばれる出力を生成します。各経路が出力値にどれだけ寄与するかを制御するため、各経路にはゲイン(KP、KI、KD)が掛けられます。ゲインを調整することで、システムが各経路にどれだけ敏感に反応するかが変わります。3つの経路をすべて合計するとPID出力になります。ゲインを0に設定すると、その経路は出力に何も寄与せず、事実上オフになります。

出力はさまざまな用途に使えますが、このコントローラーは、出力を使って測定値(PV)に影響を与えることを目的として設計されています。適切に調整された PIDコントローラーによるこのフィードバックループは、短時間で設定値に到達し、振動を最小限に抑え、外乱にも素早く対応できます。

したがって、温度を調整したい場合は、センサーは温度センサーで、フィードバックデバイスは加熱・冷却が可能なデバイスになります。温度が設定値を下回っていると、出力値は正の値になりヒーターが作動します。温度は望ましい温度に向かって上昇し、これにより誤差が減って出力が小さくなります。このフィードバックループは、誤差が0になるまで(そしてその時点で出力も0になるまで)続きます。温度が設定値を超えてさらに上昇し続ける場合(許容範囲内であることもあります)、PIDは負の出力を生成し、冷却デバイスが再び温度を下げて誤差を小さくします。冷却デバイスの助けを借りずに温度を自然に下げられる場合は、冷却デバイスを省略してシステムを簡素化できます。

KP、KI、KDを効果的に使うコントローラーを実装するのは難しく、また多くの場合不要でもあります。たとえばKIとKDを0に設定すると、それらの経路はオフになり、非常にシンプルなPコントローラーになります。PIコントローラーもよく使われます。まずKPだけを有効にして始め、次にKPとKIの組み合わせを試し、最後に3つすべてを使うことが推奨されます。システムは空間の体積、断熱の程度、接続されたデバイスがどれだけ影響を与えるかなど、多くの要因に左右されるため、各経路は実際に試しながら効果的な出力が得られるよう調整する必要があります。

かんたん設定例~

これらの設定例は、KP、KI、KDのゲインを理想的な値に設定する方法を示すものではなく、特定の方向への調整をどう設定するかを示すためのものです。PID値を決定するために開発されたさまざまな手法・技法を扱ったオンライン資料は数多くあります(こちらこちらこちらこちらこちら)。そのため、変数を理解し効果的に実装するには、自分自身で調査・実験を行うことが欠かせません。

PID値がどれだけばらつくかを示すために挙げると、ある構成では、温度PIDの値(上昇方向の調整)はKP = 30、KI = 1.0、KD = 0.5であり、湿度PIDの値(上昇方向の調整)はKP = 1.0、KI = 0.2、KD = 0.5でした。これらの値は最適ではなかったものの、環境チャンバーの条件下では問題なく機能しました。

正確な温度調整~

このシステムは、2台の調整用デバイス(加熱用1台、冷却用1台)を使って、温度を特定の値まで上げ下げします。

センサーを追加し、各センサーに適切なデバイスとピン/アドレスを保存してから、センサーを有効化します。

出力を2つ追加し、それぞれのGPIOとオントリガー状態を保存します。

PIDを追加し、先ほど作成したセンサーを選択します。設定値 を目標温度に変更し、調整方向 を「両方」に設定します。上昇出力 には加熱デバイスに接続されたリレーを、下降リレー には冷却デバイスに接続されたリレーを設定します。

KP = 1、KI = 0、KD = 0に設定してから、PIDを有効化します。

温度が設定値を下回っている場合、PIDコントローラーが決定する間隔でヒーターが作動し、温度は設定値まで上昇します。温度が設定値(または設定値+バッファ)を超えて上昇すると、冷却デバイスが作動し、温度は設定値に戻ります。温度が設定値に到達しない場合は、KPの値を大きくして、システムへの影響を観察してください。読み取り間隔 とKPだけを調整して、適切な調整が行われるようにしてみてください。KPだけでうまく調整できるようになるまでは、KIとKDは0のままにしておきます。

6~12時間の時間範囲でグラフを確認し、温度が設定値に対してどれだけうまく調整されているかを見てください。「うまく調整されている」状態がどの程度かは、用途や許容範囲によって異なります。ほとんどのPIDコントローラーの用途では、妥当な時間内に適切な温度に到達し、設定値付近での振動が少ないことが望まれます。

調整がうまくいったら、KPをわずかに(およそ25%)下げ、KIを低い値(たとえば0.1や0.01)まで上げてPIDを開始し、コントローラーがどれだけうまく調整できているかを観察します。振動が少なく、かつ調整が速くなるよう、KIを少しずつ上げていきます。ここまでくれば、システムとKDの値を試す準備が整います。KDは、KPとKIを調整し終えた後に試してください。

高温調整~

双方向の調整が不要な場合は、システムを簡素化できます。たとえば冷却が不要であれば、それをシステムから取り除き、上昇方向の調整だけを使うことができます。

正確な温度調整の例と同じ構成を使いますが、調整方向 を「上昇」に変更し、「下降リレー」の項目は変更せずそのままにしておきます。

PIDオートチューン~

Warning

この機能は実験的なものです。PIDの理論・動作・チューニングに慣れてから使用することを推奨します。

オートチューン機能は、PIDコントローラーで使う適切なKp・Ki・Kdのゲインを決定するための、独立したコントローラーです。オートチューナーは出力を操作し、特定の環境・システムの測定応答を分析します。PIDのゲインを計算するのに十分なデータを集めるため、選択した出力を使ってシステムを何度か擾乱させる必要があります。この機能を使うには、測定値と、その特定の測定条件を調整できる出力を選択します。次にノイズバンドと出力ステップを設定し、機能を有効化します。オートチューナーのログは、デーモンログ([歯車アイコン] -> AoTログ -> デーモンログ)に表示されます。オートチューニングの実行中は、その測定値と出力を含んだダッシュボードのグラフを作成しておくことを推奨します。これにより、PIDオートチューナーが何をしているか、また設定したオートチューンの内容によってどのような問題が起こり得るかを確認できます。オートチューニングの完了に時間がかかりすぎる場合、操作対象のシステムには、信頼できるPIDゲインの組を計算するのに十分な安定性がない可能性があります。これは、システムへの外乱が大きすぎる場合や、条件の変化が速すぎて安定した測定値の振動が得られない場合に起こり得ます。その場合は、システムを変更して安定性を高め、測定値が一定して振動するようにしてみてください。オートチューニングが正常に完了したら、再び擾乱を与えることで、PIDコントローラーがそれに対応できるかどうかをさらに調整できます。

設定 説明
測定値 出力が影響を与える特定の条件を測定する、入力または機能の測定値です。たとえば温度の測定値で、出力はヒーターかもしれません。
出力 測定値に影響を与える出力です。オートチューン機能は、測定値が設定値を超えるよう、この出力を周期的にオンにします。
周期 出力がオンになる間隔です。これはPIDコントローラーで使う周期と同じ値に設定してください。周期が異なると、オートチューンが算出するPIDゲインに大きく影響することがあります。
設定値 望ましい測定条件の値です。たとえば温度を測定している場合、出力が有効化されたときに温度が設定値を超えるよう、現在の温度より数度高い値を設定します。
ノイズバンド 出力がオフになるまでに、測定条件が設定値を上回っていなければならない幅です。同様に、出力が再びオンになるまでに、測定条件が設定値を下回っていなければならない幅でもあります。
出力ステップ PIDの各周期の中で出力がオンになる秒数です。たとえば出力50%でオートチューンを行うには、出力ステップをPID周期の半分に設定します。
方向 出力が測定値に与える方向です。たとえばヒーターは温度を上げ、クーラーは温度を下げます。

一般的なグラフの出力は、次のようになります。

そして一般的なデーモンログの出力は、次のようになります。

2018-08-04 23:32:20,876 - aot.pid_3b533dff - INFO - Activated in 187.2 ms
2018-08-04 23:32:20,877 - aot.pid_autotune - INFO - PID Autotune started
2018-08-04 23:33:50,823 - aot.pid_autotune - INFO -
2018-08-04 23:33:50,830 - aot.pid_autotune - INFO - Cycle: 19
2018-08-04 23:33:50,831 - aot.pid_autotune - INFO - switched state: relay step down
2018-08-04 23:33:50,832 - aot.pid_autotune - INFO - input: 32.52
2018-08-04 23:36:00,854 - aot.pid_autotune - INFO -
2018-08-04 23:36:00,860 - aot.pid_autotune - INFO - Cycle: 45
2018-08-04 23:36:00,862 - aot.pid_autotune - INFO - found peak: 34.03
2018-08-04 23:36:00,863 - aot.pid_autotune - INFO - peak count: 1
2018-08-04 23:37:20,802 - aot.pid_autotune - INFO -
2018-08-04 23:37:20,809 - aot.pid_autotune - INFO - Cycle: 61
2018-08-04 23:37:20,810 - aot.pid_autotune - INFO - switched state: relay step up
2018-08-04 23:37:20,811 - aot.pid_autotune - INFO - input: 31.28
2018-08-04 23:38:30,867 - aot.pid_autotune - INFO -
2018-08-04 23:38:30,874 - aot.pid_autotune - INFO - Cycle: 75
2018-08-04 23:38:30,876 - aot.pid_autotune - INFO - found peak: 32.17
2018-08-04 23:38:30,878 - aot.pid_autotune - INFO - peak count: 2
2018-08-04 23:38:40,852 - aot.pid_autotune - INFO -
2018-08-04 23:38:40,858 - aot.pid_autotune - INFO - Cycle: 77
2018-08-04 23:38:40,860 - aot.pid_autotune - INFO - switched state: relay step down
2018-08-04 23:38:40,861 - aot.pid_autotune - INFO - input: 32.85
2018-08-04 23:40:50,834 - aot.pid_autotune - INFO -
2018-08-04 23:40:50,835 - aot.pid_autotune - INFO - Cycle: 103
2018-08-04 23:40:50,836 - aot.pid_autotune - INFO - found peak: 33.93
2018-08-04 23:40:50,836 - aot.pid_autotune - INFO - peak count: 3
2018-08-04 23:42:05,799 - aot.pid_autotune - INFO -
2018-08-04 23:42:05,805 - aot.pid_autotune - INFO - Cycle: 118
2018-08-04 23:42:05,806 - aot.pid_autotune - INFO - switched state: relay step up
2018-08-04 23:42:05,807 - aot.pid_autotune - INFO - input: 31.27
2018-08-04 23:43:15,816 - aot.pid_autotune - INFO -
2018-08-04 23:43:15,822 - aot.pid_autotune - INFO - Cycle: 132
2018-08-04 23:43:15,824 - aot.pid_autotune - INFO - found peak: 32.09
2018-08-04 23:43:15,825 - aot.pid_autotune - INFO - peak count: 4
2018-08-04 23:43:25,790 - aot.pid_autotune - INFO -
2018-08-04 23:43:25,796 - aot.pid_autotune - INFO - Cycle: 134
2018-08-04 23:43:25,797 - aot.pid_autotune - INFO - switched state: relay step down
2018-08-04 23:43:25,798 - aot.pid_autotune - INFO - input: 32.76
2018-08-04 23:45:30,802 - aot.pid_autotune - INFO -
2018-08-04 23:45:30,808 - aot.pid_autotune - INFO - Cycle: 159
2018-08-04 23:45:30,810 - aot.pid_autotune - INFO - found peak: 33.98
2018-08-04 23:45:30,811 - aot.pid_autotune - INFO - peak count: 5
2018-08-04 23:45:30,812 - aot.pid_autotune - INFO -
2018-08-04 23:45:30,814 - aot.pid_autotune - INFO - amplitude: 0.9099999999999989
2018-08-04 23:45:30,815 - aot.pid_autotune - INFO - amplitude deviation: 0.06593406593406595
2018-08-04 23:46:40,851 - aot.pid_autotune - INFO -
2018-08-04 23:46:40,857 - aot.pid_autotune - INFO - Cycle: 173
2018-08-04 23:46:40,858 - aot.pid_autotune - INFO - switched state: relay step up
2018-08-04 23:46:40,859 - aot.pid_autotune - INFO - input: 31.37
2018-08-04 23:47:55,860 - aot.pid_autotune - INFO -
2018-08-04 23:47:55,866 - aot.pid_autotune - INFO - Cycle: 188
2018-08-04 23:47:55,868 - aot.pid_autotune - INFO - found peak: 32.36
2018-08-04 23:47:55,869 - aot.pid_autotune - INFO - peak count: 6
2018-08-04 23:47:55,870 - aot.pid_autotune - INFO -
2018-08-04 23:47:55,871 - aot.pid_autotune - INFO - amplitude: 0.9149999999999979
2018-08-04 23:47:55,872 - aot.pid_autotune - INFO - amplitude deviation: 0.032786885245900406
2018-08-04 23:47:55,873 - aot.pid_3b533dff - INFO - time:  16 min
2018-08-04 23:47:55,874 - aot.pid_3b533dff - INFO - state: succeeded
2018-08-04 23:47:55,874 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,875 - aot.pid_3b533dff - INFO - rule: ziegler-nichols
2018-08-04 23:47:55,876 - aot.pid_3b533dff - INFO - Kp: 0.40927018474290117
2018-08-04 23:47:55,877 - aot.pid_3b533dff - INFO - Ki: 0.05846588600007114
2018-08-04 23:47:55,879 - aot.pid_3b533dff - INFO - Kd: 0.7162385434443115
2018-08-04 23:47:55,880 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,881 - aot.pid_3b533dff - INFO - rule: tyreus-luyben
2018-08-04 23:47:55,887 - aot.pid_3b533dff - INFO - Kp: 0.3162542336649691
2018-08-04 23:47:55,889 - aot.pid_3b533dff - INFO - Ki: 0.010165091543194185
2018-08-04 23:47:55,890 - aot.pid_3b533dff - INFO - Kd: 0.7028026111719073
2018-08-04 23:47:55,891 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,892 - aot.pid_3b533dff - INFO - rule: ciancone-marlin
2018-08-04 23:47:55,892 - aot.pid_3b533dff - INFO - Kp: 0.21083615577664605
2018-08-04 23:47:55,893 - aot.pid_3b533dff - INFO - Ki: 0.06626133746674728
2018-08-04 23:47:55,893 - aot.pid_3b533dff - INFO - Kd: 0.3644161687558038
2018-08-04 23:47:55,894 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,894 - aot.pid_3b533dff - INFO - rule: pessen-integral
2018-08-04 23:47:55,895 - aot.pid_3b533dff - INFO - Kp: 0.49697093861638
2018-08-04 23:47:55,895 - aot.pid_3b533dff - INFO - Ki: 0.0887428626786794
2018-08-04 23:47:55,896 - aot.pid_3b533dff - INFO - Kd: 1.04627757151908
2018-08-04 23:47:55,896 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,897 - aot.pid_3b533dff - INFO - rule: some-overshoot
2018-08-04 23:47:55,898 - aot.pid_3b533dff - INFO - Kp: 0.23191977135431066
2018-08-04 23:47:55,898 - aot.pid_3b533dff - INFO - Ki: 0.03313066873337365
2018-08-04 23:47:55,899 - aot.pid_3b533dff - INFO - Kd: 1.0823160212047374
2018-08-04 23:47:55,899 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,900 - aot.pid_3b533dff - INFO - rule: no-overshoot
2018-08-04 23:47:55,900 - aot.pid_3b533dff - INFO - Kp: 0.1391518628125864
2018-08-04 23:47:55,901 - aot.pid_3b533dff - INFO - Ki: 0.01987840124002419
2018-08-04 23:47:55,901 - aot.pid_3b533dff - INFO - Kd: 0.6493896127228425
2018-08-04 23:47:55,902 - aot.pid_3b533dff - INFO -
2018-08-04 23:47:55,902 - aot.pid_3b533dff - INFO - rule: brewing
2018-08-04 23:47:55,903 - aot.pid_3b533dff - INFO - Kp: 5.566074512503456
2018-08-04 23:47:55,904 - aot.pid_3b533dff - INFO - Ki: 0.11927040744014512
2018-08-04 23:47:55,904 - aot.pid_3b533dff - INFO - Kd: 4.101408080354794

条件付き機能~

条件付き機能は、ユーザーが作成したPythonコードにもとづいて、単純なものから複雑なものまでさまざまなタスクを実行するために使われます。条件付き機能はPython 3のコードを実行し、コードの中でAoTとやり取りするための条件(Conditions)とアクション(Actions)を使えるようにします。条件は一般的にAoTからデータを取得するために使われ(たとえば入力の測定値)、アクションはAoTに影響を与えるために使われます(たとえば出力を作動させたり、PIDコントローラーを一時停止したりする)。追加した各条件・各アクションには、Pythonコードでの使い方を示す説明とサンプルコードが用意されています。

Note

Timeout は、Run Python Code の実行にかかる時間より長く設定してください(Timeout を短く設定しすぎると、コードの一部しか実行されないことがあります)。

Note

Period は、Run Python Code の実行にかかる時間より長く設定してください。そうしないと、前回の実行が終わる前にコードが再度実行されてしまいます。

Note

このコードは、AoTが動作しているPythonの仮想環境の中で実行されます。そのため、コード内でPythonのライブラリを使うには、その仮想環境にライブラリをインストールする必要があります。この仮想環境は /opt/AoT/env にあり、たとえば「my_library」をpipでインストールするには sudo /opt/AoT/env/bin/pip install my_library を実行します。

条件付き機能の設定~

設定 説明
Pythonコードをインポート Pythonライブラリをインポートするために使うPython 3のコードです。条件付き機能のコードが生成される際、クラスが作成される前に実行されます。
Pythonコードを初期化 クラスの初期化中(__init__() の中)に実行されるPython 3のコードです。ここで、クラス内で使う変数を初期化します。
実行するPythonコード 設定した周期ごとに実行されるPython 3のコードです。条件やアクションはここで実行されます。条件またはアクションを追加すると、その条件・アクションごとに実行できる関数が、その条件・アクションの上に表示されます。
Pythonコードのステータス 他のコントローラーやウィジェットに情報を渡す辞書を返すことができます。たとえば、機能ステータスウィジェットはこの情報をダッシュボードに表示します。情報を返す必要がない場合は、このコードを削除してもかまいません。
周期(秒) `実行するPythonコード` が実行される周期(秒)です。
開始オフセット(秒) 条件付き機能が有効化されてから、最初に実行されるまでに待機する時間(秒)です。
ログレベル: デバッグ デーモンログにデバッグ行を表示します。
メッセージにコードを含める アクションに渡されるメッセージ(self.message)にPythonコードを含めます。

条件とは、実行するPythonコード の中で使える、特定の情報を返す関数のことです。

条件 説明
測定値(単一・最後) 入力またはデバイスから最後の測定値を取得します。最大経過時間(秒)を設定して、値を受け入れる期間を制限できます。最後の値がこの経過時間より古い場合は「None」が返されます。
測定値(単一・過去・平均) 入力またはデバイスから過去の測定値を取得し、その平均値を計算します。最大経過時間(秒)を設定して、値を受け入れる期間を制限できます。すべての値がこの経過時間より古い場合は「None」が返されます。
測定値(単一・過去・合計) 入力またはデバイスから過去の測定値を取得し、その合計値を計算します。最大経過時間(秒)を設定して、値を受け入れる期間を制限できます。すべての値がこの経過時間より古い場合は「None」が返されます。
測定値(複数・過去) 入力またはデバイスから過去の測定値を取得します。最大経過時間(秒)を設定して、値を受け入れる期間を制限できます。この経過時間の範囲内に値が見つからない場合は「None」が返されます。「測定値(単一)」条件と異なり、こちらは 'time' と 'value' のキーを持つ辞書のリストを返します。
GPIO状態 現在のGPIOの状態を取得し、HIGHなら1、LOWなら0を返します。最後の値がこの経過時間より古い場合は「None」が返されます。
出力状態 出力が現在オンであれば 'on'、オフであれば 'off' を返します。
出力オン時間 出力がオンになっている秒数を返します。オフの場合は0を返します。
コントローラー実行状態 コントローラーが有効な場合はTrue、無効な場合はFalseを返します。
太陽: 昼/夜 その場所が現在昼であればTrue、夜であればFalseを返します。位置は、この条件付き機能が地図上に配置された位置から継承されます(配置がなければゾーンまたはサイトの位置が使われます)。ここで座標を設定する必要はありません。日の出・日の入りのオフセット(分)で、昼の時間帯の両端をずらすことができます。たとえば日の入りのオフセットを-30にすると、日の入りの30分前から夜として扱われます。白夜の地域では常にTrue、極夜の地域では常にFalseになります。
太陽: イベントまでの時間 次に選択した太陽イベント(日の出、日の入り、南中、市民薄明の始まり、市民薄明の終わり)までの秒数を返します。イベントのオフセット(分)に負の値を指定すると、イベントより前の時点までの秒数を数えます。たとえば-60を指定すると、イベントの1時間前までの残り秒数が返されます。位置はこの条件付き機能から継承されます。その日にイベントが発生しない場合(極域)は「None」が返されます。
最大経過時間(秒) 測定値に許容される最大の経過時間(秒)です。最後の測定値がこれより古い場合は、測定値の代わりに「None」が返されます。

条件付き機能の設定ガイド~

これらの条件付き機能は、Python 3の環境で実行されます。Pythonコード内では、以下の関数を使用できます。

Note

Pythonコードのインデントには、必ず半角スペース4つを使用してください(半角スペース2つ、タブなどは使用できません)。

以下は、条件付き機能で使えるサンプルの一部です。それぞれの self.condition("ID") は、その条件についての最新の測定値を返しますが、値が返されるのは設定した最大経過時間の範囲内にある場合だけです。

# 例1: 測定値がNoneの場合
# 入力が正常に動作していないときにメール通知アクションを実行するのに便利です。
if self.condition("asdf1234") is None:
    self.run_all_actions()  # すべてのアクションを実行

# 例2: 2つの測定値の条件をテストする
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    # 両方の測定値がNoneでない場合
    if measure_1 < 20 and measure_2 > 10:
        self.run_all_actions()  # すべてのアクションを実行

# 例3: 2つの測定値とその合計をテストする
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    sum_ = measure_1 + measure_2
    if measure_1 > 2 and 10 < measure_2 < 23 and sum_ < 30.5:
        self.run_all_actions()

# 例4: 条件を組み合わせる
measurement = self.condition("asdf1234")
if measurement is not None and 20 < measurement < 30:  # 条件を組み合わせる
    self.run_all_actions()

# 例5: 2つの測定値をテストする
# Edge入力を0または1からTrueまたはFalseに変換する
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    if bool(measure_1) and measure_2 > 10:
        self.run_all_actions()

# 例6: "or" 条件と、四捨五入した測定値のテスト
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    if measure_1 > 20 or int(round(measure_2)) in [20, 21, 22]:
        self.run_all_actions()

# 例7: selfを使って、実行のたびに変数を保持する
measurement = self.condition("asdf1234")
if not hasattr(self, "stored_measurement"):  # 変数を初期化する
    self.stored_measurement = measurement
if measurement is not None:
    if abs(measurement - self.stored_measurement) > 10:
        self.run_all_actions()  # 差が10より大きい場合
    self.stored_measurement = measurement  # 測定値を保存する

「測定値(複数)」条件は、最後の測定値だけでなく、設定した最大経過時間の範囲内で過去に特定の値が発生したかどうかを調べたいときに便利です。これは、たとえば各数値が別々のアラートを表すアラートシステムにおいて、その特定の値が過去の値の中に存在したかどうかを確認する場合などに使えます。以下は、過去30分間(最大経過時間: 1800秒)のすべての測定値を取得し、返されたリストの中に「119」のような値が存在するかどうかを確認する例です。「119」が存在すればアクションが実行され、breakfor ループを抜けます。

# 例1: 過去30分間の測定値の中から特定の値を探す(最大経過時間: 1800秒)
measurements = self.condition_dict("asdf1234")
if measurements:  # リストが空でない場合
    for each_measure in measurements:  # リスト内の各測定値を順に処理する
        if each_measure['value'] == 119:
            self.logger.info("Alert 119 was found at timestamp {time}.".format(
                time=each_measure['time']))
            self.run_all_actions()
            break  # forループを抜ける

より高度な 実行するPythonコード の例:

以下の例は、上記の基本的な例を発展させ、特定のアクションを実行するようにしたものです。これらの例では、条件付き機能の Actions セクションにあるIDを参照するアクションを使用しています。ここでは "qwer1234" と "uiop5678" という2つのサンプルのアクションIDを使用します。また、ここでは self.run_all_actions() が使われており、これは作成した順にすべてのアクションを実行します。

# 例1
measurement = self.condition("asdf1234")
if measurement is None:
    self.run_action("qwer1234")
elif measurement > 23:
    self.run_action("uiop5678")
else:
    self.run_all_actions()

# 例2: 2つの測定値をテストする
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    if measure_1 < 20 and measure_2 > 10:
        self.run_action("qwer1234")
        self.run_action("uiop5678")

# 例3: 2つの測定値とその合計をテストする
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    sum_ = measure_1 + measure_2
    if measure_1 > 2 and 10 < measure_2 < 23 and sum_ < 30.5:
        self.run_action("qwer1234")
    else:
        self.run_action("uiop5678")

# 例4: 1つの条件にまとめる
measurement = self.condition("asdf1234")
if measurement is not None and 20 < measurement < 30:
    self.run_action("uiop5678")

# 例5: 2つの測定値をテストし、Edge入力を0/1からTrue/Falseに変換する
measure_1 = self.condition("asdf1234")
measure_2 = self.condition("hjkl5678")
if None not in [measure_1, measure_2]:
    if bool(measure_1) and measure_2 > 10:
        self.run_all_actions()

# 例6: "or" 条件と、四捨五入した測定値のテスト
measure_1 = self.measure("asdf1234")
measure_2 = self.measure("hjkl5678")
if None not in [measure_1, measure_2]:
    if measure_1 > 20 or int(round(measure_2)) in [20, 21, 22]:
        self.run_action("qwer1234")
        if measure_1 > 30:
            self.run_action("uiop5678")

アクションがメッセージを受け取る種類のもの(E-Mailやノートなど)である場合、そのメッセージに追加の情報を含めるよう変更できます。これにより、ノートやE-Mailなどとして配信される前に、新しい情報を機能へ渡すことができます。これを行うには、変数 self.message に文字列を追加し、それを self.run_action()self.run_all_actions()message パラメータに渡します。以下にいくつか例を示します。変数 self.message に文字列を追記するために = ではなく += を使っている点に注目してください。これにより、既存の値を上書きすることなく追記できます。

# 例1
measurement = self.measure("asdf1234")
if measurement is None and measurement > 23:
    self.message += "The measurement is {}".format(measurement)
    self.run_action("uiop5678", message=self.message)

# 例2
measure_1 = self.measure("asdf1234")
measure_2 = self.measure("hjkl5678")
if None not in [measure_1, measure_2]:
    if measure_1 < 20 and measure_2 > 10:
        self.message += "Measurement 1: {m1}, Measurement 2: {m2}".format(
            m1=measure_1, m2=measure_2)
        self.run_all_actions(message=self.message)

self.logger を使うと、ログ機能を使ってデーモンログにメッセージを記録することもできます。ログレベルには "info"、"warning"、"error"、"debug" があります。デバッグ用のログ行は、入力のログレベルが「デバッグ」に設定されている場合にのみデーモンログに表示されます。

# 例1
measurement = self.measure("asdf1234")
if measurement is None and measurement > 23:
    self.logger.error("Warning, the measurement is {}".format(measurement))
    self.message += "The measurement is {}".format(measurement)
    self.run_action("uiop5678", message=self.message)

条件付き機能を有効化する前に、想定されるすべてのシナリオを十分に検討し、競合が起きない構成をあらかじめ計画しておくことを推奨します。デバイスや出力によっては、急にオン・オフを繰り返すと異常な反応を示したり、故障したりすることがあります。そのため、デバイスを出力に接続する前に、その構成でのドライラン(試運転)を行ってください。

トリガー~

トリガーコントローラーは、出力のオン/オフ、GPIOピンの電圧状態の変化(エッジ検出、立ち上がりまたは立ち下がり)、時間イベント(継続時間・時間間隔・特定時刻などさまざまなタイマーを含む)、あるいは特定の緯度・経度における日の出/日の入り時刻のようなイベントがトリガーされたときにアクションを実行します。トリガーを設定したら、そのイベントがトリガーされたときに実行したいアクションを好きなだけ追加できます。

出力(オン/オフ)オプション~

出力の状態を監視します。

設定 説明
出力条件 状態の変化を監視する出力です。
状態条件 出力の状態がオンまたはオフに変化したときに条件がトリガーされます。「オン(継続時間を問わない)」を選択すると、出力がどれだけの時間オンになっていても条件がトリガーされますが、「オン」のみを選択すると、出力が設定した「継続時間(秒)」の間オンになっている場合にのみ条件がトリガーされます。
継続時間条件(秒) 「オン」を選択した場合、出力が特定の継続時間(秒)オンになっている場合にのみ条件がトリガーされるよう設定できます。

出力(PWM)オプション~

PWM出力の状態を監視します。

設定 説明
出力条件 状態の変化を監視する出力です。
状態条件 出力のデューティサイクルが設定した値より大きい・小さい・等しいときに、条件付きアクションがトリガーされます。
デューティサイクル条件(%) 出力のデューティサイクルと比較する基準値です。

エッジオプション~

ピンの状態の立ち上がりエッジ・立ち下がりエッジを監視します。

設定 説明
エッジ検出 状態の変化が検出されたときに条件がトリガーされます。状態がLOW(0ボルト)からHIGH(3.5ボルト)に変化する立ち上がりエッジ、HIGH(3.3ボルト)からLOW(0ボルト)に変化する立ち下がりエッジ、または両方のいずれかを選択できます。

PWMメソッド実行オプション~

継続時間メソッドを選択すると、選択したPWM出力が、そのメソッドで指定されたデューティサイクルに設定されます。

設定 説明
継続時間メソッド 使用するメソッドを選択します。
PWM出力 使用するPWM出力を選択します。
周期(秒) デューティサイクルを計算し、PWM出力に適用するまでの時間間隔を選択します。
周期ごとにトリガー 周期ごとに条件付きアクションをトリガーします。
有効化時にトリガー 条件付き機能が有効化されたときに条件付きアクションをトリガーします。

Note

「有効化時にトリガー」は、有効化または設定の再読み込みの後、トリガーが次に確認を行うタイミングで発火します。実際に有効化・再読み込みが起きた瞬間ではなく、最大でもサンプル間隔1回分(デーモンが一般的なトリガー/条件付き機能の確認に使う周期)だけ遅れます。これを同期的に発火させていた頃は、設定の再読み込み中にトリガーがまれに行き詰まり、二度と発火しなくなるデッドロックのおそれがありました。

選択した継続時間メソッドにまだ値がない場合(たとえば有効化された直後で、メソッドがまだ開始時刻を記録していない場合)、PWM出力には壊れたコマンドを送るのではなく、そのまま何もせず残します。トリガーは次の周期を待って、あらためて試みるだけです。出力側が計算結果は受け付けたもののコマンド自体を拒否した場合(オフライン、タイムアウトなど)は、その拒否が今はエラーとしてログに記録されます。設定値の曲線は、出力に到達できたかどうかにかかわらず、そのまま進み続けます。

日の出/日の入りオプション~

緯度・経度にもとづいて、日の出または日の入り(またはそのオフセット時刻)にイベントをトリガーします。

設定 説明
日の出または日の入り 条件付き機能をトリガーするタイミングを選択します。日の出または日の入りのいずれかを選択します。
緯度(十進数) 日の出/日の入りを計算する緯度を10進数の形式で入力します。
経度(十進数) 日の出/日の入りを計算する経度を10進数の形式で入力します。
天頂角 太陽の天頂角を設定します。
日付オフセット(日) 日の出/日の入り時刻の日付オフセットを設定します(正・負どちらも可)。
時間オフセット(分) 日の出/日の入り時刻の時間オフセットを設定します(正・負どちらも可)。

タイマー(期間)オプション~

設定した周期ごとに条件付きアクションをトリガーするタイマーを実行します。

設定 説明
周期(秒) 条件付きアクションがトリガーされる時間間隔(秒)です。
開始オフセット(秒) 条件付き機能が有効化されてから、最初のトリガーが実行されるまでに待機する時間(秒)です。

タイマー(毎日の特定時刻)オプション~

毎日、特定の時刻に条件付きアクションをトリガーするタイマーを実行します。

設定 説明
開始時刻(HH:MM) 条件付きアクションをトリガーする時刻を「HH:MM」の形式で設定します。HHは時、MMは分で、24時間表記で入力します。

タイマー(毎日の時間帯)オプション~

設定した開始時刻と終了時刻の間、特定の周期で条件付きアクションをトリガーするタイマーを実行します。たとえば開始時刻を10:00、終了時刻を11:00、周期を120秒に設定すると、10:00から11:00の間、120秒ごとに条件付きアクションがトリガーされます。

これは、出力を特定の時間帯の間ずっとオンにしておく必要があり、かつ単純な特定時刻タイマーのサイクルが停電によって中断されないようにしたい場合に便利です。たとえば開始時刻から終了時刻までの間、数分おきに出力をオンにするよう設定しておくと、その時間帯の間、出力の状態を維持しやすくなります。

設定 説明
開始時刻(HH:MM) 条件付きアクションをトリガーする開始時刻を「HH:MM」の形式で設定します。HHは時、MMは分で、24時間表記で入力します。
終了時刻(HH:MM) 条件付きアクションをトリガーする終了時刻を「HH:MM」の形式で設定します。HHは時、MMは分で、24時間表記で入力します。
周期(秒) 条件付きアクションがトリガーされる時間間隔(秒)です。

トリガー - シーケンス~

シーケンス は、複数の出力デバイス(バルブ、ポンプ、照明など)を、決まった順序とタイミングで自動的にオン・オフする機能です。「バルブAを30分開いて、次にバルブB、それからバルブC」というように、段階を追って進む作業を、人の手でひとつずつ操作する代わりに自動化したいときに使います。かん水サイクルや、多段階の換気(開口部を開ける → 待機 → ファンを動かす)などで特に役立ちます。

設定例: メインポンプ + 直列につながる3つのバルブ~

もっとも一般的な使用例を見てみましょう。メインのかん水ポンプが1台と、順番に3つのゾーンへかん水するバルブA・B・Cがあるとします。実現したいのは次のような動作です。

  • ポンプ は、かん水が実行されている間、最初から最後まで継続してオンのままにしておく。
  • バルブA → B → C の順に、それぞれ30分間ずつ動作させ、そのあと自動的にオフにする。

これを設定する手順は次のとおりです。

  1. 機能の一覧から、新しい シーケンス を追加します。
  2. アクションを追加 で「出力: オン/オフ/継続時間」を選び、メインポンプの出力を選んで追加します。モードは 全体(Total) に設定します。これは、シーケンス全体が実行されている間ずっとオンでなければならないデバイスのためのモードです。
  3. バルブA・B・Cをこの順番で追加します。それぞれのモードは 単独(Single) にし、継続時間は1800秒(30分)に設定します。
  4. 保存すると、追加した順序どおりに各ステップが実行されます(ウィジェット上でドラッグして並び替えることもできます)。

時間の経過にともなう動作は、次のようになります。

経過時間 0~30分 30~60分 60~90分
ポンプ(全体) ON ON ON
バルブA(単独) ON → OFF
バルブB(単独) ON → OFF
バルブC(単独) ON → OFF

全体(Total) モードのパターンは、ほかのすべてのステップが終わるまでオンのままでなければならないデバイス1台(多くの場合メインポンプ)のためのものです。残りのステップは 単独(Single) モードで、順番に1つずつ実行されます。

初期設定のままにしておくと、ポンプはバルブAと まったく同じ瞬間 にオンになり、バルブCと同じ瞬間にオフになります。閉じたバルブに対してポンプを先に動かしたり、ポンプが動いたままバルブを閉じたりすると配管に負担がかかるため、ポンプのステップに 余裕時間(開始遅延/早期停止) を持たせ、ポンプの区間をバルブの区間の内側に収めることを推奨します。詳しくは下記の余裕時間を参照してください。

設定例: 複数のバルブを同時に開く~

上の例で、バルブBとCを順番にではなく 同時に 開きたい場合はどうすればよいでしょうか。この場合は、2つのステップを デバイスグループ にまとめます。ウィジェットまたは統合モーダルで、両方のバルブのグループ欄に同じ名前(たとえば zone2)を入力すると、2つのバルブが1つのスロットにまとめられ、同時にオン・オフするようになります。

経過時間 0~30分 30~60分
ポンプ(全体) ON ON
バルブA(単独) ON → OFF
バルブB+C(グループ zone2 ON → OFF(同時)

このように、順次実行するステップ(ポンプや単独のステップ)と、同時実行するステップ(デバイスグループ)を自由に組み合わせて使うことができます。グループ化されたバルブは1つの継続時間を共有します。詳しいルールは、下記のデバイスグループを参照してください。

モード: 単独 vs. 全体~

  • 単独(Single、既定): 各ステップに、それぞれ独立した継続時間を適用します。
    • 計算式: 合計の動作時間 = 先頭オーバーラップ + 基本継続時間 + 末尾オーバーラップ
    • 動作: 前のステップが終わる オーバーラップ 秒前に次のステップが開始し、スムーズな切り替えを実現します(たとえば、現在のバルブを閉じる数秒前に次のバルブを開いておくことで、配管の圧力が急に下がらないようにします)。
  • 全体(Total、フルスパン): 上のポンプの例のように、シーケンス全体が実行されている間ずっとオンでなければならないステップに使います。シーケンスの開始から最後の 単独 ステップが終わるまで保持され、余裕時間 によってその区間を両端から狭めることができます(下記参照)。

余裕時間: ポンプをバルブの内側に収める~

全体(Total) モードのステップは、初期設定ではサイクルの0秒目にオンになり、最後のステップと同時にオフになります。つまり、最初のバルブとポンプが同じ瞬間にオンになり、最後のバルブとポンプが同じ瞬間にオフになるということです。実際のかん水では、この順序が重要です。

  • バルブが開く前にポンプが動くと、ポンプがそのまま全圧を受けてしまいます。
  • ポンプが動いたままバルブが閉じると、水撃(ウォーターハンマー)が発生します。

全体モードのステップには、これに対応するための値が2つ用意されています。どちらも単位は秒で、初期値はいずれも0です(これまでの動作と同じです)。

内容
開始遅延total_lead シーケンスの開始からこの秒数だけ経過してからオンにします。その間にバルブが先に開きます。
早期停止total_lag シーケンスが終わるこの秒数前にオフにします。バルブが閉じる前に圧力が抜けます。

90分のサイクルで、開始遅延10秒・早期停止15秒を設定した場合、次のようになります。

開始 終了
バルブ(すべての単独ステップ) 0秒 5400秒
ポンプ(全体) 10秒 5385秒

ポンプの区間はバルブの区間の内側に完全に収まるため、常に「バルブが開く → ポンプが動く … ポンプが止まる → バルブが閉じる」という順序が保たれます。停止時にも、同じ理由から全体モードのステップが他より先にオフになります。

これを設定できる場所は2か所あり、どちらもモードが 全体 に設定されているステップにのみ、該当する項目が表示されます。

  • 機能設定画面のステップ行: モードを 全体 に切り替えると、開始遅延早期停止 の欄が表示されます。
  • ダッシュボードのシーケンスウィジェット: ステップ名をクリックして開く設定ダイアログの 余裕時間(秒)

余裕時間の合計がサイクル自体より長く、ポンプがまったく動作できなくなる場合は、その設定は無視されて全区間が使われ、警告がログに記録されます。

その他の主要な概念~

  • 動的な継続時間: action_duration_id オプションを使うと、特定の入力の測定値を実行時間として使うことができます。
    • 形式: Input_UUID または Input_UUID,Measurement_UUID
    • 有効性: time_offset_minutes の範囲内にある最新の測定値のみが使われます。存在しない場合は、設定した基本の action_duration が使われます。
  • オーバーラップ: output_duration の設定は、ステップ間の切り替え時間を決めます。最初のアクションには 末尾オーバーラップ のみ、途中のアクションには 先頭オーバーラップ末尾オーバーラップ の両方、最後のアクションには 先頭オーバーラップ のみが適用されます。
  • 制約(実行可能な時間帯とレイテンシ):
    • 実行可能な時間帯: シーケンスは timer_start_time から timer_end_time までの間でのみ開始・実行されます。この範囲外では強制的に終了します。
    • 開始レイテンシ: トリガー(有効化)から実際にシーケンスが開始するまでの待機時間(timer_start_offset)を秒単位で設定します。

設定項目リファレンス~

設定キー 説明
period シーケンス全体のサイクルが繰り返される周期です(秒単位)。
output_duration アクション間のオーバーラップ時間です(秒単位)。
timer_start_offset 有効化からシーケンス開始までの遅延です。
time_offset_minutes 動的な継続時間の測定値が有効とみなされる最大経過時間です(分単位)。
enabled 個々のアクションが有効かどうかです。
sequence_mode 'single' または 'total' を選択します。
total_lead (全体モードのみ) シーケンスの開始からこの秒数だけ経過してからオンにします。初期値は0です。
total_lag (全体モードのみ) シーケンスが終わるこの秒数前にオフにします。初期値は0です。
action_duration そのステップの基本の実行時間です(秒単位)。
action_duration_id 動的な実行時間を取得する対象のデバイス/測定値のIDです。
group_name デバイスグループの名前です。同じ名前を持つステップは1つのスロットにまとめられ、同時に動作します(下記参照)。空欄の場合、そのステップは単独で動作します。
display_name ウィジェットの一覧に表示するカスタムラベルです。空欄の場合はデバイス名が使われます。

デバイスグループ(同時動作)~

上の例で示したように、複数のステップを 1つのデバイスグループ にまとめると、それらは順番にではなく 同じ時間帯の中で同時に 動作するようになります。詳しいルールは以下のとおりです。

  • グループ化の方法: ウィジェットまたは統合モーダルでステップ名をクリックし、グループ欄に同じグループ名を入力します。同じ名前を持つステップは1つのスロットにまとめられます。グループ欄を空にすると、そのステップはグループから外れ、単独動作に戻ります。
  • 共通の継続時間(先頭メンバーからの継承): グループは1つの共通した動作時間を共有します。あるステップが既存のグループに加わると、そのグループの共通の action_duration(および動的な継続時間を読み取る action_duration_id)を自動的に継承します。スロットの代表(もっとも早い位置にあるメンバー)が、グループ全体の継続時間と動的な参照元を決定します。
  • 実行順序: スロットの順序は、それぞれのグループが最初に現れた位置にしたがいます。すでにあるグループの後から加わったメンバーは、新しいスロットを作らず、そのグループの既存のスロットに合流します。
  • 制約: total(フルスパン)モードのステップはグループ化できません。グループは本質的に single(同時・単独)モードです。

週間スケジュール~

開始・終了時刻を1組だけ設定する代わりに、曜日ごとに異なる稼働時間と周期 を設定することもできます。このスケジュールは Trigger.timer_schedule にJSON形式で保存され、2つのモードに対応しています。

  • shared モード: すべての曜日が、1組の開始・終了時刻・周期を共有します。有効にする曜日だけを選択します(これまでの動作と同じです)。
  • per_day モード: 月曜から日曜まで、曜日ごとに独立した開始(start)・終了(end)・周期(period)・有効/無効(enabled)を持ちます。さらに、曜日ごとに以下の項目を個別に上書きできます。
    • actions: 曜日ごとのステップの有効/無効(全体設定の enabled フラグを上書きします)。
    • groups: 曜日ごとのデバイスグループへの所属(全体設定の group_name を上書きします)。空文字列は「その曜日はグループから除外する」ことを意味します。
    • durations: 曜日ごとの動作時間(全体設定の action_duration を上書きします)。

時間に関するルール:

  • 曜日のインデックスはPythonの慣例にしたがいます: 0=月、1=火、…6=日。
  • 時刻は デバイスのローカルタイムゾーン における実時計の HH:MM です。
  • 終了時刻の 24:00 は「その日の終わり」を意味し、内部的には1440分として保存されます。
  • 深夜をまたぐ時間帯(start >= end)は許可されません。各曜日は 00:0024:00 の範囲内でのみ動作します。
  • 深夜をまたぐ連続性: 前日の終了時刻が 24:00 で、翌日の開始時刻が 00:00 であり、両方の曜日が有効になっていて、かつ日付として連続している場合、デーモンは深夜にサイクルをリセットせず、そのまま継続して動作します。

Note

周期(period)がその曜日の稼働時間帯の長さより長い場合、サイクルはその時間帯の中で途中までしか進まず打ち切られます。この場合、設定画面には警告が表示されます。

時間帯が終わるまでに残された時間が、1回分のサイクルを完了させるのに足りない場合、そのサイクルは開始されずにスキップされます。以前はそれでも開始されていたため、バルブが開いたものの時間帯が終わるタイミングで打ち切られることがありました。そして、そのように打ち切られたステップはオン時間を記録しないため、実際にどれだけ水が与えられたかを知る手立てがありませんでした。

時間帯の長さとちょうど1回分のサイクルの長さが一致する場合、最後のステップの終了と時間帯の終了が同じ瞬間になります。この際、時間帯の確認処理が先に働いてしまうと、ステップは自力で終わる前にオフにされてしまい、オン時間が記録されません。そのため、まもなく終わろうとしているステップには、正常に終了できるよう数秒の猶予が与えられます。まだ時間が残っているステップについては待機しません。それは自然な終了ではなく、正真正銘の打ち切りであり、待ってしまうと時間帯を超過するだけだからです。

シーケンスをオフにすると、その場で即座に停止します~

機能一覧やウィジェットからシーケンスを無効化すると、実行中の制御はその場で停止し、その瞬間に開いていたステップは正常な手順でクローズされます。次の時間帯が来ても、再び自動で開始することはありません。

要求が制御デーモンまで届かなかった場合、画面には、シーケンスがまだ動作中である旨が表示されます。バルブが動き続けたまま設定だけが保存されてしまうことがあるため、しばらくしてから再試行するか、出力を直接確認してください。以前はこのケースでも「保存しました」と表示されてしまい、画面上ではシーケンスがオフに見えるのに、実際にはかん水が続いているという状態になっていました。

Warning

per_day モードでは、ウィジェットから周期を変更すると、その変更はその日にしか適用されません。 ウィジェットに表示される周期は今日の値であるため、ほかの曜日はそれぞれの設定を保ったままになります。曜日ごとに個別に設定するには、その曜日を選択した状態で周期を変更するか、統合モーダルの曜日別設定を使用してください。

再有効化したとき: 続きから動くか、最初からやり直すか~

シーケンスをオフにしてから再びオンにすると、既定では停止した位置から続きが実行されます。これは、一時的に中断された実行を、望みどおり再開できる動作です。設定を変更してすべてを最初からやり直したい場合は、シーケンスウィジェットのオプションにある 再度オンにしたとき を「最初から開始」に設定してください。

再びオンにしたときの動作
停止した位置から再開(既定) 中断されたサイクルを、残りのステップから再開します
最初から開始 最初のステップから実行します

「続きから」の設定であっても、1周期分より長く中断されたサイクルは、再開すべき対象が残っていないため、新規に開始されます。

Note

デーモンの再起動は、この設定の影響を受けません。 システムの更新や再起動による制御の一時停止は、利用者がオフにしたわけではないため、進行中のかん水はそのまま継続します。この設定が対象とするのは、あくまで人によるオン・オフの操作だけです。

Note

本当の意味での再起動のあとに始まる最初のサイクルは、決まった時刻の区切りではなく、まさに「今」を起点として開始されます。 これが当てはまるのは、引き継ぐべき前のサイクルが存在しない場合(まったく新規のシーケンスの場合や、「最初から開始」で前のサイクルがクリアされたあとに再有効化した場合)のみです。以前はこのケースでも、同日中のサイクルが表流しないようデーモンが使っている、あの決まった時刻の区切り(上記の「開始されずにスキップされる」サイクルについての注記を参照)を起点にしてしまっていました。そのため、時間帯の途中でシーケンスをオンにすると、新しいサイクルがすでに何時間も経過しているものとして計算され、その中のすべてのステップがすでに終わったものとして扱われてしまうことがありました。前のサイクルの状態が存在する場合は、たとえ再開するには古すぎる状態であっても、デーモンは引き続きその時刻の区切りを起点にします。これは、そのケースが「利用者がシーケンスをオンにしただけ」ではなく「デーモンが停止していた」ことを意味するためです。

共通 ↔ 曜日別の切り替え~

曜日別から共通モードに戻すと、最初に有効な曜日 の設定が共通の値として昇格します。これは開始・終了・周期といった時間帯だけでなく、その曜日のデバイスグループと各ステップの継続時間も含まれます。共通モードは曜日別のマップを一切読み込まないため、ボタンを押した瞬間に、それ以外の内容はすべて失われてしまいます。

基準となる曜日は、時間帯の場合と同じルール(最初に有効な曜日)にしたがいます。ほかの曜日に設定していた差分は保持されないため、どの曜日を共通の基準にするかは、切り替える前に決めておいてください。

設定モーダルは、常に今の値を表示します~

開始・終了時刻、周期、日をまたぐ時刻、再開時の挙動は、このウィジェット以外の経路、たとえば曜日別スケジュールエディター(時刻ホイール)や機能の設定ページからも変更できます。そうした変更はかん水にすぐさま反映され、このウィジェットの設定モーダルは、ダッシュボードを開くたびにそれらの値を読み直します。以前どこかで保存した値のまま、このウィジェットをあらためて保存するまで固定されている、ということはありません。以前は、すでに曜日別スケジュールが使われている状態で機能の設定ページから開始/終了時刻や周期を編集すると、成功したと表示されるにもかかわらず、実際にデーモンが従っているスケジュールは変わらないままになることがありました。現在はどの保存経路でも、同じ内部スケジュールに書き込まれます。

Note

曜日別モードでは、機能そのものの設定ページにある開始/終了時刻・周期の欄も、同じ理由(1つの共通の値を設定すると曜日別の設定が消えてしまうため)で反映されません。そこで保存しようとすると、以前のように黙って「成功しました」と表示するのではなく、その旨が伝えられるようになりました。曜日別の時刻は、代わりにシーケンスウィジェットのステップ一覧から編集してください。

ステップ の設定(継続時間、デバイスグループ、曜日ごとのオン/オフ)をシーケンスの実行中に変更した場合、その変更は次のサイクルだけでなく、現在進行中のサイクルにも反映されます。以前はこうした変更が次のサイクルが始まるまで反映されず、周期が長い場合には何時間も先になることがありました。それにもかかわらず、設定画面ではすぐに保存されたと表示されていました。実行中の変更が誤作動しないよう、2つの安全策が設けられています。今回のサイクルですでに終わったステップは、前のステップを短縮したことでタイミングがずれ、あらためて実行対象になったとしても、再びオンになることはありません。また、今日の予定から外れたステップ(その日はオフにされた、または削除された)は、追跡対象から単に外れるのではなく、明示的にオフにされるため、その出力が誰にも気づかれないまま開いたままになることはありません。

深夜をまたぐ時間帯(同じ日の中で終了時刻が開始時刻より早い設定)は、保存しようとした時点で、理由の説明とともに拒否されます。以前は機能の設定ページからこのような時間帯を保存できてしまい、デーモン側では結局、同日内に切り詰められた時間帯にフォールバックし、曜日別設定の残りの部分は黙って破棄されていました。

Note

シーケンスウィジェット自体の設定ダイアログには、開始時刻・終了時刻を直接入力するテキスト欄はもうありません。これらは、曜日別スケジュールがひとたび使われるようになると正しく機能しなくなっていたため、開始・終了時刻は、下記の統合モーダルにある時刻ホイールからのみ設定するようになっています。

統合モーダルと時刻ホイール~

時刻・グループ・名前・曜日別スケジュールは、シーケンスウィジェットのステップ一覧にある 1つの統合モーダル から編集します。

  • ステップ名をクリックすると、表示名(display_name)、モード(single/total)、デバイスグループをまとめて編集できるモーダルが開きます。
  • 開始・終了時刻は 時刻ホイール コンポーネントで入力するため、モバイル端末でも時・分を正確に選択できます。
  • 従来の開始/終了/曜日の各列は、スケジュールが保存されるたびに自動的に同期される(下位互換のため)ため、スケジュールを使わない古い画面でも、代表的な値はそのまま保たれます。

統合環境制御 - 育苗場モード~

統合環境制御は、登録されたすべてのアクチュエーターをVPDの目標値に合わせて協調させる機能です。このセクションでは育苗場モードのオプションのみを扱います。それ以外のオプションについては、機能自体の設定ページを参照してください。

育苗の苗を特別に扱う必要がある理由~

噴霧は、温度を下げると同時に湿度を上げるため、VPDをもっとも速く下げる手段です。そのため、コーディネーターはVPDが上昇するたびに、まず噴霧に頼ろうとします。

難しいのは、VPDが最大になるタイミングが、太陽がもっとも高くなるタイミングと重なることです。生育の進んだ作物であれば、これは問題になりません。葉が濡れることに耐えられますし、気化冷却もむしろ歓迎されます。しかし、発芽したばかりの苗にはまだクチクラ層がないため、強い日差しの下で子葉に残った水滴が光を集めてレンズのように葉に焦点を結ばせ、乾く際には溶けていた塩類を濃縮させてしまいます。その結果、葉が焼けてしまうのです。

育苗場モードはVPDの目標値そのものを変更しません。変更するのは、その目標値に到達するためにどのアクチュエーターを使ってよいかという点で、日差しが強い時間帯には噴霧の優先順位を下げ、遮光や換気を先に使うようにします。

育苗場モードの設定~

設定 説明
育苗場(苗)モード 以下の保護機能を有効にします。ノズルが「濡らすタイプ」に該当するかどうかは、施設図面のノズル配置(流量、散水半径、噴射方向)から判断されるため、ここでノズルの仕様を入力する必要はありません。点滴配管や、本物の高圧ミストは対象外です。
噴霧遮断日射量(W/m²) この値以上の室内光量になると、濡らすタイプの噴霧が完全に遮断されます。室内光量は推定値が使われるため、遮光スクリーンを閉じると遮断が緩和されます。
噴霧解除日射量(W/m²) 光量がこの値を下回ると噴霧が再び許可され、この値と遮断のしきい値との間では直線的に弱められます。2つのしきい値の間に幅を持たせることで、雲の通過などで噴霧が入り切りを繰り返すのを防ぎます。
最大噴霧時間(秒) 1回あたりの噴霧の最大時間です。加湿は、噴霧の長さではなく頻度によって調整されます。これは、かん水が一定間隔で決まった量を与えるのと同じ考え方です。
強制乾燥間隔(秒) 噴霧が終わってからこの時間が経つまでは、まったく噴霧を行いません。これにより、葉が乾く時間を確保します。
日没前の噴霧を許可 かん水は通常、日の出・日の入りの前後に行われますが、夕方の噴霧は葉を濡れたまま夜に持ち越してしまい、葉が濡れている時間が長いほど灰色かび病やべと病のリスクが高まります。これをオフにすると、日没前の噴霧を止めることができます。作物によっては夕方のかん水が必要な場合もあるため、選択は利用者に委ねられています。この設定は湿度管理のための噴霧のみを対象とし、同じバルブに設定された別のかん水スケジュールには影響しません。
日没前の噴霧停止時間(分) 上記のオプションがオフのとき、日没の何分前に噴霧を止めるかです。噴霧は次の日の出まで遮断されたままになります。多くの場合、日が暮れるまでに葉を乾かすには2時間あれば十分です。日没の時刻は施設の地図上の位置から算出されます。座標が特定できない場合、噴霧は遮断されません。
噴霧原水 未処理の地下水は硬度が高く水温が低いことが多いため、水滴が乾く際に塩類が濃縮して残り、日射を受けた葉に低温ショックを与えることがあります。これを選択すると、遮断のしきい値が自動的に下げられます。

パルス状の噴霧~

ミスターをパーセンテージで駆動すると、各サイクルのその割合だけずっと噴霧し続けることになり、葉が乾く時間がまったくなくなってしまいます。そのため、濡らすタイプのミスターは、育苗場モードのオン/オフに関わらず、常に短いパルスと強制的な間隔に分割されます。生育の進んだ作物であっても、連続した噴霧は病害を招くためです。育苗場モードは、単にその数値をより厳しくするだけです。葉に届く前に蒸発する高圧ミストや点滴配管は、通常どおりの連続的な調節のままです。

補足~

噴霧の遮断は、高温時の緊急対応と最小湿度制限のどちらよりも優先されます。真夏の正午は、高温緊急対応が作動するタイミングであると同時に、焼け付きのリスクがもっとも高まるタイミングでもあり、湿度の目標を満たすことよりも苗を守るほうが重要だからです。止まるのは噴霧だけで、換気口・スクリーン・ファンは通常どおり動作を続けます。

この保護機能は、苗が順化していくのに合わせて段階的に緩めていくべきもので、一度に解除すべきではありません。日中の噴霧をまったく行わない状態から、一気に日中の噴霧を全開にしてしまうと、まだわずかにしか準備ができていない苗に対して、まさにこのモードが防ごうとしていた状況を再現してしまうことになります。

日焼けとされる被害の一部は、光ではなく水そのものに原因があります。硬水はミネラル分の跡を残し、冷たい水は日差しを受けた葉に低温ショックを与え、鉄分による斑点は日焼けとほとんど見分けがつきません。希釈した酸で跡をふき取ってみれば見分けがつきます。色が薄くなれば鉄分によるものです。水そのものが悪ければ、どんな制御設定でも解決できません。

1台のデバイスでかん水と加湿の両方をまかなう場合~

育苗場では、かん水と加湿の両方を同じ一群のオーバーヘッドスプリンクラーでまかなうことがよくあります。そうしたノズルを統合環境制御にゆだねると、かん水と競合してしまいます。コーディネーターは、現在使っていないアクチュエーターに対しても、周期ごとに「オフのままにする」というコマンドを送るため、別のかん水コントローラーがバルブを開いても、次の周期でまた閉じられてしまうことがあります。このコマンドは夜明けにもっとも確実に送られますが、それはちょうど加湿がまったく必要とされていないタイミングです。

水の振る舞いも異なります。かん水用に設計されたスプリンクラーは、加湿に必要な量よりはるかに多くの水を出すため、これを短い加湿用の噴霧に使うと、葉の上には薄い水の膜しか残りません。この膜は流れ落ちることができず、その場で乾いて、水に含まれていたものをすべて残していきます。一方、朝にたっぷりとかん水を行うとその逆のことが起こり、ほとんどの水が流れ落ちて、それまでの散布で残っていたものを洗い流します。同じ水、同じノズルでも、結果はまったく逆になるのです。

加湿に濡らすタイプの噴霧を使用 をオフにすると、統合環境制御はそれらのノズルにいっさいコマンドを送らなくなります。ノズルはすべてかん水スケジュールや土壌水分コントローラーに委ねられ、湿度はスクリーン・換気口・ファンで管理されます。葉に届く前に蒸発する本物の高圧ミストは、この設定に関わらず加湿用のアクチュエーターとして引き続き機能します。加湿器や点滴配管、そのほかのアクチュエーターも同様です。

これにより、真昼の加湿手段としての噴霧は使えなくなりますが、たいていの場合それは大きな損失にはなりません。遮光スクリーンをもう1枚引くだけで、水を使わず、塩類を残すこともなく、同程度の冷却効果が得られるからです。