Badge settings, reachable from the app (client #970, #971, #975)

Material 3 blue seed, light, drawn at 390×844 against the real widgets. Wire: 0xC5 as of meshcore-firmware 3e788e2a (#1801, branch epic/1788-client-settings, running on QCC2), read 2026-10-25 in OffbandConfigProtocol.h; badge screens read in BadgeScreens.cpp, BadgeLayout.h, TimeZones.h, BatteryGauge.h at the same commit. Supersedes the #970 slot mockup sent 2026-10-24. Values are examples; the bullets are the behavior to build. Built under #970, #971, #986 and #987. APPROVED 2026-10-25

The badge's screens against the app

Badge screen and rowWire (0xC5 sub-code, caps byte 2)App beforeApp after this
Tones › Sound (All, Self, None)0x01/0x02, 0x01Buzzer and tonesunchanged (frame 2)
Tones › DM, Channel, Room, New contact, Ack, Sent0x0F/0x10 EVTONE, 0x10missingsix rows + picker (frames 2, 4)
Each picker: Silent, Chime, Kerplop, Tick, Bloop, Drop, Knock, filled slotssame "picker's rule" on every setmissingone shared picker (frames 4, 7)
Picker plays each tune as you move0x11 TUNE_PLAY, 0x10missingplay button per row (frames 3, 4, 5)
Tones › Custom: all eight slots, named or "(empty)"0x09 SLOT_GET, 0x10missingslot list (frame 3)
Custom › edit a slot (keyboard)0x12 SLOT_READ + 0x0A SLOT_SET, 0x10missingeditor, prefilled (frame 6)
Channel's own tone, with Default0x0B/0x0C CHTUNE, 0x10codec built, no screen"Radio tone" in the channel sheet (frame 7)
Settings › Nav text, Message text0x13 GET, 0x14 TEXT_SET, 0x40missingScreen page (frame 8)
Settings › Screen off (15 s, 30 s, 1 m, 2 m, 5 m)0x15 SCROFF_SET, 0x40missingScreen page (frame 8)
Settings › Time zone (40 zones plus "not set", which shows ages)0x16 TZ_SET, 0x40missingzone list (frame 9)
Settings › Battery: 100% point, Set 100% here, Back to auto0x17 BATT_SET, 0x40missingBattery page (frames 10, 11)
Settings › GPS0x0D/0x0E, 0x20Location (#977)unchanged
Settings › Hibernate, Device pagesnot settings (AmberForge 1350): an action and a navigationn/an/a

One caps change to carry into the code already written: 0x10 is now TUNES (slots, channel tone, event tones, preview), not channel tone alone, and the slot sub-codes moved from the buzzer bit to it. A radio with a buzzer but no tune engine advertises 0x01 without 0x10 and keeps today's scope-only screen.

Buzzer and tones

1Node Settings gains Screen and Battery

The badge's own hardware settings sit with Button actions, gated on 0x40. A radio without it shows today's card.

Node Settings
Node name
QCC2
Button actions
Assign what the button does
Screen
Text size, screen off, time zone
Battery
100% at 4150 mV, learned
Public key
a1f3 07c2 9e44 … 5b10

2The scope, then the six tones

The badge's Tones screen, in its order: Sound first, because nothing below can sound while it says None.

Buzzer and tones
Device notification scope
All
Beep for any received message
Self
Beep only for direct messages and @[mentions]
None
Never beep
Tones
What this radio plays for each event.
DM
Chime (radio default)
Channel
Kerplop (radio default)
Room
Mario
New contact
Bloop
Ack
Silent
Sent
Silent (radio default)

3Custom tunes, every slot

Scrolled down. All eight slots are rows, as on the badge: an empty slot is where you go to fill one.

Buzzer and tones
Sent
Silent (radio default)
Custom tunes
Eight tunes stored on this radio, in RTTTL. A saved tune can be picked for any event or channel.
1 Mario
142 characters
2 Zelda
96 characters
3 (empty)
Tap to add a tune
4 (empty)
Tap to add a tune
5 Nokia
58 characters
6 (empty)
Tap to add a tune
7 (empty)
Tap to add a tune
8 (empty)
Tap to add a tune

4Pick a tone, hear it first

One picker for all six events, with the badge's list. Play auditions on the radio; tapping the name chooses it.

Buzzer and tones
DM tone
Plays for every direct message.
Silent
Chime
Now playing for DMs
Kerplop
Tick
Bloop
Drop
Knock
Your tunes
Mario
Zelda
Nokia
Cancel

5Why a preview made no sound

The radio says why it refused. The app says it in words, as the badge does with "Buzzer: OFF".

Buzzer and tones
Device notification scope
All
Beep for any received message
Self
Beep only for direct messages and @[mentions]
None
Never beep
Custom tunes
1 Mario
142 characters
Sound is off on this radio. Set the scope to All or Self to hear it.OK

6Edit a slot, starting from what is there

The editor reads the stored tune back first, so a filled slot opens with its text and can be changed, not only replaced.

Slot 1
RTTTL
Mario:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b
Plays as "Mario"142 / 240
Clear slotPlay savedSave
Read from the radio: 142 of 142 characters

7A channel's tone names its Default

The channel sheet's "Radio tone" picker (#971), now able to say what Default plays, the way the badge shows "Default Kerplop".

Channels
Radio tone
#okimesh
Default
Kerplop, the radio's channel tone
Silent
Chime
Kerplop
Tick
Bloop
Drop
Knock
Your tunes
Mario
Zelda

Screen and Battery

8Screen

The badge's Nav text, Message text and Screen off rows, with the same choices and no others.

Screen
Text size
Menus and lists
LargeMediumSmall
Messages
LargeMediumSmall
Screen off
How long the screen stays on after the last key press.
15 s30 s1 m2 m5 m
Time zone
Eastern
UTC-4 now. Message times show as clock times.

9Time zone

The badge's 40 zones, its "not set", and a suggestion: the badge suggests from GPS, the app from the phone.

Time zone
Search zones
Eastern
Matches this phone
UTC-4
not set
Messages show their age
UTC
UTC+0
Eastern
Current
UTC-4
Central
UTC-5
Mountain
UTC-6
Arizona
UTC-7
Pacific
UTC-7

10Battery

The badge's Battery screen: where 100% is, how it got there, and its two actions.

Battery
96%
Reading 4120 mV
100% at 4150 mV
Learned after a full charge
The radio learns where full is after a complete charge. Set it by hand only if the bar never reaches 100% when charged.
Set 100% hereBack to auto

11Refused, with the radio's reason

The radio refuses a reading that is not a plausible full cell, and says which way it is wrong.

Battery
Not charged yet. Charge the radio fully, then set 100% again. Nothing was changed.
71%
Reading 3890 mV
100% at 4200 mV
Default for this board
Set 100% here

Owner decisions, 2026-10-25

1. Screen and Battery under Node Settings

They are this radio's own hardware settings, beside Button actions, and they appear only on radios that have them. The rejected alternative was a new top-level "Device display" category, which would be empty on most radios.

2. Play is a separate button

The badge auditions as you move because moving and choosing are separate keys. On a phone, a tap is the choice, so play is its own button and the name chooses. A preview never changes the setting.

3. No way back to "radio default"

Firmware refuses 0xFF on an event because the badge's picker has no Default row for events, and Screen off accepts only its five steps. The app matches that. A way back would be a firmware change.

4. "Menus and lists" and "Messages"

The badge says "Nav text" and "Message text", which fit 21 columns. The app has room to say what each governs.

Why these choices

The radio is the record, everywhere

Every reply on this list re-reads after the write: EVTONE and CHTUNE carry stored and effective, SCREEN carries the whole set. The app draws only from replies, stores none of it, and so has nothing per radio to isolate (#853) or to drift.

The app offers exactly what the badge offers

Firmware refuses anything its own screens would not offer. Building each list from the same rule (named built-ins plus filled slots, five Screen off steps, three sizes, the zone table) means the app never offers a choice the radio will reject.