Asopitech With · 空気質モニター
Airthings 空気質グラフ with Alopex Skulk
Airthingsは、ラドンや粒子状物質、VOCなどの室内の空気を測り、アプリで過去のグラフと通知を見せる空気質モニターです。これをAlopex Skulkで作り直すと…?
更新: 2026/10/13
どんなサービスか
AirthingsのView Plusは、複数のセンサーで、ラドン、粒子状物質、VOCなど、目に見えない空気の汚れを測ります。アプリは、ラドンやVOCの値を追い、過去の空気質のグラフ、花粉の情報、通知を見せます。今回作り直すのは、測った値の記録とグラフの部分です。
データの置き場所
- Skulkの時系列:ラドン、粒子状物質、VOCなどの値を、部屋と機器のタグを付けてSkulkに追記します。
- 時間で区切る集計:日ごと、週ごとの平均を、時間で区切る集計で出し、グラフに渡します。
- PromQL:値がしきい値を超えた時間を、PromQLで問い合わせて通知に使います。
センサーから値を読んで書き込むのは、機器とアプリのコードです。
配置の形
Skulkを、モニターの機器とスマホのアプリに組み込みます。記録は手元にたまり、建物や家をたくさん見る側では、同じエンジンのSkulkをサーバー、クラスタとして動かして集めます。
Alopex Skulkが合う理由
空気質のデータは、センサーごとの数値の時系列です。Skulkは、取り込み、時間の集計、PromQLを、機器やアプリに組み込んだまま行います。貯めたデータはParquetで、長い期間の分析にもそのまま使えます。
コードで見る
空気質の計測をLine ProtocolでSkulkに取り込み、読み出す中心だけを取り出したコードです(Rust)。
use alopex_skulk::ingest::line_protocol::LineProtocolDecoder;
use alopex_skulk::ingest::{IngestLimits, Ingestor};
use alopex_skulk::model::FieldValue;
use alopex_skulk::store::recovery::{RecoveryConfig, RecoveryStore};
fn main() -> alopex_skulk::Result<()> {
std::fs::create_dir_all("airthings-data").unwrap();
let store = RecoveryStore::open("airthings-data", RecoveryConfig::default())?;
let limits = IngestLimits::default();
let mut ingestor = Ingestor::new(store, limits);
// CO2 の計測を Line Protocol で取り込む(measurement,tag field timestamp[ns])
let base: i64 = 7_200_000_000_000;
let now = base + 300_000_000_000;
for (i, co2) in [450.0, 620.0, 800.0].iter().enumerate() {
let ts = base + (i as i64) * 60_000_000_000;
let line = format!("air,room=living co2={co2} {ts}");
let batch = LineProtocolDecoder::new(limits).decode(line.as_bytes(), now)?;
assert_eq!(ingestor.ingest(batch, now)?.accepted_count(), 1);
}
ingestor.sink_mut().flush_all()?;
// 取り込んだ CO2 を読み出す
for row in &ingestor.sink().read_measurement("air")? {
if let Some(FieldValue::Float(co2)) = row.row().field("co2") {
println!("t={} co2={co2}", row.row().timestamp());
}
}
Ok(())
}取り込みは ingest() が返った時点でWALに永続します。日ごと・週ごとの平均や、しきい値を超えた時間の抽出は、SkulkのPromQL/時間で区切る集計で出します。
センサーの時系列を機器の中で貯めて集計できるAlopex Skulkで、空気のグラフを作ってみよう。