Slackのbotから部屋の気温・湿度を返す
家に帰ってくるといつも部屋が暑い。
帰宅前に部屋の気温が何度なのか知りたくなり作ってみました。
簡単に言えばIoTの一種です。
ハードウェア選定
ハードウェアはどこのご家庭にもある(!?)Raspberry piをサーバとして使用します。
もちろん、本体はインターネットと電源に常時接続していなければいけません。
気温センサにはストロベリーリナックス社の
USB温度・湿度センサ(USBRH) を使いました。
I2C接続のセンサの方が選択肢が多いですが、どれもラズパイ基板上に乗せるタイプです。
こんな本体熱の影響をモロに受ける物を選ぶ訳にはいきません。
ソフトウェア構成
Slackで特定のダイレクトメッセージに応答という経路です。実際のシーケンスは次の通りです。
Zoom
問い合わせ先であるSlackbotのAPIには
hubot を使用しました。これが一番事例が多かったためです。
USBRHはドライバをインストールすると、通常のドライブと同様にアクセス出来、テキストで計測値を得られます。
計測値はただ単に返すだけでは面白くないので、
MySQL へ記録する方式としました。
記録、問い合わせはMySQLのコンソールをそのまま使います。
クエリ結果をそのままSlackへ垂れ流してもいいのですが、どうしてもグラフが欲しくなります。
gnuplot を使い、クエリをグラフ化、画像として保存、さらにhubotがタイムラインへ投稿します。
当然ながら、プロセスそれぞれが簡単に動くわけありません。かなり迷い設計変更を何回もしました。
詳細を書いていきます。
hubot
node.jsで動くらしいです。どういう仕組みか知らんけど。
導入方法とnode.jsの仕組みは他を当たってください。めんどくさいので。
botの挙動はここで定義します。
問題は挙動を定義するスクリプトにCoffeescriptというJava Scriptを生成するための中間言語みたいなものを使わなければいけない点でした。
ググるとまずサジェストに「Coffeescript オワコン」と出てくる始末です(爆
処理はシェルスクリプトで行い、hubot側は受け渡し窓口だけにしました。
すなわち、hubot側がシェルスクリプトを実行し、必要であれば標準出力をSlackに垂れ流します。
child_process = require 'child_process'
module.exports = (robot) ->
robot.respond /now/, (m) ->
child_process.exec "mysql -uユーザ名 -pパスワード temp -e 'select DT,D000,D001 from (SELECT ID,DT,D000,D001 FROM temp.USBRH order by ID desc limit 30) as sub order by ID'", (error, stdout, stderr) ->
if !error
m.send stdout
else
m.send "db error"
robot.respond /p/, (m) ->
child_process.exec ('"/home/pi/slackbot/scripts/plot.sh"'), (error, stdout, stderr) ->
if !error
filename = "/home/pi/slackbot/scripts/p.png"
channel = m.message.rawMessage.channel
m.send "uploading"
child_process.exec "curl -F file=@#{filename} -F channels=#{channel} -F token=#{process.env.HUBOT_SLACK_TOKEN} https://slack.com/api/files.upload", (error, stdout, stderr) ->
else
m.send "sh error"
温度センサ
何とLinux用のドライバが公式にありません。ストロベリーリナックスなのに。
第三者が作ったドライバをソースからビルドしてインストールします。導入方法は
fgd氏の記事 に詳しいです。
参考元にある通り、ラズパイでのコンパイルには問題がいくらか起きます。
Linuxカーネル(すなわちRaspbian)のソースが別途いる(ドライバのビルドだから)
gccのバージョンが違う(カーネルソースのバージョンと現カーネルのバージョンが合わないから)
libncurses5-devがいる(元コードの依存関係)
めんどくさい奴ですねぇ・・・。
そんなことで、計測値をMySQLに登録するシェルスクリプトを書きました。
temp=`cat /proc/usbrh/0/temperature`
rh=`cat /proc/usbrh/0/humidity`
dt=`date +"'%Y-%m-%d %H:%M:%S'"`
mysql -uユーザ名 -pパスワード temp -e "insert into USBRH(DT,D000,D001) values(${dt},${temp},${rh})"
あとはcronでこのシェルスクリプトを定時実行すればいいだけです。ここは問題無しでした。
MySQL
ここは特になしです。
普通のコマンドラインと同じです。
導入方法は他を当たってください。めんd(ry
gnuplot
コイツも問題です。学生時代の苦労が再びやってきました。
時系列のグラフ、軸が2個あるグラフを描く設定をいちいち思い出し、それらしいグラフを描きます。
gnuplotは対話型インターフェイスかつ、コマンドライン引数の類がほとんどありません。
ちなみにMySQLも対話型インターフェイスですが、触れないことにします。
パイプが直接出来ないのでいったんクエリ結果をリダイレクトし、シェルスクリプト中でgnuplotのコマンドをバッチ処理する事でグラフPNG画像を保存します。
描画が終わったらクエリ結果のファイルは削除してしまいます。
とりあえず描画範囲は現時刻から数時間前とします。ここはSQLで勝手に変えられますね。
mysql -uユーザ名 -pパスワード temp -e "SELECT DT,D000,D001 FROM temp.USBRH order by ID desc limit 180" > tmp.txt
gnuplot -p <<KUSO
set nokey
set datafile separator '\t'
set xdata time
set timefmt '%Y-%m-%d %H:%M:%S'
set format x '%H:%M'
set key inside
set grid
set y2tics
set yrange [0:40]
set y2range [20:100]
set ylabel "Temp [deg]"
set y2label "Humid [%]"
set term png size 800,480
set output "p.png"
p 'tmp.txt' every ::1 u 1:2 with line ti "Temp", 'tmp.txt' u 1:3 with line axes x1y2 ti "Humid"
set output
KUSO
rm tmp.txt
Slackに画像を投稿する
curlコマンドを起動し、所定のURIへファイルを送り付ければOKです。
コードは先に描いたhubotのスクリプト中にあります。
設定にはSlackのチャンネル名、botのトークンを渡します。
チャンネル名もトークンもスクリプト内のメンバから取り出せます。
動作風景
Zoom
Slackのインターフェイスに繋がれば、どこでも部屋の状態を知る事が出来ます。
データベースに記録を行うようにしたので解析等やりたい放題です。
ただし、部屋の気温を知る事が出来ても、帰るまでに部屋の気温が快適にならなければ意味がありません。続く。