オムロンの環境センサー「2JCIE-BL01」で測定した温度、湿度などのデーターを、Bluetooth Low Energy(BLE)でRaspberry Piに送り、Raspberry Pi3からAmbientに送って可視化します。Raspberry Pi3のプログラムはPythonで記述しました。

オムロンの環境センサー「2JCIE-BL01」

オムロンの環境センサー「2JCIE-BL01」は温度、湿度、気圧、照度、UV、音の6種類のデーターを測定し、BLEで送信するセンサー端末です。ボタン電池(CR2032)1個で動作します。ウェザーニュース社の「WxBeacon2」も中身は同じもののようです。今回はこの「WxBeacon2」を使いました。

「2JCIE-BL01」のBLEインタフェースは「Communication Interface Manual」という資料で公開されています。

全体の構成

センサー端末から温度、湿度などのデーターをBluetooth Low Enrgy (BLE)で送ります。Raspberry Pi3をゲートウェイにしてBLEでデーターを受信し、Ambientに送信して可視化します。BLEではセンサー端末をペリフェラル、ペリフェラルにデーターを取りにいくものをセントラルといいます。今回の場合、Raspberry Pi3がセントラルになります。

Raspberry Pi3の準備

Raspberry Pi3はBluetooth Low Energyの通信モジュールが搭載されているので、追加するハードウェアはありません。Raspberry Pi3のOSは最新のRaspbian GNU/Linux 9.4 (stretch)を使いました。jessieでも動作すると思います。

プログラミング言語では、Pythonとnode.jsにBLEを扱うライブラリーがあります。今回はPythonを使うことにします。Raspberry Pi3 stretchにはPython2.7とPython3がインストールされていますが、pyenvを導入し、環境を切り替えて使います。pyenvの使い方は「RaspberryPiにpyenvを導入」などをご覧ください。Pythonのバージョンは3.6.5を使いました。

PythonでBLEを扱うライブラリーはいくつかあります。その中でドキュメントが一番しっかりしているbluepyを使いました。次のようにインストールします。pi$と書かれたものはRaspberry Pi3上のコマンド実行です。

 pi$ sudo apt-get install libglib2.0-dev
 pi$ pip install bluepy

pyenvを使わず直接python3を使う方は、pipの代わりにsudo pip3としてください。

Ambientのライブラリーもインストールし ます。

 pi$ pip install git+https://github.com/AmbientDataInc/ambient-python-lib.git

環境センサー「2JCIE-BL01」とRaspberry Pi3の動作確認

Raspberry Pi3のBluetoothのバージョンは5.43です。

 pi$ bluetoothd -v
 5.43

「2JCIE-BL01」に電池を入れ、hcitoolコマンドでBLEのスキャンをしてみます。

 pi$ sudo hcitool lescan
 LE Scan ...
 EC:B3:46:BA:78:75 Env

スキャンで見つかったBLE端末が複数表示されます。その中で名前が「Env」のものが「2JCIE-BL01」です。名前の左(例ではEC:B3:46:BA:78:75)が「2JCIE-BL01」のアドレスです。

次にgatttoolコマンドで「2JCIE-BL01」にコネクトし、サービスを調べます。hcitoolで見つけた「2JCIE-BL01」のアドレスを-bオプションで指定します。最後の「-I」は大文字の「i」です。

 pi$ gatttool -b EC:B3:46:BA:78:75 -t random -I
 [EC:B3:46:BA:78:75][LE]> connect
 Attempting to connect to EC:B3:46:BA:78:75
 Connection successful
 [EC:B3:46:BA:78:75][LE]> primary
 attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
 attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
 attr handle: 0x000c, end grp handle: 0x0016 uuid: 0000180a-0000-1000-8000-00805f9b34fb
 attr handle: 0x0017, end grp handle: 0x0025 uuid: 0c4c3000-7700-46f4-aa96-d5e974e32a54
 attr handle: 0x0026, end grp handle: 0x003a uuid: 0c4c3010-7700-46f4-aa96-d5e974e32a54
 attr handle: 0x003b, end grp handle: 0x0043 uuid: 0c4c3030-7700-46f4-aa96-d5e974e32a54
 attr handle: 0x0044, end grp handle: 0xffff uuid: 0c4c3040-7700-46f4-aa96-d5e974e32a54

「connect」コマンドを入力し、しばらくして「Connection successful」が表示されればコネクトに成功しています。「primary」コマンドを入力すると「2JCIE-BL01」で定義されているサービスが確認できます。1行目の「uuid: 00001800-・・・」の5文字目から8文字目までの1800が「Generic Access Service」というサービスUUIDで、端末の名前などが取得できます。詳細は「2JCIE-BL01」のマニュアルをご覧ください。

プログラム1(コネクトモード)

「2JCIE-BL01」はアドバタイズして、セントラルに見つけてもらい、セントラルからコネクトされてデーターのやり取りやモード設定などをおこなうモード(コネクトモードと呼ぶことにします)と、アドバタイズデーターにセンサー値を載せて送ってしまうモード(ブロードキャストモードと呼びます)があります。

デフォルトではコネクトモードになっているので、まずコネクトモードの「2JCIE-BL01」からセンサーデーターを取得してAmbientに送信するRaspberry Pi3のプログラムを作ります。PythonのBLEライブラリーbluepyのクラス定義の資料を参照しながらお読みください。

スキャンをおこなうにはScannerクラスのオブジェクトを作り、scanメソッドを呼びます。このとき、withDelegateでスキャンハンドラーを指定しておくと、デバイスを見つけ次第ハンドラーが呼ばれます。スキャンとスキャンハンドラーは次のようなプログラムになります。

スキャンハンドラーに渡されるdevはScanEntryクラスのオブジェクトで、getScanDataでアドバタイズデーターを取り出せます。「2JCIE-BL01」はアドバタイズデーターとしてデータータイプが’Short Local Name’で、値が’Env’という情報を送るので、
次のようにすると「2JCIE-BL01」を見つけられます。見つけたあとは「2JCIE-BL01」にコネクトしてセンサーデーターを取得するので、そのためにスレッドを起動しています。

BLEデバイスと通信するためにbluepyではPeripheralというクラスが用意されています。今回は5分ごとに「2JCIE-BL01」にコネクトしてセンサーデーターを取得し、Ambientに送るスレッドを作るので、PeripheralクラスとThreadクラスを多重継承したEnvSensorというクラスを作りました。コンストラクターでは親クラスのコンストラクターを呼び、Ambientの初期化もおこないます。

スレッドの処理はrunメソッドに記述します。中身はデバイスにコネクトして、
センサーデーターを取得し、Ambientに送信して300秒(5分)待つという処理の繰り返しです。

「2JCIE-BL01」はSensor Serviceの中に最新データー(Latest data)というCharacteristicがあり、これをreadすると温度、湿度などの最新データーが取得できます。デフォルトの測定間隔は300秒(5分)です。getCharacteristicsでLatest dataのUUID(0x3001)を指定してCharacteristicを取得し、readして、最新のセンサーデーターを取得しています。データーは温度、湿度などが19バイトにまとめららたbytesタイプです。それをそのままAmbientに送る関数send2ambientに渡しています。

send2ambientで19バイトにまとめられたbytesタイプのデーターをstruct.unpackを使って温度、湿度など個々のデーターに分解し、Ambientに送信しています。

scanやconnect、getCharacteristics、readなどのメソッドの中でBLEデバイスと通信します。通信に失敗した時などには例外が発生するので、実際のプログラムには例外処理が加えてあります。プログラム全体はGithubに公開しました。

Raspberry Pi3のBLEモジュールにアクセスするにはroot権限が必要なので、プログラムは次のように起動します。

 pi$ sudo python env2ambientCS.py
 New Env ec:b3:46:ba:78:75 ←スキャンして「2JCIE-BL01」を見つけた
 connected to ec:b3:46:ba:78:75 ←「2JCIE-BL01」にコネクト
 11 25.94 57.2 263 0.02 1010.7 37.71 73.82 23.0 2.956 ←最新のセンサーデーターを取得
 sent to Ambient (ret = 200) ←Ambientに送信

Raspberry Pi3からログアウトしてもプログラムが終了しないようにするには、次のように起動します。

 pi$ sudo nohup python env2ambientCS.py < /dev/null &

Ambientのチャネルページを見ると、送られたデーターを確認できます。

プログラム2(ブロードキャストモード)

「2JCIE-BL01」のモード変更

「2JCIE-BL01」にはアドバタイズデーターにセンサー値を載せて送るブロードキャストモードがあります。更にブロードキャストモードの動作として一定間隔(デフォルトで1.285秒間隔)で発信するモードと10秒発信して50秒休むというように間欠動作するモードの二つがあります。発信と休止の時間幅も変更できます。休止中は通信モジュールをオフにしているようで、コネクトもリード/ライトもできなくなり、消費電力を抑えています。「2JCIE-BL01」を間欠動作のブロードキャストモードに設定し、送られたデーターを取得してAmbientに送信するプログラムを作ります。

アドバタイズの動作設定はParameter Service(UUID: 0x3040)のADV settingというCharacteristic(UUID: 0x3042)でおこないます。プログラムを作ってもいいのですが、スマホアプリでやってみます。アプリは「BLE Scanner」を使います。

「BLE Scanner」を立ち上げると、スキャンして見つかったBLEデバイスが表示されます。

「EnvSensor-BL01」と表示されたものが環境センサー「2JCIE-BL01」です。それをタップするとアドバタイズデーターとサービスが表示されます。サービスの中に「0C4C3040-7700-・・・」というUUIDのものがあり、これがParameter Serviceです。

これをタップすると、Characteristicが表示されます。「0C4C3042-7700-・・・」というUUIDのものがADV settingです。

値が「0x0808a0000a0032000800」と表示されています。9バイト目がビーコンモードで「08」はEventBeaconを表します。これを「03」のLimited Broadcaster 1に変更します。Limited Broadcaster 1が間欠動作モードです。このCharacteristicをタップして、値を0808a0000a0032000300にして書き込みます。

値を書き込んだら「2JCIE-BL01」の電池を入れ直してリセットすると、新しいモードで動き出します。もう一度「BLE Scanner」を立ち上げると、デバイスの名前がIM-BL01に変わっていることが確認できます。

Raspberry Pi3側のプログラム

ブロードキャストモードの時のRaspberry Pi3側のプログラムもまずスキャンをします。スキャンハンドラーを指定してスキャンを起動するところまではコネクトモードの時のプログラムと同じです。

スキャンハンドラーに渡されるdevのgetScanDataメソッドを呼び、アドバタイズデーターを取り出します。ブロードキャストモードの時「2JCIE-BL01」はアドバタイズデーターの中にデータータイプが’Manufacturer’で、その時の値の先頭の文字列が’d502’という情報を送るので、次のようにすると「2JCIE-BL01」のアドバタイズデーターを見つけられます。

値の5文字目、6文字目(value[4:6])はシーケンス番号で、測定をおこなうごとに値が一つ増やされます。デフォルトの測定間隔は300秒(5分)なので、5分に1回値が増えます。シーケンス番号が更新されたらデーターをAmbientに送信します。

Ambientに送信する関数send2ambientもコネクトモードの時とほぼ同じです。コネクトモードの時はCharacteristicをreadした値はbytesタイプでしたが、スキャンで得られるデーターは文字列なので、bytes.fromhexでbytesタイプに変換し、温度、湿度などのデーターに分解しています。

プログラムは次のように起動します。

 pi$ sudo python env2ambientBS.py

プログラム全体はGithubに公開しました。