๐ SomnoTrace v2.0.0 Release Notes
โจ Highlights & What's New Since v1.4.2
SomnoTrace v2.0.0 marks a major milestone for the firmware, transitioning the project into the v2.0 architecture. This release brings a completely modularized EDF export engine, bulletproof storage coordination between uploads and session recording, zero-leak BLE sync, full civil calendar/DST accuracy, verified transactional consistency on SD card exports, and an advanced physics-based battery monitoring subsystem with dynamic CC/CV fuel gauging and persistent RTC state.
1. ๐งฉ Modular EDF Subsystem (v2.0 Architectural Foundation)
- Decoupled Engine: Decomposed the monolithic export generator into clean, single-responsibility modules:
edf_header: Fixed 256-byte EDF headers, patient/recording IDs, and metadata sidecars.edf_waveform: High-rate breath waveforms (BRP.edf), per-breath stats (PLD.edf), and oximetry (SA2.edf).edf_annotations: Event annotations (EVE.edf) and Cheyne-Stokes logging (CSL.edf).edf_summary: Multi-record daily summary (STR.edf) from ResMed protobuf spools and settings snapshots.edf_data_dict: Master signal dictionary defining physical and digital boundaries for 134 channels.
- Native ResMed SD Parity: Generated exports match native AirSense 11 SD card layouts and binary formats 1:1, ensuring out-of-the-box compatibility with OSCAR, SleepHQ, and clinical analysis software.
2. ๐ก๏ธ Resilient Storage & Export Coordination (No More Dropped Exports)
- Deferred Export Recovery: When therapy stops while a background cloud or SMB upload holds the storage lock, SomnoTrace no longer drops the export. It queues a deferred export marker and automatically exports the day as soon as the storage lock becomes available.
- Granular Storage Leases: The upload scheduler now acquires storage locks on a per-day basis rather than locking the SD card for the entire upload session, preventing export starvation during long cloud syncs or SleepHQ polling.
- Smart Upload Reconciliation: Upload passes now reconcile newly added or rebuilt sessions instead of forgetting the whole day, eliminating duplicate session uploads to SleepHQ.
3. ๐ BLE Protocol Hardening & Memory Leak Elimination
- Spool Fragment Leak Fix: Fixed an issue where transient timeouts during BLE summary spool downloads over weak radio links leaked accumulated memory buffers (~90 KB per failed attempt).
- Race-Free Teardown: The spool fragment collector is now detached before releasing memory, preventing late-arriving BLE notifications from corrupting freed state during disconnects.
4. โฐ Full Daylight Saving (DST) & Calendar Accuracy
- Civil Calendar Math Across DST Transitions: Replaced naive 24-hour UTC arithmetic with proper civil calendar transitions. Morning sessions during 23-hour spring-forward transitions now reliably map to the correct therapy day instead of landing in yesterday's folder.
- Standardized Noon-Day Derivation: Unified noon-day cutoffs across session logging, oximetry correlation, upload indexing, and portal management via a centralized
as11_timemodule.
5. ๐ซ Cheyne-Stokes Respiration (CSR) Event Support
- Dedicated CSL.edf Layer: Added full support for ResMed
CSL.edfannotation exports. CsrStart and CsrEnd events are captured, timestamped with backdate offsets, and deduplicated, allowing OSCAR and SleepHQ to accurately display Cheyne-Stokes breathing episodes.
6. ๐พ SD Card Data Integrity & Checksum Reliability
- Transactional Sidecar Checksums:
Identification.crcandCurrentSettings.crcgeneration is now strictly gated on the successful write of their respective.jsonfiles. If a JSON write fails, any existing stale.crcis actively unlinked, guaranteeing that downstream tools never encounter corrupt or mismatched checksums.
7. ๐งช Automated Property-Based Test Suite
- Host-Executable Test Harness: Added an automated property test suite with 37 property tests and 8 state-machine scenarios covering fixed-point scaling, rounding, clamping, sentinels, and boundary dates without requiring physical hardware.
8. ๐ Physics-Based Battery Monitoring & Dynamic CC/CV Fuel Gauge
-
โก Dynamic CC/CV Slew Rate Limiting: Accurately models the physical charging curve of the ETA6098 switching charger. When plugged in, the gauge rate-limits percentage increases based on the active charge regime:
-
0% โ 69%(Constant Current Phase): 35 seconds per 1% step for rapid, linear accumulation under the full ~500 mA charge rate. -
70% โ 84%(Early CV Transition): 60 seconds per 1% step as cell voltage reaches 4.15 V and current begins tapering. -
85% โ 94%(Deep CV Absorption): 120 seconds (2 minutes) per 1% step as current decays to ~150โ200 mA. -
95% โ 99%(Trickle Saturation): 180 seconds (3 minutes) per 1% step during final saturation (<100 mA). -
100%(Charge Termination): Snaps instantly to 100% when the hardware charger IC turns off above 4140 mV. - Direction Lock: Prevents artificial percentage decreases while actively connected to a charger.
-
-
๐ Two-Tier Discharge Guardrail:
-
20% โ 100%: Gated to at most 1% drop per 30 seconds, dampening transient voltage dips caused by Wi-Fi and BLE transmission bursts while tracking real drain (~120โ180s per 1%). -
0% โ 19%: Accelerates to 15 seconds per 1% step to reliably track the steep discharge knee before the PMU low-voltage cutoff (~3.3 V). - Direction Lock: Strictly non-increasing while discharging.
-
-
โ๏ธ Honest Uncalibrated State Machine (
--%):- Eliminates misleading false-100% readings on boot: cold booting while plugged into USB in the constant-voltage float zone ($\ge 4100\text{ mV}$) displays
--% โกon the LCD and--% (X.XXV) โก (Calibrating)in the Web Portal until the true state of charge is established. -
Electrochemical Surface Relaxation: Unplugging from an uncalibrated state enters a 10-second relaxation window (
BAT_UNPLUG_SETTLE_S = 10) to allow surface charge to dissipate, then snaps directly to the true relaxed Open Circuit Voltage (OCV) percentage and engages normal discharge guardrails. - Snaps directly to 100% if left plugged in until the hardware charger IC completes full saturation.
- Eliminates misleading false-100% readings on boot: cold booting while plugged into USB in the constant-voltage float zone ($\ge 4100\text{ mV}$) displays
-
๐ง Persistent State Across Warm Reboots & USB Flashing (
RTC_NOINIT_ATTR):- Displayed percentage and filtered millivolts are preserved in ESP32-S3 RTC Fast SRAM across warm reboots, software restarts, watchdog triggers, and USB firmware flashing using the
.rtc_noinitmemory section, protected by a 32-bit magic header (0x534E5442) and CRC validation. - Cold power-ons (battery reconnection) naturally fail CRC due to uninitialized RAM, safely re-entering the calibration state machine.
- Displayed percentage and filtered millivolts are preserved in ESP32-S3 RTC Fast SRAM across warm reboots, software restarts, watchdog triggers, and USB firmware flashing using the
-
โฑ๏ธ Decoupled 10-Second Burst Sampling & Debouncing:
- Unified 10-second sampling cycle using a 256-sample ADC burst over 1s, trimmed-mean averaging (discarding highest and lowest 1/8th to reject noise spikes), and an IIR low-pass filter.
- Fast 2-second edge debounce (
BAT_DEBOUNCE_SEC = 2) for rapid 2โ3s detection of physical charger plug and unplug events.
9. ๐จ Top Bar UI Polish & Slender Bluetooth Indicator
- แ Slender Pixel-Perfect Bluetooth Rune: Replaced the ambiguous CPAP mask graphic with a sleek, Nordic Bluetooth rune (
แ) rendered in light blue (#50B4FF) atx=199, y=11with uniform 1-pixel stroke geometry, perfectly matching the adjacent Wi-Fi signal icon. - โก Rescaled Battery Gauge & Bold Charging Bolt:
- Rescaled the battery indicator frame to 22ร14px with a 3ร6px terminal nub and 20ร12px inner cavity, aligning flush with the 14px line height of digits and header icons.
- Prominent 11ร8px bold lightning bolt in vivid yellow (
#FFCC00) centered inside the cavity during active charging, and proportional multi-level fill when running on battery. - Color-coded percentage readout: Green (>30%), Orange (16โ30%), Red (โค15%), and Muted Slate-Blue for
--%calibrating state.
- ๐ Header Alignment & Visual Breathing Room:
- Repositioned the "CUR" label to the left margin (
x=12) and "AVG" to the right margin (x=193), providing 22px of symmetrical breathing room around the central "Leak (L/min)" title and eliminating visual crowding.
- Repositioned the "CUR" label to the left margin (
- โก Low-Latency Status Bar Refresh:
- Decoupled battery UI updates from the 3-second display loop to run every 1 second upon state changes, providing instant visual feedback on plug/unplug events without redrawing unchanged frames.
10. ๐ Web Portal Telemetry & User Configuration
- โ๏ธ Battery Indicator Toggle: Added a configurable
battery_enabledtoggle in the Web Portal under Display & Sound and via the REST API (POST /api/device/settings). Users operating solely on USB power without a Li-ion battery can cleanly hide the battery indicator from the LCD status screen. - ๐ Live Battery Telemetry in Web Portal: The portal Status tab displays live battery percentage, cell voltage (
X.XXV), charging bolt status, uncalibrated state (Calibrating), orUSB Power (No battery)when disabled.
11. ๐ Comprehensive Formal Specifications
- Spec 0012 (Battery Monitoring & Power Management): Full technical specification documenting ADC burst sampling, OCV curves, electrochemical surface relaxation, dynamic CC/CV slew rate limiting, uncalibrated state machine, RTC Fast RAM persistence, and power latch pin controls.
- Spec 0011 (Web API Endpoints): Updated REST and SSE API contracts for battery telemetry under
GET /api/statusand configuration schema inPOST /api/device/settings. - Spec Documentation Index: Updated
spec/README.mdto catalog Specifications 0009 through 0012.
๐ค Credits & Acknowledgements
A huge thank you to everyone involved in making this milestone release possible through code contributions, rigorous protocol analysis, and real-world testing:
๐ป Code Contributions
- @Plantucha:
- Pull Request #187: Implemented the deferred export queue on storage lease contention (
SD_LEASE_EXPORT), non-blocking lease probing, and smart day reconciliation to prevent duplicate uploads to SleepHQ. - Pull Request #196: Fixed the BLE spool fragment memory leak on collection timeouts (~90 KB accumulation under weak signal) and implemented race-free collector detachment during teardown.
- Pull Request #187: Implemented the deferred export queue on storage lease contention (
๐ Technical Analysis, Bug Reports & Architectural Review
- @Plantucha:
- Issue #200: Discovered and proved the 23-hour spring-forward DST boundary defect in noon-day derivation across multiple timezones.
- Issue #190: Identified Cheyne-Stokes Respiration (CSR) event labeling requirements in
CSL.edf, driving the backdate timing and deduplication implementation. - Issue #198: Uncovered the sidecar
.crcfailure path where checksums could be written despite.jsonwrite failures. - Issue #199: Conducted comprehensive dimensional analysis on
STR.edfsummary metric scaling across all 53 signals. - Issue #186 & Discussion #191: Detailed review and verification of the EDF modularization and STR data dictionary parity.
๐ฉบ Testing & Community Feedback
- @cwm12345 and @moldbuster for upstream storage and UI pull requests (#171, #172, #173, #178, #179).
- @irfanguder, @Asad-Foresite, and community testers for continuous real-world session verification, SleepHQ sync testing, and hardware log captures across diverse AirSense 11 and O2 Ring setups.