RaspberryPiで測定したデータを可視化する

せっかくRaspberryPiで測定したデータ.LCDに表示するだけではもったいない.

これらをグラフとして可視化しない手はない.

IoTプラットフォームとOSS

既にいくつもの商用サービスが展開しており,これらを使う手がある.

Google Cloud IoT - フルマネージド IoT サービス
Google Cloud IoT と AI を使用して、ビジネス上の課題に対処する強力で堅牢なハイブリッド IoT ソリューションを構築しましょう

もちろんOSSを使って自宅サーバやレンタルサーバ上に自分で構築することも出来る.

可視化する前段で,データをパイプ処理する仕組みもいろいろ.

その他にも色々あるので,自身の環境にあったものを適当に選ぶ.

今回は既に構築済みの Rsyslog+Elasticsearch+Kibana を使う.

Rsyslog + Elasticsearch + Kibana

送信フォーマットを決める@RasPi

送信データのフォーマットを決めて,loggerコマンドで送信する.

フォーマットは気温,湿度,気圧のカンマ区切りとする.

$ logger --server ${RsyslogServerIP} --tcp --port 514 "$(./i2c-dev/htu21d.sh t),$(./i2c-dev/htu21d.sh h),$(./i2c-dev/bmp180.py p)"

適当なスクリプトを書いてcronで定期的に送信するといい.

Rsyslogを設定する@Server

サーバはCentOS7,Rsyslogは8.2002.0を使う.Rsyslogのインストールは長そうなので割愛する.

Rsyslogの役割は,RasPiからメッセージを受け取って,メッセージをElasticsearchに登録出来るフォーマットに変換して,メッセージElasticsearchに送る.

まずは送信側で決めたフォーマットのパースルールを作る.

受信したメッセージはRsyslogのmmnormalizeを使ってパースする.rulebaseファイルの記述方法はLiblognormのドキュメントを参照する.rulebaseファイルの内容で正しくパース出来るかlognormalizerコマンドで確認する.

$ cat raspi.rulebase
version=2
rule=:%temp:float%,%humi:float%,%press:float%
$ echo "30.73,59.81,99641.00" | lognormalizer -r raspi.rulebase
{ "press": "99641.00", "humi": "59.81", "temp": "30.73" }

続いてデータ入力部分の設定する.既存のrsyslog.confに不足部分を書き足す.

$ cat /etc/rsyslog.conf
global(workDirectory="/var/lib/rsyslog")
module(load="imtcp")                   # TCPで受信して,
module(load="mmnormalize")             # mmnormalizeでパースして,
module(load="omelasticsearch")         # Erasticsearchに出力する
input(type="imtcp" port="514" ruleset="raspi")  # 514/tcpで受信して,ルールセット'raspi'を設定
include(file="/etc/rsyslog.d/*.conf")  # 細かい設定は切り出す

続いてパースから出力までの部分を設定する.パースした結果をテンプレートに埋め込み,Elasticsearchへ出力する.どの変数にパースされたかよくわからない場合はjsonmesgの中身を適当なファイルに出力してみるといい.

template(name="ins_erasticsearch"
         type="list"
         option.json="on") {
            constant(value="{")
            constant(value="\"timereported\":\"")           property(name="timereported" dateFormat="rfc3339")      constant(value="\",")
            constant(value="\"hostname\":\"")               property(name="hostname")                               constant(value="\",")
            constant(value="\"syslogfacility-text\":\"")    property(name="syslogfacility-text")                    constant(value="\",")
            constant(value="\"syslogpriority-text\":\"")    property(name="syslogpriority-text")                    constant(value="\",")
            constant(value="\"syslogtag\":\"")              property(name="syslogtag")                              constant(value="\",")
            constant(value="\"temperature\":\"")            property(name="$!temp")                                 constant(value="\",")
            constant(value="\"humidity\":\"")               property(name="$!humi")                                 constant(value="\",")
            constant(value="\"pressure\":\"")               property(name="$!press")                                constant(value="\"")
            constant(value="}\n")
}

template(name="tmp"
         type="string"
         string="TMP: %jsonmesg%\n"
)

ruleset(name="raspi"){
    action(type="mmnormalize" ruleBase="/etc/rsyslog.d/raspi.rulebase")
    #action(type="omfile" dirCreateMode="0700" FileCreateMode="0644" File="/tmp/raspi.log" Template="tmp")
    #action(type="omfile" dirCreateMode="0700" FileCreateMode="0644" File="/tmp/raspi.log" Template="ins_erasticsearch")

    ## Elasticsearch index definition for dynSearchIndex
    $template raspi-index,"raspi-%timereported:1:10:date-rfc3339%"

    action(type="omelasticsearch"
           server="localhost:9200"
           template="ins_erasticsearch"
           dynSearchIndex="on"
           searchType="_doc"
           searchIndex="raspi-index"
           bulkmode="on"
           queue.type="linkedlist"
           queue.size="5000"
           queue.dequeuebatchsize="300"
           action.resumeretrycount="-1")
    & stop
}

Elasticsearch/Kibanaを設定する@Server

Elasticsearchにデータを蓄積して,Kibanaで可視化する.Rsyslog同様,導入の説明は長そうなのでここでは割愛.

RDB同様,Elasticsearchにもデータ型がある.何も設定しなくてもデータ型のマッピングは動的に割り当てられるが,一度インデックスにマッピングが適用されると変更する方法がない.お作法としてテンプレートを作成しておく.

Kibana の Management > Index Management からIndex Template を作成する.

Elasticsearchを冗長化していないので"number_of_replicas": "0"を設定しておく.

RDBで言うところのカラム名と型を設定する.どんなデータを設定すればいいかわからない場合は一旦動的マッピングを作成して,内容を確認するといい.

大事な部分はこんなところ.その他の項目は適当に設定しておく.

ErasticsearchのデータをKinbanaから見えるように Management > Index Patterns を設定しておく.実際の画面を見れば理解出来ると思うので詳細は割愛.

グラフ化して見る

約1位日分のデータを可視化するとこんな感じ.

気温と湿度がわかると,厚さ指標であるWBGTに当てはめて熱中症の危険度合いがわかる.Kibanaではヒートマップを作成出来るので,それっぽいものを作る.

厚生労働省パンフレット「熱中症を防ごう!」

この日の傾向としては警戒レベルだった.

ちなみに気圧,気温,湿度の最大値,平均,最小値は以下の通り.

1日の内で大気圧がどの程度変化するかは,東京工科大の江頭教授がアメダスデータを利用して最大50.8hPaと見積もりしている.今回の差分は5.33hPaであり,そこまで大きな差はなかった.台風が来たら改めてデータを見ることにする(たぶん).

おわりに

Rsyslog,Erasticsearch,Kibanaの導入過程が気になる場合ははてなブログの方を参照.

熱中症に気をつけよう.

コメント

タイトルとURLをコピーしました