Revise README for version 6.1.0

Updated project details and version information in README.
This commit is contained in:
2026-02-01 22:07:41 +01:00
committed by GitHub
parent aafe962c4c
commit 25fc31fb3b
+502 -230
View File
@@ -1,309 +1,581 @@
# Electricity Price Ticker for XIAO ESP32C3 (Slovenia, EnergyCharts) # Electricity Price Ticker for XIAO ESP32C3 (EnergyCharts)
This project is an ArduinoIDEfriendly firmware for the **Seeed XIAO ESP32C3** that: This project is an ArduinoIDEfriendly firmware for the **Seeed XIAO ESP32C3** that:
- Connects to WiFi. - Connects to WiFi.
- Fetches dayahead electricity prices for **Slovenia** from [EnergyCharts.info](https://energy-charts.info). - Fetches **dayahead electricity prices** from [EnergyCharts.info](https://energy-charts.info) (Bundesnetzagentur / SMARD.de).
- Computes final consumer prices (including configurable fees + VAT). - Computes final consumer prices (including configurable powercompany fee + VAT).
- Displays current and upcoming prices on a **20x4 I²C 2004 LCD**. - Displays current and upcoming prices on a **20x4 I²C 2004 LCD**.
- Uses an LED and presence sensor to give quick visual feedback. - 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 code currently implements **Version 6.0** of the ticker, focusing on: The latest sketch implements **Version 6.1.0**, focusing on:
- Daily (not hourly) API fetching. - Daily (not hourly) API fetching.
- Robust **NVS storage** of daily price data for resilience to reboots. - Robust **NVS storage** of daily price data.
- Automatic CET/CEST handling. - Correct **CET/CEST** handling.
- Resilient **aftermidnight refresh** (no more getting stuck on “No data for today”).
- Preserved UI and button behavior from v5.5. - Preserved UI and button behavior from v5.5.
All available bidding zones (modify in the code): ---
- AT - Austria
- BE - Belgium ## Bidding Zones (BZN) / Region Selection
- BG - Bulgaria
- CH - Switzerland The firmware currently uses:
- CZ - Czech Republic
- DE-LU - Germany, Luxembourg ```text
- DE-AT-LU - Germany, Austria, Luxembourg https://api.energy-charts.info/price?bzn=SI
- DK1 - Denmark 1 ```
- DK2 - Denmark 2
- EE - Estionia Where `bzn` is the **bidding zone** code. You can change this in the `.ino`:
- ES - Spain
- FI - Finland ```cpp
- FR - France const char* api_url = "https://api.energy-charts.info/price?bzn=SI";
- GR - Greece ```
- HR - Croatia
- HU - Hungary to any supported BZN.
- IT-Calabria - Italy Calabria
- IT-Centre-North - Italy Centre North All available bidding zones (from the original README):
- IT-Centre-South - Italy Centre South
- IT-North - Italy North - `AT` Austria
- IT-SACOAC - Italy Sardinia Corsica AC - `BE` Belgium
- IT-SACODC - Italy Sardinia Corsica DC - `BG` Bulgaria
- IT-Sardinia - Italy Sardinia - `CH` Switzerland
- IT-Sicily - Italy Sicily - `CZ` Czech Republic
- IT-South - Italy South - `DE-LU` Germany, Luxembourg
- LT - Lithuania - `DE-AT-LU` Germany, Austria, Luxembourg
- LV - Latvia - `DK1` Denmark 1
- ME - Montenegro - `DK2` Denmark 2
- NL - Netherlands - `EE` Estonia
- NO1 - Norway 1 - `ES` Spain
- NO2 - Norway 2 - `FI` Finland
- NO2NSL - Norway North Sea Link - `FR` France
- NO3 - Norway 3 - `GR` Greece
- NO4 - Norway 4 - `HR` Croatia
- NO5 - Norway 5 - `HU` Hungary
- PL - Poland - `IT-Calabria` Italy Calabria
- PT - Portugal - `IT-Centre-North` Italy Centre North
- RO - Romania - `IT-Centre-South` Italy Centre South
- RS - Serbia - `IT-North` Italy North
- SE1 - Sweden 1 - `IT-SACOAC` Italy Sardinia Corsica AC
- SE2 - Sweden 2 - `IT-SACODC` Italy Sardinia Corsica DC
- SE3 - Sweden 3 - `IT-Sardinia` Italy Sardinia
- SE4 - Sweden 4 - `IT-Sicily` Italy Sicily
- SI - Slovenia - `IT-South` Italy South
- SK - Slovakia - `LT` Lithuania
- `LV` Latvia
- `ME` Montenegro
- `NL` Netherlands
- `NO1` Norway 1
- `NO2` Norway 2
- `NO2NSL` Norway North Sea Link
- `NO3` Norway 3
- `NO4` Norway 4
- `NO5` Norway 5
- `PL` Poland
- `PT` Portugal
- `RO` Romania
- `RS` Serbia
- `SE1` Sweden 1
- `SE2` Sweden 2
- `SE3` Sweden 3
- `SE4` Sweden 4
- `SI` Slovenia
- `SK` Slovakia
> Always verify uptodate BZN support in the EnergyCharts API docs.
--- ---
## Features ## Hardware Setup (Detailed)
### Core display & pricing This section merges the original v5.5 instructions with the current v6.1 hardware expectations.
Follow it carefully to reproduce the working setup.
### 1. Microcontroller
- **Seeed XIAO ESP32C3**
Typical pins used in the sketch:
- `GPIO 5` → white LED (`whiteLedPin`)
- `GPIO 21` → builtin LED (`builtinLedPin`)
- `GPIO 4` → user button / touch input (`buttonPin`)
- `GPIO 9` → presence sensor (`presencePin`)
- I²C pins → boarddefault SDA/SCL (check XIAO ESP32C3 pinout)
---
### 2. 20x4 I²C LCD (2004) PCF8574 Backpack
- LCD: **20x4 2004 character display** with I²C backpack (PCF8574 or compatible).
- Default I²C address (in code): `0x27`
(Change in the sketch if your module differs: `LiquidCrystal_I2C lcd(0x27, 20, 4);`)
**Connections:**
- **LCD backpack → XIAO ESP32C3**
- `VCC`**5V** (or 3V3 if your module explicitly supports 3.3V I²C)
- `GND`**GND**
- `SDA` → board I²C SDA pin (see XIAO ESP32C3 documentation)
- `SCL` → board I²C SCL pin
> Note: On many XIAO ESP32C3 board definitions, SDA/SCL are mapped internally. Just use the default I²C pins as documented by Seeed.
---
### 3. Pushbutton (Default) / Capacitive Touch Alternative
The firmware assumes a **momentary pushbutton** on `GPIO 4` by default.
#### Mechanical Pushbutton (default config)
- One leg → `GPIO 4`
- Other leg → `GND`
- No external pullup is required; code uses:
```cpp
pinMode(buttonPin, INPUT_PULLUP);
```
And reads the button as **activeLOW**:
```cpp
int reading = !digitalRead(buttonPin);
```
So:
- Button **pressed**`reading == 1`
- Button **released**`reading == 0`
#### Alternative: TTP223 Capacitive Touch Button
If you prefer a TTP223 capacitive touch input instead of a mechanical button:
**Wiring:**
- `VCC`**3.3V**
- `GND`**GND**
- `OUT``GPIO 4` (same as the pushbutton pin)
**Logic:**
- TTP223 output is **HIGH when touched**.
If you use TTP223, you may want to **remove the logical inversion** in the code:
```cpp
// For mechanical button (active LOW):
int reading = !digitalRead(buttonPin);
// For TTP223 (active HIGH), change to:
int reading = digitalRead(buttonPin);
```
Everything else (debounce, longpress, doubleclick) remains compatible.
---
### 4. Presence Sensor (RCWL0516, optional but supported)
The presence sensor is used to control LCD backlight and LEDs to save power and avoid annoying blinking when nobody is around.
Recommended module: **RCWL0516** microwave motion sensor.
**Wiring (from the v5.5 header, preserved in v6.x):**
- `VCC`**3.3V**
- `GND`**GND**
- `OUT``GPIO 9` (`presencePin`)
- **Required**: 10 kΩ pulldown resistor between `GPIO 9` and `GND`.
Characteristics:
- The module can be hidden behind nonmetallic surfaces.
- Firmware automatically detects if the presence sensor is connected at boot:
- If **detected**:
- Presence toggles backlight on and enables LED output.
- Absence for `backlightOffDelay` (default 30 s) turns the backlight off and disables LED output.
- If **not detected**:
- Backlight is kept on permanently.
- LEDs are allowed to operate normally.
---
### 5. White LED / LED Strip Output
The sketch uses a **white LED** (or LED strip control line) on `GPIO 5` (`whiteLedPin`).
**Basic single LED wiring:**
- `GPIO 5` → series resistor (e.g. 220470 Ω) → LED anode
- LED cathode → GND
**For LED strips or higher currents:**
- Use a suitable NPN transistor / MOSFET:
- GPIO 5 → gate/base (with proper gate/base resistor)
- LED strip or load → external supply (with common GND)
- Transistor sink/source → GND / load as per standard MOSFET wiring
- 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.
---
### 6. Power
- XIAO ESP32C3:
- Via USBC (recommended for development).
- Or via 5V pin if you have a regulated 5V supply (check Seeed docs).
- Ensure **all modules** (LCD, presence sensor, LED driver) share a **common ground** with the XIAO.
---
## Firmware Features (v6.1.0)
### Core Display & Pricing
- Data source:
```text
https://api.energy-charts.info/price?bzn=SI
```
- Data source: [EnergyCharts.info dayahead price API](https://api.energy-charts.info/price?bzn=SI) (bidding zone = `SI`).
- Resolution: - Resolution:
- Prices in **15minute intervals** (4 per hour). - Prices in **15minute intervals** (`price[]`, `unix_seconds[]`).
- Display shows: - Display shows:
- Current hour: - **Row 0**: Current hour, four 15minute values in compact format (`XX XX XX XX`).
- Hourly average. - **Rows 13**: Current hour + next two hours as hourly averages.
- Four 15minute prices in compact format (`XX XX XX XX`).
- Next 2 hours averages.
- Price calculation: - Price calculation:
- Raw MWh prices from API are converted to EUR/kWh. - Raw MWh prices are converted to **EUR/kWh**.
- Optional surcharges: - Two configurable surcharges:
- `POWER_COMPANY_FEE_PERCENTAGE` (default 12%). - `POWER_COMPANY_FEE_PERCENTAGE` (default `12.0` %).
- `VAT_PERCENTAGE` (default 22%). - `VAT_PERCENTAGE` (default `22.0` %).
- LCD: - LCD:
- **20x4 I²C (PCF8574 / 0x27)**. - `LiquidCrystal_I2C` with custom characters for:
- Custom characters for local language and low/high price markers. - Local language letters.
- Lowprice and highprice indicators.
### LED behavior ### LED Price Signalling
- One **white LED** connected to GPIO 5. The white LED (GPIO 5) reflects the **current 15minute interval** price:
- LED indicates **current 15minute segment** price:
- Very cheap (`<= 0.05 EUR/kWh`): smooth breathing.
- Cheap, normal, expensive, very expensive: different steady / blinking / doubleblink patterns.
- Negative or no data: LED off.
### Presence sensor & backlight - Very cheap (`<= 0.05 EUR/kWh`) → smooth breathing.
- Cheap / normal → steady on.
- Moderately expensive → slow blink.
- Expensive → faster blink.
- Very expensive → complex “doubleblink with long on” pattern.
- Negative price or no data → LED off.
- Optional **RCWL0516** presence sensor on GPIO 9: LED is **disabled** when:
- Presence = backlight on, LED enabled.
- No presence for a while = LCD backlight off, LED disabled.
- If no presence sensor is detected, the backlight is kept on.
### Button behavior - No data for today.
- Time is not synced.
- Presence sensor has timed out (no presence, if installed).
### Presence Sensor & Backlight
- If presence sensor is **connected**:
- Presence detected → LCD backlight on, LEDs enabled.
- No presence for `backlightOffDelay` (30 s by default) → LCD backlight off, LEDs disabled.
- If **no presence sensor** is detected at boot:
- LCD backlight is always on.
- LEDs are not gated by presence.
### Button Behavior
One button (or touch) on GPIO 4 controls the UI:
- One button (or capacitive touch) on GPIO 4.
- Uses internal pullup by default.
- Actions:
- **Single short press**: - **Single short press**:
- Scrolls through the hourly view on the **primary** screen. - On primary screen: scrolls the time offset (future hours).
- On secondary screen: scrolls through the 20line status text (4 lines at a time).
- **Double press**: - **Double press**:
- Toggles between: - Toggles between:
- Primary price view - Primary price view.
- Secondary info view - Secondary status/info view.
- **Long press (≈3s in your current repo)**: - **Long press (~3 seconds in v6.1)**:
- Forces a **manual data refresh** (API fetch), regardless of daily schedule. - While held:
- LCD shows: “Long press detected! Release to refresh”.
- On release:
- Forces a **manual data refresh**:
- Sets `nextScheduledFetchTime = now`.
- 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.
--- ---
## Version 6.0 Daily Fetch + NVS Storage ## NVS Storage (Daily Data Cache)
Version 6.0 is focused on: This firmware uses ESP32C3 **Preferences API** (`Preferences`) under namespace `"my-ticker"`.
1. **Reducing API calls** Stored keys:
2. **Persisting daily data in NVS**
3. **Making the device robust to power outages**
### 1. Daily fetch instead of hourly - **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
Previously (v5.5), the firmware fetched data **every hour** at the top of the hour. ### On Boot
In **v6.0**, the behavior is: After successful NTP time sync:
- **On boot (after WiFi + time sync):** 1. Attempt to load `data_day`, `data_mon`, `data_year`, and `data_prc` from NVS.
- Try to load **todays** data from NVS: 2. If **stored date matches current local date**:
- If found: use it directly, **no API call** at boot. - Deserialize `data_prc` into `StaticJsonDocument doc`.
- If not found or invalid: schedule an immediate API fetch. - Run `processJsonData()` as if it were fresh from the API.
- **After midnight (local time):** - Set `isTodayDataAvailable = true`.
- Detect day rollover via localtime. - **Skip** the initial API call to save traffic.
3. 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”.
- Schedules an immediate API fetch.
### After Each Successful Fetch for Today
- 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.
---
## Daily Fetch Strategy (v6.1.0)
### Goals
- **Avoid hourly polling** of the API.
- 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.
### 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…”.
- 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.
### DayRollover Detection
In the main `loop()`:
- `trackedDay` holds the last seen local day.
- Each iteration:
- Get `localtime()` for `now`.
- If `tm_mday != trackedDay`:
- Day rollover detected (midnight).
- `trackedDay` updated.
- Immediately: - Immediately:
- Invalidate yesterdays data (`isTodayDataAvailable = false`). - `isTodayDataAvailable = false`.
- Force display to show **“No data for today”**. - `displayState = NO_DATA_OFFSET`.
- Turn off the white LED (no price indication). - `timeOffsetHours = 0`.
- Enter **midnight fetch phase**. - 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”.
#### Midnight fetch phase ### “Today” Detection (Market Day Logic)
When the date changes: 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.
1. First fetch is scheduled **immediately**. In `processJsonData()`:
2. If it fails:
- The device **stays in “No data for today”**, LED off.
- Retry schedule:
- 10minute interval, up to 5 attempts.
- After 5 failures, retry once at each **top of the hour** until it succeeds.
As soon as a fetch for **today** succeeds: 1. Read `unix_seconds[]`.
2. Interpret the **LAST** timestamp as representing the end of the datasets market day.
- `isTodayDataAvailable` is set to `true`. 3. Convert it to local time (`localtime()`).
- The enforced `NO_DATA_OFFSET` state is cleared back to `CURRENT_PRICES`. 4. Compare its date (day, month, year) to the current local date.
- The LCD and LED resume showing todays prices. - If they **match**:
- Dataset is accepted as “todays” data.
> Importantly, **yesterdays data is never reused** for today, both at boot and after midnight.
### 2. NVS (nonvolatile) storage of daily data
The ESP32C3s builtin NVS is used via `Preferences`:
- Namespace: `"my-ticker"`.
- Keys (in addition to the existing WiFi credentials):
- `data_day`, `data_mon`, `data_year` calendar date of the stored data.
- `data_prc` full raw JSON response from the EnergyCharts API.
- `data_last_store` UNIX timestamp when the data was last written.
#### On boot
After time sync:
- If NVS has data whose date **matches today**:
- `data_prc` JSON is deserialized into the inRAM `doc` (`StaticJsonDocument`).
- `processJsonData()` is run, just like after a live fetch.
- `isTodayDataAvailable = true`. - `isTodayDataAvailable = true`.
- No initial API call is needed. - `lastProcessJsonAcceptedToday = true`.
- If the stored date does **not** match today (or parsing fails): - Prices are processed (hourly averages, min/max, daily average).
- The stored data is **ignored** for display. - If they **do not match**:
- The system starts from “No data for today” and will fetch new data. - Dataset is considered to belong to a **different** day (e.g. yesterday).
- `isTodayDataAvailable = false`.
- `lastProcessJsonAcceptedToday = false`.
- Function returns without updating display data.
#### After each successful fetch for today This prevents the device from accidentally treating “yesterdays dayahead curve” as if it were already “today”.
- The entire JSON payload is stored as `data_prc` with the corresponding date and timestamp. ### Midnight Retry Logic (v6.1.0 + your tuning)
- This means:
- A reboot **later in the same day** can immediately restore the latest prices from NVS.
- Reboots the next morning will detect the date mismatch and fetch new data instead of showing stale data.
### 3. Secondary info (status) screen When `midnightPhaseActive == true`, any scheduled fetch that:
The secondary menu (doubleclick to toggle) has **20 lines**, shown in 4line pages. - Fails at HTTP/JSON level, **or**
- Succeeds at HTTP/JSON level but `processJsonData()` **rejects** the dataset as “not today”
It typically includes: is treated as a **failure** for scheduling.
- Current date and time. The retry rules:
- Last successful update timestamp.
- Daily average price in EUR/kWh (with company fee + VAT applied). 1. **First hour after midnight fast retries:**
- WiFi RSSI and IP address.
- API success ratio and total calls. In `scheduleAfterMidnightFailure()` (with your current config):
- Device uptime.
- **NVS status section**: ```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).
---
## Secondary Status Screen (Debug / Info)
A **secondary screen** (toggled via **doubleclick**) provides 20 lines of status information, displayed 4 lines at a time:
Typical content:
1. Current date and time (`HH:MM DD.MM.YYYY`)
2. Separator line (`--------------------`)
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.”
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**:
- `NVS status:` - `NVS status:`
- `Data day: DD.MM.YYYY` or `Data day: none` - `Data day: DD.MM.YYYY` or `Data day: none`
- `Last save: DD.MM.YY` or `Last save: none` - `Last save: DD.MM.YY` or `Last save: none`
- `NVS: OK (today)` / `NVS: old data` / `NVS: empty` - `NVS: OK (today)` / `NVS: old data` / `NVS: empty`
- Credits + version line: 1720. Credits and version:
- `energy-charts.info` - `energy-charts.info`
- `dynamic electricity` - `dynamic electricity`
- `price ticker v6.0` - `price ticker v6.1`
- `by Amir Toki^ 2025` - `by Legolas-2025` (or your preferred credit line)
(Exact ordering and layout may differ slightly, based on your latest edits.)
--- ---
## Hardware setup ## WiFi Provisioning
### Microcontroller If NVS does not contain valid WiFi credentials, or if connecting fails repeatedly:
- **Seeed XIAO ESP32C3** 1. The device starts an **Access Point** with SSID:
### LCD (I²C 2004) ```text
MyTicker_Setup
- 20x4 (2004) character LCD with I²C backpack (PCF8574).
- Default I²C address: `0x27` (configurable in code).
- Library: `LiquidCrystal_I2C`.
### Button / touch input
- GPIO 4, internal pullup enabled.
**Mechanical pushbutton (default)**
- One leg to GPIO 4, other leg to GND.
**TTP223 capacitive touch (alternative)**
- VCC → 3.3 V
- GND → GND
- OUT → GPIO 4
Code change required for TTP223:
```cpp
// In handleButton() or wherever the button is read:
int reading = !digitalRead(buttonPin);
// Change to:
int reading = digitalRead(buttonPin); // if TTP223 output is HIGH when touched
``` ```
(Your current code uses `!digitalRead(buttonPin)` assuming an activeLOW mechanical button.) 2. LCD shows “No WiFi access! Setup WiFi: SSID: MyTicker_Setup” and the AP IP.
3. A simple captive portal is served:
### Presence sensor (RCWL0516) - Open any URL while connected to `MyTicker_Setup`.
- Enter SSID and password in the HTML form.
- VCC → 3.3 V - Values are stored in NVS: `ssid`, `pass`.
- GND → GND - Device reboots and attempts to connect with the new credentials.
- OUT → GPIO 9
- 10 kΩ pulldown resistor between GPIO 9 and GND.
If no sensor is detected at boot, the firmware keeps the LCD backlight always on.
### White LED
- LED (with appropriate series resistor) on GPIO 5.
--- ---
## WiFi provisioning ## Building & Uploading
If stored WiFi credentials are invalid or missing: 1. Install **Arduino IDE** with ESP32 board support (including XIAO ESP32C3).
2. Install required libraries:
1. Device starts in AP mode with SSID: `MyTicker_Setup`.
2. DNS server redirects to a simple captive “WiFi Setup” page.
3. You can enter SSID and password, which are stored in NVS (`Preferences`).
4. The device restarts and attempts to connect with the new credentials.
---
## Building and flashing
1. Open the `.ino` file in **Arduino IDE** (ensure ESP32 board support is installed).
2. Select:
- Board: `Seeed XIAO ESP32C3`
- Port: correct serial port
3. Install the required libraries if missing:
- `LiquidCrystal_I2C` - `LiquidCrystal_I2C`
- `ArduinoJson` - `ArduinoJson`
4. Compile and upload. - `DNSServer` (from ESP32 core)
- `WebServer` (from ESP32 core)
- `Preferences` (builtin for ESP32)
3. Open the v6.1 `.ino` file (e.g. `20260130_electricity_ticker_6_1_nvs_daily_fetch.ino`).
4. In Tools:
- Board: `Seeed XIAO ESP32C3`
- Port: choose the correct serial port.
5. Upload the sketch.
6. Open Serial Monitor at **115200 baud** to see:
- WiFi connection logs.
- NTP sync messages.
- NVS load/save status.
- Midnight rollover and retry debug output.
--- ---
## Versioning and files ## Versioning & Changelog
Key documentation files: - **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`).
- **v6.0.0** First NVSenabled version:
- Store daily price data in NVS.
- Reduce API calls to “boot + aftermidnight”.
- Add NVS status section to secondary menu.
- **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.
- 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.
- [`VERSION.md`](./VERSION.md) current firmware version and compatibility notes. See [`CHANGELOG.md`](./CHANGELOG.md) for more details.
- [`CHANGELOG.md`](./CHANGELOG.md) detailed list of changes between versions.
- `*.ino` main firmware source file (v6.0 and later).
--- ---
## License ## License
This project is licensed under the MIT License see the [LICENSE](./LICENSE) file for details. This project is licensed under the MIT License see the [`LICENSE`](./LICENSE) file for details.