数年前、Raspberry Piと電流センサを組み合わせ、Webサービスにアップロードする消費電力計を作成しました。
http://dolls.tokyo/raspberry-pi%e3%81%a8iot%e5%90%91%e3%81%91%e3%82%b0%e3%83%a9%e3%83%95%e3%82%b5%e3%83%bc%e3%83%93%e3%82%b9%e3%80%8cm2x%e3%80%8d%e3%81%a7%e5%ae%b6%e3%81%ae%e6%b6%88%e8%b2%bb%e9%9b%bb%e5%8a%9b%e3%82%92
このときに使っていたデータ・ストレージ&プロットサービスが”M2X”。
これが有料化されてしまい、我が家の電力監視はストップしたままでした。
代替えが中々見つからなかったのですが、今回Adafruit IOに引っ越せましたので手順を残します。
Adafruit IO ?
最初にデータの受け口になってくれるAdafruit IOについて。
提供元のAdafruit(エイダフルーツと読む)はRaspberry Pi & Arduino周りパーツで有名なアメリカのベンダー。
電子工作に関する面白い事を色々公開しているギークな会社。
彼らはデータの良いアウトプット先が見つからなかったため、自分たちでWebサービスを作ったそうです。
それがAdafruit IO。
Adafruit IOはAPIやMQTTによるデータを受け取るストレージ、スマホやブラウザで使うUIを自由にレイアウトできるDashboard、他サービスへのトリガーなどのサービスを提供してくれます。
プランには無料の”IO Free”と、有料の”IO+”があります。
”IO Free”のスペックはこんな感じ。
- 30 data points per minute
- 30 days of data storage
- Triggers every 15 minutes
- 10 feeds
- 5 dashboards
IFTTTとの連携も可能らしく、PからVへの橋渡しをうまくしてくれそうな期待感があります。
気をつけなければならないのはデータの保存期間。
30日間しかデータを保存してくれないため、長期のデータは自前で保管しておく必要があります。
1分あたり30個のデータを受け付けてくれるのは、M2Xの2.2個/分からすると大分自由ですね。
有料の”IO+”は60日間のデータ保管、60個/分のデータ受付、天気サービス連携などがついて$10/月または$99/年。
ラズパイ1+最新RaspiOSを準備
5年前のRaspbianでは色々不都合が出たため、最新のRaspberry Pi OSで1からセットアップしました。
Raspberry Pi OS Lite
Release date: August 20th 2020
Kernel version: 5.4
Size: 438MB
Wi-Fiの有効化
Raspberry Pi 1には無線がついていません。
前回通り、ジャンクで買ったPLANEX GW-USMicroNで無線化します。
最新OSでは、Wi-Fiドングルは最初から認識しました。
手順は上記記事を更新しましたので、そちらを御覧ください。
再起動後も自動的に繋げたいなら以下が必要。
/etc/wpa_supplicant/wpa_supplicant.confを作成した後は、/etc/rc.localに自動接続のためのコマンド
”wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf”
を追記して再起動
「一度wpa_supplicantで設定すれば自動的に繋がる。」
みたいな記事が多かったけれど、自分が試した限りではそんな事なかった。
OSイメージによって差があるのかもしれませんが。
rubyenvからrubyをインストール
LiteバージョンはRubyが入っていません。
今は”rubyenv”を使って入れるのが流儀?らしいので従います。
Raspberry piにRubyの最新版をインストールする – Qiita
rbenvのインストールして設定をbashの設定ファイルに書き込む, zshなど使う場合はそれぞれに合わせること
> sudo apt-get install rbenv > echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> .bashrc > echo 'eval "$(rbenv init -)"' >> .bashrc > sudo apt-get install git > git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build > rbenv install --list
シェルの環境設定ファイルを作成し、rubyのビルドリストを取得・更新しています。
大量のリストの中から、2.7.2をインストール。
インストール済みバージョンの確認 # ruby -v ruby 2.5.5p157 (2019-03-15 revision 67260) [arm-linux-gnueabihf] 2.7.2のインストール # rbenv install 2.7.2 Downloading ruby-2.7.2.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.2.tar.bz2 Installing ruby-2.7.2... Installed ruby-2.7.2 to /root/.rbenv/versions/2.7.2 rbenvでの利用バージョン確認(*がついている方) # rbenv versions * system (set by /root/.rbenv/version) 2.7.2 切り替え # rbenv global 2.7.2 再確認 # rbenv versions system * 2.7.2 (set by /root/.ruby-version) # ruby -v ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [armv6l-linux-eabihf]
rubyenvはダウンロードしたものをユーザーホーム配下に格納します。
環境はユーザーごとに作る必要があるため、今回はrootに作りました。
GPIOライブラリのインストール
最後にRuby用のGPIOライブラリ、piperをインストール。
# gem install pi_piper Fetching ffi-1.13.1.gem Fetching pi_piper-2.0.0.gem Fetching eventmachine-1.0.9.gem Building native extensions. This could take a while... Successfully installed eventmachine-1.0.9 Building native extensions. This could take a while... Successfully installed ffi-1.13.1 Successfully installed pi_piper-2.0.0 Parsing documentation for eventmachine-1.0.9 Installing ri documentation for eventmachine-1.0.9 Parsing documentation for ffi-1.13.1 Installing ri documentation for ffi-1.13.1 Parsing documentation for pi_piper-2.0.0 Installing ri documentation for pi_piper-2.0.0 Done installing documentation for eventmachine, ffi, pi_piper after 406 seconds 3 gems installed
過去の記事のコードをそのまま実行し、特に変更なく動く事を確認できました。
Adafruit io ruby client
次に、結果をAdafruit ioへ書き込む部分を作っていきます。
Adafruit ioは国内の実例を見つけられませんでした。
公式ガイドを意訳しながら試行錯誤したので、間違いは笑ってやって下さい。
ioに書き込むライブラリ
まずシンプルにadafruit ioにデータをアップできるか確認します。
今回は公開されているRubyクライアントを使用しました。
GitHubには詳しいHowtoも書かれています。
まずはモジュールをインストール。
# gem install adafruit-io Fetching: multipart-post-2.1.1.gem (100%) Successfully installed multipart-post-2.1.1 Fetching: faraday-0.17.3.gem (100%) Successfully installed faraday-0.17.3 Fetching: faraday_middleware-0.14.0.gem (100%) Successfully installed faraday_middleware-0.14.0 Fetching: thread_safe-0.3.6.gem (100%) Successfully installed thread_safe-0.3.6 Fetching: minitest-5.14.2.gem (100%) ERROR: Error installing adafruit-io: minitest requires Ruby version < 3.1, >= 2.2.
次に下記コードでテストします。
3-4行目のusername/api_keyは、サイトのメニューバーにある”My Key”を押すと表示されるUsername/Active Keyに置き換えてください。
require 'adafruit/io' username = '自分のusername' api_key = 'aio_XXXXXXXXXXXXXXXXXXXXXXXX' api = Adafruit::IO::Client.new key: api_key, username: username # create a feed puts "create" garbage = api.create_feed(name: "test-watt-power") # add data puts "add data" api.send_data garbage, 'test_data_1 40W' api.send_data garbage, 'test_data_2 220W' end
うまく動けば、”Feeds”にあるDefaultフィードグループへ、”test-watt-power”というFeedが作成されます。
またFeedの中には、2個のテストデータが書き込まれます。
MQTTでPublishする2つの方法
APIを使った方法では、一度書き込んだ後は追記できない仕様の様です。
これでは定期的に測ったデータをアップする事ができません。
そこで定期更新に向く、MQTTを使ったフィードの書き込み方法を試しました。
2つのデータを毎回書き込む、シンプルなコードでテストしました。
require 'adafruit/io' username = 'ユーザー名' key = 'アクティブキー' feedA = 'フィードの名前A' feedB = 'フィードの名前B' testnumberA = 'テストデータA' testnumberB = 'テストデータB' connection_opts = { port: 8883, uri: 'io.adafruit.com', protocol: 'mqtts' } mqtt = Adafruit::IO::MQTT.new username, key, connection_opts mqtt.publish feedA, testnumberA mqtt.publish feedB, testnumberB end
この結果は、上記APIでの書き込みと似たデータになります。
実行するたびにデータを増やして行く事ができます。
mqtt.publishメソッドでは、無条件にDefaultフィードグループへフィードが作成され、値が書き込まれます。
これにフィードグループを指定したい場合、mqtt.publish_groupメソッドを使います。
mqtt.publish feedA, testnumberA mqtt.publish feedB, testnumberB ↓ mqtt.publish_group('フィードグループの名前', { 'feedA' => testnumberA, 'feedB' => testnumberB, })
うまく希望するフィードグループへフィードへデータを書き込む事ができました。
完成した消費電力計コード
書き込み手段が確定できましたので、これを過去のコードへマージします。
require "pi_piper" require 'adafruit/io' #adafruit io account username = 'ユーザー名' api_key = 'アクティブキー' fd_key0 = "watt-power_ch0" fd_key1 = "watt-power_ch1" connection_opts = { port: 8883, uri: 'io.adafruit.com', protocol: 'mqtts' } #Power Factor pf = 1.1 #Vref:MCP3208 Refarence voltage ( pin 13) v_ref = 3.3 #Register rl = 1000 #Coupling constant kt = 0.98 #coil turn turn = 3000 #Sampling time ( Number / sleep time ) sampling = 20 #Sensing pow0 = 0 pow1 = 0 read_ch = 0 count = sampling * 2 RESOLUTION_AT_12BIT = 0b111111111111.to_f.freeze mqtt = Adafruit::IO::MQTT.new username, api_key, connection_opts PiPiper::Spi.begin do |spi| while count > 0 do case read_ch when 0 then _, center, last = spi.write [0b00000110, 0b00000000, 0b00000000] when 1 then _, center, last = spi.write [0b00000110, 0b01000000, 0b00000000] end center = center & 0b00001111 center = center << 8 value = center + last eo = ( ( value / RESOLUTION_AT_12BIT ) * v_ref ).round(4) io = ( eo / ( rl.to_f / turn.to_f * 0.9.to_f * kt ) ).round(4) pow = ( 100 * io * pf ).round(4) case read_ch when 0 then ( pow0 = pow0 + pow read_ch = 1 ) when 1 then ( pow1 = pow1 + pow read_ch = 0 ) end count = count - 1 sleep 0.25 end #output pow0 = ( pow0 / sampling ).round(1) pow1 = ( pow1 / sampling ).round(1) puts "[ch0 = %sW, ch1 = %sW]" % [pow0, pow1] mqtt.publish_group('Epower', { fd_key0 => pow0, fd_key1 => pow1, }) puts "[send data %s]" % [Time.now] end
#sensingのあたりの内訳を知りたい方は、過去記事を御覧ください。
実行結果です。
[ch0 = 282.4W, ch1 = 81.2W] [send data 2020-12-09 00:10:23 +0900]
機能は
- コンソールに測定データを表示します。
- “Epower” feed-groupに、”watt-power_ch0″と”…1″という2つのfeedを作成します
- 作成した2つのフィードにそれぞれch0,ch1の計測値が入ります。
- 実行するたびに値を追記します。
なお、ライブラリ製作者様は「コードの中に資格情報を入れるな(Whenever possible, we recommend you keep your Adafruit IO API credentials out of your application code by using environment variables. All the examples)」と書いていますがそんな余裕は無し。
RubyをCronで定期実行
コードのテストが完了したので、crontabで5分おきに実行するよう設定します。
例によって、シェルでのコマンドをそのまま書いても動きません。
crontabでrubyを動かすには、パスを個別に通してやる必要があるそうです。
いくつかの手法の中から、シェルスクリプトを用意しなくていいこの方法を採用させていただきました。
cronでrbenvのrubyを使う3つの方法 – sonots:blog
やり方3: bash -l を使う
おそらくこれが一番シンプル。-l オプションを使って .bash_profile を読み込んで実行する。* * * * * sonots /bin/bash -lc ‘cd /path/to/program-dir && ruby program.rb’
端末で実行する状況とcron で実行される状況が同じになるのでデバグも捗る。もちろん ~/.bash_profile に以下が書いてある事が前提。
export PATH=”$HOME/.rbenv/bin:$PATH”
eval “$(rbenv init -)”
./bash_profileはインストール時に作ってあるので問題ありません。
crontabにはこの様に書きました。ログも採取する設定です。
# crontab -l */5 * * * * /bin/bash -lc 'cd /usr/local/etc/piper && ruby epower.rb > /var/log/cronlog_epower.log 2>&1'
次回へつづく
思った以上に長くなったため、残りは次回。
後半は作成したフィードをグラフにし、一覧できるDashboardを作成します。
また、完成までに起きた様々なトラブルを公開します。
2020/12/12 後編を公開しました