前回の記事に引き続いて、FlashairとArduinoで部屋の温湿度をモニタするシステムを構築する話です。前回は、Arduino側のソースコードを紹介しましたので、今回はFlashairに書き込むluaスクリプトについて紹介します。
システム概要
まず、今回構築するシステムの概要を示します。
今回の記事で紹介するのは、④の部分になります。csvファイルをIoT Hubにアップロードするために作成したluaスクリプトを紹介します。
Flashair IoT Hubへの登録
まずは、購入したFlashairをIoT Hubに登録します。その方法は、Flashair Developersのこちらのページを参考にしてください。基本的にはこの通りに進めましたが、一つCONFIGの設定はFlashAir開発者向け非公式wikiの設定ページのこちらを参考にしました。
luaスクリプトの実行
Flashairではluaを実行するタイミングとして、二つ用意されています。一つはFlashairに電源が投入されたとき、もう一つはFlashairにファイルが書き込まれたときになります。
電源投入されたときにluaスクリプトを実行するためには、CONFIGに”LUA_RUN_SCRIPT=/bootscript.lua”を追加します。この例では、電源投入と同時にbootscript.luaが実行されます。そのほかのluaスクリプトを実行したいときは、スクリプト名を変更することで実行できます。
Flashairにファイルが書き込まれたときにluaスクリプトを実行するためには、CONFIGに”LUA_SD_EVENT=/writescript.lua”を追加します。ファイル書き込み時にluaスクリプトを実行するときには、CONFIGに”LUA_RUN_SCRIPT”が記述されていると、うまくluaスクリプトが実行されない時があるようなので、ファイル書き込み時にスクリプトを実行したいときは、削除しておきましょう。特に、デフォルトのbootscript.luaは無限ループでIoT Hubにデータを送り続けるので注意です。
CSVファイルのアップロード
Flashair Developersには、csvファイルをIoT Hubにアップロードしてそのファイルからグラフを書くための方法が紹介されています。そのページを参考にして、luaスクリプトを書いてみました。それがこちらになります。
print("HTTP/1.1 200 Internal OK\n\n") local fpath = "/" local file_path = "/SENSOR2.csv" local timestamp_type = "relative" local timestamp_unit = "second" local iothub = require("iothub") local function uploadCSV(file_path, timestamp_type, timestamp_unit) --read config local file = io.open('credentials.json') local text = file:read("*a") file:close() print(text) local config = cjson.decode(text) --get the size of the file local filesize = lfs.attributes(file_path,"size") if filesize ~= nil then print("Uploading "..file_path.." size: "..filesize) else print("Failed to find "..file_path.."... something wen't wrong!") return end --Upload! boundary = "--61141483716826" contenttype = "multipart/form-data; boundary=" .. boundary local mes = "--".. boundary .. "\r\n" .."Content-Disposition: form-data; name=\"file\"; filename=\""..file_path.."\"\r\n" .."Content-Type: text/plain\r\n" .."\r\n" .."<!--WLANSDFILE-->\r\n" .."--" .. boundary .. "--\r\n" local blen = filesize + string.len(mes) - 17 b,c,h = fa.request{ url=config.api_base .. "/v1/flashairs/self/measurements/free?timestamp_type=" .. timestamp_type .. "&timestamp_unit=" .. timestamp_unit, method="POST", headers={ ['Authorization']='Basic ' .. config.credential, ["Content-Length"]=tostring(blen), ["Content-Type"]=contenttype, }, file=file_path, body=mes, bufsize=1460*10, } print(c) print(b) return b end uploadCSV(file_path, timestamp_type, timestamp_unit) iothub.addMeasurement({10, 20}) sleep(10000) collectgarbage("collect")
まず、計測値のデータファイル名は決まっているので、f_path, file_pathにそれぞれデータファイルを置いているディレクトリ、ファイルのパスを定義します。uploadCSV関数の定義は、サンプルスクリプト”upload_csv.lua”からと同じです。
Flashair Developersのページによると、csvファイルは、1行に時刻, データ1, データ2, データ3, ・・・と書き込む必要があります。その時刻データは絶対時刻にするか、アップロードされた時刻からの相対時刻にするか選ぶことができます。今回、私が作りたいシステムではArduinoが絶対時刻を取得することはできないので、相対時刻にします。そのため、”timestamp_type=relative”に設定します。相対時刻の単位は初期値はミリ秒ですが、これだと時刻の数字が大きくなりすぎてArudinoで扱いきれなくなるので、”timestamp_type=second”に設定します。これが前回の記事で、温度と湿度の値以外に1秒ごとのカウントをcsvファイルに書き込んでいた理由になります。
iothub.addMeasurement({10, 20})はluaスクリプトが実行されたかどうか確認するために記述しています。
sleep(10000)
collectgarbage(“collect”)
上記の二行は、luaスクリプトの動作が終わって無線が安定化するのを待ち、発生した”ゴミ”をなくしてリフレッシュするために入れています。
CSVファイルがアップロードされない
上記のluaスクリプトをFlashair Developersのページにあるように、LUA_SD_EVENTを使って実行するようにしました。そして、SDカードシールドにFlashairをセットし、電源を投入しました。シリアルモニタで様子を見ていると、センサの値を読み取り、温湿度の計算、csvファイルの書き込みはできているようでしたが、IoT Hubにアップロードされませんでした。
一方で、Flashairをパソコンに接続し、csvファイルを開く⇒上書き保存すると、IoT Hubへアップロードされました。このことから、Arduinoからcsvファイルを作成しても、csvファイルが書き込まれたとFlashairが認識していないことになります。その原因として考えていることは、csvファイルの作成日時です。Arduinoで作成したcsvファイルの日時は2000年1月1日になります。このファイル作成日時が正確でない(あるいは定義されていない??ここは私の妄想)ために、luaスクリプトが実行されないのではないかと考えました。そこで、常にluaスクリプトを実行し、csvファイルを一定間隔でアップロードし続けることにしました。
常にluaスクリプトを実行する
Arduinoからのcsvファイル書き込みで、luaスクリプトが実行されないので、SDカード起動時にluaスクリプトを実行し、そのまま無限ループにはいり、一定間隔でuploadCSV()を実行すればよいと考え、次のようなスクリプトを作成しました。
while(1) do if check ~= 0 then uploadCSV(file_path, timestamp_type, timestamp_unit) end iothub.addMeasurement({cnt}) cnt = cnt + 1 check = cnt % 6 if cnt > 359 then cnt = 0 end sleep(10000) collectgarbage("collect") end
uploadCSV()の定義までは先ほどのスクリプトと同じなので、省略します。luaスクリプトが実行されているかどうかの確認用に10秒ごとにカウントした値をIoT Hubに送っています。計測データは1分ごとの値なので、1分ごとにファイルをアップロードするように、if文で条件分岐しています。これをLUA_RUN_SCRIPTで実行することで、無事に1分ごとにcsvファイルをIoT Hubにアップロードすることができるようになるかと思ったのですが、今度は別の問題が起こりました。
SDカードのサンプルスケッチの罠
新たに生じた問題は、csvファイルをSDカードに書き込んだ後、そのファイルを読み込んで、シリアルモニタにその中身を表示すると、無線LANが切れるという問題です。
この書き込んだファイルを再び開くコードは、ArduinoのSDカードのサンプルスケッチに記述されていて、動作確認に非常に便利なため、残していました。しかし、ファイルを開いた後にFlashairがオフラインになり、その後どんなに待ってもオンラインに戻らない現象が起きました。まったく理由はわからないのですが、再度開くことをやめたらオフラインにならずに済んだので、前回の記事で紹介したソースコードではその部分を削除しています。
ファイルを開いてシリアルバッファにデータが送り込まれ、それが消えないうちはWiFiがオンにならないのかと考えて、シリアルバッファにあるデータを空に(flush)したりしましたが、一度WiFiが切れてしまうとダメでした。ファイルの読み込みをやめた後もWiFiの電源が再び入ることはなく、相性が悪いようでした。デバッグ用にシリアル通信を入れているのもダメなのか?と心配になっています。
システムの完成
最後に完成したシステムの写真を紹介します。
写真のように4つのシールドを重ねた構造になっていて、下から、Arduino Uno, SDカードシールド, 温湿度センサシールド(自作), 液晶ディスプレイシールドになっています。LCDには温度と湿度が表示されています。
こちらは、IoT Hubの画面です。温度、湿度のグラフが表示されています。
まとめ
前回の記事に続いて、部屋の温度湿度をモニタするシステムのFlashair部分の紹介でした。luaスクリプトに悩まされながらも、何とか形にすることができました。次はこのシステムの小型化や、温度湿度をモニタして、その値に応じて何かFlashairにフィードバックすることができるようにしたいと思います。
それでは最後までお読みいただきありがとうございます。また次の記事でお会いしましょう。
最近のコメント