初めてのBLE (16) ESP32でペリフェラル④BME280
ESP32のI2CインターフェースにMEMSセンサのBME280をつなぎ、温度、湿度、気温を送れるBLEペリフェラルを作ります。ESP32ボードは製品によってピン配置は異なります。ここで利用しているは、22ピンがSCL、21ピンがSDAです。
●接続
BME280 | ESP32 |
---|---|
Vcc | 3V(3.3V) |
GND | GND |
SCL | 22 |
SDA | 21 |
●BME280のライブラリを利用
ライブラリ管理でBME280を検索するとたくさんのライブラリが出てきます。ここではAdafruitのライブラリを利用します。同時にSensor関連もインストールするかと聞かれたら、全部インストールしておきます。I2Cのインターフェースで接続しているので、最初にi2cscannerを動かします。見つけてきたスレーブ・アドレスは0x76でした。したがって、setup()内で、status = bme.begin(0x76);とアドレスを変更しておきます。BME280は2種類のアドレスが利用できます。
動作が確認できたら、Wireライブラリだけ残して、Adaruitのbme280testをスリムにします。
// Designed specifically to work with the Adafruit BME280 Breakout // Written by Limor Fried & Kevin Townsend for Adafruit Industries. #include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h> Adafruit_BME280 bme; // I2C void setup() { Serial.begin(9600); while(!Serial); // time to get serial running Serial.println(F("BME280 test")); unsigned status; status = bme.begin(0x76); Serial.println(); } void loop() { printValues(); delay(2000); } void printValues() { Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C"); Serial.print("Pressure = "); Serial.print(bme.readPressure() / 100.0F); Serial.println(" hPa"); Serial.print("Humidity = "); Serial.print(bme.readHumidity()); Serial.println(" %"); Serial.println(); }
●ESP32-BLE_serverと合体
前回までで作ったCPU温度を送るスケッチに上記のBME280のデータを組み合わせます。
BLEでは、一番外側がGATTと呼ばれ、その中に複数のServiceがあります。デフォルトの二つのService以外に、
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
をCPU温度用に使っていました。サービスは一つ以上のCHARACTERISTICがあります。今回、温度、気圧、湿度ように三つ用意しました。
#define CHARACTERISTIC_T_UUID "beb5483d-36e1-4688-b7f5-ea07361b26a8"
#define CHARACTERISTIC_P_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define CHARACTERISTIC_H_UUID "beb5483f-36e1-4688-b7f5-ea07361b26a8"
/* Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp Ported to Arduino ESP32 by Evandro Copercini updates by chegewara // Designed specifically to work with the Adafruit BME280 Breakout // Written by Limor Fried & Kevin Townsend for Adafruit Industries. */ #include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h> float temp = 0; float press = 0; float humi = 0; #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_T_UUID "beb5483d-36e1-4688-b7f5-ea07361b26a8" #define CHARACTERISTIC_P_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define CHARACTERISTIC_H_UUID "beb5483f-36e1-4688-b7f5-ea07361b26a8" BLECharacteristic *tCharacteristic; BLECharacteristic *pCharacteristic; BLECharacteristic *hCharacteristic; Adafruit_BME280 bme; // I2C void setup() { Serial.begin(115200); while(!Serial); Serial.println("Starting BLE work!"); bme.begin(0x76); BLEDevice::init("ESP32-BME280 peripheral"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(SERVICE_UUID); tCharacteristic = pService->createCharacteristic( CHARACTERISTIC_T_UUID, BLECharacteristic::PROPERTY_READ ); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_P_UUID, BLECharacteristic::PROPERTY_READ ); hCharacteristic = pService->createCharacteristic( CHARACTERISTIC_H_UUID, BLECharacteristic::PROPERTY_READ ); /* tCharacteristic->setValue("1"); pCharacteristic->setValue("10"); hCharacteristic->setValue("100"); */ pService->start(); // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue pAdvertising->setMinPreferred(0x12); BLEDevice::startAdvertising(); // Serial.println("Characteristic defined! Now you can read it in your phone!"); } void loop() { readBME280(); tCharacteristic->setValue(temp); tCharacteristic->notify(); pCharacteristic->setValue(press); pCharacteristic->notify(); hCharacteristic->setValue(humi); hCharacteristic->notify(); delay(2000); } void readBME280() { Serial.print("Temperature = "); temp = bme.readTemperature(); Serial.print(temp); Serial.println(" *C"); Serial.print("Pressure = "); press = bme.readPressure() / 100.0F; Serial.print(press); Serial.println(" hPa"); Serial.print("Humidity = "); humi = bme.readHumidity(); Serial.print(humi); Serial.println(" %"); Serial.println(); }
オン・セミコンダクターのBLEであるRSL10 Bluetooth Low Enaergy Exploerを使って情報を見ます。connectで接続し、Discover Serviceでサービスを表示しました。三つのデータが送られていることが確認できました。
●セントラルはNANO 33 BLE Sense
上記のペリフェラルのLocal NameはESP32-BME280 peripheralにしました。セントラルのスケッチを作ります。三つのキャラのデータを読み込み、IEEE754のunsign32ビット・データをデコードします。まったく同じ処理なので、関数にしたほうがすっきりすると思います。
#include <ArduinoBLE.h> #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_T_UUID "beb5483d-36e1-4688-b7f5-ea07361b26a8" #define CHARACTERISTIC_P_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define CHARACTERISTIC_H_UUID "beb5483f-36e1-4688-b7f5-ea07361b26a8" #define localNAME "ESP32-BME280 peripheral" void setup() { Serial.begin(9600); while (!Serial); BLE.begin(); Serial.println("\nstart BLE Central - BME280"); // start scanning for peripherals BLE.scanForName(localNAME); } void loop() { // check if a peripheral has been discovered BLEDevice peripheral = BLE.available(); if (peripheral) { // discovered a peripheral, print out address, local name, and advertised service Serial.print("Found "); Serial.print(peripheral.address()); Serial.print(" '"); Serial.print(peripheral.localName()); Serial.print("' "); Serial.print(peripheral.advertisedServiceUuid()); Serial.println(); if (peripheral.localName() != localNAME) { return; } // stop scanning BLE.stopScan(); readBME280data(peripheral); // peripheral disconnected, start scanning again BLE.scanForName(localNAME); } } void readBME280data(BLEDevice peripheral) { // connect to the peripheral Serial.print("Connecting ..."); if (peripheral.connect()) { Serial.println("Connected"); } else { Serial.println("Failed to connect!"); return; } // discover peripheral attributes Serial.print("Discovering attributes ..."); if (peripheral.discoverAttributes()) { Serial.println("Attributes discovered\n"); } else { Serial.println("Attribute discovery failed!"); peripheral.disconnect(); return; } // retrieve the BME280 characteristic BLECharacteristic tempCharacteristic = peripheral.characteristic(CHARACTERISTIC_T_UUID); BLECharacteristic pressCharacteristic = peripheral.characteristic(CHARACTERISTIC_P_UUID); BLECharacteristic humiCharacteristic = peripheral.characteristic(CHARACTERISTIC_H_UUID); if (!tempCharacteristic) { Serial.println("Peripheral does not have Temp characteristic!"); peripheral.disconnect(); return; } // else if (!ledCharacteristic.canWrite()) { // Serial.println("Peripheral does not have a writable LED characteristic!"); // peripheral.disconnect(); // return; // } Serial.println("---Found CHARACTERISTIC_UUID"); while (peripheral.connected()) { if (tempCharacteristic.canRead()) { // read the characteristic value tempCharacteristic.read(); if (tempCharacteristic.valueLength() > 0) { uint32_t data = ((uint8_t)*(tempCharacteristic.value()+3) << 24) + ((uint8_t)*(tempCharacteristic.value()+2) << 16) + ((uint8_t)*(tempCharacteristic.value()+1) << 8) + ((uint8_t)*tempCharacteristic.value()); int32_t f = pow(-1, int(bitRead(data,31))); double k =1 + ((((data<<1)<<8)>>9))/pow(2,23); int32_t s = pow(2,((((data<<1)>>24))-127)); Serial.print("\ntemp ="); Serial.println(f*k*s);
pressCharacteristic.read(); data = ((uint8_t)*(pressCharacteristic.value()+3) << 24) + ((uint8_t)*(pressCharacteristic.value()+2) << 16) + ((uint8_t)*(pressCharacteristic.value()+1) << 8) + ((uint8_t)*pressCharacteristic.value()); f = pow(-1, int(bitRead(data,31))); k =1 + ((((data<<1)<<8)>>9))/pow(2,23); s = pow(2,((((data<<1)>>24))-127)); Serial.print("press ="); Serial.println(f*k*s);
humiCharacteristic.read(); data = ((uint8_t)*(humiCharacteristic.value()+3) << 24) + ((uint8_t)*(humiCharacteristic.value()+2) << 16) + ((uint8_t)*(humiCharacteristic.value()+1) << 8) + ((uint8_t)*humiCharacteristic.value()); f = pow(-1, int(bitRead(data,31))); k =1 + ((((data<<1)<<8)>>9))/pow(2,23); s = pow(2,((((data<<1)>>24))-127)); Serial.print("humi ="); Serial.println(f*k*s); delay(5000); } } } Serial.println("Peripheral disconnected"); }
実行結果です。