ハード未接続に対応

This commit is contained in:
Koichi Ito 2026-10-09 16:07:24 +09:00
parent b8eb7bafe8
commit 2e3cd4220a
3 changed files with 117 additions and 77 deletions

View File

@ -74,14 +74,16 @@ private:
SensorLogger* logger_; SensorLogger* logger_;
}; };
void SensorLogger::begin(uint8_t soilPin) { void SensorLogger::begin(uint8_t soilPin, bool i2cConnected, bool bleDataConnected) {
// センサーとBLE通信を使い始めるための初期設定です。 // センサーとBLE通信を使い始めるための初期設定です。
soilPin_ = soilPin; soilPin_ = soilPin;
bleDataConnected_ = bleDataConnected;
pinMode(soilPin_, INPUT); pinMode(soilPin_, INPUT);
analogReadResolution(12); analogReadResolution(12);
// センサーが接続されているときだけ初期化します。 // センサーが接続されているときだけ初期化します。
// 未接続時にライブラリへアクセスすると、不要なI2Cエラーや待ち時間が発生します。 // 未接続時にライブラリへアクセスすると、不要なI2Cエラーや待ち時間が発生します。
if (i2cConnected) {
if (isI2cDevicePresent(0x38)) { if (isI2cDevicePresent(0x38)) {
aht20Ready = aht20.begin(); aht20Ready = aht20.begin();
if (!aht20Ready) { if (!aht20Ready) {
@ -98,7 +100,9 @@ void SensorLogger::begin(uint8_t soilPin) {
} else { } else {
Serial.println("[WARNING] BH1750 not detected at 0x23"); Serial.println("[WARNING] BH1750 not detected at 0x23");
} }
}
if (bleDataConnected_) {
// ESP32固有の番号を名前に加え、同じ名前の機器と区別します。 // ESP32固有の番号を名前に加え、同じ名前の機器と区別します。
uint64_t mac = ESP.getEfuseMac(); uint64_t mac = ESP.getEfuseMac();
char name[14]; char name[14];
@ -133,6 +137,7 @@ void SensorLogger::begin(uint8_t soilPin) {
advertising->setMinPreferred(0x12); advertising->setMinPreferred(0x12);
BLEDevice::startAdvertising(); BLEDevice::startAdvertising();
Serial.println("[INFO] BLE advertising started"); Serial.println("[INFO] BLE advertising started");
}
// 起動直後にも1回計測して、画面に値を表示できるようにします。 // 起動直後にも1回計測して、画面に値を表示できるようにします。
readAndStore(); readAndStore();
@ -142,10 +147,13 @@ void SensorLogger::begin(uint8_t soilPin) {
bool SensorLogger::update() { bool SensorLogger::update() {
// loopから繰り返し呼ばれ、通信と定期計測を担当します。 // loopから繰り返し呼ばれ、通信と定期計測を担当します。
if (bleDataConnected_) {
processBluetooth(); processBluetooth();
}
unsigned long now = millis(); unsigned long now = millis();
if (!bluetoothConnected_ && now - lastAdvertise_ >= kAdvertiseRetryIntervalMs) { if (bleDataConnected_ && !bluetoothConnected_
&& now - lastAdvertise_ >= kAdvertiseRetryIntervalMs) {
// 接続されていなければ、定期的にBLE広告を出し直します。 // 接続されていなければ、定期的にBLE広告を出し直します。
lastAdvertise_ = now; lastAdvertise_ = now;
BLEDevice::startAdvertising(); BLEDevice::startAdvertising();
@ -288,6 +296,10 @@ void SensorLogger::processBluetooth() {
} }
void SensorLogger::receiveBluetoothData(const String& data) { void SensorLogger::receiveBluetoothData(const String& data) {
if (!bleDataConnected_) {
return;
}
// BLEで届いた文字を命令バッファへ追加します。 // BLEで届いた文字を命令バッファへ追加します。
for (size_t index = 0; index < data.length(); ++index) { for (size_t index = 0; index < data.length(); ++index) {
char character = data[index]; char character = data[index];
@ -320,6 +332,10 @@ void SensorLogger::applyHistoricalTimeAdjustment(int64_t epoch) {
} }
void SensorLogger::processCommand(const String& command) { void SensorLogger::processCommand(const String& command) {
if (!bleDataConnected_ || txCharacteristic_ == nullptr) {
return;
}
// アプリから届いた命令を判定します。 // アプリから届いた命令を判定します。
if (command == "GET_LOG") { if (command == "GET_LOG") {
// 保存済みのログを順番に送ります。 // 保存済みのログを順番に送ります。
@ -366,6 +382,10 @@ void SensorLogger::processCommand(const String& command) {
} }
void SensorLogger::sendLog() { void SensorLogger::sendLog() {
if (!bleDataConnected_ || txCharacteristic_ == nullptr) {
return;
}
// 保存したログを1行ずつ作り、BLE通知で送ります。 // 保存したログを1行ずつ作り、BLE通知で送ります。
for (size_t index = 0; index < logCount_; ++index) { for (size_t index = 0; index < logCount_; ++index) {
size_t logIndex = (logStart_ + index) % kMaxLogEntries; size_t logIndex = (logStart_ + index) % kMaxLogEntries;
@ -390,6 +410,10 @@ void SensorLogger::sendLog() {
} }
void SensorLogger::sendNotification(const char* data) { void SensorLogger::sendNotification(const char* data) {
if (!bleDataConnected_ || txCharacteristic_ == nullptr) {
return;
}
// BLE通知には一度に送れる長さの制限があるため、短く分割します。 // BLE通知には一度に送れる長さの制限があるため、短く分割します。
constexpr size_t kNotificationSize = 20; constexpr size_t kNotificationSize = 20;
uint8_t notification[kNotificationSize]; uint8_t notification[kNotificationSize];

View File

@ -18,7 +18,7 @@ public:
static constexpr size_t kMaxLogEntries = 2000; static constexpr size_t kMaxLogEntries = 2000;
// センサー、BLE、保存データを使い始める準備をします。 // センサー、BLE、保存データを使い始める準備をします。
void begin(uint8_t soilPin); void begin(uint8_t soilPin, bool i2cConnected, bool bleDataConnected);
// BLEの受信と、一定時間ごとの計測を行います。 // BLEの受信と、一定時間ごとの計測を行います。
bool update(); bool update();
// センサーを読み取り、画面表示用の最新値を更新します。 // センサーを読み取り、画面表示用の最新値を更新します。
@ -69,6 +69,7 @@ private:
bool timeSynchronized_ = false; // 時刻合わせが済んだか bool timeSynchronized_ = false; // 時刻合わせが済んだか
bool historicalAdjustmentApplied_ = false; // 過去ログの補正が済んだか bool historicalAdjustmentApplied_ = false; // 過去ログの補正が済んだか
bool bluetoothConnected_ = false; // BLE接続中か bool bluetoothConnected_ = false; // BLE接続中か
bool bleDataConnected_ = false; // BLEデータ送受信を使うか
String bluetoothName_; // BLEに表示する名前 String bluetoothName_; // BLEに表示する名前
String commandBuffer_; // BLEから受け取った未処理の文字 String commandBuffer_; // BLEから受け取った未処理の文字

View File

@ -1,3 +1,10 @@
// I2C機器(OLED・センサー)を接続していない場合は false にします。
const bool kI2cConnected = true; // I2C機器が接続されていない場合は false にします。
// BLEでのセンサーデータ送受信を使わない場合は false にします。
const bool kBleDataConnected = true; // BLEでのセンサーデータ送受信を使わない場合は false にします。
// NeoPixelの接続ピンです。未接続の場合は -1 にすると一切使用しません。
const int kNeoPixelPin = 18; // 使用しない場合は -1 に、通常は 18番ピンに接続します。
// A2DPは、スマートフォンから音楽を受信するBluetoothの仕組みです。 // A2DPは、スマートフォンから音楽を受信するBluetoothの仕組みです。
#include "BluetoothA2DPSink.h" #include "BluetoothA2DPSink.h"
#include <Wire.h> #include <Wire.h>
@ -6,7 +13,7 @@
#include "SensorLogger.h" #include "SensorLogger.h"
// スマートフォンのBluetooth一覧に表示されるスピーカー名です。 // スマートフォンのBluetooth一覧に表示されるスピーカー名です。
const char kA2dpDeviceName[] = "BT_Speaker5.6"; const char kA2dpDeviceName[] = "BT_Speaker5.7";
// I2C接続のSDA/SCLピンです。配線に合わせてここだけ変更します。 // I2C接続のSDA/SCLピンです。配線に合わせてここだけ変更します。
// 通常基板:SDA=21, SCL=22 // 通常基板:SDA=21, SCL=22
// 開発用基板:SDA=19, SCL=5 // 開発用基板:SDA=19, SCL=5
@ -210,7 +217,9 @@ void audio_state_changed_callback(esp_a2d_audio_state_t state, void *) {
musicPlaying = state == ESP_A2D_AUDIO_STATE_STARTED; musicPlaying = state == ESP_A2D_AUDIO_STATE_STARTED;
Serial.printf("[INFO] Audio state changed: %d (playing=%s)\n", Serial.printf("[INFO] Audio state changed: %d (playing=%s)\n",
state, musicPlaying ? "yes" : "no"); state, musicPlaying ? "yes" : "no");
if (kNeoPixelPin >= 0) {
neoPixelController.setPlaying(musicPlaying); neoPixelController.setPlaying(musicPlaying);
}
updateDisplay(); updateDisplay();
} }
@ -230,8 +239,11 @@ void setup() {
Serial.begin(115200); Serial.begin(115200);
Serial.println("[INFO] Firmware starting"); Serial.println("[INFO] Firmware starting");
neoPixelController.begin(18); if (kNeoPixelPin >= 0) {
neoPixelController.begin(static_cast<uint8_t>(kNeoPixelPin));
}
if (kI2cConnected) {
// I2Cの配線を設定します。Wire.begin(SDA, SCL)の順です。 // I2Cの配線を設定します。Wire.begin(SDA, SCL)の順です。
// OLED未接続時もSDA/SCLが浮かないようにします。 // OLED未接続時もSDA/SCLが浮かないようにします。
pinMode(kI2cSdaPin, INPUT_PULLUP); pinMode(kI2cSdaPin, INPUT_PULLUP);
@ -255,8 +267,9 @@ void setup() {
} else { } else {
Serial.println("[WARNING] OLED not detected at 0x3C or 0x3D"); Serial.println("[WARNING] OLED not detected at 0x3C or 0x3D");
} }
}
sensorLogger.begin(32); sensorLogger.begin(32, kI2cConnected, kBleDataConnected);
updateDisplay(); updateDisplay();
lastDisplayUpdate = millis(); lastDisplayUpdate = millis();
@ -284,7 +297,9 @@ void setup() {
void loop() { void loop() {
// loopは何度も繰り返し実行されます。 // loopは何度も繰り返し実行されます。
if (kNeoPixelPin >= 0) {
neoPixelController.update(); neoPixelController.update();
}
bool newReading = sensorLogger.update(); bool newReading = sensorLogger.update();
unsigned long now = millis(); unsigned long now = millis();
if ((!bluetoothConnected || !musicPlaying) if ((!bluetoothConnected || !musicPlaying)