node-REDのobnizノードでコールバック形式に対応してみる


IoTLT Advent Calendar 2020の12月12日の記事、[カメラ切替器ATEM Miniをobnizで操作してみた](https://iot-gym.com/controlling-atem-mini-by-obniz/) の記事内でnode-REDとobnizノードが使われているのですが、obnizノードでのコールバック形式がわかりにくかったようです。

> 今後の課題
obnizでボタンの状態を取得する部分のプログラムは、obniz repeatノードを使ってポーリングするプログラムになっています。これでは無駄にCPUを消費してしまうし、消費を抑えようとしてポーリング間隔を長くするとボタンのレスポンスが悪くなってしまいます。

>obnizにはボタンが押された時にコールバック関数を呼び出す仕組みがあります。これを使えば上記の問題は解決するのですが、obnizのNode-REDノードでコールバックを使う方法がわかりませんでした。この部分の書き方をobnizの中の人に聞いてプログラムをバージョンアップしようと考えています。


node-redはフローに入ってしまえばわかりやすいのですが、最初のきっかけになる部分はちょっとわかりにくいところがありますよね。

今回はそのobnizノードでのコールバックの書き方をやってみたいと思います。


### obnizノードでのコールバックの書き方

といっても、内容はかんたんで、obniz functionノードを使って、node.sendを使うだけです。

![スクリーンショット 2020-12-15 11.11.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/2fcc4d73-8a38-7e2c-2a5b-11368beb81cc.png)

```javascript

obniz.switch.onchange = (pressed)=>{
    node.send({payload: pressed})
}
```

はい、これだけでスイッチの状態が押されたらpayloadにデータが入って次のノードに渡されるノードが出来上がります。
かんたんですね。

ですが、問題はこのあと（というか前？）で、このfunctionノードをいつ動かすかという問題があります・・・・。
obnizノードには「obnizがつながったら〜する」というノードが無いため、ちょっと工夫してみます。

※「obnizがつながったら〜する」という処理を書く部分はあるのですが、裏側に隠れているのでノードのフローとしては存在していないのです



### 方法１：起動１秒後とかでやってみる

node-REDを起動したときはobnizは絶対オンラインなんだ！　と信じることができれば、obniz functionノードをnode-red起動時に動かしてしまうことができます。
といっても、接続までに時間がかかることがあるので、起動1秒後でやってみます。

![スクリーンショット 2020-12-15 11.05.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/b741c0ad-e62a-5ef3-d6a1-2a5d34965652.png)


![スクリーンショット 2020-12-15 11.05.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/b2c1cd26-2bc3-f5f4-cbcd-2ede501de002.png)


環境によってはもうちょっと時間を開けたほうがいいかもしれませんが、これでとりあえずはできます。

①node-red起動
②1秒後にobniz.switch.onchangeを登録
③onchangeが呼ばれるたびに次のノードに情報が行く

この方法のメリットは、とりあえずかんたんなことですね。
デメリットとしては、①と②の間でobnizへ接続をしなくてはいけない（接続に1秒以上かかってしまったらうまく動かない）のと、一度obnizとの接続が切れてonchangeがリセットされたらもう動かないことでしょうか。


### 方法２：repeatを使うけど、1度だけしか実行しないようにしてみる

接続／切断周りをあまり管理したくないなと思ったら、obniz repeatノードを使う必要があります。

![スクリーンショット 2020-12-15 11.21.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/85fb44d3-6bdc-01e5-c086-aa9c2b321e17.png)

しかし、obniz repeatノードは名前の通り、繰り返し処理をしてしまうので、CPUをたくさん使ってしまいます。
そこで、インターバルをものすごく長い時間指定することで、擬似的に1回しか実行しないようにしてみましょう。

![スクリーンショット 2020-12-15 11.22.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/3a716b9c-c17f-4ddb-61d6-3e2c6946b91a.png)

上のスクショでは、1000000000000 ms ≒ 31 年なので、最初に1回実行されたあと、次に実行されるのは31年後です。
きっとそれほどプログラムを動かし続けてはいないだろう・・・って場合にはこれもありですね。

メリットはノード数が１個減ってシンプルになったのと、接続／再接続周りを気にしなくても良くなったことですね。obnizが切れて再接続したときもrepeatはリセットされるので、onchangeはちゃんと登録されます
デメリットは時限爆弾仕込んでるきがしてちょっと気持ちが引ける・・・ですかね。
31年後にfunctionノードが実行されても、onchangeが上書きされるだけなので問題ないんですが、気持ちの問題でちょっと嫌です。

### 方法3：方法２をちゃんとやってみる

時限爆弾を取り除きたければ、変数を使って判定する必要が出てきます。

`obnizParts.isFirstRepat`って変数を作り、初期化処理でtrueに設定、repeat内でfalse設定にして判定してみます。

![スクリーンショット 2020-12-15 11.28.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/4ccf8349-09aa-89e3-b945-b108f8d387ca.png)

![スクリーンショット 2020-12-15 11.30.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/3949265b-ffab-352c-ca8c-a687c8094b07.png)

これで時限爆弾はなくなりました。
安心して31年間放置できますね！（違

### まとめ

というわけでいろいろな方法でobnizのコールバック関数に対応してみました。

そもそもを言えばobnizノードをちゃんとアップデートしなよって声が聞こえてきそうですが、とりあえず工夫でもなんと中るよって意味でアップデートしないでやってみました。obnizノードはたくさん使ってもらえているようで、使いにくいところも少しずつ見えてきたので、またアップデートしたいと思います。