RTC表示

This commit is contained in:
Koichi Ito 2026-09-20 17:24:08 +09:00
parent 68a5f0dcce
commit 5e052dba93
3 changed files with 86 additions and 15 deletions

View File

@ -12,11 +12,17 @@ namespace {
constexpr char kNusServiceUuid[] = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
constexpr char kNusRxUuid[] = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
constexpr char kNusTxUuid[] = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
constexpr int64_t kInitialYear = 1700;
constexpr int64_t kSecondsPerDay = 86400;
Adafruit_AHTX0 aht20;
BH1750 bh1750;
bool aht20Ready = false;
bool bh1750Ready = false;
bool isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
}
class SensorLoggerCallbacks : public BLECharacteristicCallbacks {
@ -96,6 +102,47 @@ bool SensorLogger::hasReading() const {
return logCount_ != 0;
}
size_t SensorLogger::logCount() const {
return logCount_;
}
bool SensorLogger::getCurrentTime(char* buffer, size_t bufferSize) const {
if (bufferSize == 0) {
return false;
}
int64_t timestamp = currentTimestamp();
if (timeSynchronized_) {
time_t unixTimestamp = static_cast<time_t>(timestamp);
struct tm date;
localtime_r(&unixTimestamp, &date);
strftime(buffer, bufferSize, "%Y/%m/%d %H:%M:%S", &date);
return true;
}
int year = static_cast<int>(kInitialYear);
int month = 1;
int day = 1;
int64_t days = timestamp / kSecondsPerDay;
int seconds = static_cast<int>(timestamp % kSecondsPerDay);
while (days >= (isLeapYear(year) ? 366 : 365)) {
days -= isLeapYear(year) ? 366 : 365;
++year;
}
const int daysInMonth[] = {
31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
while (days >= daysInMonth[month - 1]) {
days -= daysInMonth[month - 1];
++month;
}
day += static_cast<int>(days);
snprintf(buffer, bufferSize, "%04d/%02d/%02d %02d:%02d:%02d",
year, month, day, seconds / 3600, (seconds / 60) % 60, seconds % 60);
return true;
}
void SensorLogger::readAndStore() {
sensors_event_t humidityEvent;
sensors_event_t temperatureEvent;
@ -193,7 +240,7 @@ void SensorLogger::sendLog() {
size_t logIndex = (logStart_ + index) % kMaxLogEntries;
const SensorReading& reading = log_[logIndex];
char line[128];
snprintf(line, sizeof(line), "%lu,%.2f,%.2f,%.2f,%u,%s\n",
snprintf(line, sizeof(line), "%lld,%.2f,%.2f,%.2f,%u,%s\n",
reading.timestamp,
reading.temperature,
reading.humidity,
@ -224,7 +271,7 @@ void SensorLogger::clearLog() {
logCount_ = 0;
}
unsigned long SensorLogger::currentTimestamp() const {
unsigned long elapsedSeconds = millis() / 1000UL;
int64_t SensorLogger::currentTimestamp() const {
int64_t elapsedSeconds = millis() / 1000UL;
return timeSynchronized_ ? epochOffset_ + elapsedSeconds : elapsedSeconds;
}

View File

@ -6,7 +6,7 @@ class BLECharacteristic;
class BLEServer;
struct SensorReading {
unsigned long timestamp;
int64_t timestamp;
float temperature;
float humidity;
float illuminance;
@ -21,6 +21,8 @@ public:
bool update();
const SensorReading& latest() const;
bool hasReading() const;
size_t logCount() const;
bool getCurrentTime(char* buffer, size_t bufferSize) const;
private:
static constexpr unsigned long kMeasureIntervalMs = 3600000UL;
@ -32,7 +34,7 @@ private:
void sendNotification(const char* data);
void sendLog();
void clearLog();
unsigned long currentTimestamp() const;
int64_t currentTimestamp() const;
BLEServer* server_ = nullptr;
BLECharacteristic* txCharacteristic_ = nullptr;
@ -42,7 +44,7 @@ private:
size_t logCount_ = 0;
uint8_t soilPin_ = 0;
unsigned long lastMeasure_ = 0;
unsigned long epochOffset_ = 0;
int64_t epochOffset_ = 0;
bool timeSynchronized_ = false;
String bluetoothName_;
String commandBuffer_;

View File

@ -4,7 +4,7 @@
#include "NeoPixelController.h"
#include "SensorLogger.h"
const char kBluetoothName[] = "BT_Speaker5.32";
const char kBluetoothName[] = "BT_Speaker5.4";
// I2C接続のOLED設定 (SSD1306 128x64)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
@ -18,25 +18,37 @@ String currentTitle = "未接続";
String currentArtist = "";
int currentVolumePercent = 0; // 音量 (0 ~ 100%)
bool bluetoothConnected = false;
bool musicPlaying = false;
unsigned long lastDisplayUpdate = 0;
// 画面全体を再描画する関数
void updateDisplay() {
u8g2.clearBuffer();
if (!bluetoothConnected) {
if (!bluetoothConnected || !musicPlaying) {
u8g2.setFont(u8g2_font_6x10_tf);
const SensorReading& reading = sensorLogger.latest();
char sensorLine[32];
char timeLine[24];
if (sensorLogger.getCurrentTime(timeLine, sizeof(timeLine))) {
u8g2.drawStr(0, 9, timeLine);
} else {
u8g2.drawStr(0, 9, "RTC: --/--/-- --:--:--");
}
snprintf(sensorLine, sizeof(sensorLine), "Log: %u", static_cast<unsigned int>(sensorLogger.logCount()));
u8g2.drawStr(0, 20, sensorLine);
snprintf(sensorLine, sizeof(sensorLine), "T:%5.1fC H:%5.1f%%",
reading.temperature, reading.humidity);
u8g2.drawStr(0, 12, sensorLine);
u8g2.drawStr(0, 32, sensorLine);
snprintf(sensorLine, sizeof(sensorLine), "Light: %6.1f lx", reading.illuminance);
u8g2.drawStr(0, 30, sensorLine);
u8g2.drawStr(0, 44, sensorLine);
snprintf(sensorLine, sizeof(sensorLine), "Soil: %4u", reading.soilMoisture);
u8g2.drawStr(0, 48, sensorLine);
u8g2.drawStr(0, 56, sensorLine);
u8g2.sendBuffer();
return;
}
@ -88,7 +100,7 @@ void avrc_metadata_callback(uint8_t id, const uint8_t *text) {
updated = true;
}
if (updated && bluetoothConnected) {
if (updated && bluetoothConnected && musicPlaying) {
updateDisplay();
}
}
@ -96,17 +108,22 @@ void avrc_metadata_callback(uint8_t id, const uint8_t *text) {
// 音量変更時のコールバック関数
void volume_changed_callback(int volume) {
currentVolumePercent = map(volume, 0, 127, 0, 100);
if (bluetoothConnected) {
if (bluetoothConnected && musicPlaying) {
updateDisplay();
}
}
void audio_state_changed_callback(esp_a2d_audio_state_t state, void *) {
neoPixelController.setPlaying(state == ESP_A2D_AUDIO_STATE_STARTED);
musicPlaying = state == ESP_A2D_AUDIO_STATE_STARTED;
neoPixelController.setPlaying(musicPlaying);
updateDisplay();
}
void connection_state_changed_callback(esp_a2d_connection_state_t state, void *) {
bluetoothConnected = state == ESP_A2D_CONNECTION_STATE_CONNECTED;
if (!bluetoothConnected) {
musicPlaying = false;
}
updateDisplay();
}
@ -125,6 +142,7 @@ void setup() {
sensorLogger.begin(32);
updateDisplay();
lastDisplayUpdate = millis();
// I2S ピン設定 (BCK: 27, WS: 25, DOUT: 26)
i2s_pin_config_t my_pin_config = {
@ -148,7 +166,11 @@ void setup() {
void loop() {
neoPixelController.update();
if (sensorLogger.update() && !bluetoothConnected) {
bool newReading = sensorLogger.update();
unsigned long now = millis();
if ((!bluetoothConnected || !musicPlaying)
&& (newReading || now - lastDisplayUpdate >= 1000UL)) {
lastDisplayUpdate = now;
updateDisplay();
}
}