Revise README for version 7.0 updates and features

Updated README to reflect changes in version 7.0, including new features like the Rolling 48-Hour Logic and Midnight Bridge system. Enhanced sections on API call intervals, dual-buffer NVS, and display states.
This commit is contained in:
2026-04-03 04:10:49 +02:00
committed by GitHub
parent 4ac7449163
commit 5ff76a57f9
+270 -148
View File
@@ -11,21 +11,40 @@ This project is an ArduinoIDEfriendly firmware for the **Seeed XIAO ESP32
- Uses a white LED and an optional presence sensor to give quick visual feedback.
- Stores daily price data in **NVS** to survive reboots and reduce API calls.
The latest sketch implements **Version 6.2.4**.
The latest sketch implements **Version 7.0** with the revolutionary **Rolling 48-Hour Logic & Midnight Bridge** system.
---
## Version Highlights
### v6.2.4 - Exact-boundary display refresh bug (critical fix of v6.2.3 update)
### v7.0 - Rolling 48-Hour Logic & Midnight Bridge (Major Upgrade)
This version is the **"Golden Build"** for this hardware platform. It combines all hardware stability fixes from v6.2.4 with a revolutionary new 48-hour price prediction system.
#### Key New Features
- **Midnight Bridge**: Instantly promotes pre-fetched tomorrow's data to become today's data at midnight, eliminating the "1 AM fetch gap"
- **Dual-Buffer NVS**: Stores "Today" and "Tomorrow" data independently
- **47-Hour Scrolling**: View up to 47 hours of price data when tomorrow's data is available
- **Visual Tomorrow Indicators**: Future hours are marked with `HH:>>` format
- **Smart Fetching**: Automatically fetches tomorrow's data after 14:00 (2 PM)
#### Technical Highlights
- **Instant Midnight Transition**: No more "No Data" screen at midnight
- **Power-Failure Resilience**: New day's data is saved to NVS immediately after midnight swap
- **Correct Min/Max for Tomorrow**: Price indicators correctly reference tomorrow's statistics
- **LED Indicators Pinned to Current**: White LED always reflects actual current prices
### v6.2.4 - Exact-boundary display refresh bug (critical fix of v6.2.3 update)
- Problem: At the exact top of the hour (e.g., 20:00:00), the display automatically refreshed but showed the PREVIOUS hour's data (19:00). This happened because the "next-boundary" rounding logic in findCurrentPriceIndex() incorrectly excluded the current interval if the time was exactly on the boundary.
- Fix: Simplified findCurrentPriceIndex() to use a robust "last entry <= now" comparison. This ensures the display transitions to the new hour instantaneously at XX:00:00.
### v6.2.3 - State-based display refresh logic (critical fix of v6.2.2 update)
### v6.2.3 - State-based display refresh logic (critical fix of v6.2.2 update)
- Problem: Screen would occasionally fail to update if the ESP32 was busy (fetching data or reconnecting WiFi) during the exact 00/15/30/45 minute mark.
- Fix: Switched from "Event-Based" (refresh only AT minute X) to "State-Based" (refresh IF current time != last refresh time). This ensures the screen updates immediately even if the device was busy during the transition.
### v6.2.2 - Display Blank Lines Issue Fix (critical fix of v6.2.1 update)
### v6.2.2 - Display Blank Lines Issue Fix (critical fix of v6.2.1 update)
- Problem: Sometimes rows 0 and 1 (current 15-min prices and current hour) were blank.
- Cause: The "hour suppression" logic was hiding the current hour unexpectedly.
- Fix:
@@ -51,7 +70,7 @@ Major update sketch implements **Version 6.2.0**, focusing on:
## DST (Daylight Saving Time) How It Works
### v6.2.0: Fully DST-Safe
### v6.2.0+: Fully DST-Safe
**Important**: Starting with v6.2.0, the ticker is **fully DST-safe** and requires **no manual intervention** on DST switch days.
@@ -59,9 +78,9 @@ The firmware uses **timestamp-based price lookups** that work correctly regardle
| Day Type | Hours in Day | Price Entries | Status |
|----------|-------------|---------------|--------|
| Normal | 24 | 96 | Works |
| Spring forward (March) | 23 | 92 | Works (fixed in v6.2.0) |
| Fall back (October) | 25 | 100 | Works (fixed in v6.2.0) |
| Normal | 24 | 96 | Works |
| Spring forward (March) | 23 | 92 | Works (fixed in v6.2.0) |
| Fall back (October) | 25 | 100 | Works (fixed in v6.2.0) |
### Timezone Configuration
@@ -91,6 +110,144 @@ The rest of the code works unchanged because it uses timestamp-based lookups.
---
## The Midnight Bridge (v7.0)
### The Problem with Traditional Tickers
Most electricity tickers fail at midnight because they rely on slow API calls to fetch new data. The Energy-Charts API typically doesn't publish next-day data until 1-2 AM, leaving users with a "No Data" screen for hours.
### The Solution: Midnight Bridge
The Midnight Bridge detects the moment the local clock moves from 23:59:59 to 00:00:00 and instantly promotes the pre-fetched "Tomorrow" data to become "Today" data.
**How it works:**
1. **Pre-fetching**: After 14:00 (2 PM), the ticker automatically fetches tomorrow's prices using the `&start=YYYY-MM-DD` API parameter
2. **Buffer Storage**: Tomorrow's data is stored in a separate NVS slot (`data_prc_t`)
3. **Midnight Detection**: The main loop detects day rollover by comparing `tm_mday`
4. **Instant Swap**: At 00:00:00, tomorrow's buffer instantly becomes today's data
5. **NVS Persistence**: New day's data is saved immediately after swap (power-failure protection)
### Power-Failure Protection
Immediately after the midnight swap, the new "Today" data is serialized and saved to NVS. If power is cut at 00:05 AM, the device reboots with correct data already loaded.
---
## Dual-Buffer System (v7.0)
The v7.0 firmware implements a dual-buffer system that stores today and tomorrow data independently:
### Buffer Comparison
| Buffer | Variable | NVS Keys | Contents |
|--------|----------|----------|----------|
| Today | `doc` | `data_prc`, `data_day`, `data_mon`, `data_year` | Current day's prices |
| Tomorrow | `docTomorrow` | `data_prc_t`, `data_store_t` | Next day's prices |
### Statistics Per Buffer
Each buffer maintains its own statistics:
- **Daily average**: `averagePrice` / `averagePriceTomorrow`
- **Lowest price index**: `lowestPriceIndex` / `lowestPriceIndexTomorrow`
- **Highest price index**: `highestPriceIndex` / `highestPriceIndexTomorrow`
### Display Selection
The display logic automatically selects the correct buffer based on the time offset:
```cpp
bool showTomorrow = (totalHourOffset >= 24);
StaticJsonDocument<Config::JSON_BUFFER_SIZE>& targetDoc = showTomorrow ? docTomorrow : doc;
int lowIdx = showTomorrow ? lowestPriceIndexTomorrow : lowestPriceIndex;
```
---
## 48-Hour Scrolling (v7.0)
### Extended Range
When tomorrow's data is available, users can scroll up to **47 hours ahead**:
```cpp
int maxOffsetLimit = isTomorrowDataAvailable ? 47 : 23;
```
### Visual Tomorrow Indication
Future hours (tomorrow) are displayed with `HH:>>` format to clearly distinguish them from today's hours:
```
Today's hour: 14:00 | Tomorrow's hour: 14:>>
```
### Correct Min/Max Indicators
The low/high price markers (arrows) correctly reference tomorrow's statistics when viewing tomorrow's hours:
```cpp
if (dataIndex == lowIdx) {
lcd.write(byte(3)); // Low price arrow
}
```
---
## Behavior & Display States (v7.0)
The display changes based on which data buffer is being used and the status of the fetch:
| **State** | **Display Output** | **LED Behavior** |
|----------|-------------------|-----------------|
| **Normal (Today)** | Shows current prices and 15-min details. Hours are marked as HH:00. | White LED reflects current price status (Breathe, Solid, or Blink). |
| **Scrolling (Tomorrow)** | Future prices are displayed. Hours are marked with HH:>> to indicate "Tomorrow". | **Pinned to Today:** The LEDs continue showing the _actual current_ price status even while you scroll through tomorrow. |
| **No Data** | Displays: "No data for today, Press & hold to, refresh manually." | White LED is turned **OFF** to avoid misleading price signals. |
| **Connecting** | "Elec. Rate SI v7.0" followed by "Connecting..." and progress dots. | Built-in LED is **OFF** until connection is established. |
### Key UX Principle: LEDs Stay Pinned to Current Time
Unlike the display which can scroll through future hours, the white LED **always** reflects the actual current price status. This means:
- Even while browsing tomorrow's cheap hours, the LED tells you the **true current** price situation
- This prevents confusion and helps you decide "should I turn on the dishwasher **now**?"
---
## API Call Intervals & Retry Strategy (v7.0)
### Primary Scheduling (Daily Fetch)
The device aims to maintain a rolling 48-hour data window by fetching today's and tomorrow's data at specific times:
- **Initial Boot:** An API call is attempted immediately upon startup and time synchronization.
- **Tomorrow's Data (Smart Fetching):** Starting at **14:00 (2 PM) local time**, the device begins checking for the next day's prices. It will attempt to fetch this data periodically until successful.
- **Midnight Rollover:** At exactly **00:00:00**, the device "promotes" tomorrow's data to the today buffer. If tomorrow's data was already successfully fetched and stored, **no API call is needed at midnight**.
### Retry Logic (Exponential Backoff)
If a scheduled API call fails (e.g., due to a temporary server error or WiFi glitch), the device uses a safety-oriented retry interval:
- **Max Retries:** 5 attempts (`HTTP_GET_RETRY_MAX = 5`)
- **Backoff Factor:** 2 (`HTTP_GET_BACKOFF_FACTOR = 2`)
- **Typical Progression:** After a failure, it waits a short period, then doubles that wait time for each subsequent failure until the maximum retry count is reached
### "Midnight Phase" Recovery
If the device reaches midnight but **does not** have tomorrow's data ready (meaning the afternoon fetches failed), it enters a high-priority state called `midnightPhaseActive`:
- **Behavior:** Bypasses the standard daily schedule and retries the API **more aggressively**
- **Initial Interval:** Attempts every minute until successful
- **Goal:** Clear the "No Data" screen and restore the price display as quickly as possible once the energy provider's server updates
### Background Monitoring
While not making API calls constantly, the device performs these checks continuously:
- **Loop Pacing:** The main system loop runs every **100ms** to check if it's time for a scheduled fetch
- **Display Refresh:** The screen logic checks the time every loop but only refreshes the UI every **15 minutes** (at :00, :15, :30, :45) to match the price data intervals
---
## Bidding Zones (BZN) / Region Selection
The firmware currently uses:
@@ -161,7 +318,7 @@ All available bidding zones (from the original README):
## Hardware Setup (Detailed)
This section merges the original v5.5 instructions with the current v6.1 hardware expectations.
This section merges the original v5.5 instructions with the current v7.0 hardware expectations.
Follow it carefully to reproduce the working setup.
### 1. Microcontroller
@@ -298,7 +455,7 @@ The sketch uses a **white LED** (or LED strip control line) on `GPIO 5` (`whiteL
- Ensure the **strip power supply shares ground** with the ESP32C3 board.
- Do **not** drive large loads directly from the GPIO pin.
The LED is driven with various patterns to indicate price level; see LED Price Signalling below.
The LED is driven with various patterns to indicate price level; see "LED Price Signalling" below.
---
@@ -311,15 +468,16 @@ The LED is driven with various patterns to indicate price level; see “LED Pric
---
## Firmware Features (v6.2.0)
## Firmware Features (v7.0)
### Core Display & Pricing
- Data source: `https://api.energy-charts.info/price?bzn=SI`
- Resolution: 15minute intervals with hourly averages
- Display shows:
- Display shows up to **47 hours** of price data (when tomorrow's data is available)
- **Row 0**: Current hour, four 15minute values
- **Rows 13**: Current hour + next two hours as hourly averages
- **v7.0 Feature**: Tomorrow's hours are marked with `HH:>>` format
- Price calculation: Raw MWh → EUR/kWh with configurable surcharges (power company fee + VAT)
- Two configurable surcharges:
- `POWER_COMPANY_FEE_PERCENTAGE` (default `12.0` %).
@@ -329,11 +487,12 @@ The LED is driven with various patterns to indicate price level; see “LED Pric
- Local language letters.
- Lowprice and highprice indicators.
- **Daily min/max markers**:
- The low/high hourly indicators consider **negative**, **0.0**, and positive prices (v6.1.1 fix).
- The low/high hourly indicators consider **negative**, **0.0**, and positive prices
- **v7.0 Feature**: Tomorrow's min/max indices are tracked separately and displayed correctly
### LED Price Signalling
The white LED (GPIO 5) reflects the **current 15minute interval** price:
The white LED (GPIO 5) reflects the **current 15minute interval** price (regardless of what's displayed on screen):
| Price Level | LED Behavior |
|-------------|--------------|
@@ -370,7 +529,7 @@ LED is **disabled** when:
One button (or touch) on GPIO 4 controls the UI:
- **Single short press**:
- On primary screen: scrolls the time offset (future hours).
- On primary screen: scrolls the time offset (future hours up to 47h in v7.0).
- On secondary screen: scrolls through the 20line status text (4 lines at a time).
- **Double press**:
- Toggles between:
@@ -378,32 +537,37 @@ One button (or touch) on GPIO 4 controls the UI:
- Secondary status/info view.
- **Long press (~3 seconds in v6.1)**:
- While held:
- LCD shows: Long press detected! Release to refresh.
- LCD shows: "Long press detected! Release to refresh".
- On release:
- Forces a **manual data refresh**:
- Sets `nextScheduledFetchTime = now`.
- Shows Manual Refresh… Please wait….
- Shows "Manual Refresh… Please wait…".
- `handleDataFetching()` will perform an immediate API fetch outside the normal schedule.
An **autoscroll timeout** resets the view to current hour / top of lists after inactivity.
An **autoscroll timeout** resets the view to "current hour / top of lists" after inactivity.
---
## NVS Storage (Daily Data Cache)
## NVS Storage (v7.0: Enhanced with Dual Buffers)
This firmware uses ESP32C3 **Preferences API** (`Preferences`) under namespace `"my-ticker"`.
Stored keys:
### Stored Keys (v7.0)
- **WiFi credentials:**
- `ssid`
- `pass`
- **Daily price data:**
- `data_day` calendar day (131)
- `data_mon` month (011)
- `data_year` full year (e.g. 2026)
- `data_prc` full raw JSON payload from the API
- `data_last_store` Unix time (`time_t`) when data was last written
**WiFi credentials:**
- `ssid`
- `pass`
**Today's price data:**
- `data_day` calendar day (131)
- `data_mon` month (011)
- `data_year` full year (e.g. 2026)
- `data_prc` full raw JSON payload from the API
- `data_last_store` Unix time (`time_t`) when data was last written
**Tomorrow's price data (v7.0 new):**
- `data_prc_t` full raw JSON payload for next day
- `data_store_t` Unix time when tomorrow's data was stored
### On Boot
@@ -412,22 +576,32 @@ After successful NTP time sync:
1. Attempt to load `data_day`, `data_mon`, `data_year`, and `data_prc` from NVS.
2. If **stored date matches current local date**:
- Deserialize `data_prc` into `StaticJsonDocument doc`.
- Run `processJsonData()` as if it were fresh from the API.
- Run `processJsonData(false)` as if it were fresh from the API.
- Set `isTodayDataAvailable = true`.
- **Skip** the initial API call to save traffic.
3. If the stored date does **not** match today or JSON parsing fails:
3. Attempt to load tomorrow's data from `data_prc_t`.
4. If the stored date does **not** match today or JSON parsing fails:
- NVS data is **ignored** for display.
- System starts from No data for today.
- System starts from "No data for today".
- Schedules an immediate API fetch.
### After Each Successful Fetch for Today
### After Each Successful Fetch
- Raw JSON payload is stored into NVS as `data_prc`, along with date (`data_day`, `data_mon`, `data_year`) and `data_last_store`.
- On reboot later the same day, the device will show prices immediately from NVS without hitting the API.
- Today's data: Raw JSON payload is stored into NVS as `data_prc`, along with date and `data_last_store`.
- Tomorrow's data (v7.0): After 14:00, tomorrow's payload is stored as `data_prc_t` with `data_store_t`.
### Midnight Bridge NVS Update (v7.0)
At midnight rollover:
1. Tomorrow's buffer is swapped to become today's buffer
2. New "today" data is immediately serialized and saved to NVS
3. Tomorrow's NVS slot is cleared
This ensures power-failure resilience: if power is lost immediately after midnight, the device boots with valid data.
---
## Daily Fetch Strategy (v6.1.0+)
## Daily Fetch Strategy (v7.0: Enhanced with Smart Tomorrow Fetching)
### Goals
@@ -435,17 +609,18 @@ After successful NTP time sync:
- Fetch:
- Once after boot (if no valid NVS data for today).
- Once per **new day** (after midnight), with robust retries while the nextday dataset is not yet published.
- **NEW in v7.0**: Tomorrow's data automatically after 14:00 local time.
### Time Sync & First Fetch
- `configTzTime(TZ_CET_CEST, "pool.ntp.org")` is used to enable CET/CEST aware `localtime()` and `getLocalTime()`.
- Until time sync completes, the UI only shows Syncing Time… Please wait….
- Until time sync completes, the UI only shows "Syncing Time… Please wait…".
- On first successful sync:
- `isTimeSynced = true`.
- `trackedDay` is set to the current `tm_mday`.
- Either NVS is used (if it has todays data) or an initial fetch is scheduled.
- Either NVS is used (if it has today's data) or an initial fetch is scheduled.
### DayRollover Detection
### DayRollover Detection (v7.0: Enhanced with Midnight Bridge)
In the main `loop()`:
@@ -455,109 +630,45 @@ In the main `loop()`:
- If `tm_mday != trackedDay`:
- Day rollover detected (midnight).
- `trackedDay` updated.
- Immediately:
- `isTodayDataAvailable = false`.
- `displayState = NO_DATA_OFFSET`.
- `timeOffsetHours = 0`.
- White LED turned off.
- **Midnight phase** is entered:
- `midnightPhaseActive = true`.
- `midnightRetryCount = 0`.
- `nextScheduledFetchTime = now` (immediate attempt).
- LCD updated to “No data for today. Press & hold to refresh manually”.
- **v7.0 Midnight Bridge Logic**:
- If tomorrow's data is available:
- Instantly swap `docTomorrow` to `doc`
- Update all statistics (`averagePrice`, `lowestPriceIndex`, etc.)
- Save to NVS and clear tomorrow slot
- Reset `timeOffsetHours` to 0
- If tomorrow's data is NOT available:
- Enter "No Data" mode
- Start midnight retry phase
### “Today” Detection (Market Day Logic)
### Smart Tomorrow Fetching (v7.0)
The EnergyCharts API can keep serving **yesterdays** market day for some time after local midnight.
To avoid accidentally accepting yesterdays data as todays, v6.1 uses a more robust rule.
After 14:00 local time, if tomorrow's data is not yet available:
```cpp
if (ti->tm_hour >= 14 && !isTomorrowDataAvailable) {
fetchAndProcessData(true); // Fetch tomorrow's data
}
```
The API URL is constructed with the `&start=YYYY-MM-DD` parameter for the next day.
### "Today" Detection (Market Day Logic)
The EnergyCharts API can keep serving **yesterday's** market day for some time after local midnight.
To avoid accidentally accepting yesterday's data as today's, v6.1+ uses a more robust rule.
In `processJsonData()`:
1. Read `unix_seconds[]`.
2. Interpret the **LAST** timestamp as representing the end of the datasets market day.
2. Interpret the **LAST** timestamp as representing the end of the dataset's market day.
3. Convert it to local time (`localtime()`).
4. Compare its date (day, month, year) to the current local date.
4. Compare its date (day, month, year) to the current local date (or tomorrow's date if `isTomorrow` is true).
- If they **match**:
- Dataset is accepted as “todays” data.
- `isTodayDataAvailable = true`.
- `lastProcessJsonAcceptedToday = true`.
- Prices are processed (hourly averages, min/max, daily average).
- Dataset is accepted as valid.
- Statistics are updated for the appropriate buffer.
- If they **do not match**:
- Dataset is considered to belong to a **different** day (e.g. yesterday).
- `isTodayDataAvailable = false`.
- `lastProcessJsonAcceptedToday = false`.
- Function returns without updating display data.
This prevents the device from accidentally treating “yesterdays dayahead curve” as if it were already “today”.
### Midnight Retry Logic (v6.1.0 + your tuning)
When `midnightPhaseActive == true`, any scheduled fetch that:
- Fails at HTTP/JSON level, **or**
- Succeeds at HTTP/JSON level but `processJsonData()` **rejects** the dataset as “not today”
is treated as a **failure** for scheduling.
The retry rules:
1. **First hour after midnight fast retries:**
In `scheduleAfterMidnightFailure()` (with your current config):
```cpp
if (midnightRetryCount < 2) {
// Retry every 20 minutes for first 2 attempts (~1 hour window)
midnightRetryCount++;
nextScheduledFetchTime = now + 1200; // 20 minutes
debugPrint(2, "Midnight retry " + String(midnightRetryCount) + "/2 in 20 minutes");
} else {
// After that, retry only at top of each hour
...
}
```
Timeline:
- 00:00 first attempt at rollover.
- If data is still yesterdays:
- 00:20 1st retry.
- 00:40 2nd retry.
- All “fast retries” remain fully within the first postmidnight hour.
2. **After the first hour hourly retries:**
Once `midnightRetryCount >= 2`, next retries are scheduled at the **top of each hour**:
```cpp
struct tm* ti = localtime(&now);
if (ti != NULL) {
time_t nextHour = now - (ti->tm_min * 60) - ti->tm_sec + 3600;
nextScheduledFetchTime = nextHour;
debugPrint(2, "Midnight retries exhausted; next fetch top-of-hour");
} else {
nextScheduledFetchTime = now + 3600;
debugPrint(2, "Midnight retries exhausted; fallback 1h");
}
```
So after ~00:40, if still no valid dataset for today, the device tries again at ~01:00, 02:00, 03:00, … until success.
3. **Success condition & exit from midnight phase:**
A scheduled fetch is treated as a **real success** only if:
- HTTP + JSON succeed **and**
- `lastProcessJsonAcceptedToday == true` (datasets last timestamps date matches today).
When this happens:
- `isTodayDataAvailable = true`.
- `midnightPhaseActive = false`.
- `midnightRetryCount = 0`.
- LCD leaves `NO_DATA_OFFSET` back to `CURRENT_PRICES`.
- White LED resumes price indication.
- `nextScheduledFetchTime` is set ≈24 hours ahead (until the next midnight rollover resets it).
- Dataset is rejected.
- Appropriate availability flag is set to false.
---
@@ -565,29 +676,29 @@ The retry rules:
A **secondary screen** (toggled via **doubleclick**) provides 20 lines of status information, displayed 4 lines at a time:
Typical content:
Typical content (updated for v7.0):
1. Current date and time (`HH:MM DD.MM.YYYY`)
2. Separator line (`--------------------`)
3. “Zadnja posodobitev: (Last update header)
3. "Zadnja posodobitev:" (Last update header)
4. Last successful fetch (for today) date & time
5. Blank
6. “Dnevno povprečje: (Daily average)
7. Daily average price in EUR/kWh (with surcharges) or Cene niso na voljo.
6. "Dnevno povprečje:" (Daily average)
7. Daily average price in EUR/kWh (with surcharges) or "Cene niso na voljo."
8. Blank
9. WiFi status and RSSI
10. Local IP address
11. API success rate (`API: xx% (succ/fail)`)
12. Device uptime in days, hours, minutes
1316. **NVS status block**:
1316. **NVS status block** (enhanced for v7.0):
- `NVS status:`
- `Data day: DD.MM.YYYY` or `Data day: none`
- `Last save: DD.MM.YY` or `Last save: none`
- `NVS: OK (today)` / `NVS: old data` / `NVS: empty`
- `NVS: Today+Tomorrow` / `NVS: Today only` / `NVS: Empty/Old`
1720. Credits and version:
- `energy-charts.info`
- `dynamic electricity`
- `price ticker v6.1`
- `price ticker v7.0`
- `by Legolas-2025` (or your preferred credit line)
---
@@ -602,7 +713,7 @@ If NVS does not contain valid WiFi credentials, or if connecting fails repeat
MyTicker_Setup
```
2. LCD shows No WiFi access! Setup WiFi: SSID: MyTicker_Setup and the AP IP.
2. LCD shows "No WiFi access! Setup WiFi: SSID: MyTicker_Setup" and the AP IP.
3. A simple captive portal is served:
- Open any URL while connected to `MyTicker_Setup`.
- Enter SSID and password in the HTML form.
@@ -620,7 +731,7 @@ If NVS does not contain valid WiFi credentials, or if connecting fails repeat
- `DNSServer` (from ESP32 core)
- `WebServer` (from ESP32 core)
- `Preferences` (builtin for ESP32)
3. Open the v6.2.0 `.ino` file (e.g. `ESP32_standalone_electricity_ticker_6_1_2_nvs_daily_fetch.ino`).
3. Open the v7.0 `.ino` file (e.g. `ESP32_standalone_electricity_ticker_v7_0_Rolling_48H.ino`).
4. In Tools:
- Board: `Seeed XIAO ESP32C3`
- Port: choose the correct serial port.
@@ -630,30 +741,41 @@ If NVS does not contain valid WiFi credentials, or if connecting fails repeat
- NTP sync messages.
- NVS load/save status.
- Midnight rollover and retry debug output.
- **v7.0 NEW**: Tomorrow fetch logs (`Fetching Tomorrow's Data...`)
---
## Versioning & Changelog
- **v7.0** Rolling 48-Hour Logic & Midnight Bridge:
- Dual-buffer NVS system for today and tomorrow data
- Midnight Bridge for seamless day rollover
- 47-hour scrolling with `HH:>>` visual indicators
- Smart fetching of tomorrow's data after 14:00
- Correct min/max indicators for tomorrow's hours
- Power-failure resilient NVS updates
- **v6.2.4** Exact-boundary display refresh bug fix
- **v6.2.3** State-based display refresh logic fix
- **v6.2.2** Display blank lines issue fix
- **v6.2.1** Current interval fix
- **v6.2.0** DST handling fully fixed via timestamp-based lookups
- **v6.1.2** LED indicator restored (broken in previous version):
- Avoid mixing PWM and `digitalWrite` on the same LED pin (ESP32 LEDC behavior).
- Ensures LED is fully off when gated off; patterns operate correctly.
- **v6.1.1** Daily low/high marker fix:
- Daily min/max and average now include negative and **0.0** prices.
- **v6.1.0** Midnight fetch & today detection fixes:
- **v6.1.0** Midnight fetch & "today" detection fixes:
- Correctly detect **market day** using the last `unix_seconds` timestamp.
- Distinguish between:
- HTTP/JSON success, but data for **wrong day** (treated as failure).
- Full success with accepted today dataset.
- Full success with accepted "today" dataset.
- Robust midnight retry scheme:
- Two retries every 20 minutes in the first hour (~00:20, ~00:40).
- Then hourly retries (topofhour) until todays dataset is available.
- Behavior on reboot and manual longpress is unchanged, but now respects the improved today logic.
- Then hourly retries (topofhour) until today's dataset is available.
- Behavior on reboot and manual longpress is unchanged, but now respects the improved "today" logic.
- **v6.0.0** NVS storage & daily fetch:
- Store daily price data in NVS.
- Reduce API calls to boot + aftermidnight.
- Reduce API calls to "boot + aftermidnight".
- Add NVS status section to secondary menu.
- **v5.5** 15minute detail mode, LED based on current 15minute slot, improved DST handling (see file `20251027a_electricity_ticker_10_5_5_latest_DST_and_midnight_fix.ino`).