M5Stackに搭載されているESP32はWi-FiとBluetooth Low Energy(以下、BLE)で通信できます。
センサーデーターをWi-Fi経由でクラウドに送信する例は「M5StackでセンサーデーターをAmbientに送る (Arduino編)」に書きました。今回はデーターをM5StackからBLEで発信する例を紹介します。また、M5Stackと同じCPUを搭載している開発ボードESPr Developer 32でも動作するようにします。発信したデーターはゲートウェイで受信して、Ambientに送ります。
全体の構成
M5StackにBME280を接続し、温度、湿度、気圧を測定し、BLEで発信します。データーはゲートウェイで受信してAmbientに送ります。M5Stackと同じCPUを搭載するESPr Developer 32でも動作するようにします。
ゲートウェイはBLE通信ができて、インターネットにも接続できるものが必要です。今回はPythonのBLEライブラリーも評価したかったので、Pythonの動くRaspberry Pi3を使います。
BLEデバイスの動作
BLEではセンサー端末をペリフェラル、ペリフェラルからデーターを取得する端末をセントラルといいます。スマホから腕時計型の活動量計にアクセスしている場合、活動量計がペリフェラル、スマホがセントラルになります。
BLE通信では、ペリフェラルが自らの存在を発信(アドバタイズ)します。セントラルはアドバタイジングパケットをスキャンし、自分が必要とするペリフェラルを見つけ、ペリフェラルに接続(コネクト)してデーターの送受信をおこないます。このやり取りをペリフェラル/セントラルモードあるいはコネクトモードと呼びます。
もう一つの通信方法は、ペリフェラルがセンサーデーターなどをアドバタイジングパケットに載せて送り、セントラルがそれを受信する方法です。ブロードキャスター/オブザーバーモードあるいはブロードキャストモードと呼びます。
コネクトモードは双方向通信ですので、ペリフェラルからデーターを取得するだけでなく、セントラル側からパラメーター設定などをおこなうといった場合はコネクトモードが必要です。ただし、ペリフェラルはセントラル側からのコネクトを待つため、一般的にはDeep Sleepできず、電力消費を抑えにくくなります。
ブロードキャストモードは単方向です。ペリフェラルからデーターを取得するだけならブロードキャストモードが適しています。しかもブロードキャストモードは、ペリフェラルがデーターを送りたいときだけアドバタイズし、あとはDeep Sleepすることができるので、電力消費も低く抑えられます。
今回はコネクトモード、ブロードキャストモードそれぞれで動作するセンサー端末と、それに対応したセントラル側のプログラムを開発します。
センサー端末のハードウェア
M5Stack版
M5StackとBME280を使うセンサー端末は「M5StackでセンサーデーターをAmbientに送る (Arduino編)」で開発したものと同じです。M5StackとBME280をジャンパーワイヤーで接続しました。
M5Stackの概要、M5Stackを使うためのArduinoの環境設定、M5Stackの動作確認、M5StackとBME280の接続については「M5StackでセンサーデーターをAmbientに送る (Arduino編)」をご覧ください。
ESPr Developer 32版
ESPr Developer 32とBME280を使うセンサー端末はブレッドボードを使って組み立てました。
回路図を示します。
ハードウェアの動作確認
M5Stack版もESPr Developer32版も、マイコンとセンサーを接続したら、動作を確認します。
動作確認プログラムも含めて今回のプログラムはGithubに公開しています。
このページの右上の「Clone or download」>「Download ZIP」をクリックして、ZIPファイルをダウンロードし、適当な場所で展開します。この中の
- src/envSensor_esp32/BME280_test/BME280_test.ino
が動作確認プログラムです。M5StackとESPr Developer 32のどちらでも動作します。
このプログラムをArduino IDEでビルドします。ビルドの際、対象がM5Stackの時はArduino IDEのツール > ボードの設定を「M5Stack-Core-ESP32」に、ESPr Developer 32の時は「ESP32 Dev Module」に設定することを忘れないでください。
プログラムを実行して、5秒ごとにシリアルに(M5Stackの場合はLCDにも)温度、湿度、気圧が表示されればハードウェアは動作しています。
ブロードキャストモードのシステム
コネクトモードはゲートウェイからセンサー端末に接続して、センサーデーターを取得します。ESP32のArduino BLEはデフォルトのままでは接続が安定しなかったため、Arduino coreを一部修正しました。ブロードキャストモードは接続をしないため、この問題はありません。Arduino coreに手を加えるのが不安な方は、ブロードキャストモードをお試しください。
アドバタイジングデーター
ブロードキャストモードはセンサーデーターをアドバタイジングパケットの中のアドバタイジングデーターという領域に載せて発信します。アドバタイジングデーターは次のような構造の最大31バイトのデーターです。
オムロンの環境センサー「2JCIE-BL01」からBLEでセンサーデーターを発信する事例を「オムロン環境センサーからBLE経由でデーターをクラウドに送る」で紹介しました。「2JCIE-BL01」のインタフェースは非常によくできているので、これを参考にして環境センサーを開発しました。
AD Typeは1バイトのデータで、AD Dataの内容を定義します。 この中にManufacturer Specific(0xFF)という値があり、 AD Dataとして2バイトの企業IDとその企業が定義するデータが入れられます。
企業ID0xFFFFがテスト用に用意されているので、これを使い、次のようなアドバタイジングデータを定義しました。
温度、湿度を100倍、気圧を10倍して整数にしてアドバタイジングデータとして送信し、 受信側で元に戻すことで、小数点以下2桁、1桁の浮動小数点を2バイトに収めています。
端末側プログラム
センサー端末側のプログラムはArduinoで開発します。ESP32のArduinoにはBLEモジュールが提供されており、プログラミングは「BLE C++ Guide」という資料に解説されています。
今回開発したプログラムはGithubに公開した中の
- src/envSensor_esp32/BLE_BME280_bcast/BLE_BME280_bcast.ino
です。
BLEの端末側プログラムの主な流れは次のようになっています。プログラム中のコメントを見ると流れが分かると思います。
デバイスを初期化し、サーバーを生成し、センサーを読んで値をアドバタイジングデーターにセットし、T_PERIOD秒アドバタイズします。その後、S_PERIOD秒休止します。休止中の消費電力を下げるために休止中はDeep Sleepします。Deep Sleepから復帰するとプログラムは先頭から実行されるので、またT_PERIODのアドバタイズを繰り返します。
動作確認
プログラムをビルドして、端末にダウンロードして動かします。プログラムはM5Stack、ESPr Developer 32のどちらでも動作します。
動作確認にはスマホアプリ「BLE Scanner」を使うのが便利です。
「BLE Scanner」を立ち上げると、スキャンして見つかったBLEデバイスが表示されます。
プログラムが期待通りに動作していれば、デバイスを初期化した時に引数で指定した名前(“AmbientEnv-02”)のデバイスが表示されます。
AmbientEnv-02をタップすると、アドバタイジングデーターを確認できます。
温度、湿度などがアドバタイジングデーターにセットされていれば、Manufacturer Dataの部分が次のようになっています。(後日、カンパニーIDは0xFF, 0xFFに変更しました)
これでブロードキャストモードのセンサー端末ができました。セントラル側のプログラムは後日公開する「BLE環境センサーのゲートウェイ(Raspberry Pi3)編」をご覧ください。
コネクトモードのシステム
ブロードキャストモードのところでも書いたように、ESP32のArduino BLEはデフォルトのままでは接続が安定しないため、Arduino coreに一部修正が必要です。Arduino coreに手を加えるのが不安な方は、ブロードキャストモードをお試しください。
GATT
BLEデバイスが提供する機能はGATT(Generic Attributes)プロファイルで定義されます。GATTプロファイルには複数のサービスが含まれ、サービスには複数のキャラクタリスティクスが含まれます。
「2JCIE-BL01」のGATTプロファイルは「Communication Interface Manual」に公開されています。これによると、「2JCIE-BL01」にはセンサーサービス、設定サービスなど8つのサービスが定義されています。センサー値を取得するのはセンサーサービスです。さらに、その中に最新のセンサー値(Latest data)など6つのキャラクタリスティクスが定義されています。最新のセンサー値は次のような19バイトのバイナリーデーターです。
端末側プログラム
今回開発したコネクトモードのプログラムはGithubに公開した中の
- src/envSensor_esp32/BLE_BME280/BLE_BME280.ino
です。
BLEの端末側の主な流れは次のようになっています。プログラム中のコメントを見ると流れが分かると思います。
サーバーとサービスとキャラクタリスティクスを生成して、サーバーを起動すると、セントラルからの接続やキャラクタリスティクスへのリード/ライトアクセスをBLEモジュールが処理するようになります。アドバタイズを起動するとアドバタイズが始まります。
この中で二つのコールバック関数を設定しています。一つはキャラクタリスティクスに対するコールバック関数で、キャラクタリスティクスにリード/ライトがあると呼ばれます。ゲートウェイからリード要求があると、センサー(BME280)を読み、センサー値をGATTで定義された構造に従ってキャラクタリスティクスに書き込んでいます。
接続時処理の修正
もう一つのコールバック関数はサーバーに対するもので、セントラルから接続/切断があると呼ばれます。
Arduino BLEのサンプルプログラムなどを見ると、特別な処理はやっていないのですが、実際に動かしてセントラルから接続すると、接続が安定せず、すぐに切断されてしまいます。
esp-idfのサンプルプログラムを見ると、接続時に接続パラメーターを更新し、タイムアウト値を4秒に指定していました。
そこで、esp-idfのサンプルプログラムと同様に、接続時に接続パラメーターを更新する処理を追加しました。さらに、標準のコールバック関数の引数では必要な情報が不足していたため、次のようにArduinoのBLEモジュールを修正し、必要な情報を引数として渡すようにしました。
スケッチブックの保存場所/hardware/espressif/esp32/libraries/BLE/src/BLEServer.h
スケッチブックの保存場所/hardware/espressif/esp32/libraries/BLE/src/BLEServer.cpp
Arduinoプログラムでは次のような接続時のコールバック関数を設定し、タイムアウト値を指定しました。
動作確認
プログラムをビルドして、端末にダウンロードして動かします。このプログラムもM5Stack、ESPr Developer 32のどちらでも動作します。
ブロードキャストモードの時と同様にBLE Scannerアプリで動作を確認します。アプリを立ち上げると、スキャンして見つかったBLEデバイスが表示されます。
デバイスを初期化した時に引数で指定した名前(“AmbientEnv-01”)のデバイスが表示されます。
AmbientEnv-01をタップすると、デバイス情報をサービスが確認できます。
プログラムで生成したUUID=b0c8be70…というサービスが表示されるはずです。そのサービスをタップすると、そのサービスに含まれるキャラクタリスティクスが確認できます。
先頭の00がシーケンス番号、次の84が温度の下位バイト、0bが上位バイトなので、温度は0x0b84、10進数だと2948になります。温度データーは10倍された値が送信されているので、実際の値は29.48℃です。
これでコネクトモードのセンサー端末ができました。
セントラル側は「BLE環境センサー・ゲートウェイ(Raspberry Pi)編」「BLE環境センサー・ゲートウェイ(ESP32編)」をご覧ください。