ファームウェアエンジニアの井田です。前回 に引き続き、Node-RED でNature Cloud APIを触るお話です。
Node-REDのフローのデータ
本記事で使用しているNode-REDのフローのデータはこちらのリポジトリに置いてありますので、適宜参照してください。
Remo3/mini2のセンサデータの取得
前回までで、Node-REDから部屋の照明の点灯・消灯の制御ができるようになりました。 いよいよセンサによる自動化を行うために、Remo3/mini2に搭載されているセンサ情報の読み出しを行います。
センサデータの取得
Remo3/mini2のセンサデータは、 /1/devices
などで返ってくるデバイス情報の中にある newest_event
フィールドの中にあります。
newest_event
フィールドは、 {"val": 値, "created_at": "時刻"}
の形式の値を0個以上持つ配列です。
例えば、Remo3は、温度センサ、湿度センサ、輝度センサ、人感センサを持っているので以下のような値が返ってきます。
{ "name": "自宅Remo3", // (省略) "newest_events": { "hu": { "val": 50, "created_at": "2023-08-23T01:02:08Z" }, "il": { "val": 39, "created_at": "2023-08-23T01:20:34Z" }, "mo": { "val": 1, "created_at": "2023-08-23T01:20:03Z" }, "te": { "val": 28.1, "created_at": "2023-08-23T01:18:09Z" } } }
各フィールドの内容は次の通りです。
フィールド名 | valの内容 | 例 | 備考 |
---|---|---|---|
hu | 相対湿度(%) | 50 | |
il | 照度レベル (0~100) | 39 | |
mo | 人感センサ (値は常に1) | 1 | created_atのみ更新される |
te | 気温 (℃) | 28.1 |
人感センサ(mo
) の値 (val
) は常に 1
を返します。代わりにイベントの発生時刻である created_at
のみ人感センサに反応があった時刻に更新されます。
Remo mini2は温度センサのみなので、 te
フィールドのみ返ってきます。また Remo nanoの場合はセンサが無いのでなにも返ってきません。
ということなので早速センサ値を取得・抽出してみましょう。アクセスするのは /1/devices
ですので、前に作った devices
取得用のノードをコピーして、センサ情報抽出用のchangeノードをつけておきます。
センサー更新 injectノードは今まで通り、 GET https://api.nature.global/1/devices
にアクセスする設定です。
センサーデータ抽出 changeノードは、JSONata式をつかって /1/devices
からのレスポンスから、目的のセンサデータを抽出します。JSONata式の中身は以下の通りです。
デバイスIDの抽出処理での条件と同様に、まずはセンサデータ取得元のRemoを名前とユーザー名から特定します。その後、 .newest_events
フィールドのみを抽出します。
payload[ name="自宅Remo3" and users[ nickname="Kenta Ida" and superuser=true ] ].newest_events
最後に センサーデータ debugノードでは、抽出した newest_events
フィールドの内容を解析して、分かりやすい形で出力します。解析のためのJSONata式は次の通りです。
"室温 " & payload.te.val & " 湿度 " & payload.hu.val & (payload.mo.created_at ? " 人感 " & (($millis() - $toMillis(payload.mo.created_at))/1000) & "秒前" : "")
payload.te.val
と payload.hu.val
はそれぞれ抽出した newest_events
の te
および hu
フィールドの値を取得して表示しているだけです。
人感センサの場合は val
フィールドは常に 1
ですが、人感センサが反応した場合に created_at
が更新されます。
現在からどれくらい前に反応したかを扱うことが多いと思いますので、最後に反応した時刻からの経過秒数を計算しています。
$toMillis(payload.mo.created_at)
で最後に反応した時刻のUNIX Epoch 1 からのミリ秒単位の経過時間が求まるので、あとは現在時刻のUNIX Epochからのミリ秒単位の経過時間を返す $millis()
の値から引いたものを1000で割れば、現在時刻までの経過秒数が求まります。
ここまででデプロイして センサー更新injectノードを起動すると、センサーデータ debugノードにセンサ情報が表示されます。
センサデータで照明の自動化
ここまでで各種センサデータが取得できるようになったので、センサデータで条件分岐して照明を制御してみましょう。
まずは先ほどdebugノードの出力で使ったのと同様のJSONata式をつかって、人感センサの反応時刻で分岐するswitchノードを追加します。 分岐に使用する値を抽出するJSONata式は以下の通りです。
payload.mo.created_at ? (($millis() - $toMillis(payload.mo.created_at))/1000) : null
payload.mo.created_at
に値が設定されていれば、最後に人感センサが反応してからの経過秒数を計算します。センサの反応時間が不明の場合は null
とします。
センサの状態に応じた処理を一つだけ実行したいので、下の方にあるリストボックスで 最初に合致した条件で終了 を選択します。
照明をON/OFFするためのボタンを設定するchangeノードを2つ追加し、msg.payload
への設定値を on
off
それぞれの値に設定しておきます。またOFFにするchangeノードの入力をswitchノードの2番目の出力、ONにするchangeノードの入力をswitchノードの3番目の出力に接続しておきます。
これにより、対応する条件を満たしたときにそれぞれのノードが実行されます。
あとは、2つのchangeノードの出力を、前回作成した照明制御用ノード群の中のchangeノードの入力に接続すれば終わりです。
デプロイして実行すると、人感センサの反応があった時刻が120秒より前なら、照明が消えます。 人感センサの反応があった時刻が120秒以内なら、照明が点きます。
動作を確認したら、 センサーを更新injectノードの設定を変更して、30秒ごとに自動実行するようにします。これで30秒ごとに自動的にセンサー情報を取得して、人感センサの反応時刻に応じて照明を点灯・消灯できるようになりました。
エアコンの制御
エアコンの手動制御
さて、では本題のエアコンの制御をしましょう。
まずは手動でエアコンの制御をしてみます。エアコンの制御、つまり、温度設定や運転モード (冷房・暖房・除湿など)の切り替え、風量設定を行うためには、 POST /1/appliances/{applianceid}/aircon_settings
を使います。 APIの仕様はこちら
基本的には照明のときと同様に、パラメータをPOSTで送信するだけです。その前にまずはエアコンのアプライアンスIDを取得しておきます。
照明のときと同様に、エアコンの登録名をつかってIDを抽出し、 flow.acApplianceId
に保存しておきます。抽出用のJSONata式は、私の部屋の場合はエアコンの登録名がそのまま エアコン
なので以下のようになります。
payload[ nickname="エアコン" ].id
エアコンのパラメータとしては以下の項目があります。
名前 | 内容 | 例 | 備考 |
---|---|---|---|
air_direction | 上下風向 | 空欄なら自動 | |
air_direction_h | 左右風向 | 空欄なら自動 | |
air_volume | 風量 | 3, auto | 空欄なら自動 |
button | 固定ボタン | power_off | 空欄なら電源ON |
operation_mode | 運転モード | cool, warm, dry | |
temperature | 温度 | 26, 26.5 | |
temperature_unit | 温度単位 (℃ or ℉) | c, f |
例えば、エアコンの風量を 6
運転モードを冷房 (cool
) 温度を 26℃
に設定するには次のパラメータを送信します。
{ "air_volume": "6", "operation_mode": "cool", "temperature": "26", "temperature_unit": "c" }
設定できるパラメータの内容はエアコンの機種によるので、詳しくはアプライアンス情報の下の aircon
フィールドの中にある range
フィールドの内容を確認してください。
画像の例の場合、運転モードとしては auto
blow
cool
dry
warm
が使用できます。また固定ボタンとして airdir-swing
から power-off
までの5種類のボタンが使えます。
injectノードの msg.payload
にJSON形式で上記のパラメータを設定しておきます。
また、URL構築用のchangeノードで、以下のJSONata式を使ってURLを構築します。
"https://api.nature.global/1/appliances/" & $flowContext("acApplianceId") & "/aircon_settings"
デプロイしてinjectノードを実行すると、エアコンの動作状態が指定した通りに変化します。
エアコンの自動制御
ここまででエアコンの設定をNode-RED上から手動で変更できるようになりました。 最後に、エアコンの設定をRemo3/mini2の温度センサに基いて制御してみましょう。
まずは温度センサ te.val
の値を条件として、エアコンのパラメータを選択します。例として、以下の条件でパラメータを設定するようにします。
条件 | 運転モード | 風量 | 温度 |
---|---|---|---|
> 28℃ | 冷房 | 6 | 26 |
27℃ <, <= 28℃ | 冷房 | 3 | 27 |
<= 27℃ | 冷房 | 1 | 27 |
さて、このままパラメータを送信すればとりあえずエアコンのパラメータが条件に応じて変化します。ただしこの場合、現在のエアコンの状態がパラメータの状態と同じであっても、指示があればRemoは赤外線信号を送出します。 (勝手にマスクすると赤外線がうまく届かなかった時のリトライなどが難しくなるので) 対策として、Node-RED上で最後の操作結果を保持しておき、最後の操作から一定時間経過するか、異なるパラメータに設定したい場合のみ、エアコンのパラメータを送信するようにします。
まず、/1/appliances/{applianceid}/aircon_settings
からのレスポンスを flow.lastAcSettings
に設定して保存しておきます。
つぎに、設定したいエアコンのパラメータと、最後に設定したときのエアコンのパラメータ (flow.lastAcSettings
) から、パラメータの設定の要・不要を判定します。
判定のJSONata式は以下の通りです。
( $lastAcSettings := $flowContext("lastAcSettings"); $not($exists($lastAcSettings)) or ($millis() - $toMillis($lastAcSettings.updated_at)) > (60*60*1000) or $lastAcSettings.temp != payload.temperature or $lastAcSettings.mode != payload.operation_mode or $lastAcSettings.vol != payload.air_volume )
JSONata式では、 :=
を使って $
から始まる名前の変数に値を設定することができます。ここでは記述の簡略化のために $flowContext("lastAcSettings")
で取得した flow.lastAcSettings
の内容を $lastAcSettings
という名前の変数に設定しておきます。また、複数行の式を記述する場合は、全体を ()
で囲んで、各式の末尾を ;
で区切ります。
次の行からは、更新が必要となる条件を or
で繋いで、いずれかの条件を満たした場合にパラメータ設定が必要と判定するようにします。
まず、 $not($exists($lastAcSettings))
で最後のエアコンのパラメータが存在しない場合は更新を行うようにします。
次に、($millis() - $toMillis($lastAcSettings.updated_at)) > (60*60*1000)
で、最後にパラメータを更新した時刻から (60 * 60 * 1000)
ミリ秒、つまり 1時間経過した場合は更新します。
残りの条件は、 温度設定 temp
, 運転モード設定 mode
, 風量設定 vol
がエアコンのパラメータの対応するフィールド temperature
operation_mode
air_volume
と異なる場合にも更新するようにします。
判定結果は msg.payload
ではなく、 msg.needAcUpdate
に設定しておきます。 msg.payload
には設定したいエアコンのパラメータが入っており、リクエスト送信ノードにそのまま伝搬する必要があるためです。
最後に、 msg.needAcUpdate
に入っているエアコンの設定更新の要・不要に基づいて処理を分岐します。
デプロイすると、設定した条件に基いてエアコンが制御されるのを確認できるはずです。
まとめ
以上、3回に分けて Node-RED をつかったNature Remo Cloud APIの呼び出し方と、それを使った照明およびエアコンの自動制御方法について解説しました。
今回解説した自動制御の内容は、Nature Remoアプリからの オートメーション設定 でも可能な内容ですが、 Nature Remo Cloud APIと Node-RED を用いると、現時点でオートメーション設定ではできないような複雑な条件による制御も可能となります。
ぜひこの機会に Nature Remo Cloud APIをご活用いただけますと幸いです。
Nature開発者Community
Natureのプロダクトに関する開発者向けの情報を交換する場として、 Nature開発者コミュニティ をDiscord上に立ち上げています。 今回の話題であるNature Cloud APIに関する話をする apiチャネル もありますので、ご興味がある方はぜひご確認いただければと思います。
ブログの内容に関するご質問などもお待ちしております。