工場などで設備の稼働状態を表すのによく使われている積層信号灯の状態をM5StickCと光センサで読み取り、Ambientに記録し、さらにそれをNoodlで読み出して見える化しました。

こんな流れです。

設備の稼働率を調べる目的があり、時系列での状態変化をAmbientに記録していたので、今回はAmbientに記録したデータをNoodlで読み出して、見える化しました。積層信号灯の現在の状態を見える化するだけなら、状態をM5StickCと光センサで読み取り、Noodlで見える化してもよさそうです。

積層信号灯の状態をM5StickCと光センサで読み取り、Ambientに記録する方法は「信号灯の状態をデジタル化」をご覧ください。

使用したNoodlのバージョンは「2.2.4」です。

Noodlプログラム全体の流れ

5秒ごとにAmbientから積層信号灯の最新の状態データを読み、状態データに従って信号灯コンポーネントの色を変えます。

信号灯コンポーネント

積層信号灯の緑、橙、赤に対応するGroupを作ります。Stateノードで入力Stateと出力GreenColor、OrangeColor、RedColorを作り、入力がGreenだったらGreenColorは明るい緑、OrangeColorは暗い橙、RedColorは暗い赤、入力がOrangeだったらOrangeColorだけ明るい橙、GreenColorとRedColorは暗い色になるように出力を設定します。出力を緑、橙、赤それぞれのGroupのBackground Colorにすることで、Stateノードの入力がGreenだったら緑だけが明るく光り、Orangeになったら橙だけが明るく光るようにしました。これをまとめてコンポーネントにしました。

Ambientからの状態データ取得

Ambientにはjavascriptライブラリがあるので、それを使って値を取得します。Script DownloaderノードでAmbientライブラリを読み込みますが、Ambientライブラリはaxiosとqsというライブラリが必要なので、次のようにこの3つのライブラリを指定します。

Script0: https://unpkg.com/axios/dist/axios.min.js
Script1: https://cdnjs.cloudflare.com/ajax/libs/qs/6.10.1/qs.min.js
Script2: https://unpkg.com/ambient-lib@1.0.3/lib/ambient-lib.js

Ambientから値を取得するのはScriptノードを使いました。Codeに次のようなjavascriptのコードを記述します。

Node.Inputs = {
    channelId: 'number',
    readKey: 'string'
}

Node.Outputs = {
    d1: 'number',
    d2: 'number',
    d3: 'number',
    d4: 'number',
    d5: 'number',
    d6: 'number',
    d7: 'number',
    d8: 'number',
    created: 'string'
}

Node.Signals.begin= function() {
    am = new Ambient(Node.Inputs.channelId, '', Node.Inputs.readKey)
}

Node.Signals.read = function() {
    console.log('read');
    am.read({n: 1}, function(response) {
        console.log(response.status)
        console.log(response.data)
        Node.Outputs.d1 = response.data[0]['d1']
        Node.Outputs.d2 = response.data[0]['d2']
        Node.Outputs.d3 = response.data[0]['d3']
        Node.Outputs.d4 = response.data[0]['d4']
        Node.Outputs.d5 = response.data[0]['d5']
        Node.Outputs.d6 = response.data[0]['d6']
        Node.Outputs.d7 = response.data[0]['d7']
        Node.Outputs.d8 = response.data[0]['d8']
        Node.Outputs.created = response.data[0]['created']
    });
}

入力はchannelIdとreadKeyの2つです。出力はd1〜d8の値とデータの生成時刻createdを返します。さらに、Ambientの初期設定をおこなうbeginシグナルと、Ambientからデータを1つ読み込むreadシグナルを定義します。Script Downloaderでライブラリの読み込みが完了するとLoadedというイベントが発生するので、それをbeginにつなぎ、ライブラリが読み込まれたらAmbientの初期設定をおこないます。これらをまとめてコンポーネントにしました。

周期処理

5秒ごとにAmbientからデータを読む周期処理はTimerノードとStatesノードを組み合わせて作ります。Statesノードでonとoffという状態を定義し、Timerノードで5秒カウントします。5秒経過するとFinishedイベントが起きるので、それをStatesノードのToggleに入力し、onとoffを入れ替えます。するとState Changedイベントが起きるので、それをTimerノードのStartに入力すると再び5秒のカウントが始まります。こうして5秒のカウントを繰り返す周期処理を実現しました。Ambientコンポーネントでライブラリの読み込みが完了するとLoadedイベントが発生するので、それをTimerノードのStartに入力してタイマーを起動します。

この周期処理もコンポーネント化しました。

Ambientのデータで積層信号灯を制御する

周期処理で5秒毎にState Changedイベントが発生できたので、それをAmbientコンポーネントのreadに入力して5秒ごとにAmbientからデータを取得します。Ambientには設備などの状態を色で表示する機能があり、データ値によって9が赤、10が橙、12が緑というように表示色が変えられます。Ambientから得られる9、10、12という値をRed、Orange、Greenという文字列に変換するために、Ambientコンポーネントと信号灯コンポーネントの間にFunctionノードを入れて変換しました。

if (Inputs.state == 12) {
    Outputs.color = 'Green';
} else if (Inputs.state == 10) {
    Outputs.color = 'Orange';
} else if (Inputs.state == 9) {
    Outputs.color = 'Red';
}

動かす

今作ったプログラムを動かしてみました。

左上のウィンドウが積層信号灯の状態、左下がそれをM5StickcC+光センサで読み取ってAmbientに送った画面、右上がAmbientのデータをNoodlで読み込んで表示したものです。5秒毎にAmbientの状態を読んでいるので、信号灯が変化してから最大5秒の遅れがあります。

これで積層信号灯のある場所まで行かなくても、設備状態が確認できるようになりました。

分からないこと

Noodlは使い始めたばかりです。Ambientからのデータ取得は、JSON形式のオプションでさまざまな方法で値が取得できます。

{n : N} // 最新N件のデータを取得
{n : N, skip : S} // S件スキップし、N件取得
{date: 'YYYY-mm-dd'} // 指定した日付のデータを取得

Ambientコンポーネントにn、skip、dateなどを個別に渡す方法は分かるのですが、JSONオブジェクトをそのまま渡す方法が分かりませんでした。ご存知の方、教えてください。