49 new TR() keys (the Pager key help, Quiet now, Shift + knob level pill,
emoji and quick-reply hints, lock and theme notes), appended as key<TAB>key
to the 14 files #755 did not translate, and the 3 invariant ones (Backspace,
N, M C H A S) to de.lang, only where the key is absent. i18n-audit is clean;
i18n_builtin.h regenerated: unchanged (placeholders are not baked).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
de.lang conflict: main's rows since the PR's base (picture dimming, the 19
missing rows) and the PR's German rows unioned, one row per key, the later
(translated) row kept. Header stays at main's ver: 31. i18n_builtin.h
regenerated with scripts/build/gen-lang-builtin.py; only the German table
changes (1334 rows).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Settings group heading "Connections" had no row in any language, so it
stayed English (CONNECTIONS above Polish rows). The headings come from
kSettingsGroups through `for (const SettingsGroupDef& g : kSettingsGroups)
... TR(g.title)`, and i18n-audit.py's range-for rule only recognised
`for (auto& x : table)`, so the key never reached the audit. The rule now
takes any element type.
The audit then lists 18 more keys added since the last pass (the old-contact
purge, vibration, browser-build notes, the web location prompt). All 19 get
a row in all 15 files: real translations in de, nl, fr, es, it, pt-br and pl,
English placeholders elsewhere. i18n_builtin.h regenerated (V4 +3.9 KB).
i18n-audit.py: every file ok.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A background picture was always toned down by a fixed amount (night: x107/256,
then every pixel held to a luma of 64; day: lifted 60% toward white, held up to
200), and the lock-screen wallpaper always sat under a black veil of 105/255.
On a dark theme that left a picture barely visible. Both now take a step: Off,
Light, Medium or Strong.
- Settings > Theme > Background: "Picture dimming" under the picture's button,
shown while Image is picked; part of the page's pending choices, saved by
Apply and restart (bgImageFit applies it once at boot).
- Settings > Lock screen > Look: "Wallpaper dimming", applies the next time the
lock screen shows (veil 0 / 40 / 72 / 105).
Strong is the default and an absent key reads as Strong, so nothing changes for
anyone until they pick a step: PictureDim.h holds the per-pixel step, and
test/test_picture_dim.cpp checks Strong against the old formula on 281k
samples, plus range, ordering and the per-step readability bounds. New keys
bg_dim and lock_dim are standalone uchar keys in the settings backup list.
Three new strings, rows in every .lang, i18n_builtin.h regenerated.
V4 (no picture option there): +1624 B flash, the string table.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Discord (gadgeteerza, ThinkNode M9, beta_100): no Central Africa zone, the
clock often half an hour behind on a Custom UTC offset, and "Sync clock from
system" with Wi-Fi on not always setting it.
Zones: the saved setting is an index into the zone table, and Custom used to
be "one past the list", so appending zones would have moved it. Custom now
keeps its id (16) forever and the new zones (Central/South/East/West Africa,
Egypt, Eastern/Western Europe, Moscow, Turkey, Arabia, Iran, Gulf, Pakistan,
Nepal, Bangladesh, Indochina, Singapore, Perth, Korea, Adelaide, Brisbane,
New Zealand, Argentina, Mexico City, Newfoundland) sit after it. The picker
shows its own west-to-east order and opens on the current zone.
Half an hour behind: not the offset. WadaNmeaLocationProvider::begin() kept
the parser's pre-rest sentence, so after a GPS saver rest the first loop pass
saw a "valid" fix, the 30-minute re-sync was due, and the clock was set to
the moment the receiver went to rest. begin() now clears the parser, and
UITask::setGpsPower(true) calls syncTime() so the core provider (V4 and
others) gets the same. test_gps_time_sync runs the real provider against a
receiver sending true UTC: the pre-fix provider set the clock 1801 s behind
after a 30-minute rest; now every set is within 1 s.
Sync from system: on the M9 the system clock is the device clock, so the
button copied a clock onto itself. And the Wi-Fi loop wrote only the FIRST
SNTP result into the mesh clock: SNTP's hourly re-syncs set the system clock
only, the PCF8563 kept its old value, and the hourly chip resync (#583)
pulled the clock back to it. Every completed sync is now written through
(SntpClockPush.h, test_sntp_clock_push), and the button with Wi-Fi up
restarts SNTP and says "Clock synced" when the answer lands.
test_time_zones: the legacy ids keep their zones, every zone's offset in
January/July/October, Egypt's DST edges, and all 65536 saved
(tz_zone, time_offs) byte pairs through the exact prefs path to localtime().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
German rows for the strings the Pager work added: vibration settings, the
battery gauge lines in the popup, chart, lock screen and screensaver, charge
limits, battery care and the low-battery warnings, the battery pack capacity,
the motion settings, the shortcuts and key help, the ship-mode power-off
notice, the knob hint in the emoji picker, the lock and battery settings
notes. Also translates two rows that still carried the English text ("Sound is
off", "Do Not Disturb is on").
The English placeholder rows main appended for #748 to #751 are replaced in
place (the last row wins), the new ones are appended, and the file's version is
left as it is. i18n_builtin.h regenerated with scripts/build/gen-lang-builtin.py.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josh <8422439+MrYoshii@users.noreply.github.com>
73 new TR() keys (vibration, charger and gauge, battery care, low battery,
motion settings, ship-mode power-off), appended as key<TAB>key to all 15
.lang files so translators see them; English until translated. Appended at
the end and only where the key is absent, so no existing translation is
shadowed. i18n_builtin.h regenerated: unchanged (placeholders are not baked).
The 17 keys i18n-audit already reported missing on main are left as they were.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nine new strings of @kremers' Map file picker and zoom limit had no rows in
the .lang files. nl, de, fr, es, it and pt-br are translated, the other
languages carry the English text until a translator picks them up.
i18n_builtin.h regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SenseCAP Indicator's partition table has no tiles partition by design,
and its microSD slot is wired to the RP2040 co-processor, which this build
does not drive. The map fell through to the generic "Map storage error.
Reflash the tiles partition." advice, which no reflash can satisfy.
New CAP_TILE_STORAGE (default 1, 0 on the Indicator) picks an honest
message instead. New string in all 15 .lang files (de, es, fr, nl
translated).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Constellation is not heading-up: it places nodes by true bearing, but
for burn-in the whole picture turns slowly about you (half a degree every
5 s, a turn an hour, following the time since boot), so north and its N
marker go round with it.
Settings > Display > Screensaver gets "Keep north up" (off by default):
the turn stays at 0 degrees, so north is at the top. The few-pixel drift,
your own node's pulse and the status changing corners still keep pixels
moving. Stored as a standalone key (ssaver_north) like the other
screensaver settings: no schema bump, no migration. The row greys out with
the screensaver off, like the others.
CAP_SSAVER_NORTH_LOCK gates it, 0 on the Tanmatsu for its AppFS ceiling
(its screensaver keeps turning, as before). nl, de, fr, es, it and pt-br
translated; the other languages carry the English for now.
test/constellation_render's render takes CST_UPTIME_MS and
CST_NORTH_LOCK=1, to render the turn 45 minutes in, with and without it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Based on @oumike's draft PR #709, made to compile and checked off-device.
- P4 SD: Launcher reads the card over SPI, and a card in SPI mode ignores the
native-mode CMD0 every SD_MMC mount starts with until it loses power. After
a failed first mount, power the slot off with all six SD lines driven low
for 300 ms, then retry the first rung before the slower ones.
- P4 store: the boot log names the 'storage' partition and its size, or says
it is missing (Launcher's own partition table from the app-only .bin), and
a boot alert says identity, channels and contacts cannot be saved. No
fallback onto another data partition: under Launcher that belongs to
another app.
- Restore: uiImportBackup reports when the identity or node prefs could not
be written (out_saved). The picker and File Transfer's Restore then say so
instead of "Imported N contacts" and a reboot into an empty store. The
BackupImport enum now sits outside the WADA_WEB_FILE_TRANSFER block (the
draft did not build without it), and the web stand-in mirrors out_saved.
- Two new strings in all 15 .lang files (de, es, fr, nl translated).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
T-Deck Plus receivers talk 38400 or 9600 depending on the unit, and newer
ThinkNode M9s 115200, so owners had to find Settings > GPS > Serial speed.
Both boards now build their GPS on WadaNmeaLocationProvider with the UART
probe the Pager, T-Deck Pro and P4 use: it tries 9600, 19200, 38400, 57600
and 115200 until a sentence with a valid checksum arrives, and locks there.
Unlike those boards it runs only while the user has not picked a speed
(CAP_GPS_BAUD_FIND): Serial speed gets an Auto tile, the default, and a picked
speed is used as it is. The speed Auto finds is kept in its own NVS key
(gps_bd_fd), apart from the user's choice and outside the settings blob, so
an older firmware never reads it as a choice; touchPrefsGetGpsBaud returns it
when nothing is picked, so the core opens the UART at the right speed on the
next start. It is written once per change of receiver, from the loop task.
The T-Deck also gets the provider's u-blox GNSS stop/start while GPS rests
(it has no enable line); receivers that do not speak UBX ignore it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contact Management (the renamed Auto-add page, which lost its old
translations with the rename), the auto-delete toasts and the four
vibration pattern names. Keeps the audit at main's count.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pl.lang: 2,132 of 2,174 strings translated (tom73god on Discord), no
format-specifier mismatches. It joins the language store at the next bump.
apps.html is the page deploy-site regenerated for beta_99.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#740 adds its "Rooms" row at the end of the same 15 files, so whichever
merged second would conflict in all of them. The row sits next to the
other "default" wording now, away from every open PR's language hunks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJdUwLehmpBq5ea6Xbpeg2
The Import picker and the Saved backups list on Settings > Backups showed
each backup's full file name, cut off with "..." on most screens. Rows now
show the date stamped into the name ("2026-06-12"), or "Default" when the
name has none (meshcore-backup.json, nodate-N, any copied .json).
Rows that would read the same gain the time (12/24 h setting), then where
the file is (SD / Internal), then a running number. Both lists share
backupListLabels(); on OOM they fall back to the file names. "Default"
added to all 15 language files.
Fixes#739
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJdUwLehmpBq5ea6Xbpeg2
The Contacts Filter sheet gets a Rooms option, listed under Repeaters, that
shows only room servers (ADV_TYPE_ROOM); the header button reads "Room".
It is filter value 6 in ctPassesFilter(), so the list, Select-all and
search all follow it. Peers is unchanged and still includes rooms.
Language rows added for all 15 languages (kept as "Rooms", like "Room").
Fixes#736
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJdUwLehmpBq5ea6Xbpeg2
The button now names the next press: "Stop" while a survey runs, "Start" when
it is idle, instead of always reading "Start". Keep the button handle and
relabel it on toggle rather than rebuilding the screen, which would reset the
page scroll.
Relabelling a button is only safe on firmware that carries the button:set fix,
so gate it on caps().panel, the same guard the music app uses; older firmware
keeps the fixed label and reports the state by toast.
Assisted-by: OpenCode:deepseek-v4.1-flash
Signed-off-by: Sebastian Rutofski <kontakt@sebastian-rutofski.de>
A CrowPanel 10.1 with a C6 on esp-hosted 2.3.0 (host 2.12) ran fine for a day,
then crashed or hung at every boot once a network was saved, since Wi-Fi then
starts on every boot; Wi-Fi scans and BLE never worked on it either. Now that a
crash restarts the device instead of halting, it would loop.
WifiCrashGuard keeps a marker in RTC no-init memory while Wi-Fi runs. A panic or
watchdog reset within 60 s of starting Wi-Fi, or a second one with Wi-Fi on
within 30 minutes, switches Wi-Fi off in the settings and the next boot says so.
With Wi-Fi and BLE off the C6 is not started at all. T-Display P4 and CrowPanel
P4 10.1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nine new keys in every .lang file: the "Use the trackball" switch and its
note, the Trackball on/off toasts, "press Enter to unlock" for the lock
screen and the lock-on-screen-off note, the power-off toast that points
at the reset button, and the P4 keyboard-light row ("Low" and its F11
note). Translated where the existing rows give the wording; pl, and "Low"
(matching the untranslated "Medium"), get English placeholders.
i18n_builtin.h regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No textual conflicts. Checked by hand: device_caps.h keeps the WADA_WEB
block (CAP_USB_FILES 0 there) under main's new native-USB CAP_USB_FILES
gate; apps.json keeps main's new and bumped apps (blackjack 1.2.2,
protreck 1.2, tripodometer 1.1, spaceinvaders) and web-build's
"radio": "own" on RF Monitor, Airtime and Wardrive; lua_builtin.h
regenerates unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Portrait, Portrait 180, Landscape and Landscape 180 are new TR() keys with
no row in any .lang file, so audit-lang listed them as missing in every
language. Each language reuses the portrait / landscape word its file
already has ("Portrait set ...", "Landscape (desktop)"); pl gets the
English placeholders. i18n_builtin.h regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both PRs appended rows to the same .lang files ("Fewest hops", "module
attached", "not attached"); the merge keeps every row and
i18n_builtin.h is regenerated from the merged files with
gen-lang-builtin.py rather than hand-merged. pl.lang gains the three keys as
English placeholders, like the rest of that file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Harness: #648 and #607 each declared the map mock's map_obj/map_centers
locals; the second declaration shadowed the first, so reset_world() and the
scenarios after it would never see the map the mock created. One declaration
is kept. tripodometer, protreck and gpscompass harness runs: ALL OK.
Catalog: the UTF-8 BOM the PR put in front of apps.json is dropped (json.load
and other strict readers refuse it), and ProTreck keeps "seed": false, which
the PR had removed: without it gen-lua-builtin.py would bake ProTreck into
every firmware image instead of serving it from the Store.
Not in langs.json yet, so the Store does not offer it and the V4's built-in
table is unchanged; it goes into the catalog once translated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both lists already show the hop count on each row; they can now be sorted
by it so the nearest repeaters come first. Combined with the Repeaters
filter this shows which repeaters are reachable directly.
Rows with no known path sink to the end in either direction, like the "?"
rows in the time-based sorts. Hops use pathHops() so 2/3-byte path hashes
don't read as 65+ hops. Language rows added for all 14 languages.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>