github ilyakruchinin/SomnoTrace v4.0.0-beta6

pre-release4 hours ago

SomnoTrace v4.0.0-beta6

✨ New since v4.0.0-beta5

🖥️ Bridge status at a glance

The LCD now shows the SomnoBridge BLE link and the EZShare card's Wi-Fi
state, so a dropped bridge or a card that failed to join is visible without
opening the portal.

🧾 Historical settings are provenance-checked

  • Imported session settings now need a verified source and matching machine
    identity before they are treated as historical facts. Legacy sessions
    without that proof stay unknown; they are no longer filled from the
    current machine's settings.
  • Native STR.edf imports keep their source files if safe processing fails,
    and a root identity/settings conflict no longer blocks unrelated day
    folders.
  • AS10 card settings use a family-specific import/export path: supported
    fields keep the card's own scaling and enum values; fields whose
    translation is not verified stay unknown instead of being guessed.
  • AirCurve 11 VAuto/S-mode settings are handled, missing snore/flow-limit
    samples are preserved, and empty dashboard panels now explain the empty
    state instead of shimmering forever.
  • Missing days in the STR calendar get explicit unknown placeholders, so a
    gap cannot shift later nights onto the wrong date.

🛟 Import recovery is isolated

Malformed or unreadable root files are retained or quarantined instead of
being consumed. One bad root file no longer stops queued day folders, and
copied or cached identity is no longer accepted as proof of a session's
machine.

🌉 Bridge sync reliability

  • Recent days are no longer hidden by a 64-entry limit. The bridge
    selects from the complete catalog, sorts newest-first, and only then
    applies the requested window.
  • Catalog activity is honest. First scans, evicted reloads and GONE-only
    changes no longer mark a folder permanently active; only real writes do.
    Budget pressure is preflighted and reported as INCOMPLETE instead of
    publishing an over-budget catalog, and a complete parent listing retires
    unscanned folders that really disappeared.
  • Failed feeds no longer look like healthy monitoring. A failed parent
    or day feed marks the round failed, marks the folder stale, and does not
    refresh therapy liveness. GONE-only changes no longer open a therapy
    session.
  • No silent truncation. LIST_DAY and LIST_DIRECTORY escape card
    names and return an explicit resource error when the complete response
    cannot fit. PREPARE_DAYS reports resident/stale/gone and honest queue
    results, and GET_FILE distinguishes gone/unscanned/evicted/stale days
    instead of reviving a removed folder.
  • FATFS-safe publication. A changed file replaces the previous copy
    through a backup protocol instead of failing on an existing destination.
  • Ledger recovery. Malformed or oversized ledgers are preserved as
    .bad, every save is checked, null timestamps compare as null, and
    duplicate keys are replaced.
  • Stricter sync validation. Malformed day/file arrays and stale
    listings are rejected, in-flight .part/.tmp and unsupported files are
    filtered, drift metadata is written atomically, and an explicit pending
    marker preserves bridge provenance when drift is unavailable.
  • Expected timestamps and day-specific drift. A source that changed
    under a transfer, or a drift record from another day, is rejected instead
    of being accepted silently.

🔔 Release status is honest

The update checker now compares versions instead of raw strings. An older
stable release is no longer offered as an update for a newer beta; optional
v, build metadata, dirty/dev builds and unparsable tags are handled
without guessing.

✅ Testing

  • SomnoTrace host suite: 33 run, 0 failed, 1 skipped (host mbedTLS absent).
  • SomnoBridge host suite: passed, including new catalog capacity/GONE tests.
  • Both ESP-IDF target builds pass.

Everything in v4.0.0-beta5

SomnoTrace v4.0.0-beta5

The SomnoBridge release. 🌉 SomnoTrace now pairs, provisions, time-syncs
and pulls therapy data through the Wi-Fi↔BLE bridge — the AirSense's SD
card never has to leave the machine.

beta5 fixes release-image builds: a clean build (which regenerates its
configuration from sdkconfig.defaults) had NimBLE security compiled
out entirely, so SomnoBridge pairing failed instantly on every attempt —
with the bridge never even contacted.

✨ New since v4.0.0-beta4

🔐 Clean-built release images could not pair at all
  • The root cause of beta4's pairing failures — build-dist.sh --clean
    deletes sdkconfig and regenerates it from sdkconfig.defaults, which
    had NimBLE SMP disabled (# CONFIG_BT_NIMBLE_SECURITY_ENABLE is not set). With SMP compiled out, ble_gap_security_initiate() is a stub
    that returns BLE_HS_ENOTSUP (8) unconditionally — before the bond
    store is consulted and before any SMP packet is sent. Every clean-built
    release image could therefore never pair a SomnoBridge; only developer
    builds with a hand-tuned sdkconfig worked.
  • SMP enabled in the defaults — CONFIG_BT_NIMBLE_SECURITY_ENABLE,
    SM_LEGACY, SM_SC (LE Secure Connections) and NVS_PERSIST (bond
    persistence across reboots) are now set in sdkconfig.defaults, so a
    clean release build pairs exactly like a developer build.
  • Diagnostics name both causes — an ENOTSUP (8) from the SM layer
    now logs "SMP disabled or bond store full; the bridge was never
    contacted", so this class of failure is one line to diagnose instead of
    a bridge-reset goose chase.
  • Verified on hardware — a build made from defaults only (the exact
    --clean path, confirmed by the 21 KB smaller image and the SMP code
    present in sdkconfig.h) completes
    link encrypted, authenticated and bonded → paired → subscribed.

✨ New since v4.0.0-beta3

🔗 SomnoBridge pairing — local bond-store failures fixed
  • Pairing no longer fails before the bridge is contacted — NimBLE's
    SM layer refuses to start pairing when its capacity check
    (ble_sm_chk_store_overflow) trips, returning BLE_HS_ENOTSUP (8)
    synchronously. That check counts stored bonds plus any active SMP
    procedure
    against CONFIG_BT_NIMBLE_MAX_BONDS — which was 2 (and 1
    in the shipped defaults). One stored bridge bond plus a single live
    pairing procedure was enough to block every attempt. The failure was
    then reported as "bridge refused pairing — FORGET_PEER is required",
    which sent users to reset the bridge for no reason.
  • Bond store now self-heals — registered a store-status callback
    that evicts the oldest peer bond (ble_store_util_delete_oldest_peer)
    when the store reports FULL, instead of refusing to pair.
  • Capacity raised — CONFIG_BT_NIMBLE_MAX_BONDS 2 → 4, and
    sdkconfig.defaults 1 → 4 (a clean build from defaults could not
    pair anything at all).
  • Honest diagnostics — rc=8 now says the refusal is local and the
    bridge was never contacted, and the portal reports "pairing blocked
    locally" instead of blaming the bridge.
  • No more spurious "Pair failed" — a connect still winding down
    answers EBUSY (15); the pair op now retries once after 400 ms
    instead of surfacing an error on a quick second press.
  • Verified on hardware — NVS bond-store dump (IDF
    nvs_partition_tool) confirmed a single valid bridge bond (LTK
    present, LESC, authenticated); live pairing completes
    encrypted, authenticated and bonded → paired → subscribed.

✨ New since v4.0.0-beta1

💾 SomnoBridge "Configure" dialog — smarter Save & Test
  • Join is now verified, not assumed — after saving a custom card
    password, the dialog polls the bridge's real link state
    (GET_STATUS.sta_connected, 1 s × 12) instead of running a redundant
    probe-join. Success shows "Bridge joined the card"; a typo'd password
    gets a clear red error instead of a false "good".
  • Security probe only when it matters — the factory-password check
    now runs only when the saved password is 88888888 or the card is
    open. Custom passwords skip it entirely.
  • Dialog closes itself on success — the button flips to OK and the
    window auto-dismisses; nothing left to configure means nothing left
    on screen. It stays open on any failure.
  • GET_STATUS added to the /api/sb/op proxy whitelist;
    EZSHARE_CHECK timeout raised 25 s → 32 s.
✍️ Portal wording — data-source direction made explicit (#345)
  • Pairing card renamed "ResMed Series 11 / SomnoBridge" — covers
    AirSense 11 and AirCurve 11 plus the bridge path (was "ResMed
    AirSense 11 CPAP" even though it pairs a SomnoBridge too).
  • Scan button renamed "Scan for ResMed / SomnoBridge".
  • Upload Window now states the direction: "days recorded on this
    device
    are uploaded from SomnoTrace to the destinations above" —
    plus a note that SomnoTrace records live over Bluetooth and cannot
    import history stored on the SD card inside your CPAP machine.
  • Reset Upload State description and confirm dialog say the same,
    and now correctly state the upload-window cap instead of "all days".
  • Maintenance section says "the SomnoTrace SD card" — no more
    ambiguity about which card an action touches.
🐛 Fixes
  • 📊 Dashboard could shimmer forever — with no sessions recorded,
    the "Connecting & loading sessions…" progress bar was never
    dismissed; "No sessions recorded yet" appeared only as a small muted
    line. This is what looked like an 18-hour hang in #345. The dashboard
    now stops loading and explains the empty state in one line.

Everything in v4.0.0-beta1

✨ Highlights

  • 🌉 SomnoBridge integration — a complete BLE client (sb_ble,
    ~1.5k LoC): discovery, passkey pairing, bonded GATT ops over the
    framed protocol, streaming file pulls, and a /api/sb/op HTTP proxy
    that drives every bridge op from the portal.
  • 🕐 Authoritative UTC & drift correction — SomnoTrace anchors its
    NTP time on the bridge's monotonic clock with periodic exchanges,
    reads back the fitted drift on every sync pass, and applies the
    estimate when importing sessions — AS11 clock wander is corrected
    instead of silently skewing therapy data.
  • ⚙️ "Configure SomnoBridge" dialog — card network picker (scrollable
    AP list, OPEN/SECURED badges, saved network), AS10/AS11 machine cards
    with the AS11 GMT-offset picker, an X close button, and an
    insecure-card flow: factory 88888888 and open cards are detected by
    a real probe-join, flagged with a warning, and can be re-secured
    in-place via EZSHARE_ADMIN — the bridge changes the card's own Wi-Fi
    password through its admin form and rejoins automatically.
  • 📊 Bridge status in the portal — pairing state, card Wi-Fi,
    therapy-active and transfer-allowed indicators, last sync, and sync
    progress straight from the bridge.
  • 📥 Session augmentation — late-recovered stream files now merge
    into already-committed sessions instead of being discarded as
    duplicates; coverage is verified against the manifest and annotations
    are regenerated byte-identically.

🐛 Fixes

  • 🗂️ Duplicate recording folders — oximetry day labels are now a pure
    function of the recording's civil digits (ESP-local noon rule) and an
    existing recording_id under any day folder wins — DST/offset changes
    can no longer file one recording under two days.
  • 🔁 Uploader fingerprint ping-pong — duplicate recording_ids across
    day folders are deduplicated in reconcile (newest day wins) so two
    files can never take turns invalidating each other's uploads.
  • 🛑 Retry storms — any unit that fails 5 uploads is parked and
    retried at most once a day, reviving automatically when its content
    changes. A local anomaly can never again become hours of HTTP 429s.
  • 📱 Logs tab scroll — narrow screens no longer open the log view at
    the oldest line of a page-long scrollback.

🏗️ Under the hood

  • sb_proto request/response framing with reassembly; BLE ops run off
    the NimBLE host task so provisioning never starves indications.
  • Transfer ledger coordination keeps already-downloaded card files from
    re-pulling — zero redundant transfers across reconnects.
  • edf_import events rendering extracted behind a byte-identical
    emit-to-file / emit-to-set abstraction for coverage checks.
  • AS11 BLE: connection handling improvements alongside the bridge path.

✅ Testing

  • New sb_ble_test host suite: 153 checks covering pairing state
    machine, framing, reassembly and op dispatch.
  • somno_ml_worker survivor tests: guards, deadlines, SST checks,
    fragment grouping.
  • Full host suite: 31 targets, 0 failures, sanitizer-clean.

📚 Docs

  • Windows 10/11 SMB share setup guide with screenshots (contributed).

Don't miss a new SomnoTrace release

NewReleases is sending notifications on new releases.