統合テスト
ノード機にデータ送信機能を追加
サーバ機のAPIが準備できましたので、統合テストの前にノード機にデータの送信機能を追加します。
HTTPプロトコルでPOSTするので、net/http ライブラリを使います。今回もまずテストプログラムを作って、ライブラリの動作確認をしてみましょう。
net/http ライブラリの使い方は、Rubyの公式ドキュメント へ掲載されていますので、これをほぼそのまま試すことができます。
- test-post.rb
require "net/http" require "uri" require "json" uri = "http://192.168.1.11/cgi-bin/index.rb?ctrl=data_post" data = {pressure: 1013.12345, temperature: 25.567} res = Net::HTTP.post_form(URI.parse(uri), {"data"=>data.to_json}) puts res.body
実行結果
ruby test-post.rb OK
OKと表示され、サーバ機では /var/log/logger/data-日付.csv ファイルにデータが追加されます。
正しい動作が確認できたら、Workerへ組込みましょう。
- worker.rb
require "al_worker" require "al_worker_timer" require "i2c" require "net/http" require "uri" require "json" ... POST_URI = "http://192.168.1.11/cgi-bin/index.rb?ctrl=data_post" ... def send_data( data ) AlWorker.log( data ) Net::HTTP.post_form(URI.parse(POST_URI), {"data"=>data.to_json}) end
統合テスト
では、実行してみましょう。既にWorkerが常駐している場合は、それを終了させてから改めて実行します。
kill `cat /tmp/al_worker.pid` ruby -I../lib worker.rb
サーバ機のデータファイルに、1分ごとにデータが追加されるのを確認します。
tail -F /var/log/logger/data-*.csv 2019-03-30 11:24:14, 1016.35, 20.1 2019-03-30 11:25:14, 1016.33, 20.1 2019-03-30 11:26:14, 1016.29, 20.1
デバッグ
うまく動作しない場合は、ノード機、サーバ機、それぞれのログファイルを確認して、何が起こっているかを把握します。
ノード機は、常駐するWorkerモジュールを使っているので、/tmp/al_worker.log です。
cat /tmp/al_worker.log
サーバ機は、apacheのcgiインタフェース経由でCGIモジュールを使っているので、/tmp/al_cgi.log です。
cat /tmp/al_cgi.log
今回のように最終的に人の手を介さないシステムでは、意図しない動作が起こった時にはログファイルがあることでトラブルシュートを圧倒的に効率的にすすめることができます。逆にログファイルが無いと、何の手がかりもなくて全くトラブルシュートができないこともあります。
Aloneでは、Rubyの例外を使って自動的にかつ効率的にログファイルを作ります。ログファイルが作られるメリットだけをとってみても、プレーンにコードを記述するよりフレームワークを使う価値はあるように思います。
自動起動の設定
すべてうまく動作している事が確認できたら、RaspberryPiの起動時に Workerも自動的に起動するように設定しておきましょう。
簡単に設定できる、昔ながらの/etc/rc.localファイルに記述する方法を使います。
- /etc/rc.local
... ruby -I /home/pi/alone/lib /home/pi/alone/bin/worker.rb exit 0
最後 exit 0 の直前に起動の指示を書きます。
コマンドラインでテストしていた時は相対パスで記述していましたが、ここではここでは絶対パスで記述します。
ファイルに記述が終わったら、再起動してみてWorkerが自動起動しているか確認してみましょう。
プログラム全体
ノード機のプログラム全体を再掲しておきます。
- worker.rb
require "al_worker" require "al_worker_timer" require "i2c" require "net/http" require "uri" require "json" ADRS = 0x5c # LPS25H NODE = "/dev/i2c-1" # I2C device node POST_URI = "http://192.168.1.11/cgi-bin/index.rb?ctrl=data_post" def to_int16( b1, b2 ) return (b1 << 8 | b2) - ((b1 & 0x80) << 9) end def to_uint24( b1, b2, b3 ) return (b1 << 16) | (b2 << 8) | b3 end class Worker1 < AlWorker def initialize2() @i2c = I2C.create(NODE) @i2c.write(ADRS, 0x20, 0x90) @timer = Timer.periodic( 60 ) @timer.run() { d = get_data() send_data( d ) } end def get_data() ret = {} buf = @i2c.read(ADRS, 5, 0xa8) p_cnt = to_uint24(buf.getbyte(2), buf.getbyte(1), buf.getbyte(0)) ret[:pressure] = p_cnt.to_f / 4096 t_cnt = to_int16(buf.getbyte(4), buf.getbyte(3)) ret[:temperature] = 42.5 + t_cnt.to_f / 480 return ret end def send_data( data ) AlWorker.log( data ) Net::HTTP.post_form(URI.parse(POST_URI), {"data"=>data.to_json}) end end worker1 = Worker1.new() worker1.daemon()