24 KiB
Changelog
All notable changes to Offband Meshcore. Pre-releases are tagged -beta.N / -rc.N.
[1.7.0] - 2026-10-26
Production successor to 1.6.0. A foundations release: per-message storage with a one-way schema upgrade, radio-profile isolation, sync-is-truth contacts, custom contact names, region scoping, a Settings restructure, and CLI for stock 1.18 companions.
Storage (one-way upgrade, schema 1 to 2)
- History stored one drift row per message with a verified blob-to-rows migration; save cost no longer grows with history (#917, #920).
- Blob read-modify-write, DM save merges, and both delete paths moved off the UI isolate (#919).
- A newer schema is refused loudly instead of rewriting the version; the migration gate asserts a superset, so keys with extra rows no longer stay stuck (#943, #952).
- Stale blob reclamation: per-key migration timestamps, an automatic sweep after 30 days, a durable audit of what it deleted, and Clear Stale History Now in App Settings > Storage that reports refusals (#962, #965, #966).
- Earlier versions cannot open a schema-2 database; disclosed in the release texts (#953).
Radio-profile isolation (#853)
- Scoping inventory with a verdict gate, and repros of the remaining bleeds (#936).
- Path history and delivery observations per radio; dead
pending_messagesAPI removed (#937). - Discovered contacts per radio (#754); a blank radio is no longer pre-blocked from another radio's list (#471); Blocked pane says "No radio connected" (#938).
- Storage scope keys cleared on an unexpected disconnect, closing the stale-read window (#939); full isolation matrix across a radio switch and a restart (#940).
- Channel notify modes scoped per radio, index fallback removed, set-and-back resets (#839, #848).
Contacts
- Sync is truth: live adverts (0x8A, 0x88) feed discovery only; the persisted list comes from the radio's contact sync, with a debounced incremental reconcile when an advert matches the radio's auto-add policy (#838, #842, #850).
- Custom Name:
customNameoverreceivedName, kept off the wire and out of exports and contact shares, scoped per radio (#750).
Region scoping (#812)
- Region model and name-derived transport key; flood-scope frames and anon-regions
discovery, gated on
FIRMWARE_VER_CODE >= 13(#813, #820, #821, #822). - Discover Regions service and screen (#814, #825, #826); per-channel region-scope store, Set Region Scope action, and per-send scoping (#815, #829, #830, #831).
- Hardware fixes: searchable, path-aware repeater picker; corrected discovery request format, multi-hop reply path, firmware-estimate timeout, one auto-retry (#830, #836).
Settings and badge parity (#975)
- Location is a top-level category and the only home for GPS (#977); Button actions in Node Settings, Buzzer and tones in Message Settings (#978).
- Over 0xC5, capability-gated: GPS mode and power-save interval (#969), event tones (#986), custom tunes with RTTTL order check and Fix order (#970), screen settings (#971, #987), channel tune codec (#981). Requires Offband firmware not yet released.
- Config import/export, GPX exports, and "Sync queued messages now" moved to Actions; Debug reordered (#902).
CLI (stock 1.18 companions)
- Population classifier and capability-gate rework (#866, #875, #876, #877, #878, #880); stock 1.18.0 classified by frame shape, not version suffix (#946).
- Companion CLI codec (frame 66/29), local CLI service, and Device CLI console (#868, #881, #882, #883, #884).
- Remote CLI to companions: contact permission flag 0x10, role-based TXT type, command service generalized to companions, inbound type 3, CLI kept out of chat, console offered only on a 1.18 radio (#870, #887, #888, #889, #890, #891, #999).
Bluetooth and stability
- Bounded, interruptible auto-reconnect: 5 attempts or 3 minutes, Stop ends it, a user connect wins; a connect waits for a disconnect still in progress (#996, #997).
- Windows: use-after-free crash on app close fixed (#989).
- ANR and exit-record capture via ApplicationExitInfo, shipped with the exported log (Android 11+) (#906, #910, #931).
Fixes
- Channel hop counts decoded from the packed path-len byte, so 2- and 3-byte path hashes render the right hop count (#985).
CI
- CI no longer reports a pass without running; Linux pinned to ubuntu-24.04 (#927, #929); docs-only changes short-circuit the required checks (#904, #905).
[1.6.0] - 2026-10-05
First stable release of the 1.5.0 line and the production successor to 1.4.0. A large feature release: a full contacts overhaul, stock-compatible config and identity export/import, region radio presets, and contact-sync recovery, on top of the 1.5.0-beta.1 groundwork (Experimental section, CoreScope, About).
Contacts
- A received contact-share on a channel renders an Add Contact card/chip (#610).
- Share your contact into a channel from a + picker (#611).
- Contact QR: show your contact as a QR and scan one to add (#629).
- Add a contact by public key, typed or pasted, or from a key alone with no advert (#627, #628).
- Parse and emit the stock contact-share URI, so contacts cross between Offband and stock MeshCore (#625, #626).
- A contact shows how far its identity is confirmed (#630).
- Add, view, or block a channel sender from an avatar tap or long-press (#565, #468).
Config and identity portability
- Stock-compatible config export and import screens and services (#572, #573, #574, #575, #576).
- Connector identity export/import, with an auto-add hop limit (#578).
Radio presets
- A region-grouped preset picker labeled by source, crediting Liam Cottle / MeshCore for the upstream presets (#727, #728, #729, #731).
- Apply a preset's path hash to a companion, observer, repeater, or room server (#730, #735, #649), with the picker in repeater and room-server settings (#734).
Sync and reliability
- Detect a short contact sync and recover it with paced, capped re-syncs and by-key checks, with a banner reporting the recovered count and contacts confirmed gone (#762, #763, #764, #674).
- Apply a remote radio setting temporarily (tempradio) (#662).
- Manage a sensor like a repeater (#745).
- Composer byte-budget logging so a debug log can evidence the BLE composer issue anywhere (#793).
Experimental and UX (from the 1.5.0-beta.1 groundwork)
- An Experimental section unlocked by a 7-tap on the Build row; disabling it clears every experimental toggle (#509, #553).
- OKIMesh CoreScope (Experimental): per-packet observer counts from OKIMesh's CoreScope service. Requires forthcoming Offband firmware and stays inert until then (#549, #550).
- An About screen in its own Settings category (#526, #527).
- Notifications moved from a bottom SnackBar to a top toast (#638).
Bluetooth reliability
- The composer is no longer locked by an unreported BLE MTU: the negotiated MTU is now reported on Linux (#717) and Windows (via a vendored BLE plugin with live MTU updates) (#686), and the floor that locked it on web is lifted (#718). A link that truly cannot carry a message explains why instead of showing a dead field (#684).
- Bounded GATT-133 connect retry with human-readable errors (#698); an unconfirmed disconnect retries and warns instead of being swallowed (#697); leaked GATT handles are closed (#696).
- USB serial no longer drops bytes: mutexes initialize before the reader runs, and each callback drains fully (#710, #711).
Fixes
- Delivered direct messages are no longer marked failed: send correlation adopts the radio's RESP_CODE_SENT ACK hash (#581).
- A short or unreadable contact sync never overwrites saved contacts, and a silent stream ends on its own (#671, #673, #672).
- Names are no longer truncated mid-codepoint on the wire (#636).
- Late repeater replies go to the app log, not the user's screen (#589).
- Add-contact failures and unknown channel-sender names surface instead of a dead tap (#565).
- CoreScope distinguishes not-found from unreachable (#678); web identity rebranded (#608).
Known issues
- Windows BLE Disconnect can leave the radio held by the OS until replug (#688).
[1.5.0-beta.1] - 2026-08-04
First beta of the 1.5.0 line, for the closed test track. Introduces an Experimental section (with CoreScope), an About screen, and repeater CLI and broker fixes.
Added
- Experimental section, unlocked by a hidden 7-tap on the Build row in settings. Disabling it clears all experimental toggles (#509, #553).
- OKIMesh CoreScope integration (Experimental). Query how many OKIMesh CoreScope observers heard each packet, over the 0xC6 protocol, with an observer/observations badge, adaptive polling with backoff, and tap / long-press to refresh (#549, #550). This is tied specifically to the OKIMesh CoreScope service, not a generic or self-hosted backend. Requires forthcoming Offband firmware (0xC6, cap2 bit and firmware ver code >= 22, tracked in #611); it stays inert on current firmware.
- About screen in its own top-level Settings category, with outbound links to the website, Play listing, and donate page (#526, #527).
Fixed
- Repeater CLI: late replies are surfaced instead of discarded, commands get their own timeout budget, the armed timeout window is reported accurately, and a prefixed reply only completes the command that owns the prefix (#528, #529, #531, #532, #533).
- Broker: import never changes the broker enabled state, and a blank-field GET no longer leaks the echoed key line (#469, #470).
- Channel "Send Again" is gated on
repeatCount == 0rather than sent status (#555).
[1.4.0] - 2026-07-30
A follow-up to the 1.3.0 production launch: settings for headless devices, a resend action for channel messages, and a batch of per-radio data-correctness fixes.
Added
- Button and buzzer settings for headless devices, capability-gated so they only appear on radios that report support (#483).
- "Send Again" resend on channel messages, with the direct-message resend action relabeled to match (#513).
- Device Info shows the second offband capabilities byte, so more capability bits are visible at a glance (#480).
@[name]self-mention matching is now ASCII case-insensitive, so a mention matches regardless of case (#486).
Fixed
- Block list is scoped per radio again: an accidental global block list was dropped, so blocking on one radio no longer leaks to another (#505, #506).
- Per-radio in-memory caches are cleared on reconnect, so data from a previously connected radio cannot linger into the next session (#472).
- Translation-model downloads retry transient 5xx errors with backoff instead of failing outright, and the backoff tracks actual elapsed time (#425).
@[name]mentions are treated as a verbatim wire token (no stray trim), matching the reference contract (#497).- Routed replies are sent at the contact's path-hash width instead of width 1 (#495).
Under the hood
- CI now guards against em-dash characters in
lib/andtest/(#464).
[1.3.0] - 2026-07-30
The first Offband release published to the Google Play production track. A large feature release on top of the 1.2.x line: cross-client reactions, Observer config profiles, log and serial-capture export, a reorganized Settings screen, richer path diagnostics, and a batch of reliability fixes.
Reactions
- Incoming reactions now record who reacted, not just the tally, and a room's own reaction is no longer misattributed to the room name (#383).
- Emoji reactions from PocketMesh / MeshCore One are parsed and rendered instead of showing as raw token text; sending is unchanged (#380).
Observer config profiles
- Import an Observer config profile from the federated catalog or a URL, preview a field-by-field diff against the current config, and apply it, with the wiring reachable from Observer settings (#404, #405, #406, #407).
- Profiles are defined by a YAML schema organized into capability sections; config fetches are cache-busted so a re-import never serves a stale copy (#402, #403, #456, #404).
Diagnostics and export
- Share the App log and BLE log as a file: Save As on desktop, download on web, system share sheet on mobile, using the platform-standard share icon (#393, #427, #433, #396).
- New serial / boot-log capture screen under Debug: enable/disable/erase/status control, a chunked download protocol with reassembly, live status polling, and a "Reboot device" action for boot-log capture (#430, #428).
- The message Path screen now shows the path type, per-message SNR, and per-message RSSI read from the reserved RX fields (#438, #439).
- Device Info shows the running build identity (branch @ sha, build time) and the active radio data scope (#397, #295).
Settings
- Settings categories reordered, with Observer moved above App Settings and the app debug-logging toggle moved into a Debug category (#271, #272, #273, #274).
- Per-channel notification mode is reachable from the channel ellipsis menu (#275).
- New keep-screen-awake setting (#269).
- The advert notification setting was renamed to plain language and a stale "Notifications" subtitle was dropped (#270, #276).
Reliability and fixes
- Sending a max-length DM or channel message no longer wedges the send path: the size cap is MTU-aware and a failed write is recovered instead of stalling all further sends (#395).
- Live channel-change push (0x91) with debounce so a burst of changes coalesces into one re-sync instead of many (#429).
- A storage-init failure now surfaces a persistent warning instead of failing silently (#385).
- Desktop builds bundle their native-assets DLLs (sqlite3, llamadart) so they run on a clean machine, including on Linux (#445).
- Back-button behavior refined: Back pops out of a channel and only top-level tabs background the app; the dead top-level back arrow is hidden on a pinned desktop layout (#389, #390).
- Android warns when the app is under battery optimization and guides the user to exempt it, including from the scanner screen (#443).
- Send-side Smaz compression removed (phase 1), and a stable per-install client id is sent in CMD_APP_START (#420, #297).
Storage
- Desktop (Windows/Linux): message history that was split across several older database files is now reunited. On launch, every discovered legacy store is unioned into the pinned database (messages by id, contacts by public key); source databases are never deleted, and a failed run leaves them intact and retries (#367, #370). Builds on the earlier fix that pins the desktop database to one fixed location (#363, #364).
[1.2.2] - 2026-07-21
A follow-up to 1.2.1 that recovers desktop history left behind in other databases.
Fixed
- Desktop (Windows/Linux): 1.2.1 pinned the database to one path but migrated only a single prior store. A user who had run several differently-built copies could have message history split across multiple databases, leaving the extras behind. On launch, every discovered legacy store is now unioned into the pinned database (messages by id, contacts by public key), so previously stranded history is brought back in. Source databases are never deleted; a store that cannot be read or is over a size guard is skipped and retried on a later launch, and a failed run leaves every source intact. Android, web, and macOS were unaffected (#367, #370).
[1.2.1] - 2026-07-21
A patch fixing a desktop data-location bug in 1.2.0.
Fixed
- Desktop (Windows/Linux): the drift / SQLite database was stored in a directory
derived from the executable's build metadata, so a differently-built copy read
a different, empty-looking database and history appeared missing. The database
is now pinned to one fixed path (Windows
%APPDATA%\Offband MeshCore; Linux likewise), and any existing database is migrated in on first launch via a safe SQLiteVACUUM INTOsnapshot, aborting cleanly on failure with the source left intact. Messages were never deleted. Android, web, and macOS were unaffected (#363, #364).
[1.2.0] - 2026-07-21
A major uplift: the storage engine moved to a real database, the app got a new navigation shell, and GIFs are now shareable across MeshCore clients. First release cut end-to-end through CI (signed, all platforms).
Storage
- Bulk data (messages, contacts, channels, and more) now lives in a drift / SQLite database instead of individual SharedPreferences entries. Existing data is migrated automatically on first launch and preserved, not discarded (#335, #355, #348).
- The database is stored in the app-support directory, so it is not caught up in OneDrive/Documents sync on desktop (#335).
- Message history is kept in full; only the in-memory window is bounded, so reopening a conversation no longer risks losing older messages (#343).
- Storage failures that used to fail silently now surface (#306, #333).
Navigation
- New app shell with a hamburger nav drawer that can be pinned open (#292).
- The channel list lives in the drawer and is switchable from inside a channel; channels swap in place so a pinned panel stays put (#289).
- Map layer toggles moved into the nav panel; Disconnect and Settings moved into the panel footer (#291, #290).
- Contacts gained a prebuilt filter rail, including a Sensors type (#307, #308).
- Back-button behavior fixed: back now backgrounds the app instead of killing it, and no longer drops a user off a connected radio (#291).
GIFs
- GIFs are now shared as a Giphy URL instead of the Offband-only
g:<code>, so other MeshCore clients can open them (#282). - Pasted Giphy / Tenor URLs render inline, behind a trusted-host allowlist (#283, #284).
Other features
- Desktop window position and size are remembered across launches (#349).
- Reach a contact's settings from its long-press menu (#351).
- FEM LNA toggle in Radio Settings and Offband capabilities shown in Device Info, gated on firmware support (#304).
- Message arrival time (rxTime) is logged and persisted, distinct from the claimed send time (#285).
Fixes
- You can no longer accidentally block your own node (#250).
- Path length decodes per the firmware contract (width-aware), and path diagnostics report units truthfully (#309, #298).
- Connecting no longer rewrites the entire preferences file per channel (#306).
Under the hood
- Offband is now available as a web app at offband.app, and every release is built, signed, and published across Android, Windows, Linux, and web through CI.
[1.1.2-rc.3] - 2026-07-17
Combined entry for rc.2 (versionCode 59) and rc.3 (versionCode 60). Both shipped to the Play closed test with only a version bump; this backfills the changelog they should have carried.
Added
- Block / mute system: block a contact or a channel sender from contacts, DMs, discovery, or a channel message; blocked DMs and adverts are suppressed with a visible marker, and a name-only block promotes to the sender's public key on the next advert or DM and ages out after 30 days. Managed from Settings → Blocked. Synced to firmware on connect where the radio supports it (#168–#180, #172–#174, #169, #170).
- Per-channel notification modes: a 3-way selector (all / mentions / mute) on the Channels screen, applied at the notification gate and stored keyed to the channel PSK (#260, #261, #262).
- Path trace and topology: width-matched path tracing, a topology service and readout, RX ingestion, and a route-builder UX that groups hops by hash width rather than raw bytes (#150, #186, #156, #155, #224).
- Channel QR: share a channel as a scannable QR and scan one to add it, unified with the community scanner and using the reference-app format (#163).
- Own device public key is now full, selectable, and one-tap copyable (#234).
- Reply-to chip shown above a reply-gif, with inline
@[Name]mention chips (#235). - GPS refresh falls back to stock-firmware self-telemetry when the fork-specific query is unavailable, chosen by firmware capability (#123).
- Queue-sync diagnostics: a file log of queue-drain activity plus a manual force-drain action (#51).
Fixed
- USB open no longer wedges ESP32-C6 boards: the DTR open pulse is gated by USB vendor ID, so it fires only for nRF52 reconnect and is skipped for chips it would reset into ROM download mode (#248).
- Outgoing DMs to a blocked contact are dropped at the send path (#252).
- Contact path-length byte decodes at the device's hash width instead of being read as a raw byte count (#224).
- Stale channel slot history is cleared on channel reassignment, and the message store's device-key scope is aligned (#193, #194).
- Enter selects the highlighted emoji or mention in autocomplete (#238).
- Manual path entry honors the configured path-hash width (#155).
Changed
- The fork-only GPS query is gated on firmware capability, so stock and non-Offband radios degrade gracefully instead of erroring (#123, #144).
1.1.2-rc.1 - 2026-06-28
Added
- Channel reply UX: replying focuses the composer, and one-click route-reply sends back along the path the message arrived on (#131, #106).
- Device Info shows the connected radio's firmware version and model, and logs them to the app log on connect (#134).
- GPS state query — when a GPS-capable radio (Offband firmware) has GPS enabled, read its live GPS state (detected / fix, coordinates, satellites) from Settings → Location (#135).
Fixed
- BLE write flood (
recv_queue/send_queuefull) during sync on slower links: the per-minute GPS refresh no longer re-initializes the whole device each minute (which had been re-walking channels and re-draining messages) (#140). - Repeater path-hash labels decode at the device's hash width, so multi-byte hashes render correctly (#115).
Changed
- The fork-only GPS query (
0xC1) is gated on firmware capability, so stock / non-Offband MeshCore radios are never sent a command they can't answer; the GPS status section is hidden on unsupported firmware (#144).
Known issues
- The connect-time contact load can hang (red sync bar stuck) if a contact frame is lost — there's no timeout/watchdog yet (#86); reconnect to clear it.
- Companion message-sync may miss public history after a long offline gap (#91); a firmware-side fix is in progress.
[1.1.2-beta.3] - 2026-06-24
Added
- Diagnostic logging of the Observer broker-pool fetch lifecycle (request sent, header count, completed with N brokers + timing, or failed with the reason) to the shared log, so a Share-logs capture shows in plain text whether a pool load succeeds or stalls (#108).
[1.1.2-beta.2] - 2026-06-24
Fixed
- Observer broker pool no longer falsely reports "the device did not finish sending it" on large pools — the broker-list GET now uses an inactivity watchdog re-armed on each frame, so a pool that streams over several seconds completes instead of timing out at a fixed deadline (#103).
1.1.2-beta.1 - 2026-06-24
First public beta.
Added
- Observer config + MQTT broker editor: field-at-a-time SET with enabled-last activation, honest enable/disable that verifies the device actually applied the change, and broker runtime-state + resolved-default hints (#80, #89, #93).
- Cross-platform file logging to a rotating file under the app support directory, with "Open logs folder" (desktop) / "Share logs" (mobile) on the log screen (#97).
- Friendlier repeater path-hash labels (#90).
- Self-contained Windows packaging that bundles the VC++ runtime so the zip runs on a clean machine (#96).
Fixed
- Channel sync advances immediately on a device error instead of stalling on empty channel slots (#82).
- The BLE connect handshake retry is capped with backoff so it can't churn the connect or starve the contact-list load (#88).
Known issues
- Companion message-sync may miss public history after a long offline gap (#91); a firmware-side fix is in progress.
- MQTT broker / Observer features require the firmware currently in review.