Repository navigation
epic(#726): in-app radio preset catalog and picker (Companion/Observer) - #744
Merged
Merged
Conversation
RadioPreset carries frequency, bandwidth, SF, CR, and optional TX power, path hash (bytes) and off-grid flag, plus its region and source. parseUpstreamPresets reads the mirrored MeshCore list (string numbers); parseOverlayPresets reads Offband's overlay (JSON numbers, retired entries dropped). Malformed entries are skipped and counted; a wrong format or a newer format_version is rejected. Upstream titles carry no region, so upstreamRegionFor derives the picker group from the title. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Presets publish path hash size in bytes; firmware takes a zero-based mode (1 byte = mode 0, 2 = 1, 3 = 2). RadioPreset.pathHashMode does the conversion and returns null when the preset carries none or an out-of-range size, so nothing is sent. Tests pin all three sizes and that a published 2 never becomes mode 2. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rom config-profiles RadioPresetService starts from the last good copy of each preset file, or the copy bundled in assets/radio_presets/ (config-profiles 857d4e9), so the picker works offline. refresh() fetches both files from config-profiles; each file that parses becomes the new saved copy, and one that fails or comes back empty never replaces a good one. Failures are logged and kept in refreshError for the picker to show. refreshIfStale() refreshes at most every 12 hours. The merged list puts the overlay over upstream on a matching title, sorted by region. An overlay edit in config-profiles therefore reaches users on their next refresh with no app release (test: "an overlay edit reaches the app with no new build"). Closes the gap recorded in #648. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… source Radio Settings now takes its presets from RadioPresetService instead of the hardcoded list, which is removed (radio_settings.dart keeps only the LoRa enums). The picker, extracted as RadioPresetPicker for reuse on the remote-node screen, groups presets under non-selectable region headers, labels each MeshCore or Offband, and shows where the list came from with a refresh button; a failed refresh stays on screen in the error colour. Selection is tracked by preset id rather than list index, because a refresh can change the list under an open form. Upstream presets carry no TX power, so a preset without one matches any power and applying it leaves TX power as it is. The form refreshes a stale list when opened. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…save Saving Radio Settings already sends radio params (cmd 11) and TX power (cmd 12). When the selected preset carries a path hash size, save now also sends CMD_SET_PATH_HASH_MODE (61) with the zero-based mode. It is sent whenever the preset has one, not compared against the reported width, because that reads as 1 when device info is short (#240). Off-grid repeat handling is unchanged. The CMD_SET_RADIO_PARAMS comment said the frequency was in Hz; stock firmware stores freq / 1000.0 as MHz, so it is kHz. Comment corrected. A frame test pins the bytes a preset puts on the wire. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The About card gains a credit line under the existing MeshCore Open attribution, and the licenses page gains a "MeshCore suggested radio presets" entry naming Liam Cottle, api.meshcore.nz, MeshCore and the config-profiles mirror, alongside the Open-Meteo entry. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RadioPreset.frequencyHz returned kHz; renamed frequencyKHz (the unit CMD_SET_RADIO_PARAMS carries). The picker is disabled while a refresh runs, so a pick can't vanish when the refreshed list lands, and the selected-item builder uses an id-to-title map. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 1, 2026
… as Canada MeshCore's "Canada" and "USA" share 910.525 / 62.5 / SF7 / CR5 and differ only in path hash (Canada 3-byte). Matching ignored path hash, and Canada sorts first, so a USA radio showed "Canada" (D1 screenshot). A preset with a path hash size now matches only a radio on that size; presets without one match as before. Epic: #726 Agent: MagentaHawk (session 5a8922d6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every preset test faked the network, so presets missing from config-profiles main passed them all and reached the owner as "Couldn't update presets" on a test build twice. The live test refreshes from the real URLs and fails on any refresh error; a second live test proves a missing file comes back as HTTP 404. The picker test now checks that a good refresh shows no error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Epic B of Feature #647 (plan of record:
docs/initiatives/standalone/647-mesh500-presets/PLAN.md). Epic: #726.What this changes
The companion and observer Radio Settings presets now come from a catalog instead of a hardcoded list:
What the user gets:
assets/radio_presets/, and refresh without an app release from config-profiles. The picker refreshes when opened if the list is over 12 hours old, or on demand with its refresh button.Verification (B6, #732)
CI-equivalent gates, run at the branch head:
check_no_emdash.py: OK.flutter analyze --fatal-infos --fatal-warnings: no issues.dart format --set-exit-if-changed: 0 files changed.flutter test: all passed (1 skip predates this work).New tests:
Hardware validation is the owner's, at Epic D (#737), per the plan.
Pre-PR Gemini review
scripts/llm-consult.py --backend gemini --model gemini-2.5-pro. Audit log~/.claude/llm-consultations/meshcore-open/2026-10-01-gemini-epicB-prompt-gemini-gemini-2.5-pro.log. Cost $0.0295.RadioPreset.frequencyHzreturns kHzfrequencyKHzin the new model. Its suggested call-site change usedbuildSetRadioFrame, which doesn't exist (rejected). The older_RadioSettingsSnapshot.frequencyHzis left as it was (out of scope)selectedItemBuilderlooks up each title linearlyAgent: MagentaHawk (session 5a8922d6)
🤖 Generated with Claude Code