Withings WS-50を使ってCO2濃度をCloudWatchメトリクスに保存する

Withings WS-50を使ってCO2濃度をCloudWatchメトリクスに保存する
公開日時

部屋のCO2濃度を計測したくなったのでセンサーを買おうかと思ったが、よくよく考えたら家で使っているWithingsのSmart Body Analyzer (WS-50)にCO2濃度計測機能が付いていたことを思い出したのでこいつを活用することに。

特別なことをしなくてもWithingsのアプリからCO2濃度を見ることはできるが、他のセンサーと同様にCloudWatchで一元管理することにした。

ただし、WS-50の場合センサ情報の送信が以下の2パターンしかないため、リアルタイムでCO2濃度を取得することはできない。

  • 1日一回どこかのタイミングで環境センサ情報(CO2濃度、温度)を送信
  • 体重を測ったタイミングで環境センサ情報も送信

なお、CO2濃度情報は30分おきに記録されている。

ws50-syncの設定

調べてみたところWithingsのAPIを使ってDomoticzというOSSのホームオートメーションシステムにデータを書き込むツールが公開されていたのでこちらを利用させていただくことにした。

  • Domoticzのインストール

Raspberry Pi - Domoticzを参考にセットアップ

  • CO2濃度計測用にVirtual meterを作成

Virtual meter - Domoticzを参考にセットアップ

  • ws50-syncの初回実行
python ws50-sync.py -u ${WITHINGS_USER} -p ${WITHINGS_PASS -d /home/pi/domoticz/domoticz.db -c 1 -f -r -l 7
  • cronで定期実行するように設定しておく
crontab -e

0 */12 * * *  /bin/bash -lc 'cd /home/pi/ws50-sync && python ws50-sync.py -u ${WITHINGS_USER} -p ${WITHINGS_PASS -d /home/pi/domoticz/domoticz.db -c 1 -l 7

これでWS-50のセンサ情報がSQLiteのDBに保存できた。

cloudwatch-syncの作成

ws50-syncを参考に、SQLite DBからCO2情報を取得してCloudWatchメトリクスに送信する[[cloudwatch-sync.py]]を作成。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import datetime, timedelta

import json
import os
import sys
import time
import sqlite3
import argparse
import hashlib
import subprocess

parser = argparse.ArgumentParser(description='Cloudwatch WS-50 Syncer')
parser.add_argument('-d', '--database', help='fully qualified name of database-file', required=True)
args = parser.parse_args()

def init_database(db):
    """Initialize database."""
    global conn
    global c
    if os.path.exists(db):
        conn = sqlite3.connect(db, timeout=60)
        c = conn.cursor()
        c.execute('SELECT * FROM Preferences WHERE Key = "DB_Version";')
        dbinfo = c.fetchall()
        for row in dbinfo:
            dbversion = row[1]
        print("[-] Attaching database " + db + " [version " + str(dbversion) + "]")
    else:
        sys.exit("[-] Database not found " + db + "\n")


def get_metric_array():
    metrics = []
    fr = open('./cloudwatch/last_update_date.txt', 'r')
    last_update_date = fr.read()
    print(last_update_date)
    if (last_update_date == ''):
      c.execute('SELECT Value, Date FROM Meter ORDER BY Date LIMIT 20')
    else:
      c.execute('SELECT Value, Date FROM Meter WHERE Date > "' + last_update_date + '" ORDER BY Date LIMIT 20')
    dbdata = c.fetchall()
    for row in dbdata:
        value = row[0]
        date = datetime.strptime(row[1], '%Y-%m-%d %H:%M:%S') - timedelta(hours=9)
        metrics.append({
          "MetricName": "Withings/co2",
          "Value": value,
          "Timestamp": date.strftime('%Y-%m-%dT%H:%M:%SZ'),
          "Unit": "None"
        })

    if (metrics[1:-1]):
        fw = open('./cloudwatch/last_update_date.txt', 'w')
        timestamp = datetime.strptime(metrics[-1]["Timestamp"], '%Y-%m-%dT%H:%M:%SZ') + timedelta(hours=9)
        last_update_date = timestamp.strftime('%Y-%m-%d %H:%M:%S')
        fw.write(last_update_date)
    return metrics

def write_metric_json():
    fw = open('./cloudwatch/metrics.json', 'w')
    metrics = get_metric_array()
    # print(metrics)
    json.dump(metrics, fw, indent=4)
    return len(metrics)


def put_meterics_to_cloudwatch():
    cmd = 'aws cloudwatch put-metric-data --namespace "Home" --metric-data file://./cloudwatch/metrics.json'
    subprocess.check_output(cmd, shell=True)

def main():
    init_database(args.database)
    length = write_metric_json()
    if length > 0:
        put_meterics_to_cloudwatch()

if __name__ == "__main__":
    main()
  • 初期設定

最終同期時刻を保存するためのファイルを作成しておく必要がある。

mkdir cloudwatch
touch cloudwatch/last_update_date.txt
  • cloudwatch-syncの初回実行
python cloudwatch-sync.py -d /home/pi/domoticz/domoticz.db'
  • cronで定期実行するように設定しておく
crontab -e

0 * * * *  /bin/bash -lc 'cd /home/pi/cloudwatch-sync && python cloudwatch-sync.py -d /home/pi/domoticz/domoticz.db

これでCO2濃度をCloudWatchメトリクスに保存できるようになった。

putMetricsの際のハマりどころ

過去のデータは2周間前以降のものしか送信できなかった。

また、過去のデータは送信してもすぐにはグラフには表示されないので注意。

そして、テストの際にメトリクス名を間違えたため削除をしようとしたが削除機能が見つからず。

調べてみるとCloudWatchメトリクスの削除はできず、2週間データ更新がなければ自動で消えるということを知った。

参考


Related #raspberry pi

ngrokの代わりにCloudflare Tunnelを使う

botやwebhookを利用するサービスの開発が捗る

Dockerのデータ保存場所を変更する

/etc/docker/daemon.jsonに追記

Alexaにゲーミングマシンと周辺環境を終了してもらう

「Alexa Steamを終了して」ができるようになった

Alexaにゲーミングマシンと周辺環境を起動してもらう

PC起動、TV起動、サウンドバー起動がまとめてできるようになった

docker-compose build時に「no Space Left on Device」が発生

1年前にも同じエラーにハマってた