この記事は、2020/10/20(火)に開催のイベント「Node-REDで色々試すハンズオン Tec-Nomad ・ ビジュアルプログラミング交流会 コラボ」のハンズオン資料として準備したものです。
ハンズオンでは、3名の講師( @kisaichi07 さん、 @kmaepu さん、自分)がそれぞれ Node-RED を利用した異なる内容を取り扱います。また Node-RED を利用する環境に enebular(エネブラー)を用います。
はじめに
この記事(ハンズオン資料)では、以下の内容を扱います。
- Node-RED のダッシュボード
- Node-RED のリアルタイム通信(Websocket)
また、イベントで 2番目に実施する内容で、その前に導入部・ 1つ目のハンズオンが実施済みとなっているはずなので、Node-RED・enebular の基本的な内容や enebular のアカウント作成方法の説明については省略します。
少しだけ書いておくと、Node-RED は PC・ラズパイ(Raspberry Pi)・クラウドといった色々な環境で利用可能で、今回のハンズオンで用いる enebular は Node-RED をクラウドで利用可能なものです(また、オリジナルの Node-RED にない機能も備えています)。
詳細については、公式のドキュメントや Web上の記事などをご覧ください。
フローを作成する
とりあえず軽くダッシュボードを使ってみる 【内容A】
最初に、ダッシュボードの基本的な機能をいくつか見ていきながら、実際に試してみましょう。ここでの説明は、enebular でフローをエディット可能な状態(以下の画像の画面)になっている想定で書いています。
まずは、入力 1つと出力 1つを試してみようと思います。
ボタンと音声合成のフローを作る
【ステップ1−1】 それでは、左側のメニューを下へとずらしていって、以下の画像のノードが表示されるところまで進んでください。
【ステップ1−2】 その中にある buttonノード と audio outノード の2つを配置して、ワイヤーでつなげてみましょう。
【ステップ1−3】 そして、buttonノード のほうのプロパティを開き(※ ノードをダブルクリックする等)、以下の赤い矢印で示した部分(「Group」という項目の右端にあるアイコン)を押します。
【ステップ1−4】 さらにその先の画面で、以下の赤い矢印で示した部分(「タブ」という項目の右端にあるアイコン)を押してください。
【ステップ1−5】 以下の画面では、右上にある「追加」ボタンを押しましょう。
今は何のための操作をしているか分からないかもしれないですが、後で補足しますので、今はとりあえず進めてみてください。
【ステップ1−6】 その後の画面で、右上にある「追加」ボタンを押します。
【ステップ1−7】 さらに後の画面で、右上にある「完了」ボタンを押しましょう。
【ステップ1−8】 ここで、以下の緑矢印で示したような三角のマーク(audio outノード のほうについているもの)が、buttonノード の上に出ていない状態になれば OK です(先ほどまでは、赤い矢印で示したあたりに出ていたはず)。
【ステップ1−9】 次に audio outノード のほうのプロパティを開きましょう。
以下の赤い矢印で指名した部分が「[ホーム]デフォルト」となっているのを確認し、以下の緑矢印で示した「完了」ボタンを押します。
【ステップ1−10】 以下の赤い矢印で示した 2箇所に三角のマークがないことを確認し、以下の緑矢印で示した「デプロイ」ボタンを押します。
【ステップ1−11】 その後、以下のように「デプロイが成功しました」という表示が出るのを待ってください。
ダッシュボードを開いてみる・フローを修正する
【ステップ1−12】 無事にその表示を確認できたら、以下の赤矢印で示した棒グラフのようなアイコンを押します。
【ステップ1−13】 そして、以下の赤矢印で示したアイコンを押してください。
【ステップ1−14】 そうすると、ブラウザの別タブが開くなどして、以下のような画面が表示されたのではないでしょうか。これが先ほどまでの「ステップ1〜13」の操作内容が反映されたダッシュボードの画面です。
【ステップ1−15】 とりあえず、細かな説明は置いておいて、以下の BUTTON と白い字が書かれている青いボタンを押してみましょう(※注意:音がでます)。
そうすると、数字やアルファベットを読み上げるような音声が聞こえたのではないでしょうか。
【ステップ1−16】 ここで、今現在、作成された内容を補足します。
先ほど作ったフローの buttonノード は、別タブで開いた画面(ダッシュボードの画面)に押下可能なボタンを表示させます。また、ボタンが押下された際に audio outノード へメッセージを送ります。読み上げられた音声は、buttonノード から送られたメッセージなのですが、それを確認するためにフローにデバッグ用のノードを追加してみましょう。
以下のように、左のノードが並んだメニューの上のほうにある debugノード をフローに追加し、buttonノード の後ろとワイヤーでつなげてください。
【ステップ1−17】 そして、画面右上にある「デプロイ」ボタンを押しましょう。
(キャプチャ画像は省略します)
【ステップ1−18】 その後、以下の赤矢印で示した虫のような見た目のアイコンを押してください。
【ステップ1−19】 この状態で、再度、別タブで開いたダッシュボードの画面の、青いボタン(白い字で BUTTON と書かれたもの)を押してみてから、フローが表示されている画面のほうに戻ってください。
【ステップ1−20】 そうすると、画面右のほうに数字やアルファベットが混在した文字列が表示されていると思います。これが、上記の「ステップ1−15」で音声合成で読み上げられていたものです。
【ステップ1−21】 これは、buttonノードから送られたメッセージで、正確にはメッセージの中の payload の中身です。そこで、以下の画像の赤矢印で示した Payload のテキストボックスに、何かテキストを入力してみてください(以下の例では「音声合成で読み上げをします」という文章を入力しました)。
【ステップ1−22】 その後に、画面右上にある「デプロイ」ボタンを押しましょう。
(キャプチャ画像は省略します)
【ステップ1−23】 そして別タブで開いているダッシュボードの画面を表示させた状態にして、再度、青いボタン(白い字で BUTTON と書かれたもの)を押してみましょう。そうすると、音声合成で読み上げられる内容が、謎の数字とアルファベットの組み合わせではなく、先ほど「ステップ1-21」で設定した文章になったのではないでしょうか。
【ステップ1−24】 ここで、フローが表示されている画面のほうを表示させ、画面右のほうを見てみてください。以下の画像の赤矢印で示した部分を見ると、デバッグノードに渡されたメッセージ(の payload)が「ステップ1-21」で設定した文章になったのが確認できると思います。
ダッシュボードについての補足(構成について)
【ステップ1−25】 画面右の棒グラフのようなアイコンを押して、以下の画像の画面を表示させてください。そして、赤矢印で示した「デフォルト」と書かれた部分を押しましょう。
【ステップ1−26】 そうすると、閉じられていたメニューが展開されて、以下の赤矢印で示した項目(button と audio out の2つの項目)が表示されると思います。
【ステップ1−27】 ここで別タブで開いたダッシュボードの画面と、これらの項目の対応関係を見てみましょう。ダッシュボード上部(青背景に「ホーム」と書かれた部分)、その下にある「デフォルト」と書かれた部分、その下にある青いボタン(「BUTTON」と白字で書かれたもの)が対応しているのが分かると思います(audio aout は、ボタン等と異なり目に見える項目ではないので、ダッシュボードのほうでは表示されるものはありません)。
上記の「ステップ1−3〜1−7」で設定していた内容は、このようなダッシュボードの画面構成を作る手順となっていました。これを活用すると、以下のページにあるような複雑な画面を作ることもできますが、詳細な説明は時間・スペースの都合で省略します。
●node-red-dashboard (node) - Node-RED
https://flows.nodered.org/node/node-red-dashboard
ダッシュボードの補足2(要素を増やしてみる)
※ ここは、ハンズオンでは時間があれば触れますが、時間がなさそうであれば飛ばす予定です
【ステップ2−1】 上記の手順では、ダッシュボード上にボタンを表示させる buttonノード を1つだけ用いましたが、これを増やすことも可能です。上記の事例で、例えば音声合成でしゃべらせたい内容の種類を複数用意することに使えたりします。具体的には、以下の画像のように buttonノード をフローに 1つ追加し、その追加したノードのプロパティを開いて「ステップ1−9・1−21」と同様の確認・操作を行い、 audio outノードとワイヤーでつなげましょう。
【ステップ2−2】 フローが表示されている画面右上の「デプロイ」ボタンを押して、その後、ダッシュボードの画面を開いて表示される内容を確認してみましょう。そうすると、以下の画面のように「デフォルト」と書かれた部分の下に 2つのボタンが表示されます。上記の「ステップ2−1」で追加したボタンのプロパティ設定で、Payload のテキストボックスに、「ステップ1−21」で設定した文章と異なるものを入力していれば、この 2つのボタンを押した時、それぞれ異なる内容の音声読み上げが行われると思います。
このように、ダッシュボードには複数の操作可能な要素を追加することもできます。
ダッシュボードで別の内容を試してみる 【内容B】
※ ここは、ハンズオンでは時間があれば触れますが、時間がなさそうであれば飛ばす予定です(または、デモを見ていただくのみにします)
ここで、別の入出力用のノードを試してみます。
sliderノード と gaugeノード を試す
【ステップ2−1】 以下のように sliderノード と gaugeノード をフローに配置します。
【ステップ2−2】 そして、上記の「ステップ1−2〜1−9」と同様の設定を行い、「ステップ1−10〜1−12」と同様の操作を進めてデプロイを行いましょう。
【ステップ2−3】 上記の「ステップ1-13」と同様の操作で別タブでダッシュボードを開くと、ゲージとスライダーの2つが表示されていると思います。その画面で、下側にあるほう(スライダー)の青い円の部分(以下の赤い矢印で示した部分)に対してドラッグアンドドロップの操作を行い、右方向へ動かしてみましょう。
【ステップ2−4】 スライダーを動かすと、それと連動して上側に表示されているゲージの針の位置が動くのが分かると思います。スライダーをさらに左右に動かして、ゲージがどのように動くかを確認してみてください。
以下は、スライダーとゲージの表示位置・操作内容が少し異なりますが、上記の「ステップ2−1〜2−4」の内容を過去に試してみた際のものです。スライダー上のいくつかの箇所をクリックすると、そこに青い円の部分が移動し、それと合わせてゲージの針も動いている様子が分かると思います。
Node-REDのノードを2つだけつなげ、軽く設定をしただけで、
— you (@youtoy) June 15, 2020
こんな感じのUIがすぐにできた。 pic.twitter.com/UeIoCOobPt
MIDIコントローラーから PCへ入力された値をダッシュボードで可視化する
以下は、PCに MIDIコントローラーを接続し、その MIDIコントローラーから PCへ入力された値を可視化したものです。これは enebular ではなく、PCにインストールした Node-RED を用い(※ この例は enebular では実行できないかもしれません)、可視化は上記の手順でも用いた gaugeノードを用いています。また、MIDIコントローラーとのやりとりを行うためのノードとして「node-red-contrib-midiノード」を用いています。
本日ゲットできたMIDIコントローラー、
— you (@youtoy) August 17, 2020
ノブを回転させた時の値の変化を、Node-REDのダッシュボードのゲージに反映させてみた!
利用したノードは「node-red-contrib-midi 」で、8つのノブがついてるけど、とりあえず4つで。
簡単に可視化できて、良い感じ! https://t.co/oJgYOKQcDi pic.twitter.com/AtzBF7OljP
リアルタイムに送られてくるデータをダッシュボードで可視化する 【内容C】
※ ここは、ハンズオンでは時間があれば触れますが、時間がなさそうであればデモを見ていただくのみにする予定です
ダッシュボード上に動的なグラフを表示する
ダッシュボードは動的に更新されるグラフを表示することもでき、例えば以下のツイートの動画にあるような折れ線グラフ(ダッシュボードで表示しているのは画面の左半分)を表示することができます。以下のツイートの動画の左半分(ダッシュボード)に2つのグラフが表示されていますが、そのうち 1つはインターネット経由でリアルタイムに送信された値を受信し、グラフ化しています。
クラウド上のNode-RED(環境は #enebular を利用、動画の左側)と、ローカルのHTMLファイル(動画の右側)で、それぞれ乱数生成&Websocket送信をして、生成した乱数+Websocket経由で相手側から受信した値をNode-REDのダッシュボード・HTMLのCanvasの上でグラフ化するテスト。 pic.twitter.com/8HNTj8iZv6
— you (@youtoy) October 17, 2020
インターネット経由での値のやりとりには Websocket を用いています。
ノードの配置・設定
【ステップ3−1】 今回は、ノードの検索機能を使って、フローを組み立てていきましょう。以下の赤矢印で示した部分に、検索キーワードとなる文字を入力します。
【ステップ3−2】 まず、リアルタイムな値のやりとりに使う Websocket に関するノードからです。「web」まで検索キーワードを入れた時点で、結果が 2つに絞りこまれました(※ 本記事の執筆時点)。
2つあるノードのうち、「websocket in」のほう(※ 受信側となるノード)を配置しましょう。
【ステップ3−3】 続いて、chartノードを検索します。こちらも chart の全ての文字を入れる前に、結果が絞りこまれるかもしれません。これもフローのほうへ配置します。
【ステップ3−4】 以下のように websocket inノードと chartノードの 2つを配置した後、ワイヤーで間をつなぎます。
【ステップ3−5】 そして、chartノードのプロパティを開いてください。そして、「ステップ1−3〜1−7」で行ったのと同じ設定をしてください(ダッシュボードの Group・タブの設定)。
【ステップ3−6】 さらに、chartノードで表示する折れ線グラフの設定をします。以下の画像の赤矢印で示した「X-axis」の部分は「10 second」にしてみましょう(グラフのX軸方向に10秒分のデータが表示されるようになります)。また、「Y-axis」の部分は min を「0」に max を「100」にします(Y軸方向の値を決めるのですが、この後に設定する Websocket で送る乱数の値に合わせた設定にしています)。
それらの設定が終わったら、プロパティの右上にある「完了」ボタンを押してください。
【ステップ3−7】 次に、websocket inノードのほうの設定をします。プロパティを開いたら、以下の画像の赤矢印で示したアイコンを押してください。
【ステップ3−8】 そして、以下の画面のパスの部分で「/ws」を設定します(これは、送信側と合わせなければいけない部分で、別の内容にもできますが、今回はこちらを使ってください)。
その後は、プロパティの右上の「追加」ボタンを押し、その後の画面の右上に表示されている「完了」ボタンを押してください。
【ステップ3−9】 一通り、ノードの設定は終わったので、画面右上の「デプロイ」ボタンを押しましょう。
(キャプチャ画像は省略します)
データの送信元を準備する
Websocket を使う場合、通常、そのやりとりのためのサーバを準備する必要があります。しかし、今回の事例では、enebular上の Node-RED がその役割をしてくれるので、後はデータの送り元のクライアントを用意するだけで OK です。
本当は、何らかのデバイスのセンサーの値を送って可視化などとしたいところですが、オンラインハンズオンで参加者の皆さんが共通の環境を用意するのも厳しいので、今回は「乱数で数字を生成する HTML+JavaScript の Webページ」で代用することにします。
【ステップ3−10】 ここから、上で説明した Websocket でデータを送るクライアントを作っていきますが、そのプログラム内で Websocket サーバを指定する必要があります。enebular の場合、以下の画像の赤矢印で示した部分を押すと、enebular で作成中のフローが動いている環境の URL を見ることができます(https で始まり、herokuapp.com で終わる URL になっていると思います)。皆さん全員が異なる URL になりますので、ご自身のものをメモしておいてください。
また、URL の下に Session Remaining と書かれてますが、これは上記でメモしていただいた URL が有効な時間を示しています(現状、皆さんが使っている環境は恒久的な URL にはなっていない状態です)。
もしご自身で Heroku のアカウントを作り、そのご自身の Heroku の環境に enebular からフローをデプロイする手順を踏めば恒久的なものにもできますが、今回は一時的に用意された環境を使います(なお、時間切れとなったら URL が変わり、また残り時間が表示されるはずです)。
【ステップ3−11】 補足説明が長くなりましたが、Websocket でデータを送るクライアントとなる Webページを HTML+JavaScript で作成します。以下がそのソースコードで、手間を省くために(また行数もそれほど多くないのもあり) 1つのファイルで HTML と JavaScript をまとめていますので、ご自身の PC 上で以下の内容を書いた HTMLファイルを作成してください。
基本的にそのままご利用いただけるはずのものですが、ソースコード中の const URL = "wss://【固有の文字列】.herokuapp.com/ws";
の部分だけは、上記の「ステップ3-10」で確認した URL を使ったものに書きかえてください。「ステップ3-10」で、 https://
から herokuapp.com
の間にあった皆さま毎に異なる固有の文字列を、以下のソースコードの「【固有の文字列】」の部分に書いてください。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ランダムな値の送信</title>
</head>
<body>
<script>
const URL = "wss://【固有の文字列】.herokuapp.com/ws";
const socket = new WebSocket(URL);
socket.onopen = function(event) {
console.log('Open');
setInterval(function() {
const random = Math.random() * 100;
console.log( "rand: " + random );
socket.send(random);
}, 500);
};
socket.onerror = function(error) {
console.log('error');
};
</script>
</body>
</html>
ここで生成するデータの値の範囲や送信するタイミングは、「setInterval」や「Math.random()」の使われている部分に関係します。「setInterval」の4行下の部分で 500 という数字がありますが、「500ミリ秒(0.5秒)」ごとに乱数を生成して Websocket で送るような処理となっています(上記「ステップ3−6」でグラフの X軸は 1秒区切りにしていますが、ここではそれより多めにデータを生成しています)。また、生成した乱数がとる値の範囲は「Math.random() * 100」の部分で決まっていて、「Math.random()関数は、0以上、1未満の範囲で浮動小数点の擬似乱数を返すため、それを 100倍した値は、0以上、100未満の不動小数点」となります。
ソースコード中の const URL = "wss://【固有の文字列】.herokuapp.com/ws";
の最後に「/ws」とつけていますが、これは上記の「ステップ3−8」で設定したパスと合わせた内容です。
その他、ソースコードについて厳密に言うと、 socket.send(random);
の部分は、サーバとの通信が確立しているかをチェックしてから処理すべき内容であったり、その他の部分も本来はもっと記載すべき処理はありますが、今回は簡単のためそういった部分は省いてますのでご注意ください(あくまで、ハンズオン用・ちょっとした自分だけでのお試し用という感じです)。
なお、リアルタイムなデータ送信を実行する方法として、今回は Websocket を用いましたが、MQTT を使うのも良いかもしれません。enebular・Node-RED で MQTT を扱う方法もありますので、ご興味がありましたら Web の記事を調べるなどして、やり方を調べてみてください。
ダッシュボードのグラフ表示を確認する
【ステップ3−12】 上記「ステップ3−11」のソースコードで「console.log( "rand: " + random );」という部分があるため、HTMLファイルを Chrome 等のブラウザで開き、開発者ツールを開いてコンソールでの出力を見ると、生成された乱数を見ることができます(なお、Webページとして表示する文字等は準備してないため、ブラウザ上では白紙のページが表示されます)。
【ステップ3−13】 ご自身の PC上で上記「ステップ3−12」の HTMLファイルを開くと、enebular のフローで、以下の画像の赤矢印で示した部分が表示されたかと思います。これは、Websocket で接続しに来ているクライアントが 1つあって接続されていることを示しています。
【ステップ3−14】 この状態でダッシュボードを開くと、以下の画像のようなグラフが表示され、そのグラフが動的に変化している様子が見られると思います。
上でも少し触れましたが、ここで送信側を何らかセンサー付きのデバイスにして、そのセンサーのデータをリアルタイムに送る形にすれば、センサーデータの可視化に用いることができます(送信側を実装する方法等にもよりますが、センサーデータの送信は MQTT を使うのも良いかもしれません)。
そして、ダッシュボードには複数の chartノードを配置することもできるので、複数のデバイスから送られたデータを可視化したり、複数の内容がセンシングできるセンサーでそれらを送る(例えば、温湿度センサーの温度と湿度を送る)というのも良いかもしれません。
おわりに
今回、30分という限られた時間枠だったため、全てを詳細に説明する時間はとれませんでした。よろしければ、ハンズオンが終わった後で記事にの内容をご覧ください。
その他
自分が過去に Qiita等に書いた Node-RED を利用した事例について、リアルタイム通信以外の内容が多いのですが、以下にリンクを書いておきます。よろしければご覧ください。
- Node-RED で Teachable Machine を試す(Node-RED のセットアップ後にノードを追加してサンプルを動かす) - Qiita
- ビジュアルプログラミングでIoTやってみませんか? / IoTLT vol.61 - Speaker Deck
- ビジュアルプログラミングで デバイス間をつなぐ / 出張IoTLT@くらでべ - Speaker Deck
- Node-RED を使って OBS を遠隔操作してみた話(obs-websocket を利用)|豊田 陽介|note
- Node-RED でカメラを使う(Simple Webcam pic と image-output) - Qiita
- Node-REDをあらためて活用してみる / IoTLT vol.64 - Speaker Deck