4673 Commits
Author SHA1 Message Date
liamcottle cced091b0c tidy comments 2026-09-08 22:18:22 +12:00
Jakub 333d739103 Revert "fix(ui): marquee's hold no longer dominates a barely-overflowing label"
This reverts commit e300db7908.
2026-09-08 11:38:31 +02:00
JakubandClaude Sonnet 5 34c2792099 docs: catch up solo_features docs with this cycle's UI changes
- settings_screen.md: document Settings > Sound > Msg wake
- clock_screen.md: document the new Sats dashboard field
- screen_lock.md: mention the lock screen's title bar (PR #32)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 11:35:19 +02:00
liamcottle 6809fed159 simplify and remove 2 as a wifi enabled state 2026-09-08 21:30:17 +12:00
JakubandClaude Sonnet 5 e300db7908 fix(ui): marquee's hold no longer dominates a barely-overflowing label
User report: a repeater path popup's short "?A1B2C3D4"-style hop tags
(often just a couple pixels over the box width) felt stuck rather than
scrolling, while longer names (Nodes list) already felt right after the
recent marqueeHoldMs() speedup.

Root cause: the swing marquee's hold applies uniformly regardless of how
much text is actually hidden. When only 1-2 codepoints overflow, the full
cycle is hold + a single, barely-there step + hold + step back -- nearly
all hold, for almost no new information revealed each side. New
marqueeHoldForSkip(skip_cp) scales the hold down (to 1/3 or 1/2) when the
computed reveal distance is small; longer overflows keep the full hold,
since there's real text worth pausing to read.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 11:12:23 +02:00
JakubandClaude Sonnet 5 57e029ccc4 feat(ui): add Sats dashboard field
New DASH_SATS clock/lock-screen dashboard field, reading
LocationProvider::satellitesCount() (already used by the GPS Tools
panel, just not previously exposed as a dashboard option). Follows the
existing DASH_GPS pattern: always selectable, "--" when built without
GPS support. Added to both dashboard-render paths (HomeScreen's CLOCK
page inline loop and formatDashVal(), shared by the LOCK page).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 11:04:14 +02:00
JakubandClaude Sonnet 5 dd87265d29 fix(ui): lock screen clock no longer overlaps its own title bar
PR #32 added a title bar (battery + status icons) to the LOCK page but
its drawClockTime() call still started at top_y=0, same row the title
bar draws into -- renderBatteryIndicator() runs unconditionally for any
_page != CLOCK (LOCK included), only the node-name text is skipped for
LOCK specifically. Landscape panels could overlap the icon row whenever
enough status badges (BT/GPS/alarm/mute/advert/trail/repeater) are
active; portrait e-ink's huge size-4 HH/MM block (the only board shape
that hits drawClockTime()'s "tall" branch) is worst hit, since it's
designed to fill most of the narrow width. Starts at top_y=lh now,
clearing the title bar row, matching how every other non-CLOCK page
already reserves that space via content_y.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:49:40 +02:00
JakubandClaude Sonnet 5 5fd887d781 docs(release-notes): add PR #32 lock-screen title bar to v1.27
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:42:00 +02:00
JakubandClaude Sonnet 5 dd170874d2 Merge pull request #32 from 3urobeat/feat/lock-screen-page-type
feat: Make lock screen a page type and display title bar on it

Moves lock-screen rendering out of a dedicated branch in UITask::loop()
into a proper HomePage::LOCK page in HomeScreen (appended after Count,
so no existing HomePage/home_pages_mask bit shifts), adds a title bar to
the lock screen (node name omitted, intentionally, for at-a-glance
anonymity), and makes drawClockTime()'s center-alignment opt-in so the
lock screen can left-align its clock. Reviewed: the two existing
drawClockTime() call sites are both updated to keep their prior
alignment, and this doesn't interact with our home_pages_mask=0 default,
msg_wake_screen_off, or the shutdown()-flush fix landed this cycle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:41:18 +02:00
ripplebizandGitHub ac7d88efe7 Merge pull request #3379 from oltaco/LR2021-preamble-arm-fix
fix: LR2021 to use correct macro for IRQ_DETECTED in startReceive()
2026-09-08 18:13:15 +10:00
JakubandClaude Sonnet 5 1f41b3a1b8 docs(release-notes): catch up v1.27 with missing entries; tune(ui): faster marquee hold
release-notes.md was missing three shipped changes: the Msg-wake toggle +
all-home-pages default, the repeater advert-interval default (2min->6min),
and three Fixes (settings-persist-on-reboot, RTC bootstrap floor-not-
rollback, ESP32 diagnostics heap/stack).

marqueeHoldMs() reverted 1500/2500 -> 700/1200 (OLED/e-ink) -- the longer
hold made the swing-marquee's full reveal cycle too slow for long message
previews.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:12:58 +02:00
Scott Powell 8660d1c973 * refactor: LPP helpers moved to LPPData class 2026-09-08 17:55:02 +10:00
taco 974f00ded0 fix: LR2021 to use correct macro for IRQ_DETECTED in startReceive() 2026-09-08 16:35:31 +10:00
JakubandClaude Sonnet 5 531eec2cd3 fix(prefs): flush settings on every reboot/shutdown path, not just per-screen exit
Root cause of "settings don't survive a reboot": every screen that edits
NodePrefs (Settings, Bot, Trail, Locator, GPS sharing, etc.) only persisted
via its own savePrefsIfDirty(_dirty) call on its own Cancel/exit path.
UITask::shutdown() -- the one function behind every real power-off/reboot,
including the low-battery auto-shutdown that fires directly from
UITask::loop() regardless of which screen is on-screen -- never called
the_mesh.savePrefs() at all. A user who changed a setting and then hit any
of those paths without first explicitly backing out of the screen (e.g.
display auto-off mid-edit, then a low-battery auto-shutdown) silently lost
the change.

Also closes two direct board.reboot() bypasses that skipped shutdown()
entirely: the phone-app CMD_REBOOT command and the serial CLI "reboot"
command. The factory-reset reboot path is deliberately left alone -- it's
supposed to wipe everything.

Verified with a real regression test (not just "it compiles"): set a pref
in memory without flushing it, cross the real low_batt_mv threshold to
trigger the actual production low-battery-shutdown code path, then a real
page.reload(), then confirm behaviourally (does an incoming message wake
the screen or not) whether the setting survived. Temporarily reverted the
fix and re-ran to confirm the test actually fails without it (screen woke,
setting lost) before restoring it and confirming it passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 08:33:46 +02:00
liamcottle 87a05e1589 allow remote management of wifi as user has cli permission 2026-09-08 18:33:37 +12:00
liamcottle bf64fafe90 simplify response message 2026-09-08 18:30:00 +12:00
liamcottle 790680e4d1 allow toggling wifi enabled regardless of stored ssid 2026-09-08 18:25:34 +12:00
WesselandDan McGee cb6f2f2255 Update src/helpers/ESP32Board.h
Co-authored-by: Dan McGee <dpmcgee@gmail.com>
2026-09-07 11:16:09 +02:00
Wessel Nieboer 35142a8896 Fix 1970 date after crash/watchdog/brownout reset on ESP32
Currently, time is only set to ~2024 when it powers on cleanly. When
time is lost, this results in time dropping to 1970. Save time as backup
to RTC slow memory. Should fix time staying accurate during brownouts
etc.
2026-09-07 11:16:08 +02:00
Scott Powell d71a54cd3d * CLI: removed "sub" and "unsub" (cannot support via command line)
* _SUBSCRIBE: binary req/resp payload changes (now keeps supplied 'push_tag')
* Sensor: added MCU temperature support in telemetry
2026-09-07 13:56:47 +10:00
Michael Graff 7c2b4d88be WiFi on/off tri-state: on when SSID set unless explicitly disabled; PicoW ships no default SSID 2026-09-06 22:18:00 -05:00
Michael Graff dac171b49c Default wifi.enabled to 0 2026-09-06 22:05:29 -05:00
Michael Graff eb2ab10de0 Add wifi.enabled pref and CLI; skip WiFi when disabled or SSID blank 2026-09-06 21:56:25 -05:00
Michael Graff 98cf4f3332 Add get wifi.status and get wifi.ip CLI commands 2026-09-06 21:44:47 -05:00
Michael Graff b11a779843 Address review: per-variant wifi src, real SSID reply, rename PicoW env 2026-09-06 21:28:04 -05:00
Michael Graff b9fa450f52 Fix review findings on Pico W WiFi/BLE 2026-09-06 20:43:37 -05:00
Michael Graff 88cc014f55 Add BLE companion support for Pico W 2026-09-06 20:15:45 -05:00
ripplebizandGitHub 89ef200efa Merge pull request #3366 from recrof/companion-cli-fix-2
Companion CLI: fixed txdelay, direct.txdelay, agc.reset.interval, int.thresh
2026-09-07 10:42:48 +10:00
JakubandClaude Sonnet 5 00c3279fa6 feat(ui): message-wake toggle + all home pages visible by default
Two independent changes, requested together:

1. Settings > Sound > "Msg wake" (NodePrefs::msg_wake_screen_off,
   0xC0DE002A) lets a user disable UITask::newMsg()'s existing behaviour
   of turning the display on for an incoming message when it was off and
   no companion app is connected. Stored inverted so both a fresh device
   and an existing saved-prefs file default to "on" (today's behaviour).
   New sim_test_set_msg_wake_disabled() hook verifies it without scripting
   Settings navigation -- confirmed end to end via a real A<->R<->B mesh
   in Playwright: message delivered while B's screen is off either wakes
   it (enabled) or doesn't (disabled), checked via real canvas pixels.

2. A brand-new or factory-reset device now shows ALL home pages by
   default instead of a curated 5-page carousel (MyMesh.cpp used to seed
   home_pages_mask = HP_DEFAULT; now seeds 0, which every other read site
   already treated as "all visible" -- HP_DEFAULT is now unused, removed).
   Existing users' saved masks are untouched. New sim_test_get_home_pages_mask()
   getter confirms a fresh instance reads back 0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 22:35:12 +02:00
3urobeat 47981da98c fix: Fix cover open being able to bypass lock (whoops) and hopefully fix flickering during password input 2026-09-06 20:25:50 +02:00
3urobeat f2209c338d feat: Hash & salt lock screen password 2026-09-06 19:49:07 +02:00
3urobeat 6404622ebf feat: Lock devices with password set on boot 2026-09-06 17:52:41 +02:00
3urobeat b710910225 feat: Add password input for screen unlock 2026-09-06 16:25:03 +02:00
Rastislav Vysoky 5d82ed352c Companion CLI: fixed txdelay, direct.txdelay, agc.reset.interval, int.thresh 2026-09-06 15:14:35 +02:00
Michael Graff d33fb4e9a7 Fix config parser aborting on an empty object
'custom:{}' (a DynamicConfigSerializer with nothing set) hits EXPECT_KEY
with a '}' and returns TOK_ERROR, so loadSerial stops there and silently
drops every property after it. Nothing follows 'custom' in NodePrefs
today, so it goes unnoticed until you add one.

Also include stdlib.h, which Arduino.h was providing on-device but not
in the native test build.
2026-09-05 23:15:13 -05:00
Michael Graff a4ac85a0d6 Address review findings on WiFi companion support
- scope the serial config CLI to RP2040; it was exposing the rescue CLI
  (cat/rm/erase) on every ESP32 WiFi build, which gates it behind a
  physical long-press
- bound and space out RP2040 rejoins: the core's join busy-waits, so cap
  it at 5s and retry every 30s instead of every 10s
- stamp the reconnect timer in setup(), so the first loop() doesn't tear
  down an association that is still finishing DHCP
- treat stored credentials as a pair, and pass NULL (not "") for an open
  network
- teach build_as_lib.py where SerialWifiInterface moved
2026-09-05 23:15:13 -05:00
Michael Graff 58181bb8a2 Fix blocking WiFi connect on RP2040, log link state
arduino-pico's WiFi.begin() blocks for up to 2x its 15s timeout, which
stalled the mesh loop on every reconnect attempt; use beginNoBlock().
Log the IP when the link comes up, and the status code when retrying.
2026-09-05 23:15:13 -05:00
Michael Graff 739a67c9f1 Allow WiFi credentials to be set at runtime
Store ssid/pwd in NodePrefs and set them with 'set wifi.ssid' /
'set wifi.pwd' over USB serial; build-time WIFI_SSID/WIFI_PWD stay as
the fallback. Headless WiFi builds get the config CLI on Serial, which
is otherwise unused there.
2026-09-05 23:15:13 -05:00
Michael Graff 0b2c47a932 Add WiFi companion support for Pico W
SerialWifiInterface has no ESP32-specific code, so move it to
helpers/wifi and reuse it on RP2040. Guard the ESP32-only WiFi
event/auto-reconnect calls and poll link state on RP2040 instead.
2026-09-05 23:15:13 -05:00
3urobeat 06e1dcdbfc feat: Add lockpass setting to configure lock screen password 2026-09-06 00:26:28 +02:00
3urobeat 4746a9a494 feat: Show title bar on lock screen
This commit aligns the clock to the left side of the screen and shows the title bar, excluding the node name (intentionally - I think it's a good idea to make a node harder to identify when locked ;) ).

TODO: I'm not sure if this clock alignment works on all display types, I only have a Wio Tracker L1 Pro OLED to test right now.
2026-09-05 22:05:15 +02:00
3urobeat ec143f577a feat: Make align center in drawClockTime optional 2026-09-05 22:01:14 +02:00
3urobeat 376fcd6bdd refactor: Make screen lock a dedicated page
This commit
- adds LOCK to the HomePage enum
- moves the lock page code from loop() to the selected page handler
- adds a forward declaration for formatDashVal to make it callable from within the selected page handler
- adds a syncLockToHome function that triggers a (un)lock page switch
2026-09-05 20:40:13 +02:00
JakubandClaude Sonnet 5 a18a821326 feat(sim): host-page buzzer mute hook + randomized repeater names
sim_buzzer_toggle_quiet()/sim_buzzer_get_quiet() (UITask.cpp) call the
literal UITask::toggleBuzzer() the real on-device Settings > Buzzer mute
toggle already calls -- persists into NodePrefs.buzzer_quiet, clears
buzzer_auto, saves prefs, shows the real "Buzzer: ON/OFF" alert. Not a
re-implementation, not a host-side Web Audio mute layered on top.

Every simple_repeater instance advertised the literal ADVERT_NAME
("repeater") -- across meshcore-solo-site's cross-visitor relay bridge
every hop in every path/relay list was an indistinguishable wall of
"repeater"s. A SIM_PLATFORM/__EMSCRIPTEN__-only default now picks a
random "<adjective> <geographic feature>" pair from
sim_instance_entropy() (real crypto.getRandomValues()-sourced entropy,
already used for RNG seeding) at first boot -- matches the real,
common ham-radio convention of naming a repeater after the hill it
sits on. Persists normally across reboots via the existing prefs
load/save path, same as a real operator-set name would.

sim_repeater_get_name() added alongside the existing
sim_repeater_get_relay_count() for host-page/test access to the
result.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iubftDmKNWmkNnhJRz8UH
2026-09-05 08:36:02 +02:00
Scott Powell 62d0556a70 * added region load/save support
* SUBSCRIBE now with timeout param (default 30 mins, max ~18 hours)
2026-09-05 15:59:29 +10:00
agessaman 6c1f4c09a6 Fix T-Beam 1W fan races and remove PWM controls 2026-09-04 16:51:53 -07:00
agessaman 8fd6893117 feat: add T-Beam 1W thermal fan control 2026-09-04 16:03:41 -07:00
João Brázio 8a418faf93 Add isGPSDetected() capability probe to SensorManager
Lets applications know whether a GPS was actually detected
(EnvironmentSensorManager reports its gps_detected state), e.g. to
hide GPS-dependent UI when no receiver is attached.
2026-09-04 21:04:20 +01:00
João Brázio 1d5283de76 Improve null checks and index validation in StaticPoolPacketManager 2026-09-04 21:03:06 +01:00
João Brázio 95214e8c40 Ensure command buffers stay NUL-terminated to prevent overflow
The serial command buffers must stay NUL-terminated within their
bounds: if they ever aren't, strlen() can return >= sizeof(command)
and the read loop would index past the buffer. Additionally, a full
buffer now becomes a completed line (end-of-line marker placed
inside the buffer, NUL terminator kept) instead of overwriting the
terminator and silently corrupting the buffer for the next pass.

Applies to the serial CLI readers of the repeater, room server,
sensor and secure chat examples, and to the CLI rescue reader of
the companion example.
2026-09-04 20:01:39 +01:00