TL;DR
SGP40 とは
- Sensirion製
- 屋内の空気質を測定するために適したセンサ
- 混合酸化化合物(MOx)センサと温度コントロール用小型ホットプレートを搭載
- 濃度値やVOCガス種のデータを出力するものではなく、屋内に存在する一般的な燃料蒸発ガス(VOC)をもとにデジタル値を出力
- 出力された値はSensirionのVOCインデックスアルゴリズムで利用可能
- 関連するVOCの変化にともなう相対濃度を検知し、24時間あたりの平均値として出力
- I2Cアドレス:
0x59
SGP40 搭載 空気質センサボードを入手
対象デバイスとセンサーとの間はI2Cで通信するのですが、I2Cの接続方法はメーカーにより様々ですので注意が必要です。
例えば、Qwiic接続システムで接続する場合は以下のボードが使えます。オンラインまたはお近くの電子部品屋さんでお求めください。
sgp40(Elixirパッケージ)
メーカー提供のCで書かれたプログラムをElixirから使えるようにしたものです。僕が色々試した結果できた産物です。よかったら使ってみてください。
CプログラムをElixirから使えるようにする方法にはいくつか選択肢がありますし、場合によってはプログラム全体をElixirプログラムに翻訳する手もあります。
Sensirion/embedded-i2c-sgp40やSGP40のデータシートを眺めた結果、頻繁に複雑な計算処理が走るのでElixirプログラムに書き換えるのは得策ではないと思い、Portを介してメーカーのCプログラムと対話することにしました。
Elixirの公式ドキュメントによると、Portは、Erlang VMの外部でオペレーティング システム プロセスを開始し、メッセージ パッシングを介してプロセスと通信するためのメカニズムを提供するとのことです。
Functions for interacting with the external world through ports.
Ports provide a mechanism to start operating system processes external to the Erlang VM and communicate with them via message passing.
Port利用する場合、開発者はErlang VMとの通信に標準入力・標準出力を使用する実行可能ファイルを書きます。
個人的にGregMefford/blinkchainプロジェクトの実装例がわかりやすいのでいつも参考にしています。
src/port_interface.h
- Cプログラムで計算した結果を
:ok
,{:ok, "hoge"}
,{:error, "hoge"}
の形式でElixirプログラムに返すための関数群。
GregMefford/blinkchainのport_interface.hをインターフェースとしてそのまま使ってます。
src/main.c
- 無限ループでElixirプログラムからコマンドが送られてくるのを待つ
- 標準入力から固定バイト数を読み取り、そこからコマンドと引数を取り出す
- 処理を実行
- 結果を
:ok
,{:ok, "hoge"}
,{:error, "hoge"}
の形式でElixirプログラムに返す
バッファーの長さは、受け取りたいコマンド、引数、区切り文字を合わせた全体の最長文字数に応じてを決定します。
不正なメッセージを誤って送信してしまった時にすぐに気がつくよう、コマンドが認識されなかった時にメッセージ全体をElixirプログラムに返すようにしておきます。
Nervesで空気質センサSGP40を使う
使い方は簡単です。
ご自身のNervesプロジェクトのmix.exs
の依存性リストに{:sgp40, ~> 0.1.5}
を追加。
あとはいつも通りファームウエアをコンパイルして、ファームウエアをmicroSD焼き、microSDを対象デバイスに搭載。
対象デバイスが起動したら、対話コンソール(IEx)を開き、SGP40モジュールの関数でセンサーを操作します。
iex> {:ok, sgp} = SGP40.start_link(bus_name: "i2c-1")
{:ok, #PID<0.1407.0>}
iex> SGP40.measure(sgp)
{:ok, %SGP40.Measurement{voc_index: 123, timestamp_ms: 885906}}
Elixir Forum
Elixir Forum に続々お便りをいただいております。ありがとうございます。
さいごに
本記事は autoracex #259 の成果です。ありがとうございます。