2
4

More than 3 years have passed since last update.

SwitchBotの温湿度計の値をNode.js(BLE)を使って取得する

Last updated at Posted at 2020-08-15

環境構築

balenaを使ってしまっていますが、debian環境なので install_packages はそのまま apt install 等で置き換えてください。

またNode.jsでBLEを扱うためのnobleというライブラリを今回は使いますが、本家よりも @abandonware/noble の方がメンテされているので、今回はこちらを使います。

Dockerfile
FROM balenalib/%%BALENA_MACHINE_NAME%%-node:12-buster-build as build
RUN install_packages bluetooth bluez libbluetooth-dev libudev-dev
RUN npm install @abandonware/noble rxjs

FROM balenalib/%%BALENA_MACHINE_NAME%%-node:12-buster-run
WORKDIR /work
COPY --from=build ./node_modules ./node_modules
COPY app.js .
CMD ["node", "app.js"]

ソースコード

SwitchBotの温湿度計のMACアドレスを予め取得しておいてください。わからない場合は、まずfilterせずにScanしてみて、それっぽいのをしぼります(filterの記述はソースコードのコメントを参照)。

まず冒頭のRxを準備するソースコード。

app.js
const noble = require('@abandonware/noble');
const SWITCHBOT_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のデバイスがスタンバイ状態になるのを待つストリーム
const blePowerdOn = fromEvent(
  noble,
  'stateChange'
).pipe(
  filter((state) => {
    console.log(state);
    return state === 'poweredOn';
  }),
  map(() => console.log('[ble]poweredOn')),
  take(1)
);

// ペリフェラルを発見したらペリフェラルを流すストリーム
// MACアドレスが不明な場合はfilterの記述を削除
// bleDevices = fromEvent(noble, 'discover')
bleDevices = fromEvent(noble, 'discover').pipe(
  filter((peripheral) => {
    return peripheral.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
const decodeSensorData = (data) => {
  const batt = data[2] & 0b01111111;
  const isTemperatureAboveFreezing = data[4] & 0b10000000;
  let temp = (data[3] & 0b00001111) / 10 + (data[4] & 0b01111111);
  if (isTemperatureAboveFreezing < 0) temp = -temp;
  const humid = 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([]);
    });

    return bleDevices;
  }),
).subscribe((peripheral) => {
  // 取得したセンサー情報を出力する
  console.log(decodeSensorData(peripheral.advertisement.serviceData[0].data));
});

出力

image.png

このように値を出力できました。あとは、好きなクラウドにアップロードしたり、画面に出力したりして楽しんでください。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4