--- description: カードの状態を監視し、MattermostのWEB API経由で通知を行います。今回は、RaspberryPi Zero W上にNode-REDをインストールし、Node-RED上のプログラムを作成します。 image: https://i.gyazo.com/5b4b598b48827f7ff9a40cd74fa55e04.png tags: RaspberryPi, raspbian, Node-RED lang: ja-jp --- # IoTカードフォルダ作成(ソフト編) ## システム RaspberryPi Zero Wで、カードの状態を監視し、MattermostのWEB API経由で通知を行います。 今回は、RaspberryPi Zero W上にNode-REDをインストールし、Node-RED上のプログラムを作成します。 ## 動作概要 カードフォルダに、カードを抜き差しすると、チャットに通知を投げます。 [![](https://i.gyazo.com/5b4b598b48827f7ff9a40cd74fa55e04.png)](https://i.gyazo.com/5b4b598b48827f7ff9a40cd74fa55e04.png) [![](https://i.gyazo.com/9f04a457196e4b2b6a3af347fad31087.png)]( https://i.gyazo.com/9f04a457196e4b2b6a3af347fad31087.png) ## GPIO入力確認 まずは、GPIOからカードの状態が取得できるか確認します。 カードフォルダ正面左から見て、1,2,3,4とすると、入力ピンとの対応は以下のようになります。 | カード番号 | 入力Pin番号 | | -------- | -------- | | CARD 1 | GPIO 12 | | CARD 2 | GPIO 16 | | CARD 3 | GPIO 20 | | CARD 4 | GPIO 21 | - カードが入っている状態 : 0 - カードが入っていない状態: 1 となります。 この状態がきちんととれるか、Node-REDのフローで確認します。 ![](https://i.gyazo.com/b805ab46d687501bf41b6cc1ddfff7c1.png) 入力ピンノードの下の小さい緑の横の数字が、そのピンの入力値です。 カードを出し入れすると、きちんと値が変化します。 デバッグログにも、表示されます。 入力ピンノードの設定は、以下の感じです。 ![](https://i.gyazo.com/04aada98e91d7caafdfb05527382860b.png) - pullup 今回は、SW ONでGNDに設置するようにしてあるので、pullupを指定しています。 これで、SW OFFのときにHIGH状態(1)になります。 - Denounce チャタリングを防止するためのウェイト時間の設定です。 SWがON/OFFする際には、接点が触れるか触れないかの状態は不安定な状態で値が何度も変化します。  そこで値が変化してから、指定した時間経過しても同じ値だった場合のみ、その値を取得するようにして、チャタリングを防止します。 デフォルトの、25mSec.のままです。 - Read initial state of pin on deploy/restart? これをチェックすると、Node-RED起動時に、一度読み取りを行います。 ## フロー(プログラム)作成 GPIOから値が取得できることが分かったので、フローを組んでいきます。 最終的にメイン部分は以下のようになりました。 [![](https://i.gyazo.com/77e40728164ded6d783f1bae9cf4120d.png)](https://i.gyazo.com/77e40728164ded6d783f1bae9cf4120d.png) ### 流れ 1. GPIO読み込み 2. GPIOの値を退避 3. 4つのGPIOの値を合成 4. カードの状態を表す文字列を作成 5. システム起動時のメッセージ送信防止 6. チャットに送るメッセージを作成 7. チャットにメッセージを送信 8. カード状態の保存 ### 1. GPIO読み込み GPIOの状態を読み出します。 注意点は、「Read initial state of pin on deploy/restart?」にチェックをいれて、Node-RED起動時にも値を読み取りに行くようにすることです。 GPIOノードの後の、Changeノードは、この後の処理を同じようにするために、どのカードのデータかわかるように識別子をつけています。 [![](https://i.gyazo.com/a611ff77f90c94455b8d76b2e198cf7d.png)](https://i.gyazo.com/a611ff77f90c94455b8d76b2e198cf7d.png) このノードを通った後は、msgコンテキストは以下のようになっています。 | プロパティ | 内容 | | -------- | -------- | | topic | カード識別子 ("card1","card2","card3","card4") | |payload| GPIOの状態 (0,1) | ### 2. GPIOの値を退避 payloadはいろいろな用途で使うので、GPIOの値をvalueに退避。 [![](https://i.gyazo.com/8bc28ba8ca356bcb53a3d04a6fffe2ca.png)](https://i.gyazo.com/8bc28ba8ca356bcb53a3d04a6fffe2ca.png) ## 3. 4つのGPIOの値を合成 joinノードで、4つのGPIOの値をまとめます。 [![](https://i.gyazo.com/56c938c994610ae15f75a87ed37b2731.png)](https://i.gyazo.com/56c938c994610ae15f75a87ed37b2731.png) 1. msg.payloadに入ってきた値を、msg.payloadに合成して出力 2. msg.topicをキーにした、key/valueオブジェクトとして出力 3. 4種類のキーを受信するまで出力しない 4. それ以降は、受信する度に、出力する このノードの後は、payloadは以下のようになります。 ``` json { "card1" : 1, "card3" : 0, "card4" : 1, "card2" : 0 } ``` ### 4. カードの状態を表す文字列を作成 4つのカードの状態を一目でわかるような文字列を作成します。 [![](https://i.gyazo.com/0024ee65009f420151f5589f0ac103d3.png)](https://i.gyazo.com/0024ee65009f420151f5589f0ac103d3.png) 文字列は絵文字を使って、 :o::x::x::o: のように、表示できるようなものにしています。 出力は、msg.resultTextにしています。 (一応payloadにもいれてる) ### 5. システム起動時のメッセージ送信防止 joinノードの出力は、4つのGPIOのデータが揃ったら出力されるので、このままだとシステム起動時に毎回4つ目の値を読み込んだ時にメッセージが表示されてしまします。 初期値を読み出したのか、値が変化したからメッセージが送られたのかがわからないので、この処理を入れています。 [![](https://i.gyazo.com/d2313bdb3bb6cb97703b90d320b8914d.png)](https://i.gyazo.com/d2313bdb3bb6cb97703b90d320b8914d.png) flow.readyFlagがtrueになっていれば、次に進み、そうでなければ終了するだけの処理です。 msgコンテキストは、トリガが発生したときに生成され、線でつながったノードの処理が終わると破棄されます。 flowコンテキストは、flowタブに存在するノード全部で共有できます。 今回の場合は、システムが起動した時点で、flow.readyFlagをfalseで初期化。 一通りGPIOの初期値を読み込んだら、flow.readyFlagをtrueに設定。 そのために以下のフローを追加しています。 [![](https://i.gyazo.com/b8f7e4151043873c37a3bb90b06aa689.png)](https://i.gyazo.com/b8f7e4151043873c37a3bb90b06aa689.png) 起動直後と、起動2秒後に起動するInjectノードを配置。 そのあとに、初期化としてflow.readyFlagにfalseをセットするノード、 flow.readyFlagをtrueにするノードをセットしています。 要するに、システム起動後2秒間は、GPIOを読み込んでもチャットに通知を送らないようにしています。 ### 6. チャットに送るメッセージを作成 2.で退避したGPIOの値を判断し、チャットに送るメッセージを作成します。 templateノードを使って、JSONデータを作成します。 {{topic}}は、msg.topicの値("card1"とか) {{resultText}}は、4つのカードの状態(":o::o::x::x:"など) [![](https://i.gyazo.com/1687d92f81a9f83b8da68821b6957d9e.png)](https://i.gyazo.com/1687d92f81a9f83b8da68821b6957d9e.png) ### 7. チャットにメッセージを送信 http requestノードを使って、チャットサービスから取得したWebhookのURLにPOSTでメッセージを送ります。 [![](https://i.gyazo.com/0e9a36ddcb2fb66c2bd3c49ac7b6e2f9.png)](https://i.gyazo.com/0e9a36ddcb2fb66c2bd3c49ac7b6e2f9.png) ### 8. カード状態の保存 所々で、カードの状態をflowコンテンツに保存しています。 これは、あとで決まった時間になったら、カードの状態を見てメッセージを送信したり、システム起動時に現在のカード状態を送信したりするためのものです。 ## 定期実行 特定の時間になると、カードの状態を判断し、チャットにメッセージを送る機能を追加します。 [![](https://i.gyazo.com/3d7fea34bb88c13f43a3f79caa8ed69a.png)](https://i.gyazo.com/3d7fea34bb88c13f43a3f79caa8ed69a.png) 月~金の15:00になると、payloadにflow.cardInfoを流す、injectノード [![](https://i.gyazo.com/76531b23affa2673bee06da4bed572be.png)](https://i.gyazo.com/76531b23affa2673bee06da4bed572be.png) カードの返却状態が4枚未満かチェックするswitchノード [![](https://i.gyazo.com/e3a17ac0616ce2f27e941ad354904db7.png)](https://i.gyazo.com/e3a17ac0616ce2f27e941ad354904db7.png) ```$sum(payload.*)```は、JSONataというフォーマットで、この場合は、payloadオブジェクトに含まれる、プロパティの合計値を意味しています。 例えば、payloadが、 ``` json { "card1" : 1, "card3" : 0, "card4" : 1, "card2" : 0 } ``` の場合、```$sum(payload.*)```は、2になります。