Fix OLED autosleep timing and battery sampling cadence

- Track last OLED activity to avoid double timeout; keep power gating on transitions
- Copy TZ before setenv() in timegm_fallback to avoid invalid pointer reuse
- Add BATTERY_SAMPLE_INTERVAL_MS and only refresh cache at batch start when due
- Keep battery sampling to a single ADC read (Arduino core lacks explicit ADC power gating)
This commit is contained in:
2026-02-02 23:01:55 +01:00
parent 90d830da6f
commit 2199627a35
6 changed files with 29 additions and 33 deletions

View File

@@ -36,10 +36,9 @@ static bool g_mqtt_ok = false;
static bool g_oled_on = true;
static bool g_prev_ctrl_high = false;
static uint32_t g_oled_off_start = 0;
static uint32_t g_last_page_ms = 0;
static uint8_t g_page = 0;
static uint32_t g_boot_ms = 0;
static uint32_t g_last_activity_ms = 0;
static bool g_display_ready = false;
static uint32_t g_last_init_attempt_ms = 0;
static bool g_last_oled_on = true;
@@ -83,7 +82,7 @@ void display_init() {
display.display();
}
g_last_init_attempt_ms = millis();
g_boot_ms = millis();
g_last_activity_ms = millis();
}
void display_set_role(DeviceRole role) {
@@ -380,27 +379,16 @@ void display_tick() {
ctrl_high = digitalRead(PIN_OLED_CTRL) == HIGH;
}
bool in_boot_window = (millis() - g_boot_ms) < OLED_AUTO_OFF_MS;
uint32_t now_ms = millis();
bool ctrl_falling_edge = g_prev_ctrl_high && !ctrl_high;
if (g_role == DeviceRole::Receiver) {
g_oled_on = true;
g_oled_off_start = 0;
} else if (in_boot_window) {
g_oled_on = true;
g_last_activity_ms = now_ms;
} else {
if (ctrl_high) {
g_oled_on = true;
g_oled_off_start = 0;
} else if (g_prev_ctrl_high && !ctrl_high) {
g_oled_off_start = millis();
} else if (!g_prev_ctrl_high && !ctrl_high && g_oled_off_start == 0) {
g_oled_off_start = millis();
if (ctrl_high || ctrl_falling_edge) {
g_last_activity_ms = now_ms;
}
if (!ctrl_high && g_oled_off_start > 0 && millis() - g_oled_off_start > OLED_AUTO_OFF_MS) {
g_oled_on = false;
}
// fall through to power gating below
g_oled_on = (now_ms - g_last_activity_ms) < OLED_AUTO_OFF_MS;
}
if (g_oled_on) {

View File

@@ -152,6 +152,10 @@ static void update_battery_cache() {
g_last_battery_ms = millis();
}
static bool battery_sample_due(uint32_t now_ms) {
return g_last_battery_ms == 0 || now_ms - g_last_battery_ms >= BATTERY_SAMPLE_INTERVAL_MS;
}
static bool sender_timesync_window_due() {
uint32_t interval_sec = SENDER_TIMESYNC_CHECK_SEC_FAST;
if (time_is_synced() && time_rtc_present()) {
@@ -742,7 +746,7 @@ static void sender_loop() {
note_fault(g_sender_faults, g_sender_last_error, g_sender_last_error_utc, g_sender_last_error_ms, FaultType::MeterRead);
display_set_last_error(g_sender_last_error, g_sender_last_error_utc, g_sender_last_error_ms);
}
if (g_build_count == 0) {
if (g_build_count == 0 && battery_sample_due(now_ms)) {
update_battery_cache();
}
data.battery_voltage_v = g_last_battery_voltage_v;

View File

@@ -34,11 +34,8 @@ void power_configure_unused_pins_sender() {
}
void read_battery(MeterData &data) {
uint32_t sum = 0;
sum += analogRead(PIN_BAT_ADC);
sum += analogRead(PIN_BAT_ADC);
float avg = static_cast<float>(sum) / 2.0f;
float v = (avg / 4095.0f) * ADC_REF_V * BATTERY_DIVIDER * BATTERY_CAL;
uint32_t raw = analogRead(PIN_BAT_ADC);
float v = (static_cast<float>(raw) / 4095.0f) * ADC_REF_V * BATTERY_DIVIDER * BATTERY_CAL;
data.battery_voltage_v = v;
data.battery_percent = battery_percent_from_voltage(v);

View File

@@ -1,6 +1,7 @@
#include "rtc_ds3231.h"
#include "config.h"
#include <Wire.h>
#include <string>
#include <time.h>
static constexpr uint8_t DS3231_ADDR = 0x68;
@@ -17,12 +18,14 @@ static time_t timegm_fallback(struct tm *tm_utc) {
if (!tm_utc) {
return static_cast<time_t>(-1);
}
char *old_tz = getenv("TZ");
const char *old_tz = getenv("TZ");
// getenv() may return a pointer into mutable storage that becomes invalid after setenv().
std::string old_tz_copy = old_tz ? old_tz : "";
setenv("TZ", "UTC0", 1);
tzset();
time_t t = mktime(tm_utc);
if (old_tz) {
setenv("TZ", old_tz, 1);
if (!old_tz_copy.empty()) {
setenv("TZ", old_tz_copy.c_str(), 1);
} else {
unsetenv("TZ");
}