Skip to content

Add NightScout support, Wi-Fi AP setup, QWERTY keyboard, mmol/L, configurable thresholds, and a couple of fixes#7

Open
lslomczynski wants to merge 30 commits into
F1ATB:mainfrom
lslomczynski:main
Open

Add NightScout support, Wi-Fi AP setup, QWERTY keyboard, mmol/L, configurable thresholds, and a couple of fixes#7
lslomczynski wants to merge 30 commits into
F1ATB:mainfrom
lslomczynski:main

Conversation

@lslomczynski

Copy link
Copy Markdown

Summary

This PR adds several new features and fixes a couple of bugs accumulated since the last sync with upstream. All changes have been tested on a physical ESP32-S3 device with a 320×480 AXS15231B display.


🆕 New Features

NightScout as a third glucose data source

  • New src/NightScout.h / NightScout.cpp: REST API client using GET /api/v1/entries.json with JWT access token passed as ?token= URL parameter
  • Connection test via GET /api/v1/status.json (Test button on Account screen)
  • Same adaptive polling logic as Dexcom (315 s normal, 90 s stale data, 30 s missed update)
  • NightScout direction strings (DoubleUp, SingleUp, FortyFiveUp, Flat, FortyFiveDown, SingleDown, DoubleDown) mapped to existing TrendArrow convention
  • clearNightScoutCache() integrated with existing clearData() flow

Account screen updated with a 3-button sensor selector (FreeStyle Libre / Dexcom / NightScout). NightScout section shows URL and Token fields with Edit buttons. All button positions and touch regions computed dynamically from screen width.

Keyboard pages 26/27 added for NightScout URL and Token entry. URL field pre-populated with https:// when empty.

AP setup page, Server.cpp, Stock.cpp all updated for NightScout (radio button, /saveConfig parsing, LittleFS persistence).

All 6 language files updated with 4 new keys: NightScoutIndefini, SetNightScout, NightScoutURL, NightScoutToken.


Wi-Fi AP first-boot captive portal

When no SSID is configured, the device now shows a choice screen (on-screen setup vs. AP mode) instead of going directly to the Wi-Fi list.

AP mode flow:

  • ESP32 starts a soft-AP GlucoMonit-xxxxx with a DNS server for captive portal redirect
  • A mobile-friendly dark-theme HTML page (/config) covers: language, timezone, Wi-Fi credentials, sensor type + credentials, glucose thresholds with mg/dL ↔ mmol/L toggle and live colour bar preview
  • pageAPInfo screen shows the AP network name, password, and IP address
  • Non-blocking restart via esp_timer (one-shot) used throughout to avoid NS_ERROR_NET_EMPTY_RESPONSE caused by blocking the TCP/IP stack before the HTTP response was sent

/eraseConfig split into GET (confirmation page) + POST (actual erase + restart polling page).


QWERTY / AZERTY keyboard layout

  • QWERTY layout added as default for all languages except French
  • French language automatically selects AZERTY
  • Layout selection is transparent to the rest of the keyboard logic via getAlphaKey() inline helper

Alternate home screen view

  • Tapping the glucose value on the home screen toggles between two views:
    • Normal: standard gauge (donut) + 8-hour bar chart below
    • Alternate: full-screen large gauge (1.5× radius), no bar chart, larger glucose value text
  • altView flag persists until next tap or page change

mmol/L glucose unit support

  • User-selectable unit (mg/dL or mmol/L) stored in glucoseUnit
  • All display functions (formatGlucoseValue(), getGlucoseUnitLabel()) handle conversion
  • pageGlucoseSettings displays and validates values in the selected unit

Configurable glucose thresholds

New pageGlucoseSettings screen with live colour bar preview for:

  • glucoseRangeMin / glucoseRangeMax — gauge scale endpoints (defaults: 0 / 400 mg/dL)
  • targetLow / targetHigh — green target range (defaults: 70 / 180 mg/dL)
  • glucoseWarn — upper warning threshold (default: 300 mg/dL)

Polish language

Added pl.h (Polish without diacritical characters) and pl_ogonki.h (an attempt at full Polish with diacritical marks via the UTF-8 → Latin-15 mapping in Gestion.cpp).

Note: pl_ogonki.h is currently not active — getting Polish diacriticals to render correctly on the AXS15231B / u8g2 font stack proved elusive, so pl.h (ASCII-safe Polish) is used for now. pl_ogonki.h is kept in the repository as a starting point for anyone who wants to pick up where this left off.


Night brightness control

LuminositeNuit (default 10%) applied via PWM when the device clock indicates night hours.


🐛 Small Fixes

Dexcom

  • Fixed DoubleUp / DoubleDown trend arrow mapping (were swapped / missing)
  • Reduced fetch window from 24 h (minutes=1440&maxCount=288) to 8 h (minutes=480&maxCount=96) — faster response, matches chart window

NightScout

  • Switched getNightScoutReadings() from https.getStream() to https.getString() for reliable buffered HTTPS reads; getStream() is unreliable with chunked transfer encoding on ESP32

FreeStyle Libre

  • Stop overwriting user-configured targetLow / targetHigh from the LibreLinkUp API response (the API returns a tight target of 140 mg/dL which silently replaced user settings on every poll)

Wi-Fi

  • Fixed premature RecordFichierParametres() on network tap — SSID was saved to flash before the password was confirmed. Added previousSsid backup; Cancel in the password keyboard now restores the original SSID via wifiRestorePreviousSsid()
  • Escape double quotes in SSID names in /scanWifi JSON response
  • Guard against empty SSID in /saveConfig

Web UI

  • Fixed TypeError in JS_Main.js.h: glucoseRangeMax, glucoseRangeMin, glucoseWarn were declared as const in JS_Commun but reassigned in the LoadGlycemie callback — this silently affected gauge, needle, trend arrow and age display in the web dashboard
  • Fixed gauge and chart scaling: rangeSpan = glucoseRangeMax - glucoseRangeMin (was using hardcoded glucoseRangeMax as the full span), matching pageAccueil.cpp logic
  • Fixed chart background colour bands: replaced stacked overlapping fillRect calls with non-overlapping bands using the seuilCoul[] approach already used on the device screen

Bar chart — 8-hour standardised window

  • Chart now always displays the last 8 hours regardless of how many points are stored
  • Points older than Tmax − 8 h are skipped via iStart index
  • Falls back to the full available range when less than 8 h of data is stored (e.g. shortly after first boot)
  • Dexcom and NightScout fetch windows aligned to 8 h

Account screen

  • Sensor type buttons (FreeStyle / Dexcom / NightScout) now vertically centre their labels using getTextBounds()-based formula, matching the Bouton_Trace helper

pageCompte — connection test countdown

  • After a successful Test, shows a 3-second countdown before navigating to the home screen

📁 Files Changed

Area Files
New sensor backend src/NightScout.h, src/NightScout.cpp
Global state src/Config.h, src/Config.cpp
Persistence src/Stock.cpp
Display — home screen src/Ecran/pageAccueil.cpp, src/Ecran/pageAccueil.h
Display — account src/Ecran/pageCompte.cpp
Display — keyboard src/Ecran/pageClavier.cpp
Display — routing src/Ecran/Gestion.h, src/Ecran/Gestion.cpp
Display — new pages src/Ecran/pageSetupChoice.*, src/Ecran/pageAPInfo.*, src/Ecran/pageGlucoseSettings.*
Display — settings src/Ecran/pageAffichage.cpp, src/Ecran/pageConfiguration.cpp, src/Ecran/pageLangue.cpp, src/Ecran/pageWifiList.*
Web server src/Server.cpp
Networking src/Internet.cpp, src/Internet.h
Time / brightness src/Heure.cpp, src/Heure.h
Web assets src/HTML/JS_Main.js.h, src/HTML/pageMain.h, src/HTML/pageSetupAP.h
Languages src/Langues/en.h, fr.h, de.h, es.h, it.h, pl.h, pl_ogonki.h, Langue.cpp, Langue.h
Sensor clients src/Libreview.cpp, src/Dexcom.cpp
Entry point src/main.cpp
Documentation README.md, CLAUDE.md, .gitignore

lslomczynski and others added 10 commits May 21, 2026 19:36
  V3.2 (pre-existing changes):
  - Dexcom: fix DoubleUp/DoubleDown trend arrow mapping
  - Add mmol/L glucose unit support
  - Add configurable glucose thresholds: glucoseRangeMin/Max,
    targetLow/High, glucoseWarn
  - Add glucoseColor option (white / colour display)
  - Add Polish language support (pl.h)
  - Add pageGlucoseSettings screen
  - Add night brightness control (LuminositeNuit 10%)

  Web UI fixes:
  - Fix TypeError: glucoseRangeMax/Min/Warn declared as const in
    JS_Commun but reassigned in LoadLGlycemie callback — blocked
    all gauge, needle, trend arrow and age display
  - Fix gauge and chart scaling to use glucoseRangeMin as baseline
    (rangeSpan = glucoseRangeMax - glucoseRangeMin), matching
    pageAccueil.cpp logic
  - Fix chart background bands: replace overlapping stacked rects
    with non-overlapping bands (seuilCoul[] approach), with colours
    tuned for web display visibility
  - Add horizontal blue line at targetLow on web chart and device
    chart (pageAccueil.cpp)

  WiFi selection fix:
  - Remove premature RecordFichierParametres() on network tap —
    SSID was saved to flash before password confirmation
  - Save previousSsid backup before changing ssid
  - Cancel in password keyboard now restores original ssid via
    wifiRestorePreviousSsid()
new file:   CLAUDE.md
- Implemented touch handling to toggle between normal and alternate views in AccueilHandleTouch function.
- Updated Trace_Gauge function to accept parameters for center coordinates and radius, improving gauge rendering.
- Adjusted layout parameters for better visual representation in both views.
- Enhanced gauge drawing logic to accommodate new parameters and maintain functionality.
First-boot flow:
- Add pageSetupChoice: two-button screen (on-screen vs AP setup) shown when
  ssid is empty, replacing the old modal + immediate WiFi list
- Add pageAPInfo: shows AP network name, password and IP address on-screen;
  Cancel returns to pageSetupChoice
- Add Internet.cpp StartAPMode() / StopAPMode(): starts ESP32 in WIFI_AP_STA
  mode with DNSServer for captive-portal redirect; Init_Server() called from
  StartAPMode() (after softAP is up) to avoid AsyncTCP semaphore assert
- Add pageSetupAP.h: self-contained mobile-friendly dark-theme HTML config
  page served at /config; sections for language, timezone, Wi-Fi, sensor
  type (LibreLinkUp / Dexcom), credentials, and glucose thresholds with
  mg/dL <-> mmol/L toggle and live color bar
- Language / timezone prompts in main.cpp now conditional on ssid being set
  (skip during first-boot AP flow)

Web server fixes:
- Replace delay()+ESP.restart() in all AsyncWebServer callbacks with
  scheduleRestart() using esp_timer one-shot (non-blocking), preventing
  NS_ERROR_NET_EMPTY_RESPONSE caused by blocking the TCP/IP stack before
  the HTTP response was transmitted
- /eraseConfig: split into GET (confirmation page) + POST (actual erase);
  POST now responds with a polling page that auto-redirects to / once the
  device comes back online
- /Restart and /saveConfig get the same non-blocking restart treatment
- /scanWifi: escape double quotes in SSIDs; /saveConfig: guard empty SSID

Navigation fixes:
- pageClavier Cancel in WiFi password context: go back to WifiListSetup()
  during first-boot (SetupEnCours), not to pageConfiguration
- pageWifiList: add Back button (visible only during first-boot) to return
  to pageSetupChoice
- pageCompte: after successful connection test show 3-second countdown then
  navigate to home screen (exits QuestionConfiguration loop automatically)

Bug fixes:
- Libreview: stop overwriting targetLow/targetHigh from API response so
  user-configured thresholds are preserved (API returns 140 as tight target)
- pageGlucoseSettings: display and validate values in the user selected unit
  (mg/dL or mmol/L) instead of hardcoded mg/dL
- AP password changed to "monitor1" (8 chars) -- WPA2 PSK minimum is 8,
  "monitor" (7 chars) caused silent failure and ESP32 fell back to open AP

Language strings (EN/FR/DE/ES/IT/PL/PL_ogonki):
- Add SetupOnScreen, SetupAP, APConnect, APOpenBrowser, APPassword keys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New src/NightScout.h and NightScout.cpp: REST API client for NightScout
  - GET /api/v1/entries.json?count=288&token=<jwt> with streaming JSON filter
  - GET /api/v1/status.json for connection test (Test button)
  - Same adaptive polling logic as Dexcom (315s / 90s / 30s based on data age)
  - Direction strings map identically to existing TrendArrow convention
  - clearNightScoutCache() for consistent clearData() integration

- Config.h/cpp: SENSOR_NIGHTSCOUT=2 enum value, nightscoutUrl/nightscoutToken globals

- pageCompte: 3-button sensor selector (FreeStyle / Dexcom / NightScout)
  - Buttons narrowed to 100px each (5px margins/gaps) to fit all three
  - NightScout section: URL and Token fields via drawPara() helper
  - Touch handler and keyboard dispatch updated for all three sensors

- Gestion.h/cpp: page constants 26/27 for NightScout keyboard pages
  - Also fixes missing Dexcom keyboard pages (24/25) in display switch

- pageClavier.cpp: NightScout URL/Token keyboard support (setup, OK, Cancel)

- Stock.cpp: nightscoutUrl/nightscoutToken persistence in LittleFS JSON

- pageSetupAP.h: NightScout radio option + URL/Token section + JS toggle

- Server.cpp: parse nsurl/nstoken params in /saveConfig handler

- All 6 language files: NightScoutIndefini, SetNightScout, NightScoutURL,
  NightScoutToken translation keys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pageAccueil: add SENSOR_NIGHTSCOUT to hasCredentials check so 'Waiting
  for glucose' is shown instead of 'Incomplete configuration' while the
  first reading is being fetched

- pageCompte: compute 3-button X positions dynamically from bw instead of
  hardcoding 110/215; fixes visual overlap on any EcranW != 320. Also
  switch margin/gap to 7 px (matching original 2-button style). All centre
  X values for PrintCentre now derived from btn[1-3]X + bw/2.
  Touch handler mirrors the same geometry.

- pageClavier: pre-populate NightScout URL field with 'https://' when
  the field is still empty, so the user only needs to type the hostname

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NightScout: switch getNightScoutReadings() from getStream() to
  getString() for reliable buffered HTTPS reads (matches Dexcom pattern);
  store response in GraphJSON; log response length for diagnostics
- NightScout: reduce count=288 (24h) to count=96 (8h) to match chart window
- Dexcom: reduce minutes=1440&maxCount=288 (24h) to minutes=480&maxCount=96 (8h)
- pageAccueil: standardise bar chart display window to 8 hours for all
  sensor sources; skip points older than Tmax-8h via iStart index;
  falls back to full available data when less than 8h is stored
- pageCompte: vertically centre FreeStyle/Dexcom/NightScout button labels
  using getTextBounds-based formula (same as Bouton_Trace)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README.md: full rewrite — add NightScout, hardware specs (AXS15231B 320x480),
  build/flash commands, first-boot AP setup, supported sensors table,
  web dashboard endpoints, OTA instructions, configuration reference,
  alternate gauge view, architecture overview
- CLAUDE.md: update SensorType enum to include NIGHTSCOUT; add NightScout
  to Sensor Data Acquisition section
- .gitignore: add /parametres.json (runtime config with user credentials)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lslomczynski

Copy link
Copy Markdown
Author

Hello! I forgot to mention in the original post: I allowed myself to propose a different colour logic - similar to those used by Libre and Dexcom where low blood sugar (very dangerous) is 'red' and higher than target is 'yellow'. As for the very high values I was inspired by Glowcose device which uses purple for the higher end of the scale segment. :-)

lslomczynski and others added 18 commits May 27, 2026 18:41
- Rename bool altView → int8_t viewMode (0/1/2) to support 3 views
- viewMode 0 = Normal (bar chart, unchanged)
- viewMode 1 = altView_01 (large gauge — identical to old altView=true)
- viewMode 2 = altView_02 (new): coloured full-screen background based on
  glucose range (RED/GREEN/ORANGE/PURPLE), inb49_mn at Sz=4 (~196 px),
  no donut gauge, no needle; glucose text forced white for contrast
- Touch cycles: Normal → altView_01 → altView_02 → Normal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Home screen now cycles through three layouts on tap (Normal ->
altView_01 -> altView_02 -> Normal):
- Normal: unchanged (semicircle gauge + 8-hour bar chart)
- altView_01: renamed from the previous single alternative view;
  behaviour is 100% identical to before
- altView_02: full-screen background colour based on glucose range
  (RED/GREEN/ORANGE/PURPLE), inb49_mn at Sz=3, no gauge, no needle;
  glucose text and unit label right-aligned and raised for clarity

Ghost-tap / tap-through fix (Gestion.cpp):
- Added PAGE_CHANGE_DEBOUNCE_MS (400 ms) suppression window after any
  page or layout transition
- PageActu changes are detected automatically in loopEcran(); layout
  changes inside pageAccueil call SuppressTouch() explicitly
- SuppressTouch() exported via Gestion.h for reuse by other pages

README: updated Display feature row and Architecture section;
added Home Screen Layouts table with per-layout description.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New /Settings endpoint (gated by physical display auth) exposes all
device parameters via browser — sensor credentials, display settings,
glucose thresholds, and home screen layout — without needing on-screen
keyboard or AP mode.

- src/HTML/pageSettings.h: new dark-themed settings page with sensor
  section (Libre/Dexcom/NightScout, passwords kept if field left blank),
  display section (language, timezone, unit, color, layout, rotation,
  brightness), threshold section (number inputs + ±10 buttons, live
  color bar, cascading validation), MQTT placeholder
- src/Server.cpp: GET /Settings (gated), GET /ajaxSettings (returns
  current config JSON, no passwords), POST /saveSettings (applies
  changes immediately: brightness via ledcWrite, NTP on TZ change,
  clearData on sensor type switch, ParaInit on language change)
- src/HTML/pageMain.h: "…" button now links to /Settings
- src/HTML/pageBrute.h: Settings added to nav menu
- src/Config.h/.cpp: viewMode and needsConfigRedraw added as globals
- src/Ecran/pageAccueil.cpp: viewMode promoted from static local to global
- src/Stock.cpp: viewMode persisted in parametres.json
- src/main.cpp: calls ParaInit() when needsConfigRedraw flag is set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rework all secondary web pages (/Brute, /OTA, /Restart, auth gate)
to match the dark-theme style of /Settings, and add several UX
improvements:

Navigation (all pages)
- Unified nav bar: Glucose | Settings | Data | Update | Restart | Erase
- Restart link styled orange (#f90), Erase link styled red — visual
  warning before destructive actions
- Nav order fixed: Restart before Erase

/Settings
- Added Erase link to nav
- Added "Test Connection" button at the bottom of Sensor Configuration:
  POSTs form credentials to new POST /testConnection endpoint; blank
  password fields fall back to the saved device config
- UI scaled up 12% (font-size: 112% on body)

/Brute (Data)
- Full dark-theme rewrite with sensor-aware section titles
- NightScout mode hides the empty ConnectionJSON section
- Collapsible JSON tree with syntax highlighting

/OTA (Update)
- Dark-theme rewrite; restored iframe listing available versions from
  f1atb.fr
- Fixed double-numbering bug (ol + translation prefixes) by switching
  to ul with list-style:none
- Fixed duplicated "3 - Click" text caused by two spans sharing the
  same data-i18n key
- UI scaled up 12%

/Restart
- GET /Restart now shows an orange confirmation page (no auto-restart)
- POST /Restart triggers the actual reboot and shows a polling
  "Restarting..." page
- New RestartingHtml constant added to pageMain.h

Server.cpp
- POST /testConnection: temporarily swaps sensor credentials with
  form-supplied values, calls the appropriate login/test function
  (loginLibreLinkUp / loginDexcomShare / testNightScoutConnection),
  restores originals, returns JSON {ok, msg}
- GET /Restart and POST /Restart split into separate handlers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace per-frame DeltaTouchX with total displacement from touch-start
  for swipe detection; eliminates accidental page switches caused by
  sensor noise near screen edges
- Clamp mapped touch Y coordinate to [0,319] for rotation=1 to prevent
  uint16_t wraparound when rawX slightly exceeds 320 (was silently
  breaking hit-zone checks in the upper screen area)
- Restore precise hit zone for altView_02 (x:60-420, y:95-260) covering
  the Sz=3 glucose value instead of the full screen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PubSubClient library and MQTT.h/MQTT.cpp (initMqtt, loopMqtt,
  publishMqttState, testMqttConnection)
- /Settings page: broker/port/user/pass fields + Test Connection button
- POST /testMqtt endpoint (gated by AutorisationPageBrute)
- HA MQTT Discovery: screen (switch), brightness (number),
  brightness_night (number), layout (select) entities
- Commands: gluco_monitor/<MAC6>/cmd/{brightness,brightness_night,screen,layout}
- State topic: gluco_monitor/<MAC6>/state (retained JSON)
- mqttScreenOff flag blocks Heure.cpp auto-dim when screen forced off
- currentBrightness tracks actual backlight; brightness != brightness_night
  in state JSON during daytime
- needsMqttStatePublish flag: layout swipe and brightness change on device
  trigger MQTT state update via main loop
- Brightness presets corrected: {15,40,100,255} -> {26,64,128,255}
  so 25% preset = 25% in MQTT state
- Auto-reconnect with 5 s back-off

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README: add /Settings browser config, MQTT/Home Assistant integration
  section (topics, entities, setup), new web endpoints table, MQTT.cpp
  in architecture tree
- pageSettings.h: widen body max-width 600px -> 700px to match /Brute
  and /OTA; fixes "Gluco-\nMonitor" text wrapping in top bar
- pageOTA.h: remove dynamic sensor-type label on Data nav link; always
  shows "Data" like every other page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These are local IDE/tooling directories that should not be tracked.
Replaced per-file ignores with directory-level .vscode/ and .claude/ rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace hardcoded 21:00/07:00 thresholds with configurable nightStartHour/Min
  and nightEndHour/Min (defaults preserved); midnight-crossing handled correctly
- Add nightScheduleDisabled flag: when set, on-device schedule is bypassed so
  MQTT/HA automations have full brightness control without conflicts
- /Settings: time fields side-by-side, checkbox in MQTT section disables section
  with opacity dimming; /config (AP-mode) gets full Night Brightness section
- On-screen Display page: gray section + single-line message when schedule disabled
- MQTT: night_schedule_disabled in state; /cmd/night_schedule ON/OFF command
- Fix Save Settings brightness: ledcWrite removed from handler; FormatteHeureDate()
  re-evaluates schedule on save (no brightness change when disabling schedule)
- Fix altView_02: reposition stale-data message to midpoint between clock and
  glucose value instead of overlapping the clock row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
InitEcran() always sets ledcWrite(GFX_BL, 255). When nightScheduleDisabled=true
FormatteHeureDate() skips the brightness block, leaving the backlight at 100%
after every restart regardless of the MQTT-set value stored in LuminositeNuit.

Apply LuminositeNuit immediately after InitEcran() when the schedule is disabled
so the last MQTT-controlled brightness level is preserved across reboots.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d web UI brightness inputs

- Add LuminositeJour (day brightness) variable with persistence and MQTT entity
- Fix MQTT /cmd/brightness to be a live override without saving to schedule variables
- Add /cmd/brightness_day and /cmd/brightness_night as separate schedule settings
- Redesign Display settings page: day/night brightness sliders, day/night start-time pickers
- Add DayStartsAt / NightStartsAt time selectors with 30-min step on device screen
- Replace night brightness radio buttons in /Settings with number inputs for day+night
- Add LuminositeJour, DayStartsAt, NightStartsAt translation keys to all 6 language files
- Update README: fix MQTT topic ranges (0-100%), add missing entities and topics

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
map() truncates; replace with round-to-nearest arithmetic so that
a 50 % command round-trips back as 50 % in the published state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add LuminositeCourante (persisted) to remember last /cmd/brightness value
- Fix main.cpp: boot was incorrectly applying LuminositeNuit when schedule
  disabled, causing nighttime brightness at any hour of the day
- /cmd/brightness now saves LuminositeCourante to flash so brightness
  survives restarts without waiting for HA automation to re-apply it
- MQTT screen ON uses LuminositeCourante when schedule is disabled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the hardcoded 5-minute polling interval for NightScout with a
user-selectable setting (1, 2, or 5 minutes + 15 s margin). The choice
is persisted in LittleFS and exposed both on the device config screen
(radio buttons below the token field) and in the web /Settings page.

Polling logic switched from age-based to timer-based (matching
LibreLinkUp), so the progress bar always fills to 100% before each
poll regardless of how old the reading already was when received from
NightScout. Stale-data retry (90 s) kicks in after 2 full intervals
without a new reading.

Also fixes a missing comma in pl_ogonki.h that silently broke Polish
diacritics translations for NightScout keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lslomczynski and others added 2 commits June 7, 2026 20:09
Allocates a 300 KB PSRAM buffer via heap_caps_malloc (MALLOC_CAP_SPIRAM)
and serves CanvaBase framebuffer as a 16-bit RGB565 BMP with BI_BITFIELDS.
De-rotates pixels from the physical 480-row x 320-col layout (rotation=1)
back to the logical 480x320 screen orientation before encoding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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