ESP32-C3を電池のみで長時間駆動させる検証を行っています。
BME280などのセンサーで取得した環境情報などをWifiを通してSQLサーバーにアップロードする方法で、データ送信時以外はDeepSleepさせることで電力消費量の削減をしました。この結果、18650型のLFPバッテリー1個を用いて、30秒間隔でデータ送信をするという条件で500時間弱の駆動を実現しました。
今回はさらなる消費電力低減を目指して、BluetoothLowEnergyを用いた方法を検証してみました。
BluetoothLowEnergyとは?
BluetoothLowEnergy(以下BLE)は低消費電力でデータを送信する仕組みです。
XBOXのゲームコントローラーやSwitchBotの各種センサーなどで使用されています。
BLEには、従来のBluetooth(BluetoothClassic)のように2つの機器間で接続を行う
通信方式(コネクション)もありますが、今回注目するのはブロードキャストという通信方式です。
この方式は、いわばデータを垂れ流しているだけの状態(*)で相手が受け取っているかどうかは確認しません。接続確認などのオーバーヘッドがないため、データ送信側の負荷を小さくできます。
*厳密には、垂れ流されているデータをただ受信するだけのPassiveScanと、追加データの送信を要求するActiveScanがあります。
全体の仕組み
システム全体の仕組みは以下のようなイメージです。上が前回紹介したWiFiを使用したシステム、下が今回検証したBLEを使用したシステムです。
BLEを利用する場合、SQLサーバーを直接叩けないため、橋渡し役のゲートウェイが必要になります。
今回はこのゲートウェイにはRaspberryPi3Aを使用しました。
なお、SQLサーバー側にはPHPで動作するスクリプトを用意し、
ゲートウェイがこれを叩くことでSQLサーバーにデータが登録されるようにしてあります。
詳細は過去の記事をご覧ください。
回路構成
回路構成は以前のWiFiの検証で使用したものと同じものを使用しています。
ESP32C3スケッチ
15秒間隔で1回につき200msecの送信を行います。
#include <Wire.h>
#include <esp_sleep.h>
#include <Adafruit_BME280.h>
// https://github.com/nkolban/ESP32_BLE_Arduino
#include <BLEDevice.h>
#include <BLEServer.h>
#define DEVICE_NAME "ESP32_BLE"
#define SCL 7
#define SDA 6
#define ADCPIN 1
#define I2CPIN 5
#define LEDPIN 8
// https://www.uuidgenerator.net/
//上記サイトでUUIDを生成して使う
#define SERVICE_UUID "de2ee0cd-bdd4-467c-adf2-8d86b1d3cecf"
#define CHARACTERISTIC_UUID "80b30b49-9832-4cf1-c2f4-2fa2df1e73a1"
const int SLEEP_TIME = 15; // sleep time (second)
const int ADVERTISING_TIME = 200; // advertising time (mili second)
Adafruit_BME280 bme;
void setAdvertisementData(BLEAdvertising* pAdvertising)
{
double t = 0;
double h = 0;
double p = 0;
double lux = 0;
int v=0;
digitalWrite(LEDPIN, HIGH);
//電圧測定
v = analogRead(ADCPIN); delay(1);
v += analogRead(ADCPIN); delay(1);
v += analogRead(ADCPIN); delay(1);
double volt = (float)v * 1.41334 / 3 / 1000;
//気圧気温湿度
digitalWrite(I2CPIN, HIGH); delay(10);
if (!bme.begin(0x76))
{
goDeepSleep();
}
bme.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // temperature
Adafruit_BME280::SAMPLING_X1, // pressure
Adafruit_BME280::SAMPLING_X1, // humidity
Adafruit_BME280::FILTER_OFF);
bme.takeForcedMeasurement();
t = bme.readTemperature();
p = bme.readPressure() / 100.0F;
h = bme.readHumidity();
digitalWrite(I2CPIN, LOW);
uint16_t temp = (uint16_t)(t * 100);
uint16_t humi = (uint16_t)(h * 100);
uint16_t pres = (uint16_t)(p * 50);
uint32_t illum = (uint32_t)(lux * 100);
uint16_t vbat = (uint16_t)(volt * 1000);
std::string strData = "";
strData += (char)0xff; // Manufacturer specific data
strData += (char)0xff; // manufacturer ID low byte
strData += (char)0xff; // manufacturer ID high byte
strData += (char)(temp & 0xff);
strData += (char)((temp >> 8) & 0xff);
strData += (char)(humi & 0xff);
strData += (char)((humi >> 8) & 0xff);
strData += (char)(pres & 0xff);
strData += (char)((pres >> 8) & 0xff);
strData += (char)(illum & 0xff);
strData += (char)((illum >> 8) & 0xff);
strData += (char)((illum >> 16) & 0xff);
strData += (char)((illum >> 24) & 0xff);
strData += (char)(vbat & 0xff);
strData += (char)((vbat >> 8) & 0xff);
strData = (char)strData.length() + strData;
BLEAdvertisementData AdvertisementData = BLEAdvertisementData();
AdvertisementData.setName(DEVICE_NAME);
AdvertisementData.setFlags(0x06);
AdvertisementData.addData(strData);
pAdvertising->setAdvertisementData(AdvertisementData);
}
void setup() {
Wire.begin(SDA, SCL);
pinMode(I2CPIN, OUTPUT);
pinMode(ADCPIN, ANALOG);
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, HIGH);
analogSetAttenuation(ADC_11db);
//BLEオブジェクト初期化
BLEDevice::init(DEVICE_NAME);
//アドバタイズオブジェクトを取得する
BLEServer *pServer = BLEDevice::createServer();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
setAdvertisementData(pAdvertising);
// Advertising
pAdvertising->start();
delay(ADVERTISING_TIME);
pAdvertising->stop();
goDeepSleep();
}
void goDeepSleep()
{
digitalWrite(LEDPIN, LOW);
digitalWrite(I2CPIN, LOW);
esp_deep_sleep(SLEEP_TIME * 1000000LL);
}
void loop() {
}
ゲートウェイ側のプログラム
PythonでBLEのアドバタイズデータを読み取り、結果をBASHスクリプトに渡して、データをSQLサーバーに送信しています。
ゲートウェイのHWはRaspberryPi3Aですが、bluepyの都合で最新のBookwormではなく、Bullseyeを使用しました。
以下のコマンドでpython3とbluepyをインストールしてください。
$sudo apt -y install python3-dev $sudo apt -y install python3-pip $sudo apt -y install libglib2.0-dev $sudo pip3 install bluepy
python(ble.py)
from bluepy.btle import Scanner, DefaultDelegate
import struct
import subprocess
# 対象のMACアドレス(小文字で統一)
macaddr = "aa:aa:aa:aa:aa:aa"
class ScanDelegate(DefaultDelegate):
def __init__(self):
DefaultDelegate.__init__(self)
def handleDiscovery(self, dev, isNewDev, isNewData):
if dev.addr.lower() != macaddr.lower():
return
for (adtype, desc, value) in dev.getScanData():
if adtype == 255:
try:
raw = bytes.fromhex(value)
payload = raw[2:] # ManufacturerID除去 3:じゃなくて2:が正解
temp = struct.unpack('<H', payload[0:2])[0] / 100.0
humi = struct.unpack('<H', payload[2:4])[0] / 100.0
pres = struct.unpack('<H', payload[4:6])[0] / 50.0
illum = struct.unpack('<I', payload[6:10])[0] / 100.0
vbat = struct.unpack('<H', payload[10:12])[0]
subprocess.run([
"bash","ble.sh",
f"{temp:.2f}",
f"{humi:.2f}",
f"{pres:.2f}",
f"{illum:.2f}",
f"{vbat:.2f}"
])
except Exception as e:
pass # 出力のみ行うのでエラーは黙殺
scanner = Scanner().withDelegate(ScanDelegate())
while True:
scanner.scan(5.0)
BASHスクリプト(ble.sh)
#!/bin/bash SCRIPT_DIR=`dirname $0` cd $SCRIPT_DIR TB="tb1111" URL="http://192.168.0.111/insdata.php?table="$TB n=0 for i in "$@"; do eval "val$n='$i'" ((n++)) done URL=$URL"&d0="$val0"&d1="$val1"&d2="$val2"&d3="$val3"&d4="$val4 curl $URL
結果
BLEでデータ送出を行ったとき、以下のような結果が得られました。
・15秒間隔の送信で503時間(平均消費電流3.57mA)
ちなみに、Wifiでデータ送信した場合、以下のような駆動時間でした。
・10秒間隔の送信で166時間(平均消費電流10.8mA)
・30秒間隔の送信で489時間(平均消費電流平均3.68mA)
これらと比較すると、概ね半分程度の消費電力になっていると思われます(*)。BLEデータを連続送信した場合には80mA程度の消費電流になっており、これはWifiとさほど変わらないイメージです。しかしながら、Wifiの場合にはコネクションの確立だけでも数百ミリ秒はかかっていましたので、200~300msecでデータ送信まで終わってしまう点が消費電力の削減につながっていると思われます。
データのドロップも1日に数回程度で、比較対象としたWifi接続と同じか少ないぐらいでした。
(*)Wifiの処理についても設定が多岐にわたりますし、同条件での比較ではないので単純には決められませんが・・・
まとめ
今回の方法ではWiFiを使用した場合よりもより低消費電力であることを確認できました。ただ、複数台使用時の衝突防止やデータのドロップ防止などまだまだ考えることも多いです。
ゲートウェイ側の処理が重くなってしまうのが難点ですが電力制限が厳しいIOT機器側の消費電力を削減できるのは大きいですね。
参考・イラスト使用
以下のサイト様を参考・使用させていただきました。
BLEについて

イラスト使用



ありがとうございます。






コメント