switchbotの温湿度計を購入したので、node.jsでデータを取得し、s3にアップロードしてみた。
データの取得
データの取得にはnobleを使用した。
nodeのv9以降では動かないようなので、v8系をインストールすること。
nobleの使い方は割愛。
microbotの開発元?のOpenWonderLabsがAPI仕様を公開しているので、それを参照しながらデータを読み取る。
https://github.com/OpenWonderLabs/python-host/wiki/Meter-BLE-open-API
ビットの操作はとっても苦手なので、苦労した。
例えば、4バイト目の後ろ7ビットには温度のデータが入っているようなので、このようにして取得。
const temperature = data.readUInt8(4) & 0x7f;
&(ビット演算子)で0x7f(1111111)をビットANDして、後ろ7桁を切り出すらしい。
前3桁が欲しかったら、こんな感じで0xE0(11100000)をビットANDして、
さらにシフト演算子 >>>
(0埋めバージョン)で後ろ5桁を溢れさせる。
var a = data.readUInt8(4) & 0xE0 >>> 5
web開発ばっかりやってた人間としては、このあたりはとっても苦手な領域。
データが取れたら fs
でファイルに書き出す。
後で扱いやすいように moment.js
を使って日時分秒をファイル名にした。
↓ソース全体(scan.js)
'use strict';
const noble = require('noble');
const fs = require('fs');
const moment = require('moment');
// living swithbot
const MAC = "xxxxxxx"; // switchbotのmacアドレス
const tmpDir = "/var/tmp/envdata/"; // データを保存したいディレクトリ
noble.on('stateChange', (state) => {
if (noble.state === 'poweredOn'){
noble.startScanning();
} else {
noble.on('stateChange', scanStart);
}
});
noble.on('scanStart', () => {
console.log('start scanning');
});
noble.on('scanStop', () => {
console.log('stop scanning');
process.exit(0);
});
noble.on('discover', (peripheral) => {
if (peripheral.uuid === MAC) {
noble.stopScanning();
const data = peripheral.advertisement.serviceData[0].data;
const deviceType = data.slice(0, 1).toString('ascii');
const battery = data.readUInt8(2) & 0x7f;
const temperature = data.readUInt8(4) & 0x7f;
const humidity = data.readUInt8(5) & 0x7f;
const time = moment().format('YYYY-MM-DD_HH:mm:ss');
const jsonData = {
"datetime": time,
"battery": battery,
"temperature": temperature,
"humidity": humidity
};
// write to file
fs.writeFileSync(tmpDir + time + '.log', JSON.stringify(jsonData));
noble.stopScanning();
}
});
s3へのアップロード
s3へのアップロードはいたって簡単です。
下準備
aws-sdk
のライブラリを npm install
する。
AWSのIAMでアップロード用のユーザ作ってAmazonS3FullAccess
のポリシー(uploadだけだったら権限絞ったポリシーで良い気もする)付けて、そのcredential情報をjsonファイルに書き出しておく。
{
"accessKeyId": "xxxxxxxxxxxxx",
"secretAccessKey": "xxxxxxxxxx"
}
こんな具合。
S3への接続
こんな感じでs3オブジェクトをセットアップ。
AWS.config.loadFromPath('/home/pi/.aws/credential.json'); // 保存したcredentialファイルのパスを指定
AWS.config.update({region: 'ap-northeast-1'});
const s3 = new AWS.S3();
あとはアップロードしたいファイルの情報を整えて s3.putObject()
でアップロード。
↓ソース(upload.js)
const AWS = require('aws-sdk');
const fs = require('fs');
AWS.config.loadFromPath('/home/pi/.aws/credential.json');
AWS.config.update({region: 'ap-northeast-1'});
const s3 = new AWS.S3();
const tmpdir = '/var/tmp/envdata/';
fs.readdir(tmpdir, (err, files) => {
if (err) throw err;
files.forEach( (file) => {
var params = {
Bucket: 'switchbot-room',
Key: file
};
params.Body = fs.readFileSync(tmpdir + file);
s3.putObject(params, (err, data) => {
if (err) throw err;
fs.unlinkSync(tmpdir + file, (err) => {
if (err) throw err;
});
});
});
});
自動起動設定
cron設定するだけ。
*/5 * * * * /usr/local/bin/node /home/pi/swithbot/scan.js
*/5 * * * * /usr/local/bin/node /home/pi/swithbot/upload.js
5分間隔でデータを取得して、アップロード。
今のところ問題なくデータが上がってます。
NextAction
次は、上がったデータを可視化したい。
QuickSight, Mackerel, ES + Kibana どれでやろうか検討中。chart.js使って自分で作ってもいいけど、
一番費用が掛からない方法がいいな。