Commit Graph
4026 Commits
Author SHA1 Message Date
MarekZegare4andClaude Opus 4.8 b624d03e96 docs(companion): make the entity-reference cleanup contract explicit
The onContactRemoved/onChannelRemoved hooks already clear every NodePrefs
field keyed on a contact pubkey or channel index (verified complete), but the
convention was opt-in with no reminder — new per-entity state could silently
forget to register, the class of bug fixed earlier this session.

Add a CONTRACT comment above each hook listing what it covers and instructing
additions to land there, plus a terse [del->onContactRemoved] /
[del->onChannelRemoved] tag on each of the eight keyed fields in NodePrefs.h.
Now editing either side (struct field or hook) points at the other. Comments
only; no behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 18:17:38 +02:00
MarekZegare4andClaude Opus 4.8 325b200d07 fix(companion): compile-time tripwire for NodePrefs serialization drift
NodePrefs is written/read field-by-field in DataStore::savePrefs/loadPrefsInt;
the on-disk format is the struct's field layout, with nothing checking that the
two hand-written sequences still match the struct. A forgotten read/write
silently misaligns every later field — the highest-blast-radius convention in
the codebase.

Add a static_assert on sizeof(NodePrefs): changing a data member trips it with
a checklist (sync save/load, clamp on load, bump SCHEMA_SENTINEL, update the
size). A manual checkpoint, not a proof, but it turns silent drift into a build
break. Size is variant-stable (all arrays sized by NodePrefs' own constants),
verified on both nRF52 boards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 18:13:05 +02:00
MarekZegare4andClaude Opus 4.8 089048a036 refactor(ui): align screens to the documented UI conventions
Audit pass against docs/design/solo_ui_framework.md, converging deviations:

- prev/next: replace hand-rolled (c == KEY_LEFT || c == KEY_PREV) with
  keyIsPrev()/keyIsNext() in QuickMsgScreen, RingtoneEditor, TrailScreen,
  FullscreenMsgView. Two were real rotary-encoder gaps, not just style:
  NearbyScreen's filter and WaypointsView's hemisphere toggle used raw
  KEY_LEFT/RIGHT with no encoder twin, so the encoder couldn't drive them.
- NearbyScreen's list right column used a manual setCursor(width -
  getTextWidth(...)) instead of the existing drawTextRightAlign() helper
  (which also UTF-8-translates) — now uses it, like Diagnostics/Repeater.
- RepeaterScreen hand-rolled the whole drawList skeleton (scroll clamp +
  reserve + row loop + indicator); collapsed onto drawList().

No D-pad behaviour change; more uniform encoder support. Net -19 lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 18:01:29 +02:00
MarekZegare4andClaude Opus 4.8 e44df01b9b docs: add a solo UI framework developer guide
Document the reusable building blocks the solo UI has grown — the UIScreen
model and screen wiring, DisplayDriver layout metrics, drawList/AccordionList,
the popup/keyboard/digit-editor/fullscreen/nav components, the geo + state-store
+ persistence helpers, mini-icons, input conventions, and the cross-cutting
gotchas (single-thread render, e-ink pacing, reference cleanup). Ends with a
worked "add a new Tools screen" example.

No code change; the helper layer is already well-factored (the recent dedup
passes closed the remaining gaps), so this captures it for contributors rather
than extracting more. Linked from the README docs table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 17:51:15 +02:00
MarekZegare4andClaude Opus 4.8 fe19d1b0a7 refactor(companion): dedup age formatting + reply-prefix parsing; drop dead code
Consolidation pass over the message/nearby UI, no functional change beyond
one intentional display tweak:

- Age tags: NearbyScreen::fmtAge, the nearby list's inline column, and
  QuickMsgScreen::fmtMsgAge each reimplemented the same s/m/h bucket ladder
  on top of geo::fmtAgeShort. All now delegate to it (fmtMsgAge removed).
  Visible effect: ages over 24h render as "Nd" instead of capped hours,
  matching the Locator target picker which already used fmtAgeShort.
- Reply prefix: the "@[nick] " parse was duplicated in skipReplyPrefix() and
  FullscreenMsgView::render(). Extracted to one msgReplyBody() helper (body,
  plus optional addressee nick) — one place to handle its edge cases.
- LiveTrack: the expiry predicate was duplicated in expire()/isActive();
  extracted to a private expired() helper.
- Removed a dead M_PI define (and unused <math.h>) in NearbyScreen.h, and a
  comment pointing at a CODE_REVIEW.md that doesn't exist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 17:43:17 +02:00
Liam CottleandGitHub 1869b57d62 Merge pull request #2853 from HDDen/dev
Add Data-Type to number_allocations.md
2026-06-29 21:49:19 +12:00
HDDen 58b0f7df9c Update number_allocations.md 2026-06-29 12:41:44 +03:00
MarekZegare4andClaude Opus 4.8 31d602c88a fix(companion): reply to the right author in rooms (and keep nicks UTF-8)
A room is viewed through DM history, where each post is stored "Author:
text" and shown attributed to that author. The reply path, though, built
the @[nick] prefix from _sel_contact.name — the room server's own name —
so replying to someone's post in a room addressed the room, not the person.

New buildDmReplyPrefix() derives the addressee from the same author the
history shows (via dmDisplayParts): the post's author in a room, the
contact name in a 1:1 DM. It also stores the nick raw (UTF-8), like the
channel reply path, instead of running it through the lossy display
transliterator — the prefix is sent over the air verbatim, so a non-ASCII
nick was previously corrupted on the wire.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 12:27:16 +02:00
MarekZegare4andClaude Opus 4.8 57ebd80fa7 fix(eink): fall back to polling when no GPIOTE channel is free
begin() claimed the trampoline slot and set _isr_slot before calling
attachInterrupt(), so a button that lost the GPIOTE race (only 8 channels,
shared with the radio's DIO1) would take the ISR branch forever while its
interrupt never fired. attachInterrupt() returns 0 when channels are
exhausted — only commit the slot on success, else leave _isr_slot = -1 so
check() uses the polling path. Combined with the live-pin reconcile, an
exhausted button degrades cleanly to plain polling instead of misbehaving.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 12:21:30 +02:00
MarekZegare4andClaude Opus 4.8 d8c5fa83de fix(eink): self-heal button state against the live pin; drop dead code
The interrupt path trusted the replayed edge stream alone (btn = prev) and
never sampled the live pin. Any lost edge — buffer overflow, a debounce-
dropped settling edge, or a missed GPIOTE event — left prev diverged from
the hardware until the next captured edge, i.e. a stuck button. After
draining the queue, reconcile against digitalRead(): a no-op when the edge
stream already matches, a one-call self-heal when it doesn't.

Also remove dead code in applyTransition() (a local `event` that was always
BUTTON_EVENT_NONE, making its cancel-on-click branch unreachable) carried
over verbatim from the original inline logic. No behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 11:53:23 +02:00
MarekZegare4andClaude Opus 4.8 1387cc9507 fix(eink): drive ringtone note advance from TIMER1 IRQ, not loop() poll
On nRF52 the buzzer advanced notes by polling millis() >= _note_end_ms in
loop(). A blocking display refresh (e-ink endFrame) starves loop(), so a
note boundary that falls inside a refresh is serviced late — the note
plays long, or the next is skipped. The keypress-time 300 ms render delay
only masked the first note.

Advance notes from a hardware TIMER1 compare interrupt instead, scheduled
for each note's exact duration, so timing is independent of render cadence.
TIMER0 is the SoftDevice's; TIMER1 is free (tone() uses PWM2, nrfx TIMER1
driver is disabled). loop() becomes a no-op on nRF52; the UITask keypress
render-delay workaround is removed.

_disarmNoteTimer() clears the latched NVIC pending IRQ (not just the event)
on stop()/_nrfBegin(), so a note-advance latched just before a stop can't
fire spuriously — which would skip a new melody's first note or blip after
an explicit stop. Event read-backs flush the write buffer per the nRF52
event anomaly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 11:37:48 +02:00
MarekZegare4andClaude Sonnet 4.6 7a5247d5d4 fix(companion): show the sender's own timestamp for synced/queued messages
DM, room and channel history always stamped a message with receipt time
(rtc_clock.getCurrentTime()), even though the sender's real timestamp was
already available (and, for DMs/rooms, already threaded through to
addDMMsg -- just never used for display). Live-received messages hid this
because receipt lags origination by only seconds, but a room-sync replay or
an offline-queued message held by a repeater can arrive long after it was
sent, so a burst of backlog messages all showed as "just now".

storeDMMsg() now prefers msg_ts (falling back to receipt time only when
unknown). addChannelMsg() gained a timestamp parameter, threaded from
onChannelMessageRecv() down through AbstractUITask/UITask, with the same
fallback. The DM dedup check and outgoing-message timestamps are unaffected
(they use msg_ts directly, already correct).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 11:00:45 +02:00
HDDen bc35208682 Update number_allocations.md
Added Data-Type range for MeshCore Images codec (range is for small reserve to future versions)
2026-06-28 00:32:22 +03:00
Scott Powell 4f8cb8db78 * ACK packets being 'clipped' (in Dispatcher send). Needed to extend max_airtime timeout calc for short packets 2026-06-27 21:06:01 +10:00
Liam CottleandGitHub 5ff39c6243 Merge pull request #2570 from IoTThinks/MCdev-Fixed-flashmode-XiaoC6-202605
Added flash_mode=dio to avoid boot loop when flashing using merge.bin
2026-06-27 11:32:10 +12:00
Liam CottleandGitHub dc200cf22d Merge pull request #2639 from sefinek/fix/typos-in-comments
fix: fix typos in source code comments
2026-06-27 11:26:54 +12:00
Liam CottleandGitHub 62b95b4e48 Merge pull request #2844 from oltaco/fix-rx-boosted-gain
Fix for Rx boosted gain on LR1110
2026-06-27 11:22:47 +12:00
MarekZegare4andClaude Sonnet 4.6 6a394e2d7a fix(companion): clear stale channel-index refs when a channel is removed
CMD_SET_CHANNEL clearing a slot (empty secret) left bot_channel_idx,
loc_share_channel_idx, and the per-channel melody bitmasks pointing at that
index. A new channel added later at the same slot would then silently
inherit the old one's bot target, Live Share target, or notification
melody. New onChannelRemoved() hook, mirroring onContactRemoved(), turns
the bot/Live Share channel target off (fail closed) and clears the melody
bits for that index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v1.21-rc2
2026-06-27 00:39:10 +02:00
MarekZegare4andClaude Sonnet 4.6 43c3f43e10 fix(companion): also clear stale contact refs on silent auto-eviction
onContactOverwrite() (the contact-table-full LRU eviction path) deleted the
contact's blob and notified the companion app, but never called the new
onContactRemoved() cleanup -- so a Favourites Dial slot, Locator target, or
Live Share target could still go stale, just via the silent auto-evict path
instead of an explicit removal. This is likely the main real-world cause of
the "(gone)" tile the docs described, since auto-eviction happens far more
often than an explicit CMD_REMOVE_CONTACT.

Also sync the two docs that described the old (now wrong) behaviour:
Locator's "survives delete" claim, and Favourites Dial's "(gone) until
reassigned" claim.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 00:31:06 +02:00
MarekZegare4andClaude Sonnet 4.6 3c34809af7 fix(companion): stable per-slot channel indices (channels2 -> channels3)
CMD_SET_CHANNEL saves immediately after clearing a channel slot, and
loadChannels() reassigned indices 0,1,2... sequentially on every load,
skipping gaps. Removing a channel and rebooting would then silently shift
every later channel down a slot -- anything that remembers a channel by
index (Live Share's target, the bot's channel, per-channel melody bitmasks)
could end up pointing at the wrong channel.

channels3 records now carry their original slot index instead of padding,
so a removed channel just leaves a hole. One-time migration: if channels3
doesn't exist yet, load the legacy channels2 with its old sequential
semantics, then resave as channels3 so the fallback never runs again.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:48:16 +02:00
MarekZegare4andClaude Sonnet 4.6 5c4607cca9 fix(companion): clear stale Locator/Live Share/favourite refs on delete
Deleting a waypoint left the Locator pointed at coordinates that no longer
existed (it's a coordinate snapshot, so nothing noticed). Removing a contact
was worse: nothing cleared its favourite slot, its Locator/Live Share target,
or its per-contact mute/melody entry, so all four kept referencing a pubkey
that no longer resolved to anything.

- WaypointsView's Delete now calls UITask::clearTargetIfWaypoint() first.
- New AbstractUITask::onContactRemoved() hook, called from MyMesh.cpp's
  CMD_REMOVE_CONTACT handler, clears the favourite slot, the Locator target,
  and dm_notif/dm_melody entries for that pubkey. Live Share's DM target
  turns auto-share off instead of guessing a new recipient.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 17:48:05 +02:00
MarekZegare4 50cd56cd0c Merge branch 'fix/trail-gps-off-prompt'
Trail: prompt to enable GPS when starting a recording with GPS off,
instead of silently running a session that records nothing.
2026-06-26 15:19:44 +02:00
taco f3d4d8cd5e always save boosted gain setting 2026-06-26 22:36:49 +10:00
MarekZegare4andClaude Opus 4.8 5d71fde980 fix(companion): prompt to enable GPS when starting a trail with GPS off
Starting trail recording with GPS switched off used to call setActive(true)
immediately -- the session timer ran while the screen sat on "Waiting for
GPS fix" forever and recorded nothing, with no hint that GPS was the
problem. Choosing "Start tracking" now opens a "GPS is off" confirmation
(Enable GPS & start / Cancel); confirming enables GPS and starts the
session. Behaviour is unchanged when GPS is already on.

Gated on a new UITask::hasGPS() so the prompt only appears on boards that
expose a toggleable GPS, not where GPS is simply absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 14:11:48 +02:00
MarekZegare4 ab4cd09edc Merge branch 'feat/save-app-room-password'
Persist app/USB-entered room passwords on device (rooms post standalone
after reboot), plus Messages-screen docs for on-device room login.
2026-06-26 11:51:06 +02:00
MarekZegare4andClaude Opus 4.8 e80092522c docs(solo): document on-device room login with saved passwords
Add a "Rooms — logging in" section and a room context-menu entry to the
Messages screen docs: auto password prompt, passwords remembered across
reboots, self-healing on failure, re-login via Login…, app-entered
passwords also saved, and the ASCII-only keyboard caveat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:51:06 +02:00
MarekZegare4andClaude Opus 4.8 c81b95b8b9 feat(companion): persist app/USB-entered room passwords on device
The on-device login path already saved room passwords to /room_pw; do the
same for logins issued by the phone/USB app (CMD_SEND_LOGIN). The password
is stashed when the login is sent and persisted once the server confirms,
gated to ADV_TYPE_ROOM contacts; a failed login forgets any stale saved
password, mirroring the on-device path. This lets the device post to a
room standalone after a reboot without re-prompting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:34:08 +02:00
Quency-DandGitHub 341aa5e0f4 Merge pull request #14 from meshcore-dev/dev
merge Dev
2026-06-26 17:16:23 +08:00
MarekZegare4 3e0debee1b Merge branch 'feat/on-device-room-login'
On-device room-server login with saved passwords (atomic-write persisted),
self-healing on failed login, and password cleanup on contact removal.
2026-06-26 11:02:14 +02:00
MarekZegare4andClaude Opus 4.8 ac8ddc7e28 fix(companion): forget saved room password when its contact is removed
CMD_REMOVE_CONTACT already drops the contact's advert blob; also drop any
saved /room_pw login for that key so a deleted room doesn't leave an
orphaned (and now useless) password behind until FIFO eviction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 10:59:35 +02:00
MarekZegare4andClaude Opus 4.8 be9f3db8c6 feat(companion): on-device room login with saved passwords
Log in to a room server from the device UI with no phone app: picking a
room prompts for its password (blank allowed for open rooms), and a
context-menu "Login..." allows re-login. Successful passwords are
persisted to a dedicated /room_pw file so a previously-used room logs
back in after reboot without retyping; a failed login forgets the
(now-stale) saved password so the next attempt prompts again.

The room-password file is written via a temp file + atomic rename
(new DataStore::commitFile helper), matching the crash-safety of
contacts/channels persistence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 10:55:24 +02:00
Liam CottleandGitHub 3d4eec4a6a Merge pull request #1194 from ViezeVingertjes/nibble_zero_connect
Added support for the nibble zero connect
2026-06-26 13:59:59 +12:00
taco b07aba7937 fix: report error when rxgain setting is unsupported or rejected 2026-06-26 08:45:03 +10:00
MarekZegare4andClaude Sonnet 4.6 64a48f2aea fix(eink): capture button edges via GPIO interrupt to survive display refresh
E-ink panel refreshes block the main loop for 500ms-3.6s (GxEPD2's
display.display() waits on the BUSY pin), and MomentaryButton::check()
only ever samples the live pin level once per loop iteration. A full
press+release that lands entirely inside a refresh is never sampled,
not just delayed - users on WioTracker L1 Eink were losing taps.

Add an opt-in ISR path (BUTTON_USE_INTERRUPTS) that latches each edge
with its own timestamp into a small ring buffer from attachInterrupt(),
independent of what the main loop is doing. check() replays buffered
edges through the existing transition/multi-click logic afterwards, so
click-duration and multi-click-window math still uses the edge's actual
capture time rather than "now".

Scoped to wio-tracker-l1-eink only for now: it's the one board this was
reported against and the only GxEPDDisplay-class variant that currently
builds clean on main. OLED boards refresh in ~20-30ms so polling already
catches every press; analog-button boards (rak4631/rak3401) can't use
attachInterrupt(CHANGE) at all.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 23:56:08 +02:00
taco 1f9bb67400 return bool when setting rx boost 2026-06-26 07:44:01 +10:00
ViezeVingertjes b8f1fad654 Add trailing underscore to nibble_screen_connect env names to exclude from automatic builds 2026-06-25 23:27:07 +02:00
ViezeVingertjes eb938a9b78 Address review comments and sync with dev 2026-06-25 23:26:55 +02:00
ViezeVingertjes 69df5c7a95 Remove NeoPixel configuration as its unused. 2026-06-25 23:26:55 +02:00
ViezeVingertjes 9c7d71b9be Added support for the nibble zero connect 2026-06-25 23:26:55 +02:00
taco 5d0ff7fe6e remove guard on MyMesh::setRxBoostedGain() 2026-06-26 07:06:37 +10:00
MarekZegare4andClaude Opus 4.8 57774d41f3 feat(companion): live location sharing, Locator geofencing, trail auto-pause
Squash merge of feat/location-beacon-alerts-autopause (v1.21).

Features:
- Live Location Sharing — broadcast position as movement-gated [LOC]
  messages to a channel or contact; live shares show as map pins with
  distance/bearing in Nearby Nodes and a status-bar indicator. [LOC] is
  parsed in DMs, channel messages and room messages; DM shares name the
  sender.
- Locator (geofence) — arm a geofence around a saved waypoint or a person
  (live [LOC] or last-known position), alert on arrive/leave or near/far,
  with an optional homing beeper (gated to arrive/both modes). Arm from
  Tools > Locator, Nearby Nodes, or Waypoints; target picker lists
  favourites first, clearable via a "None" entry. Active target is drawn
  as a flag on the map.
- One active target shared across Locator / Navigate / Map via a single
  resolver (resolvePersonPos / activeTargetPos) that prefers a live
  [LOC] share over the last-advertised GPS fix.
- Follow live contacts — Navigate to a live-sharing contact follows them
  as they move and adds an ETA line; quick-share your own position from
  the Map.
- Map & status-bar upgrades — home mini-map gets a north marker, scale
  tick, and a connected trail line (was disconnected dots); status line
  shows tracked-node count, an arrow + distance to the active Locator/Nav
  target (falling back to the nearest live-tracked contact); GPS fix icon
  in the top status bar, shown only on GPS boards with GPS enabled.
- Trail auto-pause — recording freezes on stops (banking elapsed time,
  breaking the map line across the idle gap) and resumes on movement
  without ending the session.
- Streaming trail simplification — GPS points are simplified in-stream
  via a fixed-corridor (Reumann-Witkam) pass tuned for fidelity: straight
  runs collapse to their endpoints, curves stay bounded to the Min-dist
  tolerance, so the 512-point buffer covers a far longer route than a
  flat point budget would suggest.
- Collapsible Tools (Location / Comms / System sections, fold-in-place
  like Settings) and page-indicator icons on the home carousel.
- Waypoint coordinate editor — add a waypoint by scroll-editing lat/lon
  digit by digit.

Fixes:
- Critical: low-heap hang and contact loss on RAM-tight builds. Halved
  message-history scrollback rings (recovering ~14 KB free heap) and
  made contacts/channels/prefs persistence atomic (temp file + rename),
  so an interrupted save can no longer corrupt or wipe the store.
- Serial.write() bounded so a stalled USB host can't hang the device.
- Nearby Nodes: live [LOC] senders respect the type filter, sort by
  shared position, and the list refreshes so live shares bubble up.
- Map: live contacts are labelled before waypoints.
- GPS status icon hidden when GPS is off in Settings.
- Splash screen no longer truncates a pre-release tag's own dash (e.g.
  v1.21-rc1) when stripping the build's commit-hash suffix.
- Null-guarded the Locator target picker; clamped loc-share channel
  index on load.

Under the hood:
- -Os size optimisation on the e-ink and GAT562 30S solo envs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v1.21-rc1
2026-06-25 19:04:21 +02:00
liamcottle b975180fc8 initial support for elecrow thinknode m7 2026-06-25 16:03:27 +12:00
Nick Dunklee 7a2764ebd6 Added Heltec t096 and seeed t1000-e
Tested Heltec t096 and Seeed t1000-e, both support this
hardware feature.
2026-06-24 15:58:09 -06:00
Nick Dunklee 4ac8742ce0 feat: use RAK hardware crypto on advert processing
While working on some sensor code implementations, I ran into
some hard crashes that root-caused to the 4KB loop task stack
being exhausted.

Looking for various optimization schemes resulted in this relatively
low-lift fix. RAK3401 and RAK4631 both support hardware crypto.

Rather than loading in one of the two software crypto libs,
we can just use the onboard hardware. This is faster, should
consume less power, and in testing used a scant up to 700
bytes in the run loop vs 2.5-3KB per advert.

This change **only** affects advert verification processing, which
currently consumes a significant chunk of the 4KB run loop.

I figured such a change should likely be implemented in phases.

After soaking, this hardware crypto verification
process could be implemented across the entire MeshCore
cryptographic function on RAK nodes. Also possible other nodes
have available hardware crypto, however, I have not checked,
so future improvements may also exist there.

Tested on:
  - RAK3401 RAK 1W
  - RAK4631 19001
2026-06-23 11:39:20 -06:00
UltimateCodeWarriorand=UltimateCodeWarrior b8b6598dd3 Fix blank OLED on T-Beam Supreme V3 (I2C bus + 0x3D address)
The SH1106 OLED on the LilyGo T-Beam Supreme V3 never lights up because:

1. The primary I2C bus (Wire) that the OLED, BME280 and magnetometer share
   is never initialized. The PMU/RTC use Wire1 (via XPowersLib); nothing
   brings up Wire on PIN_BOARD_SDA/PIN_BOARD_SCL, so the display driver
   talks on the wrong default pins.
2. The OLED is at I2C address 0x3D on this board (0x3C is taken by the
   QMC6310 magnetometer), but SH1106Display::begin() only tried 0x3C.

Initialize Wire for TBEAM_SUPREME_SX1262, and have SH1106Display::begin()
prefer 0x3D (only ever used by the OLED) before falling back to 0x3C.
Backwards-compatible for boards with the OLED at 0x3C.

Closes #2609
2026-06-22 23:39:34 -07:00
ripplebizandGitHub 3192684582 Merge pull request #2752 from Quency-D/heltec-tower-v2
Add Heltec tower v2
2026-06-23 11:51:03 +10:00
ripplebizandGitHub aa1cb1f663 Merge pull request #2765 from fizzyfuzzle/ESP32-Reset-Reason
Add ESP32 Reset Reason to existing pwrmgt.bootreason cli command
2026-06-23 11:41:57 +10:00
ripplebizandGitHub 6a63dfce1c Merge pull request #2771 from oltaco/nrf52-framework-buildfix
Point Heltec Mesh Solar and Mesh Pocket at our NRF52 framework fork
2026-06-23 11:37:03 +10:00
MarekZegare4andClaude Opus 4.8 c935287627 fix(companion): reset NaN/inf radio params before constrain() on load
constrain() is a min/max macro and NaN compares false against both bounds,
so a corrupted or layout-shifted prefs file that decodes a float field as
NaN/inf would pass it straight through to setParams() and could hang the
radio at boot (stuck after "Loading...", recoverable only by erasing flash).
Reset freq/bw/airtime_factor/rx_delay_base to safe defaults before the
existing constrain() so a non-finite value can never reach the driver.

Note: a defensive hardening of the boot path, not a confirmed root cause for
the reported brick.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 02:03:19 +02:00
MarekZegare4andClaude Opus 4.8 9b4c8431c9 fix(companion): show room-server messages on device, attributed to sender
Incoming room-server posts fired the notification and reached the app via
the offline queue, but never appeared when the room was opened directly on
the device: the on-device history (addDMMsg) was gated to ADV_TYPE_CHAT only,
while rooms (ADV_TYPE_ROOM) share that same history list (keyed by the
server's pubkey). Include ADV_TYPE_ROOM so room posts are stored too.

A room carries many guests, so prefix each stored post with its author —
resolved from the signed message's sender pubkey prefix (fallback: short
hex) — and have the DM history view split "Sender: text" for room contacts
so each line is attributed to the guest who wrote it, instead of showing the
room server's name for every message.

Builds verified: WioTrackerL1 + GAT562 30S solo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:31:47 +02:00