昨年末にこの記事を読んで以来、昼過ぎにが眠くなるのは CO2 濃度のせいでは無いかと思い始め、CO2センサーへの興味が湧いて仕方がなっかのだが、CO2センサーはいかんせん高い。そう悩んでいたところ、格安のセンサーを見つけたのでUSBで値を取れるようにしてみた。
まとめ
- CO2mini というセンサーは何処にも書いてないが、USBデバイスとして認識できる
- gem を作ったので bundle install すれば Mac でも Linuxでも値がとれる。
- 僕のオフィスのCO2濃度は別に高く無さそう。
センサー選び
CO2 濃度を計れるセンサーは、専門家向けのものが多く価格帯が高い。 PCから値を取ろうと思うと、手頃のなのは
【日本正規代理店品・保証付】Netatmo ウェザーステーション NET-OT-000001
- 出版社/メーカー: Netatmo
- 発売日: 2013/10/10
- メディア: エレクトロニクス
- この商品を含むブログ (3件) を見る
だが 2万4000円もするし、最近売り切れてたりするので、本稿では www.monotaro.com
- 出版社/メーカー: カスタム
- メディア: Tools & Hardware
- この商品を含むブログを見る
何処にもUSBで値がとれるとは書いてないので不安になるが、 http://www.co2meter.com/collections/fixed-wall-mount/products/co2mini-co2-indoor-air-quality-monitor これと同じなので実はUSBで値がとれる。 ただし、いつUSB出力の機能がオミットされるかはわからないので自己責任で。あるいは販売店に問い合わせてほしい。
値のとりかた。
ruby スクリプトを作ったのでこれを利用してもらえればと思う。 github.com
$ brew install hidapi # or apt-get install libhidapi-hidraw0 など Linux では環境に応じてHIDAPIライブラリをインストールしてほしい $ git clone https://github.com/kurain/co2mini.git $ cd co2mini/examples $ bundle install $ bundle exec ruby -I./lib examples/co2show.rb
これだけだと、コンソールに値が見えるだけなので、僕の場合はMackerel に流して可視化 and 監視してる。 co2post.rb を参照してほしい。
※gem 化の準備はしてるのに、git を勧めるのは依存してるパッケージにPRを送ってるけれど採用されてないから!
参考資料兼余談
本稿で使ったもの以外のセンサーについて。
USB で繋がるものや、センサー単体で販売しているものが
http://www.co2meter.com/collections/co2-sensors
このサイトに沢山ある。日本でこの価格帯でかつ、オンライン販売で売ってるセンサーはほとんどない。 このサイトで買うとすると、安いセンサーで$80、輸送費が$35くらいなので、14000円くらい。 キャリブレーションどうするとかいう不安もある。
USBプロトコルについて
co2mini から値をとるソフトウェアは co2meter.com から取得できる。が windows 版しかない。 ありがたい事にプロトコルを解析してる人がいて
https://hackaday.io/project/5301-reverse-engineering-a-low-cost-usb-co-monitor
にまとめてくれている。逆アセンブルして調べたようで、上記のサイトの記事は相当おもしろい。おすすめである。 コードも github にまとまっている
https://github.com/henryk/fhem-co2mini
さらにサイトのコメントを見てると、各言語にポートしてる人も居て
node.js
https://github.com/maddindeiss/co2monitor
C言語
https://github.com/dmage/co2mon
の実装があるので、ruby 版を書くのはわりと簡単な話だった。
HIDAPI
co2mini はHIDデバイスとして認識される。HIDはUSBデバイスのなかの一つのクラスで、汎用的なのでよく使われているようだ。 ただ、libusb というメジャーな USB ライブラリからは扱いが難しく、libusb のサイトでも HIDデバイスを扱うときは
を使えと書いてある。HIDAPIは各OS(Linux, Mac, Win)でのHIDの扱いを抽象化していて、これを使えばOSをまたいで動く コードが書ける。今回 Mac で実験して、実運用は Raspberry Pi というのを考えていたので、こちらを採用した。 先に紹介した他の人の実装は、オリジナルのperlのやつとnode.jsの実装は Linux 環境のみを想定している、C言語実装のものは、HIDAPIを利用している。
ちなみに Linux には /dev/hidraw にHIDがマウントされるという、便利機能があって HIDAPI はこれを利用する。(libusbをつかう事もできる) Macの場合はIOKITに含まれるIOHIDから制御可能で、HIDAPIも利用してるっぽい。MacのUSBまわりはこちらが詳しい。
ruby_hid_api
HIDAPIのrubyバインディングは ruby_hid_api とruby_hidapi の2つがある。前者はFFIを使っていて、後者は拡張ライブラリ。 FFIを使ってるほうが、OSが違った時に動く可能性が高いので、私は ruby_hid_api を利用している。 HIDAPIの send_featurer_request 関数に対応する部分が未実装だったので、実装してPR出しているけれど 音沙汰がないのが残念。
プロトコルの実際
プロトコルの詳細はコード見てくれという感じなんだけれど、面白かったので少しだけ解説しておく。
co2mini では 'Feature Report' でデバイスを初期化する。初期化前には 'Input Report' (HIDAPIにおけるread関数)では値がとれない。 初期化時に8バイトの値(マジックテーブル)を渡すのだけれど、この後 Input Report で返ってくる値は、マジックテーブルの値と XORが取られていたり、ビットシフト が行われたりしていて、簡単な暗号化がされている。 co2mini.rb の _decrypt が復号化メソッドなので、詳細はそちらを参考にしてほしい。 他のUSBデバイスを知らないので、一般的な動作なのかわからないのだが、不思議な挙動である。
def _decrypt(key, data) offset = [0x48, 0x74, 0x65, 0x6D, 0x70, 0x39, 0x39, 0x65] #"Htemp99e" shuffle = [2, 4, 0, 7, 1, 6, 5, 3]; phase1 = shuffle.map{|i| data[i] } phase2 = (0..7).map{|i| phase1[i] ^ key[i] } phase3 = (0..7).map{|i| ( (phase2[i] >> 3) | (phase2[ (i-1+8)%8 ] << 5) ) & 0xff } ctmp = (0..7).map{|i| ( (offset[i] >> 4) | offset[i] << 4 ) & 0xff } result = (0..7).map{|i| (0x100 + phase3[i] - ctmp[i]) & 0xff } return result; end
おわりに
というわけで、co2 濃度の可視化と記録を始めてみた。近代的オフィスなので、空調がとまると濃度が酷いことになる。
普通の時間帯は、空調とまらないのでほとんど問題ない。