Skip to content

feat: night mode — extended sleep interval during 22:00-06:00 - #25

Open
stritti wants to merge 5 commits into
feat/power-optimizationfrom
feat/night-mode
Open

feat: night mode — extended sleep interval during 22:00-06:00#25
stritti wants to merge 5 commits into
feat/power-optimizationfrom
feat/night-mode

Conversation

@stritti

@stritti stritti commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Zusammenfassung

Nacht-Modus für den Pool Monitor: Zwischen 22:00 und 06:00 Uhr verlängert sich das Wake-Intervall von 3 Minuten auf 4 Stunden.

Energiebilanz

Kennzahl Ohne Nachtmodus Mit Nachtmodus
Wake-ups Nacht (22–6) 160 2
Wake-ups Tag (6–22) 320 320
Gesamt/Tag 480 322
Tagesverbrauch ~40 mAh ~27 mAh
Autonomie 500 mAh 12,5 Tage 18,5 Tage

Funktionsweise

  • Uhrzeit wird aus + vergangener Uptime rekonstruiert (kein zusätzlicher NTP-Call nötig)
  • Nacht-Modus aktiviert sich erst nach erstem erfolgreichem NTP-Sync (vorher Standard-Intervall)
  • Die 2 nächtlichen Wake-ups (22:00, 02:00) dokumentieren den Temperaturverlauf für morgendliche Graphen

Konfiguration (Config.hpp)

Konstante Wert
NIGHT_START_HOUR 22
NIGHT_END_HOUR 6
NIGHT_SLEEP_INTERVAL_SECONDS 14400 (4h)

Build & Check

  • pio run --environment LILYGO_T5_V231: ✅ SUCCESS
  • pio check --environment LILYGO_T5_V231 --skip-packages: ✅ PASSED

Between NIGHT_START_HOUR (22) and NIGHT_END_HOUR (6) local time, the
device wakes only every 4 hours instead of every 3 minutes. Reduces
night-time wake-ups from ~160 to ~2, cutting daily power consumption
from ~40 mAh to ~27 mAh.

Night mode only activates after the first NTP sync (valid epoch time).
Time is reconstructed from stored epoch + uptime, so it works across
deep-sleep cycles without additional network requests.
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Super-linter summary

Language Validation result
CPP Pass ✅
EDITORCONFIG Pass ✅
GITLEAKS Pass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eeb8a6fb5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/PoolMonitor/PoolMonitorContext.cpp
… deep-sleep cycles

Codex P1: When night mode selects a 4-hour sleep interval, the next boot
must increment total_uptime by the actual duration (not just TIME_TO_SLEEP_SECONDS).
Without this fix, the time reconstruction drifts by ~3h57m every night cycle,
causing the device to stay in night mode well into the day.

- prepareForSleep(): save 'last_sleep_sec' to NVS before deep sleep
- setup(): read 'last_sleep_sec' when incrementing total_uptime, then remove it
  so normal cycles without the key default to TIME_TO_SLEEP_SECONDS

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a7d7dbf63f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/PoolMonitor/PoolMonitorContext.cpp
When the device enters night mode at an hour not aligned to the intended
22:00/02:00 cadence (e.g. 00:30 after a restart), the unconditional 4-hour
sleep could carry it past 06:00 into morning. The fix calculates the
remaining seconds until NIGHT_END_HOUR and clamps the sleep interval, so
the device always wakes at or before 06:00 to resume normal operation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a4f196b33

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/PoolMonitor/PoolMonitorContext.cpp
During night mode (4h sleep), no_wifi_count was only incremented by 1,
undercounting skipped wake cycles by a factor of ~80. This caused the
post-night wake (06:00) to skip WiFi/MQTT/display because the counter
hadn't reached the SKIP_WIFI_WAKE_CYCLES threshold.

Now the increment is scaled by lastSleepDuration / TIME_TO_SLEEP_SECONDS,
so a 4-hour night sleep correctly advances the counter by ~80 cycles.

Addresses P2 feedback from Codex review on PR #25.
@stritti

stritti commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Antwort auf Codex Reviews

P1: Account for night sleep in persisted uptime ✅

Bereits im Branch implementiert: prepareForSleep() persistiert die tatsächliche Schlafdauer als last_sleep_sec, und setup() addiert diesen Wert zu total_uptime (total_uptime += lastSleepDuration, Zeile 104-108). Die Uptime-Abrechnung ist damit korrekt für alle Schlafintervalle.

P2: Clamp night sleeps to the 06:00 boundary ✅

Bereits im Branch implementiert: secondsUntilEnd Clamping (Zeilen 251-268) begrenzt den Nacht-Sleep auf die verbleibende Zeit bis NIGHT_END_HOUR (06:00). Bei 04:30 Aufwachzeit wird z.B. auf 5400s (1,5h) statt 14400s (4h) verkürzt.

P2: Keep network cadence during night sleeps 🔧 Gefixt in 0bdf956

no_wifi_count wurde nur um 1 erhöht, unabhängig von der tatsächlichen Schlafdauer. Bei 4h-Nachtschlaf (entspricht ~80 normalen 180s-Zyklen) wurde der Zähler unterschätzt, sodass der 06:00-Wake ggf. das Network übersprang.

Fix: Der Increment wird jetzt über lastSleepDuration / TIME_TO_SLEEP_SECONDS skaliert. Ein 4h-Schlaf incrementiert den Zähler um 80 statt 1, sodass der nächste Wake korrekt ein Network-Cycle wird.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0bdf95635c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

preferences_->putUInt("no_wifi_count", 0);
} else {
preferences_->putUInt("no_wifi_count", cyclesWithoutWiFi + 1);
preferences_->putUInt("no_wifi_count", cyclesWithoutWiFi + skipIncrement);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply elapsed skip count before deciding WiFi

When the previous sleep was a night interval and no_wifi_count was still below the threshold, doNetwork has already been computed before this scaled increment is written, so that wake still skips WiFi/MQTT even though 4 hours elapsed; for example, entering night right after a network cycle makes the 02:00 wake skip the retained MQTT sample and display update. Fresh evidence in this revision is that the scaled increment is only persisted here after the network decision was made, so the intended long-sleep catch-up applies one wake too late.

Useful? React with 👍 / 👎.

cppcheck's --unusedFunction cannot resolve calls across translation units
for PlatformIO builds, producing false positives for every function called
from PoolMonitorContext.cpp to DisplayManager, NetworkManager, and
TimeClientHelper, plus the Arduino framework entry point PoolMonitorContext::setup().

Changes:
- Added --inline-suppr to platformio.ini check_flags
- Added // cppcheck-suppress unusedFunction with ; comment syntax to 11
  cross-TU functions that are genuinely called from other .cpp files
- Removed DisplayManager::getWidth() and getHeight() which were genuinely
  unused (callers use getDisplay().width()/.height() directly)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec569c062c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

unsigned long totalUptime = preferences_->getULong("total_uptime", 0);
unsigned long lastEpoch = preferences_->getULong("last_epoch", 0);

if (lastEpoch > 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject bogus epochs before enabling night mode

When an NTP update fails after WiFi connects, getCurrentTime() returns "--:--" but setup still persists timeClient.getEpochTime(); on a fresh boot that can be a small nonzero uptime value. This new lastEpoch > 0 gate then treats the bogus 1970-era timestamp as valid local time (typically inside the 00:00-06:00 night window), so an NTP outage during the day can put the device into repeated 4-hour sleeps and delay MQTT/display/OTA work. Require a successful sync or reject implausible epochs before using last_epoch for night-mode scheduling.

Useful? React with 👍 / 👎.

- currentMinute * 60 - currentSecond;
}

if (secondsUntilEnd > 60 && sleepSeconds > static_cast<uint32_t>(secondsUntilEnd)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clamp the final minute before morning

When the device evaluates night mode in the last minute before NIGHT_END_HOUR—for example after a restart or network cycle at 05:59:30—secondsUntilEnd is <= 60, so this guard skips the clamp and leaves sleepSeconds at the 4-hour night interval, waking around 09:59 instead of just after 06:00. Fresh evidence beyond the earlier clamp discussion is the secondsUntilEnd > 60 condition, which still allows this boundary oversleep; fall back to the normal interval or clamp the remaining time here.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant