環境構築
balenaを使ってしまっていますが、debian環境なので install_packages
はそのまま apt install
等で置き換えてください。
またNode.jsでBLEを扱うためのnobleというライブラリを今回は使いますが、本家よりも @abandonware/noble
の方がメンテされているので、今回はこちらを使います。
Dockerfile
FROM balenalib/%%BALENA_MACHINE_NAME%%-node:12-buster-build as buildRUN install_packages bluetooth bluez libbluetooth-dev libudev-dev
RUN npm install @abandonware/noble rxjs
FROM balenalib/%%BALENA_MACHINE_NAME%%-node:12-buster-runWORKDIR /workCOPY --from=build ./node_modules ./node_modulesCOPY app.js .CMD ["node", "app.js"]
ソースコード
SwitchBotの温湿度計のMACアドレスを予め取得しておいてください。わからない場合は、まずfilterせずにScanしてみて、それっぽいのをしぼります(filterの記述はソースコードのコメントを参照)。
まず冒頭のRxを準備するソースコード。
app.js
constnoble=require('@abandonware/noble');constSWITCHBOT_MAC_ADDR=process.env.SWITCHBOT_MAC_ADDR||'aa:bb:cc:dd:ee:ff';// コロンあり小文字でconst{fromEvent,forkJoin,interval,empty,}=require('rxjs');const{filter,map,mergeMap,take,}=require('rxjs/operators');// BLEのデバイスがスタンバイ状態になるのを待つストリームconstblePowerdOn=fromEvent(noble,'stateChange').pipe(filter((state)=>{console.log(state);returnstate==='poweredOn';}),map(()=>console.log('[ble]poweredOn')),take(1));// ペリフェラルを発見したらペリフェラルを流すストリーム// MACアドレスが不明な場合はfilterの記述を削除// bleDevices = fromEvent(noble, 'discover')bleDevices=fromEvent(noble,'discover').pipe(filter((peripheral)=>{returnperipheral.address===SWITCHBOT_MAC_ADDR;}));
アドバタイズのデータから温度と湿度とバッテリー残量を取得する処理。
参考: https://qiita.com/c60evaporator/items/7c3156a6bbb7c6c59052#%E3%82%BB%E3%83%B3%E3%82%B5%E5%80%A4%E5%8F%96%E5%BE%97%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90
app.js
constdecodeSensorData=(data)=>{constbatt=data[2]&0b01111111;constisTemperatureAboveFreezing=data[4]&0b10000000;lettemp=(data[3]&0b00001111)/10+(data[4]&0b01111111);if(isTemperatureAboveFreezing<0)temp=-temp;consthumid=data[5]&0b01111111;return{'SensorType':'SwitchBot','Temperature':temp,'Humidity':humid,'BatteryVoltage':batt};};
最後に実際に動かす部分。
app.js
forkJoin({ble:blePowerdOn}).pipe(mergeMap(()=>{console.log('[ble]scanning...');noble.startScanning([]);// 10秒ごとにスキャンする(この中でやる必要はなさそう)interval(10*1000).subscribe(()=>{noble.stopScanning();noble.startScanning([]);});returnbleDevices;}),).subscribe((peripheral)=>{// 取得したセンサー情報を出力するconsole.log(decodeSensorData(peripheral.advertisement.serviceData[0].data));});
出力
このように値を出力できました。あとは、好きなクラウドにアップロードしたり、画面に出力したりして楽しんでください。