RTC表示
This commit is contained in:
parent
68a5f0dcce
commit
5e052dba93
|
|
@ -12,11 +12,17 @@ namespace {
|
||||||
constexpr char kNusServiceUuid[] = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
|
constexpr char kNusServiceUuid[] = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
|
||||||
constexpr char kNusRxUuid[] = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
|
constexpr char kNusRxUuid[] = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
|
||||||
constexpr char kNusTxUuid[] = "6E400003-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;
|
Adafruit_AHTX0 aht20;
|
||||||
BH1750 bh1750;
|
BH1750 bh1750;
|
||||||
bool aht20Ready = false;
|
bool aht20Ready = false;
|
||||||
bool bh1750Ready = false;
|
bool bh1750Ready = false;
|
||||||
|
|
||||||
|
bool isLeapYear(int year) {
|
||||||
|
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SensorLoggerCallbacks : public BLECharacteristicCallbacks {
|
class SensorLoggerCallbacks : public BLECharacteristicCallbacks {
|
||||||
|
|
@ -96,6 +102,47 @@ bool SensorLogger::hasReading() const {
|
||||||
return logCount_ != 0;
|
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() {
|
void SensorLogger::readAndStore() {
|
||||||
sensors_event_t humidityEvent;
|
sensors_event_t humidityEvent;
|
||||||
sensors_event_t temperatureEvent;
|
sensors_event_t temperatureEvent;
|
||||||
|
|
@ -193,7 +240,7 @@ void SensorLogger::sendLog() {
|
||||||
size_t logIndex = (logStart_ + index) % kMaxLogEntries;
|
size_t logIndex = (logStart_ + index) % kMaxLogEntries;
|
||||||
const SensorReading& reading = log_[logIndex];
|
const SensorReading& reading = log_[logIndex];
|
||||||
char line[128];
|
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.timestamp,
|
||||||
reading.temperature,
|
reading.temperature,
|
||||||
reading.humidity,
|
reading.humidity,
|
||||||
|
|
@ -224,7 +271,7 @@ void SensorLogger::clearLog() {
|
||||||
logCount_ = 0;
|
logCount_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long SensorLogger::currentTimestamp() const {
|
int64_t SensorLogger::currentTimestamp() const {
|
||||||
unsigned long elapsedSeconds = millis() / 1000UL;
|
int64_t elapsedSeconds = millis() / 1000UL;
|
||||||
return timeSynchronized_ ? epochOffset_ + elapsedSeconds : elapsedSeconds;
|
return timeSynchronized_ ? epochOffset_ + elapsedSeconds : elapsedSeconds;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ class BLECharacteristic;
|
||||||
class BLEServer;
|
class BLEServer;
|
||||||
|
|
||||||
struct SensorReading {
|
struct SensorReading {
|
||||||
unsigned long timestamp;
|
int64_t timestamp;
|
||||||
float temperature;
|
float temperature;
|
||||||
float humidity;
|
float humidity;
|
||||||
float illuminance;
|
float illuminance;
|
||||||
|
|
@ -21,6 +21,8 @@ public:
|
||||||
bool update();
|
bool update();
|
||||||
const SensorReading& latest() const;
|
const SensorReading& latest() const;
|
||||||
bool hasReading() const;
|
bool hasReading() const;
|
||||||
|
size_t logCount() const;
|
||||||
|
bool getCurrentTime(char* buffer, size_t bufferSize) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr unsigned long kMeasureIntervalMs = 3600000UL;
|
static constexpr unsigned long kMeasureIntervalMs = 3600000UL;
|
||||||
|
|
@ -32,7 +34,7 @@ private:
|
||||||
void sendNotification(const char* data);
|
void sendNotification(const char* data);
|
||||||
void sendLog();
|
void sendLog();
|
||||||
void clearLog();
|
void clearLog();
|
||||||
unsigned long currentTimestamp() const;
|
int64_t currentTimestamp() const;
|
||||||
|
|
||||||
BLEServer* server_ = nullptr;
|
BLEServer* server_ = nullptr;
|
||||||
BLECharacteristic* txCharacteristic_ = nullptr;
|
BLECharacteristic* txCharacteristic_ = nullptr;
|
||||||
|
|
@ -42,7 +44,7 @@ private:
|
||||||
size_t logCount_ = 0;
|
size_t logCount_ = 0;
|
||||||
uint8_t soilPin_ = 0;
|
uint8_t soilPin_ = 0;
|
||||||
unsigned long lastMeasure_ = 0;
|
unsigned long lastMeasure_ = 0;
|
||||||
unsigned long epochOffset_ = 0;
|
int64_t epochOffset_ = 0;
|
||||||
bool timeSynchronized_ = false;
|
bool timeSynchronized_ = false;
|
||||||
String bluetoothName_;
|
String bluetoothName_;
|
||||||
String commandBuffer_;
|
String commandBuffer_;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include "NeoPixelController.h"
|
#include "NeoPixelController.h"
|
||||||
#include "SensorLogger.h"
|
#include "SensorLogger.h"
|
||||||
|
|
||||||
const char kBluetoothName[] = "BT_Speaker5.32";
|
const char kBluetoothName[] = "BT_Speaker5.4";
|
||||||
|
|
||||||
// I2C接続のOLED設定 (SSD1306 128x64)
|
// I2C接続のOLED設定 (SSD1306 128x64)
|
||||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
|
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
|
||||||
|
|
@ -18,25 +18,37 @@ String currentTitle = "未接続";
|
||||||
String currentArtist = "";
|
String currentArtist = "";
|
||||||
int currentVolumePercent = 0; // 音量 (0 ~ 100%)
|
int currentVolumePercent = 0; // 音量 (0 ~ 100%)
|
||||||
bool bluetoothConnected = false;
|
bool bluetoothConnected = false;
|
||||||
|
bool musicPlaying = false;
|
||||||
|
unsigned long lastDisplayUpdate = 0;
|
||||||
|
|
||||||
// 画面全体を再描画する関数
|
// 画面全体を再描画する関数
|
||||||
void updateDisplay() {
|
void updateDisplay() {
|
||||||
u8g2.clearBuffer();
|
u8g2.clearBuffer();
|
||||||
|
|
||||||
if (!bluetoothConnected) {
|
if (!bluetoothConnected || !musicPlaying) {
|
||||||
u8g2.setFont(u8g2_font_6x10_tf);
|
u8g2.setFont(u8g2_font_6x10_tf);
|
||||||
const SensorReading& reading = sensorLogger.latest();
|
const SensorReading& reading = sensorLogger.latest();
|
||||||
|
|
||||||
char sensorLine[32];
|
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%%",
|
snprintf(sensorLine, sizeof(sensorLine), "T:%5.1fC H:%5.1f%%",
|
||||||
reading.temperature, reading.humidity);
|
reading.temperature, reading.humidity);
|
||||||
u8g2.drawStr(0, 12, sensorLine);
|
u8g2.drawStr(0, 32, sensorLine);
|
||||||
|
|
||||||
snprintf(sensorLine, sizeof(sensorLine), "Light: %6.1f lx", reading.illuminance);
|
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);
|
snprintf(sensorLine, sizeof(sensorLine), "Soil: %4u", reading.soilMoisture);
|
||||||
u8g2.drawStr(0, 48, sensorLine);
|
u8g2.drawStr(0, 56, sensorLine);
|
||||||
u8g2.sendBuffer();
|
u8g2.sendBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +100,7 @@ void avrc_metadata_callback(uint8_t id, const uint8_t *text) {
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated && bluetoothConnected) {
|
if (updated && bluetoothConnected && musicPlaying) {
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,17 +108,22 @@ void avrc_metadata_callback(uint8_t id, const uint8_t *text) {
|
||||||
// 音量変更時のコールバック関数
|
// 音量変更時のコールバック関数
|
||||||
void volume_changed_callback(int volume) {
|
void volume_changed_callback(int volume) {
|
||||||
currentVolumePercent = map(volume, 0, 127, 0, 100);
|
currentVolumePercent = map(volume, 0, 127, 0, 100);
|
||||||
if (bluetoothConnected) {
|
if (bluetoothConnected && musicPlaying) {
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_state_changed_callback(esp_a2d_audio_state_t state, void *) {
|
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 *) {
|
void connection_state_changed_callback(esp_a2d_connection_state_t state, void *) {
|
||||||
bluetoothConnected = state == ESP_A2D_CONNECTION_STATE_CONNECTED;
|
bluetoothConnected = state == ESP_A2D_CONNECTION_STATE_CONNECTED;
|
||||||
|
if (!bluetoothConnected) {
|
||||||
|
musicPlaying = false;
|
||||||
|
}
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,6 +142,7 @@ void setup() {
|
||||||
|
|
||||||
sensorLogger.begin(32);
|
sensorLogger.begin(32);
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
|
lastDisplayUpdate = millis();
|
||||||
|
|
||||||
// I2S ピン設定 (BCK: 27, WS: 25, DOUT: 26)
|
// I2S ピン設定 (BCK: 27, WS: 25, DOUT: 26)
|
||||||
i2s_pin_config_t my_pin_config = {
|
i2s_pin_config_t my_pin_config = {
|
||||||
|
|
@ -148,7 +166,11 @@ void setup() {
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
neoPixelController.update();
|
neoPixelController.update();
|
||||||
if (sensorLogger.update() && !bluetoothConnected) {
|
bool newReading = sensorLogger.update();
|
||||||
|
unsigned long now = millis();
|
||||||
|
if ((!bluetoothConnected || !musicPlaying)
|
||||||
|
&& (newReading || now - lastDisplayUpdate >= 1000UL)) {
|
||||||
|
lastDisplayUpdate = now;
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue