Skip to content

Releases: ilyakruchinin/SomnoTrace

v0.6.3

v0.6.3 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 05 Aug 06:19
c3a6c0e

Changes since v0.6.2

OTA Firmware Update

  • Download firmware from URL — device fetches and flashes directly from GitHub or any HTTPS URL, no computer needed
  • "I'm Feeling Adventurous" button — auto-finds and installs the latest release with one click
  • Real-time progress bar — shows download and flash progress during update
  • Fixed OTA download failures — TLS buffer too small for GitHub's CDN caused silent handshake failures; now uses full-size TLS buffers with on-demand allocation to keep RAM usage low
  • Concurrent uploads supported — OTA download works even while SleepHQ upload is running

BLE Reconnect

  • Auto-reconnects when AS11 is turned on later — if the CPAP is off at boot, the device keeps retrying every 60s instead of giving up and requiring a reboot
  • Cleaner disconnect handling — retry loop exits immediately when pairing is cleared or user disconnects

Faster Dashboard Graph Loading

  • Halved breathing-graph download size — flow and pressure data now stored in separate files; the dashboard only fetches flow (pressure comes from the summary data), cutting transfer size in half
  • Backwards compatible — old sessions still load; new sessions use the split format automatically

NTP Failure Recovery

  • BOOT button escape on Wi-Fi failure — if NTP sync fails, the alarm sounds but you can now hold BOOT to enter Wi-Fi setup instead of waiting for a forced reboot

Stream Quality Diagnostics

  • BLE stream health metrics — session list now shows notification count, gap events, and missing-sample compensation for each session

v0.6.2

v0.6.2 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 03 Aug 07:07
3b6effa

Changes since v0.6.1

STR.edf bi-level mode superset expansion + bug fixes

Commit: f5dce49 — Expanded STR.edf signal count from 78 to 134 signals

File changed: main/edf_gen.c (+354 / −113)

Bug fixes

  • Fixed missing settings summary for users with 30+ days of history. The STR.edf generator had a hard 30-record cap (calloc(30, ...) + n_records < 30 guard) that prevented the current day's synthesized STR record from being added when 30 historical spool files already existed. Since the AS11 doesn't finalize the current day's spool until noon rollover, the current day was never found in the parsed spools, and the synthesis branch was blocked by the n_records < 30 guard being false. OSCAR would then fall back to copying stale settings and flag noSettings, hiding the settings summary for that day. Fixed by allocating 31 record slots and changing the guard to n_records < 31. This works for any number of spool files on disk (60, 180, 600+) because the spool trim always reduces parsed records to ≤30 — the extra slot is solely for the synthesized current-day record.
  • Fixed AutoSetForHerProfile MOP mapping from index 11 → 2 (APAP/Her), which previously caused settings to not appear at all in OSCAR for AutoSet For Her users.

New features

  • Added bi-level therapy mode signals (VAuto, Spont, ST, Timed, ASV, ASVAuto) to build_str_data_values(), including start pressure, EPAP, IPAP, PS, PSMin/Max, TiMin/Max, backup rate, trigger/cycle sensitivity, EasyBreathe, and ERatio settings
  • Added new summary stat signals: SpontTriggerPercentage, SpontCyclePercentage, TargetMinuteVentilation, IeRatio, InspiratoryDuration (Ti)
  • Added iVAPSProfile (9) and PACProfile (10) to profile_name_to_mop()
  • Added enum conversion helpers for trigger/cycle sensitivity, EasyBreathe mode, and RespiratoryRateEnable

Internal changes

  • Shifted all existing signal indices (CPAP/AutoSet, comfort/settings, spool-derived stats) to accommodate the new bi-level signals inserted at indices [14–58]
  • Updated rec_buf size from 115 to 171 int16s (133 data signals + Crc16, accounting for 2 signals with 20 samples-per-record)
  • Updated all hardcoded 115 references in the record writing/CRC code to match the new buffer size

v0.6.1

v0.6.1 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 01 Aug 16:00
3b6effa

Changes since v0.6.0

WiFi Configuration UX

  • Configured SSIDs now visible on page load. The /api/status endpoint now returns ssids (array of SSID strings) and has_pass (array of booleans) so the web UI can display all saved WiFi networks immediately — no scan required. Passwords are never sent to the frontend.
  • Pre-populated networks use text-input mode. Saved SSIDs appear as editable text fields instead of empty dropdowns, making them visible as soon as the settings page loads.
  • Cache invalidation after save. save_post_handler now sets s_status_cache.cfg_valid = false after saving WiFi config, so the next /api/status call returns the updated SSID list without waiting for the 2-minute cache TTL.

Display — New "Backlight always off" Mode

  • Added LCD_THERAPY_ALWAYS_OFF mode (battery-friendly). A third display mode option complements the existing "Show live graph" and "Backlight off":
    • Show live graph — backlight always on (unchanged)
    • Backlight off — backlight off during therapy, on otherwise (unchanged)
    • Backlight always off (battery) — backlight fully off in all states except during boot and SoftAP setup mode
  • Centralized backlight policy. New bsp_display_apply_backlight_policy() function evaluates the current LCD mode and therapy state to set the correct backlight on/off. Called after boot completes, when entering SoftAP, and when the mode is changed via the web UI.
  • SoftAP force-on override. A s_backlight_force_on flag ensures the backlight stays on during SoftAP/portal mode regardless of the selected display mode, so users can always interact with the setup screen.
  • Immediate effect on save. Backlight policy is evaluated after the new mode is persisted to NVS (not before), so selecting "Backlight always off" turns the LCD off immediately without waiting for therapy to start.
  • Therapy stop respects always-off. When therapy ends, LCD_THERAPY_OFF restores the backlight but LCD_THERAPY_ALWAYS_OFF keeps it off.

v0.6.0

v0.6.0 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 31 Jul 13:17
3b6effa

SomnoTrace v0.6.0 Release Notes

🚨 CRITICAL: FULL FLASH REQUIRED (0x0)
Due to updates in the partition table (addition of a dedicated 64 KB coredump partition), OTA update will NOT work for this release. You must perform a full flash over USB at offset 0x0 using somnotrace-v0.6.0-merged.bin.


🚀 What's New & Changed (since v0.5.7)

🛠️ Crash Diagnostics & Reliability

  • On-Flash Core Dumps: Added a dedicated coredump flash partition. On firmware crashes (panic/watchdog), crash state and call stacks are preserved to flash.
  • On-Boot Diagnostics: Added automatic crash report processing on boot. Crash summaries (crashed task, exception PC, backtrace stack, ELF hash) are logged into the download log buffer to make troubleshooting seamless.
  • Reset Reason Logging: Every boot now logs the precise hardware/software reset reason (POWERON, SOFTWARE, PANIC, TASK_WDT, BROWNOUT, etc.).

📺 Display & Therapy Graph Fixes

  • Decoupled Therapy Graph Activation: Fixed an issue where the live therapy flow graph failed to trigger on the LCD if SD card initialization was delayed or encountered an error. Live graph rendering now triggers unconditionally on TherapyStart.
  • Enhanced Display Logging: Added comprehensive state transition and task status logging for display state management.

⚡ Flashing Instructions (Full Flash)

  1. Hold the "BOOT" (left) button and connect the device to USB-C (screen will remain black/off).
  2. Open a Web Flasher in Chrome/Edge:
  3. Select the merged binary (somnotrace-v0.6.0-merged.bin) and flash to offset 0x0.

⚙️ Initial Setup & Usage

  • First Boot / Setup: The device will enter SoftAP mode on first boot. Connect to the Wi-Fi access point and navigate to http://192.168.4.1 to configure your Wi-Fi and timezone.
  • Main UI Access: Once Wi-Fi is configured, the device reboots into the main interface where you can access the full Web UI.
  • Manual SoftAP Mode: Hold the "BOOT" (left) button for 5 seconds from the main UI to force SoftAP mode.
  • Powering Off: Hold the "POWER" (middle) button for 10 seconds.

🔗 Pairing AirSense 11 (AS11)

  1. On your AS11 screen, navigate to MoreMyAir AppOK, downloadedConnect.
  2. Perform the pairing procedure from the SomnoTrace Web UI.
  3. Note: If your mobile phone's MyAir app is currently connected via BLE, disconnect it first, or it will hold the connection and prevent pairing from succeeding.

ℹ️ Data Analysis & Upload Notes

  • OSCAR Usage: We recommend using OSCAR with separate test profiles.
  • SleepHQ Duplicate Protection: If you upload a session to SleepHQ via SomnoTrace and later attempt to upload the same therapy session files directly from the AS11 SD card, SleepHQ will likely return an error. This is expected behavior from SleepHQ (duplicate detection). Please choose to upload a given session either via SomnoTrace or via SD card import, not both. Different therapy sessions upload fine.

v0.5.7

v0.5.7 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 31 Jul 06:52
3b6effa

Battery: adaptive 100% charge anchor and charger-transition filter reset

Adaptive full-charge anchor

  • The OCV curve hardcoded 4200 mV as 100%, but real Li-ion cells terminate charging at ~4130 mV, so the display never reached 100% (peaked at ~94%).
  • When CHG_STAT goes high (charge complete), the current filtered terminal voltage is recorded as the 100% anchor. The top segment of the OCV lookup table is stretched to use this anchor instead of 4200 mV.
  • The anchor is persisted to NVS (bat namespace, key full_mv) via the existing nvs_writer task (internal RAM stack), so it survives reboots. Loaded at boot before the monitor task starts.
  • Anchor only accepted in the 4000–4200 mV range to reject transient spikes and partial-charge false triggers. NVS write only occurs when the value actually changes.

IIR filter and percentage reset on charger transitions

  • When charging stopped, the 120 mV IR-offset subtraction was removed, but the IIR filter only moved 25% per cycle — taking ~4 cycles to catch up. The slew-limited percentage then took additional minutes to walk to the new target.
  • Both filtered_mv and shown_pct are now reset to -1 on any charger state change (plug or unplug). The next sample adopts directly, eliminating the lag.

nvs_writer_init() in battery monitor start

  • Added nvs_writer_init() call in bsp_power_battery_monitor_start() to ensure the internal-stack NVS writer task exists in both STA and SoftAP modes, not just when the connected HTTP server starts.

v0.5.6

v0.5.6 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 31 Jul 04:23
3b6effa

SomnoTrace — Changes since v0.5.5

Battery Monitoring (comprehensive rewrite)

Battery sampling

  • ADC calibration: Uses ESP-IDF eFuse-backed curve-fitting calibration (adc_cali_curve_fitting) instead of nominal scaling. Without eFuse data, falls back to nominal (reads a few percent low).
  • Trimmed-mean sampling: 256 samples spread over ~1 second (4 ms apart) with lowest/highest 12.5% discarded. Rejects Wi-Fi/BLE TX burst dips that corrupted back-to-back samples.
  • OCV-based percentage: Li-ion discharge curve is non-linear (flat 3.9–3.6 V, cliff below). Replaced linear voltage-to-percent map with a piecewise-linear OCV lookup table (4200 mV = 100%, 3300 mV = 0%).
  • Charging IR offset: Subtracts 120 mV from terminal voltage while charging to approximate true OCV.
  • Slew limiting: Published percentage moves at most 1 point per update cycle (60 s discharge / 20 s charge) with monotonic-while-charging rule. Eliminates visible "jump" on plug-in.
  • Unplug settle: 30-second hold after charger disconnect lets terminal voltage relax to OCV before trusting the reading.

No-battery detection

  • Threshold: If VBAT > 4250 mV (above any real Li-ion cell max of ~4200 mV), the battery is considered absent. USB power with no cell installed pegs the ADC at ~5 V through the 200 kΩ / 100 kΩ divider.
  • Behaviour: Publishes valid = false and percent = -1, causing the LCD battery indicator to be hidden. Filter state is reset so a newly installed battery is detected within one sample cycle.
  • Stale state fix: bat_publish() now clears valid / percent / millivolts when ok = false, preventing stale readings from persisting after battery removal.

Battery API (bsp_power.h)

  • New bsp_battery_t struct: percent, millivolts, charging, valid, age_s.
  • bsp_power_battery_monitor_start() — background monitor task ( sole ADC owner, samples on slow cadence, publishes snapshot).
  • bsp_power_battery_get() — non-blocking snapshot read, safe from any task.
  • bsp_power_battery_percent() — convenience wrapper.
  • bsp_power_is_charging() — reads CHG_STAT (GPIO3) directly, cheap and always current.

Wi-Fi — Stale Connection Fix & Failover

Stale connection bug

  • Root cause: ESP-IDF Wi-Fi event handler does not automatically clear the application-level "connected" flag on WIFI_EVENT_STA_DISCONNECTED. The old code left s_connected / s_connected_ip stale, so the LCD and /api/status kept advertising a dead connection.
  • Fix: Added link_mark_down() called on disconnect, which immediately clears the published IP and SSID. Consumers read live state via netprov_get_link() and never cache "connected".

Autonomous failover

  • Problem: esp_wifi_connect() only retries the single SSID currently programmed into the driver. Without intervention, a permanently disappeared network strands the device even when another configured network is in range.
  • Fix: Event handler counts failed reconnects; after 5 failures it sets a rescan flag. A background link_supervisor_task performs a full scan-and-rank across all configured networks and connects to the best available candidate. Credentials are cached at initial connect so the supervisor can rescan without NVS access.

Link state API (net_provision.h)

  • New netprov_link_t struct: up, ssid, ip, rssi, rssi_valid.
  • netprov_get_link() — non-blocking snapshot, safe from any task.
  • netprov_is_link_up() — convenience boolean.

LCD status display

  • Replaced hardcoded "Wi-Fi Connected" text with the actual SSID from netprov_get_link() in all three status display paths (boot, periodic refresh with SD OK, periodic refresh with SD error).

EDF Export — Enum Mapping Fixes (edf_gen.c)

  • AutoSetComfort (S.AS.Comfort): Removed invalid "Plus" value (does not exist in AS11 JSON). Fixed Off mapping from 0 → 1 (AS11 EDF convention: raw enum + 1). OSCAR decrements by 1 for AS11, so EDF value 1 → OSCAR 0 = "Standard", EDF value 2 → OSCAR 1 = "Soft".
  • Mask type (S.Mask): Fixed mapping to use raw + 2 convention. Pillows = 2, Nasal = 4, Pediatric = 5 (was incorrectly 1/2/4).
  • Tube type (S.Tube): Fixed 15mmNonHeated mapping from "3m" to correct string match, value 3.
  • Documentation: Updated inline comments to reference spec/0002-edf-export.md §4.3.4 for the enum convention.

OTA Firmware Update

Backend (net_provision.c)

  • Endpoint: POST /api/ota accepts raw binary (application/octet-stream), max 4 MB.
  • Architecture: Two-task design to work around ESP32-S3 PSRAM cache freeze:
    • httpd handler (PSRAM stack) — receives HTTP body in 4 KB chunks, pushes to an 8 KB FreeRTOS stream buffer.
    • ota_flash_task (internal RAM stack via xTaskCreate) — reads from stream buffer, calls esp_ota_begin / esp_ota_write / esp_ota_end / esp_ota_set_boot_partition. Internal stack required because esp_ota_* functions freeze the SPI cache, which asserts the task stack is not in PSRAM.
  • Flow: Validate size → create stream buffer → launch flash task → feed data from socket → wait for flash task completion → respond {"ok":true} → reboot after 1.5 s delay.
  • Error handling: Every stage has cleanup (esp_ota_abort, vStreamBufferDelete). Stream buffer timeout (10 s) and flash task timeout (30 s) prevent hangs.

Build (CMakeLists.txt)

  • Added app_update to REQUIRES for esp_ota_ops.h.

Frontend (portal.html)

  • New "Firmware Update (OTA)" card in the Actions tab with file picker (.bin only, 4 MB max).
  • Real-time progress bar with percentage and KB counter via XMLHttpRequest.upload.onprogress.
  • Confirmation dialog before flashing. Inputs disabled during upload to prevent double-submit.
  • Status messages: uploading → complete/rebooting, or error with details.

Documentation

  • docs/hardware/README.md: Added battery monitoring section (divider, ADC calibration, TX burst rejection, charging IR offset, OCV curve, slew limiting, sampling cadence) and Wi-Fi section (RSSI selection, stale connection fix, failover, retry timing).
  • spec/0002-edf-export.md: Added §4.3.4 documenting AS11 EDF enum conventions (raw + 1 for most signals, raw + 2 for S.Mask) with OSCAR decrement behavior.

v0.5.5

v0.5.5 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 30 Jul 14:04
3b6effa

Changes since v0.5.4

Bug fixes

  • MaskEvents undercount in STR.edfMaskEvents was set to the number of
    on/off pairs instead of the total number of on+off events. OSCAR divides
    MaskEvents by 2 to get the pair count, so the reported session count was
    half of what it should have been.
    (main/edf_gen.c)

  • Repeating -120 L/min flow spikes in OSCAR/SleepHQ — BLE notification
    drops (typically every ~10 minutes) triggered insertion of SNT_MISSING
    (INT16_MIN) sentinels into BRP flow/pressure data. During EDF conversion
    these were clamped to dig_min = -1000, which OSCAR scales by gain = 0.12
    (L/s→L/min), producing visible -120 L/min spikes. Changed BRP gap
    compensation to hold-previous-value (matching the existing SA2/PLD
    strategy). Gaps are typically 200–400 ms (<10 % of a breath cycle), so the
    held value is visually indistinguishable from real data. The AS11 native EDF
    never has missing BRP data, and OSCAR has no sentinel convention for
    breathing waveforms.
    (main/session_writer.c, main/edf_gen.c)

v0.5.4

v0.5.4 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 30 Jul 12:38
3b6effa

Changes since v0.5.3:

  1. AS11 settings EDF mapping fixes (edf_gen.c):

    • Added "Auto" → 3 to on_off_to_edf() for HeatedTubeSettingEnable
      and other On/Off/Auto enum fields. Fixes Temperature and
      Temperature Enable not displaying in OSCAR when set to "Auto".
    • Added "Off" → 0 for AutoSetComfort (S.AS.Comfort / Response).
    • Added "Full" → 1 for PatientView (S.PtAccess), treating it as
      a firmware rename of "Advanced".
  2. SMB upload timestamp preservation (uploader_smb.c):

    • Added smb_set_mtime() — sends SMB2 SET_INFO with
      FILE_BASIC_INFORMATION to set remote file last_write_time
      and change_time to match the local file's mtime.
    • Called before smb2_close() so destination files retain
      original modification timestamps instead of upload time.
  3. FAT32 rename / HTTP header fixes (uploader_state.c, sdkconfig.defaults):

    • Remove destination file before rename() to avoid FAT32 EEXIST
      errors on the uploader state file.
    • Increase HTTPD_MAX_REQ_HDR_LEN from 2048 to 4096 to accommodate
      Cloudflare Access proxy headers (cookies + JWT).

v0.5.3

v0.5.3 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 29 Jul 05:23
3b6effa

Changes since v0.5.2

Battery Charge Indicator (LCD)

  • Added battery percentage reading via ADC1 (GPIO1) with 200k/100k voltage divider compensation
  • Added charger status detection via GPIO3 (active-low when charging)
  • Battery icon with percentage text and yellow lightning bolt when charging, displayed on the LCD top row alongside Wi-Fi and AS11 indicators
  • Calibrated voltage-to-percentage mapping (3.3V–3.93V → 0–100%)
  • Periodic updates every 3 seconds in both normal and SoftAP modes

BLE RX Buffer Improvements

  • Moved BLE notification RX buffers to PSRAM to free internal RAM
  • Increased RX_BUF_MAX from 4KB to 16KB — fixes truncated settings summaries from large AS11 notifications

SD Card Format Support

  • Added sd_storage_format() — unmounts, formats (f_mkfs), remounts, and recreates the directory tree
  • Exposed via API for in-field card formatting without removing the card

Session Writer Robustness

  • Therapy auto-start now handles SD card not ready gracefully — displays "SD Card Error" warning instead of silently failing
  • bsp_display_set_therapy_active(true) only called when session actually starts

Web UI (portal.html)

  • Dashboard progress bar: Fixed display:none bug preventing the loading progress bar from appearing; bar now stays visible as a green separator after load completes (no layout jump)
  • Double-tap reset: Reduced touch double-tap zoom-reset threshold from 300ms to 200ms to prevent accidental triggers on mobile

HTTP Server Tuning

  • max_open_sockets: 10 → 24 to handle parallel dashboard fetches
  • recv_wait_timeout: 5s → 2s to proactively close idle connections before browser RSTs
  • Enabled TCP keepalive (5s idle / 5s interval / 3 retries) to detect dead connections
  • Reduces "error in recv : 104" (ECONNRESET) warnings from browser connection pooling

What needs to be tested

  • Battery charging indicator and percentage display on LCD
  • Boot without SD card — warning displayed
  • Therapy start without SD card — "SD Card Error" warning shown
  • Dashboard progress bar visibility during and after data load (no layout jump)
  • BLE settings summary no longer truncated
  • HTTP server stability under parallel dashboard fetches

v0.5.2

v0.5.2 Pre-release
Pre-release

Choose a tag to compare

@ilyakruchinin ilyakruchinin released this 27 Jul 08:17
50c4b1d

v0.5.2

Accuracy release: exported files and dashboard summaries now line up with what
the AirSense 11 writes itself.

Fixed

  • Daily summary records were dated one day early. The noon-to-noon day for
    each daily record was picked using clock-corrected time, which shifted every
    record back a day and pushed its session start/stop times out of the valid
    range. OSCAR treated those times as corrupt and discarded them, falling back
    to less precise values — which is why daily usage and AHI could read a minute
    (and a fraction of a point) below the SD card import.
  • Session end detection. Session data now ends on the machine's own data
    gating signal, mirroring how the start is already detected. Previously the end
    relied on an event that some sessions never emit (for example when SmartStop
    triggers), in which case no trimming happened at all.
  • Start/end alignment precision. Session boundaries now use the
    higher-precision timestamps available and round to the nearest sample instead
    of always rounding down. This removes a sub-second offset that slightly moved
    average leak rate and large-leak totals.
  • Aborted sessions are no longer exported. A session where the mask was
    never detected and no therapy data was produced now produces no files at all,
    matching the machine's behaviour. Previously it created empty data files
    without their companion event files, adding a phantom session to the day.
  • Web dashboard now matches OSCAR/SleepHQ. Graphs and summary statistics are
    limited to the machine's own therapy data window, so the pre-therapy pressure
    ramp no longer inflates average leak rate and 95th-percentile figures.
    Sessions with no therapy are excluded from the graphs and statistics.

Notes

  • No changes to how raw session data is captured or stored, and no action needed
    on upgrade. Machine settings, event annotations and waveform data were already
    correct and are unchanged.
  • Existing exports can be regenerated to pick up the corrected daily records.