先日の記事でBeagleBone Black(BBB)を自宅の制御サーバにする件、徐々に環境移行をしていて、今回はそれ関係でmuninのプラグインを開発してみた。
従来は制御ボードのAPIを叩くCで組んだWindowsプログラムだったのだけど、サーバを組み込みLinux(Ubuntu on BBB)に移した関係で諸々の書き換え・作り替えを実施している。
特に大きいのがセンサーを長々と配線して直接繋ぐ形から、センサーの側にマイコンを置いてデータ化して中央のBBBに集約する形にしている。
昨今は、ワンチップマイコン(それも8ビット機)を割と簡単にネットワーク接続することが出来る(ネットワークコントローラにTCP/IPまで組み込まれている)ので、大きめのUSBメモリ位のサイズのユニットが普通にイーサネットに繋がって、HTTP等でデータ交換出来てしまうのだ。
今回は試作として、Arduinoに大気圧センサーモジュールとイーサネットシールドを組み合わせた簡易HTTPサーバとそのmuninプラグインを制作した(温度センサーだけでかまわなかったのだが、単機能センサーよりもBMP085気圧センサーの方が安かった・・・)
HTTPについては、このブログを見ている人なら基本部分はおわかりかと思う。
GET /sensor.dat HTTP/1.1 とか送って、200 OKとか返すわけだけど、muninは結構利用していてもプロトコル自体はあまり知らないと思う。
私も知らなかったので、軽く調査してみたところ、簡単な仕組みだったのでプラグインを作ってみた。
muninプラグインを作る場合のポイント
・muninプラグインはmuninサーバ側(munin-cron)は基本的に何も作る必要なく、munin-node側さえ書けば動く
・muninプラグインはどんな言語でも作ることが出来る(特別なライブラリを必要としない)
・munin-nodeはポート4949で普通に平文テキスト形式で通信するので、munin-nodeプログラムを使わず直接ノードを構築することも簡単(Arduino上にも簡単に実装出来る)
munin-nodeを叩くとある程度対話的に操作可能なインタフェイスがある。
ローカルホストのデフォルト設定のmunin-nodeに接続するなら、
1 |
telnet localhost 4949 |
でOK。
繋ぐと・・・
1 2 3 4 |
Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. # munin node at bbblog |
とか、帰ってくる。
とりあえず、Enterキーとか押してみると・・・
1 |
# Unknown command. Try cap, list, nodes, config, fetch, version or quit |
とか、普通にコマンドリストが帰ってきた。
それぞれ実行してみた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
cap cap multigraph dirtyconfig list cpu df if_err_eth0 if_eth0 load memory uptime nodes bbblog . config # Unknown service config cpu graph_title CPU usage graph_order system user nice idle iowait irq softirq graph_args --base 1000 -r --lower-limit 0 --upper-limit 100 graph_vlabel % graph_scale no graph_info This graph shows how CPU time is spent. graph_category system graph_period second system.label system system.draw AREA system.min 0 system.type DERIVE system.info CPU time spent by the kernel in system activities user.label user user.draw STACK user.min 0 user.type DERIVE user.info CPU time spent by normal programs and daemons nice.label nice nice.draw STACK nice.min 0 nice.type DERIVE nice.info CPU time spent by nice(1)d programs idle.label idle idle.draw STACK idle.min 0 idle.type DERIVE idle.info Idle CPU time iowait.label iowait iowait.draw STACK iowait.min 0 iowait.type DERIVE iowait.info CPU time spent waiting for I/O operations to finish when there is nothing else to do. irq.label irq irq.draw STACK irq.min 0 irq.type DERIVE irq.info CPU time spent handling interrupts softirq.label softirq softirq.draw STACK softirq.min 0 softirq.type DERIVE softirq.info CPU time spent handling "batched" interrupts steal.label steal steal.draw STACK steal.min 0 steal.type DERIVE steal.info The time that a virtual CPU had runnable tasks, but the virtual CPU itself was not running . fetch # Unknown service fetch cpu user.value 2157842 nice.value 5056908 system.value 1135668 idle.value 68884854 iowait.value 1282979 irq.value 81 softirq.value 11064 steal.value 0 . version munins node on bbblog version: 1.4.6 quit Connection closed by foreign host. |
capはmunin-nodeの機能の話?
versionとquitはそのまんまだね。
listは動作しているプラグインのリスト表示。
nodesは取得出来るノード名のリスト表示。
configはプラグインの設定を得られる(config プラグイン名)
fetchはプラグインの値を得られる(fetch プラグイン名)
最低限の動作は、listにプラグイン名が出て、configでプラグインの情報を得て、fetchでプラグインの値を取得する。
1,プラグイン名は、/etc/munin/plugins/以下のファイル名で自明。
今回試作するプラグインは、気圧センサーの値を取得するので
/etc/munin/plugins/env.barometic
と言うプラグインファイルを作成した。 このファイルは、実行可能である必要がある(chmod +x env.barometic)
munin的にはperlが基本だろうけど、今回は簡単にshellで作成、と言うことで
1 |
#!/bin/bash |
で書き始め。
1 2 |
#!/usr/bin/php <?php |
でPHPプログラムでもOKだね。
2,config情報はプラグインの第1引数にconfigと与えた場合の戻り値そのまま
なので、第1引数をifして、先のconfigの戻り値みたいなテキストを戻す。
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/bin/bash if [ "$1" = "config" ]; then echo 'graph_title Arduino BP Sendor'#グラフ名として描画される文字列 echo 'graph_vlabel Pressure'#グラフの縦軸ラベル echo 'graph_category Environment'#グラフのカテゴリ(disk:df disk:iostatみたいに複数のグラフがグループ化される場合のdiskの括り) echo 'graph_scale no'#補助単位系を使うか使わないか(yes/no) echo 'graph_args --lower-limit 900 --upper-limit 1100 --rigid'#グラフのその他の設定。 この場合、最低値900、最高値1100、最低値と最高値を固定描画 echo 'pres.label sensor1[hPa]'#presは、自分で定義するデータ系列の名前AでもBでもかまわない。 labelはデータ系列名 echo 'pres.max 1100'#pres系列の最高値で、fetchしたときにこれを超えると取得失敗と判断される echo 'pres.min 900'#名前の通り、maxに対する最低値の定義 exit 0 fi |
これで、実行権限を付けてmunin-nodeを再起動すれば、次回のmunin-cronが回ってきたときにはグラフ一覧ページに追加される。
データ系列を追加するなら、
1 2 3 |
echo 'pres2.label sensor2[hPa]' echo 'pres2.max 1100' echo 'pres2.min 900' |
みたいに、.前の名前を変えて列挙していく。
3,fetchの戻り値は引数無しで実行した場合の戻り値
なので、引数チェックが引っかからなかった場合に
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/bin/bash if [ "$1" = "config" ]; then echo 'graph_title Arduino BP Sendor'#グラフ名として描画される文字列 echo 'graph_vlabel Pressure'#グラフの縦軸ラベル echo 'graph_category Environment'#グラフのカテゴリ(disk:df disk:iostatみたいに複数のグラフがグループ化される場合のdiskの括り) echo 'graph_scale no'#補助単位系を使うか使わないか(yes/no) echo 'graph_args --lower-limit 900 --upper-limit 1100'#グラフのその他の設定。 この場合、最低値900、最高値1100 echo 'pres.label sensor1[hPa]'#presは、自分で定義するデータ系列の名前AでもBでもかまわない。 labelはデータ系列名 echo 'pres.max 1100'#pres系列の最高値で、fetchしたときにこれを超えると取得失敗と判断される echo 'pres.min 900'#名前の通り、maxに対する最低値の定義 exit 0 fi pres=`wget -q http://192.168.0.123/getP -O -` pres=`expr $pres / 100` echo "pres.value $pres"#pres系列の値 |
今回はネットワーク上の192.168.0.123にArduinoで作ったセンサーユニットがあって、/getPをHTTPで取得するとパスカル単位の気圧がただ出力されるようにしてあるので、それをhPaに変換(100で割るだけ)して出力している。
センサーユニットが192.168.0.124, 192.168.0.125にもある場合、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#!/bin/bash if [ "$1" = "config" ]; then echo 'graph_title Arduino BP Sendor' echo 'graph_vlabel Pressure' echo 'graph_category Environment' echo 'graph_scale no' echo 'graph_args --lower-limit 900 --upper-limit 1100 --rigid' echo 'sensor1.label sensor1[hPa]' echo 'sensor1.max 1100' echo 'sensor1.min 900' echo 'sensor2.label sensor2[hPa]' echo 'sensor2.max 1100' echo 'sensor2.min 900' echo 'sensor3.label sensor3[hPa]' echo 'sensor3.max 1100' echo 'sensor3.min 900' exit 0 fi pres=`wget -q http://192.168.0.123/getP -O -` pres=`expr $pres / 100` echo "sensor1.value $pres" pres=`wget -q http://192.168.0.124/getP -O -` pres=`expr $pres / 100` echo "sensor2.value $pres" pres=`wget -q http://192.168.0.125/getP -O -` pres=`expr $pres / 100` echo "sensor3.value $pres" |
これで、123~125の3個のセンサーを読んできて1枚のグラフにまとめてプロットするプラグインが完成。
BBBのADCを利用する場合・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#!/bin/bash if [ "$1" = "config" ]; then echo 'graph_title BBB.Analog' echo 'graph_vlabel Voltage' echo 'graph_category ADC' echo 'graph_scale no' echo 'graph_args --lower-limit 0 --upper-limit 1800' for (( i=0; i<=7; i++ )) do echo "ADC$i.label ADC$i[milli Volt]" echo "ADC$i.max 1800" echo "ADC$i.min 0" done exit 0 fi for (( i=0; i<=7; i++ )) do value=`cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/helper.14/AIN$i` sleep 0.1 echo "ADC$i.value $value" done |
これで、BBBのADCの0~7の生電圧を記録してグラフ化出来る。
組み込みマイコンで1からグラフ描画とかを作るのは非常に面倒だが、Linuxの利点である既存のOSS(今回はmunin)利用によって、簡単にグラフ化してWebインタフェイスで見られる訳だ。
ADCにLM35温度センサーをぶら下げているならば、LM35の特性は10mV/degCなので、そのままでも気温の10倍の値が表示されるし、value=expr $value / 10
を挟めばぴったりセ氏温度になる。
AC712電流センサーをつければ、殆どプログラムらしいプログラムを書くこと無くWebインタフェイスでグラフ表示可能な電力計ができあがってしまう。
↓PC置き場に設置したArduinoセンサーノードをBBB上のmuninで監視してみる。
温度
気圧計
ネットワーク接続センサー・ロガー等の設計・試作、量産対応可能です(デバイスからインターネット連動システムまで全般対応可能)
お問い合わせください。 > inquiry at studioes.net
(811)