All notable changes to this project are documented here.
Summary
This release fixes a regression introduced in v6.1.1 where the white LED price indicator could remain dimly lit even when the LCD backlight turned off, and the intended blink/breathe patterns no longer behaved correctly.
Problem (v6.1.1):
- The sketch uses
analogWrite()to drive the LED with PWM for breathe/blink patterns. - However, in some “LED OFF” branches the code used
digitalWrite(LOW)on the samewhiteLedPin. - On ESP32 (LEDC), once PWM is attached to a pin,
digitalWrite(LOW)may not fully disable PWM output. - Result:
- LED could remain faintly on (dim glow) when LEDs were supposed to be off (e.g., presence timeout / backlight off).
- Some patterns could appear “stuck” or inconsistent.
Solution (v6.1.2):
- LED control is now PWM‑only inside
updateLeds():- Use
analogWrite(whiteLedPin, 0)instead ofdigitalWrite(whiteLedPin, LOW). - Use
analogWrite(whiteLedPin, 255)instead ofdigitalWrite(whiteLedPin, HIGH). - Blink/double‑blink toggles now switch between PWM 0 and 255.
- Use
- This ensures the LED is truly off whenever LED output is gated off (no data, no time sync, or presence timeout).
Summary
This release fixes a bug where the daily lowest / highest hourly price marker ignored negative prices (and also ignored 0.0), which could cause the ticker to incorrectly mark the **lowest positive[...]
Problem (v6.1.0):
-
In
processJsonData()the daily min/max scan used:if (hourlyAvg > 0) { ... }
-
This had two side effects:
- Negative hourly averages were completely skipped.
- A true price of 0.0 was also skipped (even though 0 can be a valid market price).
-
Additionally, the daily average was computed as
sum / 24.0even though hours were being skipped fromsum, making the daily average incorrect whenever any hour was excluded.
Solution (v6.1.1):
- The min/max and average scan now:
- Treats an hour as valid based on data availability (having all 4×15‑minute entries), not based on value sign.
- Includes all values (negative, zero, positive) when computing:
lowestPriceIndexhighestPriceIndexaveragePrice
- Computes
averagePriceusing the number of valid hours (normally 24).
Summary
This release fixes a bug where the ticker could remain indefinitely on the “No data for today” screen after midnight, even though the API was already returning fresh data. It also refines the [...]
Problem (v6.0.0):
- After midnight, the device:
- Detected day rollover and entered a “no data” state.
- Scheduled an immediate API fetch.
- However:
- The API can continue to serve yesterday’s market day for some time after local midnight.
- The code only checked the first
unix_secondsentry against the current local day. - HTTP + JSON success always incremented
apiSuccessCount, even ifprocessJsonData()subsequently decided the dataset was “not for today”. - The scheduler treated such fetches as successful, pushed
nextScheduledFetchTime24 hours into the future, and never retried. - Result: the ticker stayed on NO_DATA_OFFSET forever, until:
- A manual long‑press triggered a fresh fetch at a time when the API finally returned recognized “today” data, or
- The device was rebooted later in the day.
Solution (v6.1.0):
-
Market Day Detection:
processJsonData()now determines the “market day” using the lastunix_secondstimestamp from the API’s dataset (assumed to cover one full day in 15‑minute steps).- It compares that calendar date (local time) against the current local date.
- If they differ:
- The dataset is treated as “not for today”.
isTodayDataAvailable = false.- The function returns false, and a new flag
lastProcessJsonAcceptedTodayremainsfalse.
-
Logical Failure vs HTTP/JSON Failure:
- New global flag:
lastProcessJsonAcceptedToday–trueonly whenprocessJsonData()accepts the dataset as “today’s” data.
- In
handleDataFetching():- A scheduled fetch is considered a real success only if:
- HTTP + JSON succeeded, and
lastProcessJsonAcceptedToday == true.
- In all other cases (including “HTTP 200 + parse OK but data still for yesterday”):
- The fetch is treated as failure for scheduling purposes.
- If
midnightPhaseActive == true,scheduleAfterMidnightFailure()is invoked to plan a retry.
- A scheduled fetch is considered a real success only if:
- New global flag:
-
Midnight Phase Cleanup:
- When a fetch finally provides a dataset for today:
isTodayDataAvailable = true.lastProcessJsonAcceptedToday = true.midnightPhaseActiveis cleared;midnightRetryCountreset to 0.nextScheduledFetchTimeis set to 24 hours ahead.
- When a fetch finally provides a dataset for today:
As a result, the ticker will keep retrying after midnight until a correct market‑day dataset appears, instead of giving up after the first HTTP 200.
In scheduleAfterMidnightFailure() the retry strategy when midnightPhaseActive == true has been tuned.
Old behavior (v6.0.0, conceptual):
- First few failures after midnight:
- Retried every 10 minutes up to 5 attempts.
- Afterwards:
- Switched to hourly retries (top of each hour).
New behavior (v6.1.0 + user configuration):
-
Fast retry phase fully contained within the first hour after midnight.
-
You configured:
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 – initial attempt (triggered by day rollover).
- If dataset is still for previous day:
- 1st retry at ~00:20.
- 2nd retry at ~00:40.
- After that:
- Retries only at the top of the next hours (01:00, 02:00, …), until a dataset with market day = today is accepted.
This configuration significantly reduces overnight API load while still ensuring the ticker picks up the new day as soon as the API publishes it.
- NVS caching of daily data:
- On boot, if NVS contains a dataset whose date matches today’s local date:
- The JSON is deserialized and processed.
- A new API call is skipped.
- After each accepted “today” fetch:
- Raw JSON payload, date, and a timestamp are stored in NVS.
- On boot, if NVS contains a dataset whose date matches today’s local date:
- Manual long‑press refresh:
- Still triggers immediate fetch via
nextScheduledFetchTime = now;. - Now also respects the improved “today” detection; “yesterday’s” data is not accepted as today.
- Still triggers immediate fetch via
- CET/CEST time handling:
- Unchanged, still uses
TZ_CET_CESTwithconfigTzTime.
- Unchanged, still uses
- Secondary menu and NVS status lines:
- Retained from v6.0.0; updated only for version string and minor wording.
Summary
First major redesign focused on reducing API traffic and improving resilience using non‑volatile storage.
- NVS namespace
"my-ticker"introduced with keys:ssid,pass– Wi‑Fi credentials.data_day,data_mon,data_year– stored data calendar day.data_prc– raw JSON string from API.data_last_store– Unix time when data was stored.
- Boot behavior:
- Try to load and validate NVS data.
- If date matches today → reuse it and skip initial API call.
- After‑midnight behavior:
- NVS is overwritten with each successful new‑day dataset.
- In‑RAM data for yesterday is invalidated at day rollover.
- Primary list:
- 15‑minute detail for current hour.
- Hourly averages for current + next 2 hours.
- Secondary list:
- Expanded to 20 lines to include:
- Time/date, last update, daily average.
- Wi‑Fi RSSI, IP address.
- API success rate, uptime.
- NVS status block.
- Credits & version line.
- Expanded to 20 lines to include:
Earlier versions (v5.x and below) had:
- No NVS‑based caching of daily API data.
- More frequent API calls (e.g., hourly refresh pattern).
- Less robust handling of DST and daily boundaries.
For exact details, see older .ino files and their header comments in this repository.