Arduino UNO R4 WiFiでBLE ⑤ BME280のBLEペリフェラル
前回、気圧センサBME280で、気圧と温度、湿度を測定し、グラフィック・ディスプレイに表示しました。
ここでは、測定した二つのデータをBLE(Bluetooth Low Energy)で送信するBLEペリフェラル(peripheral )を作成します。受信するほうはBLEセントラル(central )と呼ばれます。
ArduinoBLEライブラリを利用してスケッチを作成します。執筆時点では、1.3.6が最新です。
前の気圧センサLPS22では、データは、測定した実数をそのまま送信しました。キャラクタリスティックはBLEFloatCharacteristicでした。ここでは、実数を10倍もしくは100倍し、整数で送ることにします。使うのは、BLEIntCharacteristicです。
このほかに、下記のキャラクタリスティックが利用できます。
ArduinoBLE - BLECharacteristic() BLEBoolCharacteristic(uuid, properties) |
●使用環境
- Arduino UNO R4 WiFi
- Arduino IDE 2.2.1
- Windows10 22H2
●BLEの各種定義
ペリフェラルとセントラル間でBLEが接続されたとき、GATT通信が行われます。GATTはGeneric attribute profileの略です。
GATT通信の中には複数のService(サービス)が入っています。ここでは、BME280という名称の一つのサービスだけが存在します。
サービスの中には、複数のCharacteristic(キャラクタリスティック)が含まれています。ここでは、温度と気圧、湿度の三つです。
キャラクタリスティックには、説明;Descriptor(ディスクリプタ)をつけられます。ない場合もあります。
いろいろな機器の間でそれらのサービスやキャラクタリスティックとかが重ならないようにユニークなUUIDで識別します。
BLEReadはセントラル側でCharacteristicの値を読み出し、BLENotifyはペリフェラル側でCharacteristicの値を通知する処理内容です。セントラルは、読み出しを実行したときに新しいデータを受信します。Notifyは、その機能をオンしておけば、常に新しいデータを受信できます。
Descriptorの2901は、ユーザが可読できるCharacteristicの説明文字列(UTF-8)の指定です。
●setupーBLE
最初に初期化します。
BLE.begin();
localnameを指定します。
#define localNAME "BME280_int"
BLE.setLocalName(localNAME);
service、characteristic、descriptorをBLEに追加します。
Characteristicに初期値を入れます。
準備が整ったので、セントラルからの接続待ち=アドバタイズを起動します。
BLE.advertise(); // start advertising
Serial.println("Bluetooth device active, waiting for connections...");
●loopーBLE
セントラルとの接続を待ちます。
つながったら、メッセージを出します。
接続が切れると、メッセージを出します。
// This is a library for the BME280 humidity, temperature & pressure sensor
// Designed specifically to work with the Adafruit BME280 Breakout
// ----> http://www.adafruit.com/products/2650
// Written by Limor Fried & Kevin Townsend for Adafruit Industries.
#include <ArduinoBLE.h>
#define BME280_SERVICE_UUID "F000AA30-0452-4000-B000-000000000000" // BLE Service
BLEService Sensor_BME280_Service(BME280_SERVICE_UUID);
#define BME280_Temp_Characteristic_UUID "F000AA31-0452-4000-B000-000000000000" // BLE Characteristic
#define BME280_Press_Characteristic_UUID "F000AA32-0452-4000-B000-000000000000"
#define BME280_Humidity_Characteristic_UUID "F000AA33-0452-4000-B000-000000000000"
BLEIntCharacteristic BME280_Temp(BME280_Temp_Characteristic_UUID, BLERead | BLENotify);
BLEIntCharacteristic BME280_Press(BME280_Press_Characteristic_UUID, BLERead | BLENotify);
BLEIntCharacteristic BME280_Humidity(BME280_Humidity_Characteristic_UUID, BLERead | BLENotify);
#define BME280_Temp_Descriptor_UUID "2901" // BLE Descriptor
#define BME280_Press_Descriptor_UUID "2901"
#define BME280_Humidity_Descriptor_UUID "2901"
BLEDescriptor BME280_Temp_Descriptor(BME280_Temp_Descriptor_UUID, "Temperature: `C int format");
BLEDescriptor BME280_Press_Descriptor(BME280_Press_Descriptor_UUID, "Pressure: hPa");
BLEDescriptor BME280_Humidity_Descriptor(BME280_Humidity_Descriptor_UUID, "Humidity: %");
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_SSD1306.h>
float tempC;
float pressure;
float humidity;
Adafruit_BME280 bme; // I2C
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
#define localNAME "BME280_int"
int oldValue = 0; // last value
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println(F("BME280 + ssd1306 + BLE"));
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
unsigned status;
// default settings
status = bme.begin();
// You can also pass in a Wire library object like &Wire2
// status = bme.begin(0x76, &Wire2)
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1) delay(10);
}
Serial.println();
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
display.display();
delay(500); // Pause for 2 seconds
display.setTextSize(1);
display.setTextColor(WHITE);
display.setRotation(0);
display.clearDisplay();
BLE.setLocalName(localNAME);
BLE.setAdvertisedService(Sensor_BME280_Service); // add the service UUID
Sensor_BME280_Service.addCharacteristic(BME280_Temp); // add characteristic
Sensor_BME280_Service.addCharacteristic(BME280_Press);
Sensor_BME280_Service.addCharacteristic(BME280_Humidity);
BME280_Temp.addDescriptor(BME280_Temp_Descriptor); // add descriptor
BME280_Press.addDescriptor(BME280_Press_Descriptor);
BME280_Humidity.addDescriptor(BME280_Humidity_Descriptor);
BLE.addService(Sensor_BME280_Service); // Add service
BME280_Temp.writeValue(oldValue); // set initial value for this characteristic
BME280_Press.writeValue(oldValue);
BME280_Humidity.writeValue(oldValue);
BLE.advertise(); // start advertising
Serial.println("Bluetooth device active, waiting for connections...");
}
void loop() {
// wait for a BLE central
BLEDevice central = BLE.central();
// if a central is connected to the peripheral:
if (central) {
delay(100);
Serial.print("Connected to central: ");
// print the central's BT address:
Serial.println(central.address());
while (central.connected()) {
updateValue();
delay(1000);
}
// when the central disconnects
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
}
void updateValue() {
display.clearDisplay();
display.setCursor(0, 0);
tempC = bme.readTemperature();
pressure = bme.readPressure() / 100.0;
humidity = bme.readHumidity();
Serial.print("Temperature = ");
Serial.print(tempC);
Serial.println(" °C");
Serial.print("Pressure = ");
Serial.print( pressure);
Serial.println(" hPa");
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.println(" %");
Serial.println();
display.println("Temperature: - `C");
display.print(tempC, 2);
display.println("");
display.println("");
display.println("Pressure: - hPa");
display.print(pressure, 1);
display.println("");
display.println("");
display.println("Humidity: - %");
display.print(humidity, 1);
display.display();
// if value has changed
if (tempC != oldValue) {
// update characteristic
BME280_Temp.writeValue((int)(tempC*100.0));
BME280_Press.writeValue((int)(pressure*10.0));
BME280_Humidity.writeValue((int)(humidity*10.0));
oldValue = tempC; // save the level for next comparison
}
}