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週間データ更新がなければ自動で消えるということを知った。