Skip to content

CLIENT_BASE: Act like ROUTER_LATE for fav'd nodes, instead of like ROUTER#8567

Merged
thebentern merged 7 commits into
meshtastic:developfrom
korbinianbauer:late_window_client_base
Dec 19, 2025
Merged

CLIENT_BASE: Act like ROUTER_LATE for fav'd nodes, instead of like ROUTER#8567
thebentern merged 7 commits into
meshtastic:developfrom
korbinianbauer:late_window_client_base

Conversation

@korbinianbauer

@korbinianbauer korbinianbauer commented Nov 6, 2025

Copy link
Copy Markdown
Contributor

As requested by @NomDeTom on discord in #transport-layer

Hey, could you do a favour here and make the changes to firmware to make client_base act like router_late for favourite nodes, please?
We're discussing it on the ⁠contributor-hangout , and it's agreed that this is the correct thing to do.

🤝 Attestations

  • I have tested that my proposed changes behave as described.
  • I have tested that my proposed changes do not cause any obvious regressions on the following devices:
    • Heltec (Lora32) V3
    • LilyGo T-Deck
    • LilyGo T-Beam
    • RAK WisBlock 4631
    • Seeed Studio T-1000E tracker card
    • Other (please specify below)

@korbinianbauer korbinianbauer changed the title Late window client base CLIENT_BASE: Act like ROUTER_LATE for fav'd nodes, instead of like ROUTER Nov 6, 2025
Comment thread src/mesh/FloodingRouter.cpp Outdated
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) {
iface->clampToLateRebroadcastWindow(getFrom(p), p->id);
}
if (config.device.role == meshtastic_Config_DeviceConfig_Role_CLIENT_BASE && iface) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also check for isFromOrToFavoritedNode() here then.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also check for isFromOrToFavoritedNode() here then.

I thought about adding it for clarity, but it would be checking the same thing twice.

We don't get here if roleAllowsCancelingDupe() returns true, and that already depends on isFromOrToFavoritedNode()

if (config.device.role == meshtastic_Config_DeviceConfig_Role_CLIENT_BASE) {
// CLIENT_BASE: if the packet is from or to a favorited node,
// we should act like a ROUTER and should never cancel a rebroadcast (i.e. we should always rebroadcast),
// even if we've heard another station rebroadcast it already.
return !nodeDB->isFromOrToFavoritedNode(*p);
}

I believe checking again would set us up for strange bugs in the future, even if it seems more clear now.

I could add a comment for clarity instead?

Alternatively, what would probably be the cleanest way is to introduce something like roleCancelsOnDupe(p) and roleClampsToLateWindowOnDupe(p) and fix the multiple responsibility/vagueness problem that roleAllowsCancelingDupe() has right now. But that'd be a bigger diff.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should also check isFromOrToFavoritedNode() (because otherwise this will unintentionally move ordinary CLIENT-style rebroadcasts to be later)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@compumike

If we hit perhapsCancelDupe(), CLIENT-style rebroadcast is already off the table, no?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@korbinianbauer can you take a look at this suggestion?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@korbinianbauer Ah, I believe I see what you mean! Sounds like the case of the duplicate packet arriving over LoRa is already okay. (However, I'm imagining that with some of the other transport layer discussions going on, it's possible that in the future, a CLIENT won't always cancel upon hearing a dupe. So a comment, at the very least, would be a pointer that a check might be helpful there in the future.)

However, if a CLIENT_BASE sees a duplicate packet arrive over non-LoRa (i.e. MQTT), then with the current PR the CLIENT_BASE will always move that packet from the normal CLIENT window to the ROUTER_LATE window, even if it's not to/from a favorited node. So this behavior is not 100% consistent with the "behaves like CLIENT for non-favorited nodes". If you were to add the check for isFromOrToFavoritedNode() in here, then it will keep that 100% consistency, as far as I can tell.

With the goal of 100% consistency with the statement "CLIENT_BASE behaves exactly like CLIENT for non-favorited nodes", I'd probably still suggest adding the extra isFromOrToFavoritedNode() check here, even though it burns some extra CPU time for a CLIENT_BASE. However, I admit this is really an edge case (dupe received over MQTT) and the consequences don't seem too bad (only moves it to ROUTER_LATE window).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@compumike Got you. I have to admit I didn't think too hard about MQTT and saving that extra check is not a hill I need to die on :)

@GUVWAF

GUVWAF commented Nov 8, 2025

Copy link
Copy Markdown
Member

@compumike Would like to know your thoughts on this also.

@thebentern thebentern added the enhancement New feature or request label Nov 11, 2025
@compumike

Copy link
Copy Markdown
Contributor

@GUVWAF I didn't hear / don't see any record of the #contributor-hangout conversation, so I don't have context of what problem this change is trying to solve.

But in general I'm okay with this change in behavior! 👍

Net effects of moving CLIENT_BASE to act in the ROUTER_LATE window:

  • 🔴 higher latency
  • 🔴 higher total airtime / channel congestion (because a message may be rebroadcasted first by a CLIENT and then later by the CLIENT_BASE)
  • 🟢 slightly higher reliability of message deliverability
  • 🟢 better resistance to misconfiguration (unintended favorites)

Which is a real tradeoff, but also is a totally reasonable set of tradeoffs to make!

@NomDeTom

NomDeTom commented Dec 2, 2025

Copy link
Copy Markdown
Collaborator

@korbinianbauer are you able to address the comments above?

@geirgp

geirgp commented Dec 3, 2025

Copy link
Copy Markdown

@compumike you're right about the tradeoffs. To add some context on a problem this issue is helping to solve:

In sparse meshes with a "rooftop base + intermediate relay + distant node" topology, the current CLIENT_BASE (acting as ROUTER for favorites) can actually reduce message propagation to favorited nodes:

  1. Indoor node sends message
  2. CLIENT_BASE roof node rebroadcasts early (ROUTER priority)
  3. Critical intermediate CLIENT node (not favorited, ~1km away) hears the CLIENT_BASE rebroadcast
  4. Intermediate node cancels its own rebroadcast (managed flooding: "someone already rebroadcast this")
  5. Message never reaches the wider mesh because the critical hop was suppressed

In my testing, ROUTER_LATE on the roof consistently solved this, while CLIENT_BASE performed worse than having no roof node at all in some cases.

However, ROUTER_LATE on the rooftop is advised against by official docs because it rebroadcasts every packet it hears, significantly increasing airtime usage and potentially degrading the mesh. But since it obviously works well for this specific topology, having it replace ROUTER behavior in CLIENT_BASE (for favorited nodes only) would be ideal - giving us the late rebroadcast timing without the airtime concerns of a full ROUTER_LATE deployment.

@korbinianbauer

Copy link
Copy Markdown
Contributor Author

@korbinianbauer are you able to address the comments above?

Full agree on the comments by @compumike from my side.

I also think the trade-off is absolutely worth it. The latency and ChUtil downsides are something that can and should be adressed by A) using an appropriate SF and B) throttling traffic at the origin, not by waiving reliability.

@korbinianbauer korbinianbauer left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added extra check for fav'd source for consistency

@compumike

Copy link
Copy Markdown
Contributor

This PR looks good and I think it can be merged 👍


Reviewing the larger section of ROUTER_LATE behavior, I have a question for @GUVWAF :

Should ROUTER_LATE rebroadcast late always, or only after receiving dupe?

With regards to @geirgp 's "critical intermediate node" example:

My understanding is that ROUTER_LATE (and after this PR, CLIENT_BASE) will initially receive a packet and schedule a rebroadcast during the normal CLIENT window. They'll only move the rebroadcast to the later clampToLateRebroadcastWindow once they hear that packet a second time! (Because clampToLateRebroadcastWindow is only called from perhapsCancelDupe.)

This means there's still a random race between the ROUTER_LATE roof node and the CLIENT intermediate node. ~50% of the time, the roof node will still win, suppressing the intermediate node.

Instead, what if ROUTER_LATE (and CLIENT_BASE, when from/to favorite) always enqueued their rebroadcasts with clampToLateRebroadcastWindow, even when they've only heard a packet once?

Slightly higher latency, but this would make it so that in this example, the intermediate node would never be suppressed by the roof node.

I can imagine:

  • bool RadioInterface::shouldRebroadcastLateLikeRouterLate(meshtastic_MeshPacket *p)
  • modify RadioInterface::getTxDelayMsecWeighted to check it and add delay accordingly

(I don't think this question should delay merging this PR.)

@korbinianbauer

Copy link
Copy Markdown
Contributor Author

@compumike

Slightly higher latency, but this would make it so that in this example, the intermediate node would never be suppressed by the roof node.

Note that the "Late" Window is only guaranteed to be later than the Client window at similar SNR.

Even if Router_Late was to always rebroadcast in the late window, there is a good chance it will still supress a Client.

See Point 4 in #8431

@compumike

Copy link
Copy Markdown
Contributor

@compumike

Slightly higher latency, but this would make it so that in this example, the intermediate node would never be suppressed by the roof node.

Note that the "Late" Window is only guaranteed to be later than the Client window at similar SNR.

Even if Router_Late was to always rebroadcast in the late window, there is a good chance it will still supress a Client.

See Point 4 in #8431

Ah, thanks @korbinianbauer -- I had not seen that in #8431!

@thebentern thebentern merged commit ee64497 into meshtastic:develop Dec 19, 2025
73 of 74 checks passed
thebentern added a commit that referenced this pull request Dec 20, 2025
…UTER (#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
scobert969 pushed a commit to zeropt/meshtastic-firmware that referenced this pull request Dec 22, 2025
…UTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
matkam pushed a commit to matkam/meshtastic-firmware that referenced this pull request Dec 29, 2025
…UTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
ssp97 added a commit to ssp97/meshtastic_fw that referenced this pull request Jan 4, 2026
* Upgrade trunk (meshtastic#8976)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Update GitHub Artifact Actions (meshtastic#8954)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* rp2xx0: Update to arduino-pico 5.4.4 (meshtastic#8979)

* Update protobufs (meshtastic#8982)

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>

* Update meshtastic/device-ui digest to 862ed04 (meshtastic#8980)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* PIO: Fix ESP32 sub-variant inheritance (meshtastic#8983)

* Replace PIO fuzzy version matches (reproducible builds) (meshtastic#8984)

This change does not introduce version *changes*, but simply "updates" to the version already being referenced by the fuzzy-match (^)

* PIO: Remove useless inheritence (references extends env) (meshtastic#8987)

Remove lib_deps section for all PlatformIO envs which are unneeded (only references the `extends` lib_deps, thus pointless)

This makes the configs more concise and make future PIO variants/ libdeps audits easier.

* Upgrade trunk (meshtastic#8989)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Implement Long Turbo preset (meshtastic#8985)

* Implement Long_Turbo preset

* Oops

* Start to DRY up menu handler by actually using OO concepts instead of jank separate arrays

* Move the implementation back into the method

* Dummy comment

* Listen to copilot feedback and prevent dangling pointer

* Static and optional

* Detect if NTP is active on native (meshtastic#8962)

* Detect if NTP is active on native

* Drop debug warning

* Update RDEF parameters for CN region

* Upgrade trunk (meshtastic#9000)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Upgrade all esp32 targets to NimBLE 2.X (meshtastic#9003)

* Upgrade all esp32 targets to NimBLE 2.X

* Remove guard

* Renovate all the things (meshtastic#8994)

* Prep work for better Store and Forward (meshtastic#8999)

* make channels.h getHash public

* router.* make the encrypted packet copy available for modules to access

* Update src/mesh/Router.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Set p_encrypted to nullptr after release

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* PlatformIO: Restructure networking_base for re-use (meshtastic#8964)

* Macro guard heap_caps_malloc_extmem_enable from SENSECAP_INDICATOR (meshtastic#9007)

* More blinkenlights work for Thinknode-m3 (meshtastic#8940)

* More blinkenlights work for Thinknode-m3

* Update src/mesh/NodeDB.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Upgrade trunk (meshtastic#9011)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* CLIENT_BASE: Act like ROUTER_LATE for fav'd nodes, instead of like ROUTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

* Be more judicious about responding to want_response in existing meshes (meshtastic#9014)

* Be more judicious about sending want_response in existing meshes and responding to nodes we already heard from

* Turns out we don't actually use this

* For our first position send on boot, validate that we have received a fresh position (meshtastic#9023)

* Add Rebooting to DFU mode notification as a simple pop-up (meshtastic#8970)

* Add DFU notification as a simple pop-up

* Add safe conditional of IF_SCREEN

* Forgot #if HAS_SCREEN

* rp2xx0: Update to arduino-pico 5.4.4 (meshtastic#8979)

* CLIENT_BASE: Act like ROUTER_LATE for fav'd nodes, instead of like ROUTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

* Macro guard heap_caps_malloc_extmem_enable from SENSECAP_INDICATOR (meshtastic#9007)

* Actions: Compact manifest job output summary (meshtastic#8957)

* fmt

* Additional Emoji (meshtastic#9020)

* Refactor emote dimensions to 16x16 pixels

Updated the dimensions of various emotes in emotes.h from 30x30 or 25x25 to 16x16 pixels for consistency and optimization. Added new emotes including heart_smile, Heart_eyes, and others, all with the same 16x16 size. This change improves memory usage and aligns with the design specifications for smaller emotes.

* Add new emotes and their corresponding bitmap definitions

* Add strong emoji and first quarter moon face

* Add definitions for new emoji graphics

* Fix missing newline at end of file in emotes.cpp

* Add new emotes: eyes, eye, shrug, turkey, turkey leg

* Add turkey and related emote definitions

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/emotes.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Emoji naming convention consistency

* Automated version bumps (meshtastic#9025)

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>

* Automated version bumps (meshtastic#9025)

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>

* In protobuf update, allow develop branch to auto-update (meshtastic#9027)

* Update protobufs (meshtastic#9028)

Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com>

* Fix -ota.zip in manifest and build output

* Revert "Automated version bumps (meshtastic#9025)"

This reverts commit 1021d96.

* Adding support for InkHUD joystick navigation for the Seeed Wio Tracker L1 E-ink (meshtastic#8678)

* TwoButtonExtened mirrors TwoButton but added joystick functionality

* basic ui navigation with a joystick

settings->joystick.enabled setting added and SETTINGS_VERSION
incremented by one in InkHUD/Persistence.h

in seeed_wio_tracker_L1_eink/nicheGraphics.h enable joystick and
disable "Next Tile" menu item in

implement prevTile and prevApplet functions in
InkHUD/WindowManager.h,cpp and InkHUD/InkHUD.h,cpp

onStickCenterShort, onStickCenterLong, onStickUp, onStickDown,
onStickLeft, and onStickRight functions added to:
- InkHUD/InkHUD.h,cpp
- InkHUD/Events.h,cpp
- InkHUD/Applet.h

change navigation actions in InkHUD/Events.cpp events based on
whether the joystick is enabled or not

in seeed_wio_tracker_L1_eink/nicheGraphics.h connect joystick events to
the new joystick handler functions

* handle joystick input in NotificationApplet and TipsApplet

Both the joystick center short press and the user button short press can
be used to advance through the Tips applet.

dismiss notifications with any joystick input

* MenuApplet controls
allows menu navigation including a back button

* add AlignStickApplet for aligning the joystick with the screen

add joystick.aligned and joystick.alignment to InkHUD/Persistence.h for
storing alignment status and relative angle

create AlignStick applet that prompts the user for a joystick input and
rotates the controls to align with the screen

AlignStick applet is run after the tips applet if the joystick is
enabled and not aligned

add menu item for opening the AlignStick applet

* update tips applet with joystick controls

* format InkHUD additions

* fix stroke consistency when resizing joystick graphic

* tweak button tips for order consistency

* increase joystick debounce

* fix comments

* remove unnecessary '+'

* remap joystick controls to match standard inkHUD behavior

Input with a joystick now behaves as follows

User Button (joystick center):
- short press in applet -> opens menu
- long press in applet -> opens menu
- short press in menu -> selects
- long press in menu -> selects

Exit Button:
- short press in applet -> switches tile
- long press in applet -> nothing for now
- short press in menu -> closes menu
- long press in menu -> nothing for now

---------

Co-authored-by: scobert <scobert57@gmail.com>
Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>

* implement basic github action comment reporting target diffs (meshtastic#9022)

This is missing logic:
- report average
- don't bother reporting if the results are negligeable
- praise the user if it's improving the situation
- shame the user if it's not improving the situation

* RTC: PCF85063 support, port to SensorLib 0.3.1 (meshtastic#8061)

* RTC: PCF85063 support, port to SensorLib 0.3.1

* Tidy up defines

* Remove RTC/PCF8563 mentions from unrelated variants

* Bump SensorLib 0.3.2

* Use SensorRtcHelper

* Consistent warning message

* Fix oversight

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* add namiji-c3v1

* add namiji-c3v1 for github action build

* in shame.py do not complain about missing targets (meshtastic#9032)

PR CI only runs a small subset of all tests.

It is very likely a file we didn't found in the PR is just not tested in PR.

* In statusLEDModule, also detect isCharging (meshtastic#9050)

* PlatformIO: Re-Org ESP32 family shared props (meshtastic#9060)

* Update meshtastic-esp8266-oled-ssd1306 digest to b34c681 (meshtastic#9062)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Upgrade trunk (meshtastic#9047)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Cleanup: Remove icarus custom arduino-esp32 (meshtastic#9064)

* Update lewisxhe/SensorLib to 0.3.3 (meshtastic#9061)

* Upgrade trunk (meshtastic#9067)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* M6 shutdown and LEDs work (meshtastic#9065)

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

* Fix gps pin defs for various NRF variants. (meshtastic#9034)

* fix on nrf52_promicro

* try fix for GPS issue

* fix GPS pin assignment in variant.h

* cleared up some comments and confirmed pinouts from schematics

---------

Co-authored-by: macvenez <macvenez@gmail.com>

* Multi message storage (meshtastic#8182)

* First try at multimessage storage and display

* Nrf built issue fix

* Message view mode

* Add channel name instead of channel slot

* trunk fix

* Fix for DM threading

* fix for message time

* rename of view mode to Conversations

* Reply in thread feature

* rename Select View Mode to Select Conversation

* dismiss all live fix

* Messages from phone show on screen

* Decoupled message packets from screen.cpp and cleaned up

* Cannedmessage cleanup and emotes fixed

* Ack on messages sent

* Ack message cleanup

* Dismiss feature fixed

* removed legacy temporary messages

* Emote picker fix

* Memory size debug

* Build error fix

* Sanity checks are okay sometimes

* Lengthen channel name and finalize cleanup removal of Broadcast

* Change DM to @ in order to unify on a single method

* Continue unifying display, also show message status on the "isMine" lines

* Add context for incoming messages

* Better to say "in" vs "on"

* crash fix for confirmation nodes

* Fix outbound labels based to avoid creating delays

* Eink autoscroll dissabled

* gating for message storage when not using a screen

* revert

* Build fail fix

* Don't error out with unset MAC address in unit tests

* Provide some extra spacing for low hanging characters in messages

* Reorder menu options and reword Respond

* Reword menus to better reflect actions

* Go to thread from favorite screen

* Reorder Favorite Action Menu with simple word modifications

* Consolidate wording on "Chats"

* Mute channel fix

* trunk fix

* Clean up how muting works along with when we wake the screen

* Fix builds for HELTEC_MESH_SOLAR

* Signal bars for message ack

* fix for notification renderer

* Remove duplicate code, fix more Chats, and fix C6L MessageRenderer

* Fix to many warnings related to BaseUI

* preset aware signal strength display

* More C6L fixes and clean up header lines

* Use text aligns for message layout where necessary

* Attempt to fix memory usage of invalidLifetime

* Update channel mute for adjusted protobuf

* Missed a comma in merge conflicts

* cleanup to get more space

* Trunk fixes

* Optimize Hi Rez Chirpy to save space

* more fixes

* More cleanup

* Remove used getConversationWith

* Remove unused dismissNewestMessage

* Fix another build error on occassion

* Dimiss key combo function deprecated

* More cleanup

* Fn symbol code removed

* Waypoint cleanup

* Trunk fix

* Fixup Waypoint screen with BaseUI code

* Implement Haruki's ClockRenderer and broadcast decomposeTime across various files.

* Revert "Implement Haruki's ClockRenderer and broadcast decomposeTime across various files."

This reverts commit 2f65721.

* Implement Haruki's ClockRenderer and broadcast decomposeTime across various files. Attempt 2!

* remove memory usage debug

* Revert only RangeTestModule.cpp change

* Switch from dynamic std::string storage to fixed-size char[]

* Removing old left over code

* More optimization

* Free Heap when not on Message screen

* build error fixes

* Restore ellipsis to end of long names

* Remove legacy function renderMessageContent

* improved destination filtering

* force PKI

* cleanup

* Shorten longNames to not exceed message popups

* log messages sent from apps

* Trunk fix

* Improve layout of messages screen

* Fix potential crash for undefined variable

* Revert changes to RedirectablePrint.cpp

* Apply shortening to longNames in Select Destination

* Fix short name displays

* Fix sprintfOverlappingData issue

* Fix nullPointerRedundantCheck warning on ESP32

* Add "Delete All Chats" to all chat views

* Improve getSafeNodeName / sanitizeString code.

* Improve getSafeNodeName further

* Restore auto favorite; but only if not CLIENT_BASE

* Don't favorite if WE are CLIENT_BASE role

* Don't run message persistent in MUI

* Fix broken endifs

* Unkwnown nodes no longer show as ??? on message  thread

* More delete options and cleanup of code

* fix for delete this chat

* Message menu cleanup

* trunk fix

* Clean up some menu options and remove some Unit C6L ifdefines

* Rework Delete flow

* Desperate times call for desperate measures

* Create a background on the connected icon to reduce overlap impact

* Optimize code for background image

* Fix for Muzi_Base

* Trunk Fixes

* Remove the up/down shortcut to launch canned messages (meshtastic#8370)

* Remove the up/down shortcut to launch canned messages

* Enabled MQTT and WEBSERVER by default (meshtastic#8679)

Signed-off-by: kur1k0 <zhuzirun@m5stack.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>

---------

Signed-off-by: kur1k0 <zhuzirun@m5stack.com>
Co-authored-by: Riker <zhuzirun@m5stack.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

* Correct string length calculation for signal bars

* Manual message scrolling

* Fix

* Restore CannedMessages on Home Frame

* UpDown situational destination for textMessage

* Correct up/down destinations on textMessage frame

* Update Screen.h for handleTextMessage

* Update Screen.cpp to repair a merge issue

* Add nudge scroll on UpDownEncoder devices.

* Set nodeName to maximum size

* Revert "Set nodeName to maximum size"

This reverts commit e254f39.

* Reflow Node Lists and TLora Pager Views (meshtastic#8942)

* Add files via upload

* Move files into the right place

* Short or Long Names for everyone!

* Add scrolling to Node list

* Pagination fix for Latest to oldest per page

* Page counters

* Dynamic scaling of column counts based upon screen size, clean up box drawing

* Reflow Node Lists and TLora Pager Views (meshtastic#8942)

* Add files via upload

* Move files into the right place

* Short or Long Names for everyone!

* Add scrolling to Node list

* Pagination fix for Latest to oldest per page

* Page counters

* Dynamic scaling of column counts based upon screen size, clean up box drawing

* Update exempt labels for stale bot workflow

Adds triaged and backlog to the list of exempt labels.

* Update naming of Frame Visibility toggles

* Fix to scrolling

* Fix for content cutting off when from us

* Fix for "delete this chat" now it does delete the current one

* Rework isHighResolution to be an enum called ScreenResolution

* Migrate Unit C6L macro guards into currentResolution UltraLow checks

* Mistakes happen - restoring NodeList Renderer line

---------

Signed-off-by: kur1k0 <zhuzirun@m5stack.com>
Co-authored-by: Jason P <applewiz@mac.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Riker <zhuzirun@m5stack.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: whywilson <m.tools@qq.com>
Co-authored-by: Tom Fifield <tom@tomfifield.net>

* Upgrade trunk (meshtastic#9072)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Implement HAS_PHYSICAL_KEYBOARD for devices with physical keyboards (meshtastic#9071)

- Implement HAS_PHYSICAL_KEYBOARD for devices with physical keyboards
- Add HAS_PHYSICAL_KEYBOARD to variant.h for:
  - TDeck
  - TLora Pager
  - TDeck Pro

* update: namiji-c3v1 and namiji-c3v0

* disable some board

* disable some board

* In autoconf, don't probe Wire unless i2c device is set (meshtastic#9081)

Found another bit of code that crashes my desktop, by probing the wrong i2c bus.

* action: skip trying to comment binary size change results if it is not a PR (meshtastic#9033)

* action: skip trying to comment binary size change results if it is not a PR

* action: fix halucinations in the clanker's code

* action: cleanup one line

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Austin <vidplace7@gmail.com>

* Correctly set type for event_mode max() position threshold (meshtastic#9083)

Fixes EVENT_MODE firmware builds

* pioarduino .gitignore (meshtastic#9085)

I'm already going insane!

* Upgrade trunk (meshtastic#9076)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Fix PR#8061 SensorLib nRF ThinkNode M-series (meshtastic#9084)

* pass GH_TOKEN to shame's gh run download step (meshtastic#9087)

* Fix -ota.zip in manifest and build output

* Revert "Automated version bumps (meshtastic#9025)"

This reverts commit 1021d96.

* In statusLEDModule, also detect isCharging (meshtastic#9050)

* Update meshtastic-esp8266-oled-ssd1306 digest to b34c681 (meshtastic#9062)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Upgrade trunk (meshtastic#9047)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Upgrade trunk (meshtastic#9067)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* M6 shutdown and LEDs work (meshtastic#9065)

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

* Upgrade trunk (meshtastic#9072)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* In autoconf, don't probe Wire unless i2c device is set (meshtastic#9081)

Found another bit of code that crashes my desktop, by probing the wrong i2c bus.

* Upgrade trunk (meshtastic#9076)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* PIN_PWR_DELAY_MS --> PERIPHERAL_WARMUP_MS (meshtastic#8467)

It turns out we had two methods for delaying startup while peripherals
warmed up. They were invented within months of each other and just missed
the chance to merge.

Let's delete PIN_PWR_DELAY_MS and use PERIPHERAL_WARMUP_MS, since it's
most common and earlier in the sequence.

* Fix gps pin defs for various NRF variants. (meshtastic#9034)

* fix on nrf52_promicro

* try fix for GPS issue

* fix GPS pin assignment in variant.h

* cleared up some comments and confirmed pinouts from schematics

---------

Co-authored-by: macvenez <macvenez@gmail.com>

* Implement HAS_PHYSICAL_KEYBOARD for devices with physical keyboards (meshtastic#9071)

- Implement HAS_PHYSICAL_KEYBOARD for devices with physical keyboards
- Add HAS_PHYSICAL_KEYBOARD to variant.h for:
  - TDeck
  - TLora Pager
  - TDeck Pro

* Improve sanitizeString function for Node Names (meshtastic#9086)

* Add menus for Smart Position, Broadcast Interval and Position Interval (meshtastic#9080)

* Add menus for Smart Position, Broadcast Interval and Position Interval

* Realigned time intervals to match Android app options

* Fixed missing last option

* GPS Menu Validation Fix - Missed in Reviews (meshtastic#9093)

* Reviews sometimes miss things, whoops
* Validation is hard - but this fixes it

* Use IF_SCREEN macro to guard against null screen object

* Update meshtastic/device-ui digest to caff403 (meshtastic#9104)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Upgrade trunk (meshtastic#9106)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* chore(deps): update meshtastic/device-ui digest to d234bd9 (meshtastic#9108)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update protobufs (meshtastic#9109)

Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com>

* Noop "download" portion of #shame (meshtastic#9114)

* Update meshtastic/device-ui digest to 7656d49 (meshtastic#9111)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Upgrade trunk (meshtastic#9121)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* Calculate hops correctly even when hop_start==0 (meshtastic#9120)

* Calculate hops correctly even when hop_start==0.

* Use the same type (int8_t) in the loop, avoiding signed/unsigned mismatches.

* Clarify defaultIfUnknown is returned for encrypted packets.

* Revert "Upgrade all esp32 targets to NimBLE 2.X (meshtastic#9003)" (meshtastic#9125)

This reverts commit 40f1f91.

* Calculate hops correctly even when hop_start==0 (meshtastic#9120)

* Calculate hops correctly even when hop_start==0.

* Use the same type (int8_t) in the loop, avoiding signed/unsigned mismatches.

* Clarify defaultIfUnknown is returned for encrypted packets.

* Add a welcome message for new contributors (meshtastic#9119)

To assist with onboarding the denizens of the greater internet with
our norms and ways of working, this action will post a message on
PRs and issues from first-timers.

* Add STORE_FORWARD_PLUSPLUS_APP to core portnum checks (meshtastic#9127)

* Add Temporary Mute to Home frame and unbury Notification Options (meshtastic#9097)

* Add Temporary Mute to Home frame and unbury Notifications

* Only show Temporary Mute if it applies

* Remove banner notification, we display the icon immediately

* Remove extranous isMuted, there are better ways!

* chore(deps): update meshtastic/device-ui digest to 940ba85 (meshtastic#9129)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Rak3112 support (meshtastic#8591)

* Add rak3112 to board variants

* Add rak3112 to architecture definitions

* Disable SDcard support

* Update comments

* Remove duplicate definitions and use expected SPI naming for SDcard module

* SDcard module serial interface chip set definition

* Refactor modular variant into existing environment

* Make requested changes

* Extend 3312 variants

* Remove duplicate architecture definition

* Fix definition naming

* Apparently I marked board level extra on the wrong tbeam target

* Add null check for p_encrypted before MQTT publish (meshtastic#9136)

* Add null check for p_encrypted before MQTT publish

A user on BayMesh observed a strange crash in MQTT::onSend that seemed to be a null pointer dereference of this value.

* Trunk

* Syntax fix for first timer welcome bot. (meshtastic#9144)

URL formatting was inverted.

* KZ_863 is not wide lora (meshtastic#9075)

KZ_863 was set to wide_lora = true. This was a mistake, induced because the
regulations would allow SHORT_TURBO. However, that interpretation of the code
was incorrect and wide_lora has a different meaning.

Fixes meshtastic#9054

* chore(deps): update meshtastic/device-ui digest to a8e2f94 (meshtastic#9140)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dorny/test-reporter action to v2.4.0 (meshtastic#9135)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat(platformio): add non-USB environment configuration for esp32c3_super_mini

* Update security policy to reflect new stage

* Automated version bumps (meshtastic#9030)

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>

* Refactored some of the system menus to the new DRY method (Redux) (meshtastic#9152)

* Refactored some of the system menus to the new DRY method

* Fix menu name from Position to GPS

* I think this is supposed to be extra

* Add custom coding rate configuration for LoRa (meshtastic#9155)

* Faster rotary encoder events (meshtastic#9146)

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

* Fix link formatting in welcome message (meshtastic#9163)

---------

Signed-off-by: kur1k0 <zhuzirun@m5stack.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Austin <vidplace7@gmail.com>
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jason P <applewiz@mac.com>
Co-authored-by: korbinianbauer <64415847+korbinianbauer@users.noreply.github.com>
Co-authored-by: Ixitxachitl <kramerfm@gmail.com>
Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com>
Co-authored-by: zeropt <ferr0fluidmann@gmail.com>
Co-authored-by: scobert <scobert57@gmail.com>
Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>
Co-authored-by: Jorropo <jorropo.pgm@gmail.com>
Co-authored-by: WillyJL <me@willyjl.dev>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
Co-authored-by: Tom <116762865+NomDeTom@users.noreply.github.com>
Co-authored-by: macvenez <macvenez@gmail.com>
Co-authored-by: Riker <zhuzirun@m5stack.com>
Co-authored-by: whywilson <m.tools@qq.com>
Co-authored-by: Tom Fifield <tom@tomfifield.net>
Co-authored-by: Eric Severance <esev@esev.com>
Co-authored-by: Ford Jones <107664313+ford-jones@users.noreply.github.com>
Co-authored-by: brad112358 <brad112358@gmail.com>
derpyspike pushed a commit to derpyspike/mt-firmware that referenced this pull request Jan 4, 2026
…UTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
@aerodan

aerodan commented Jan 23, 2026

Copy link
Copy Markdown

The following scenario still exists. Though the effect is now downgraded to an accidentally favorited node acting like router_late instead of router, it's still an unwanted outcome and a mesh nuisance.

  1. User configures Client_Base hoping to have a local or onsite router in their control.

  2. The same user sends a DM to a nearby direct node. That node is auto-favorited and now acts as router_late despite not being qualified to do so.

Fsvorites are a poor way to define a router, as users commonly see it as "these are my friends". This still appears to have mesh health considerations.

@NomDeTom

Copy link
Copy Markdown
Collaborator

The following scenario still exists. Though the effect is now downgraded to an accidentally favorited node acting like router_late instead of router, it's still an unwanted outcome and a mesh nuisance.

  1. User configures Client_Base hoping to have a local or onsite router in their control.
  2. The same user sends a DM to a nearby direct node. That node is auto-favorited and now acts as router_late despite not being qualified to do so.

Not quite. DMs no longer auto-favourite on the client apps. This was an app-based behaviour. The alternative to this current pr was to pull the feature, which is currently a new favourite (pun intended) role.

Fsvorites are a poor way to define a router, as users commonly see it as "these are my friends". This still appears to have mesh health considerations.

Yes, we needed a quick and easy way to get started rather than bamboozle users with another nother tag or list.

@aerodan

aerodan commented Jan 23, 2026

Copy link
Copy Markdown

The following scenario still exists. Though the effect is now downgraded to an accidentally favorited node acting like router_late instead of router, it's still an unwanted outcome and a mesh nuisance.

  1. User configures Client_Base hoping to have a local or onsite router in their control.
  2. The same user sends a DM to a nearby direct node. That node is auto-favorited and now acts as router_late despite not being qualified to do so.

Not quite. DMs no longer auto-favourite on the client apps. This was an app-based behaviour. The alternative to this current pr was to pull the feature, which is currently a new favourite (pun intended) role.

Fsvorites are a poor way to define a router, as users commonly see it as "these are my friends". This still appears to have mesh health considerations.

Yes, we needed a quick and easy way to get started rather than bamboozle users with another nother tag or list.

Would it be a quick and dirty at-least-for-now fix to have a small table of a static nodes (max of lets say five) stored on the router, that are tagged as My_Base_Clients? Then the act of Favoriting is no longer burdened with special powers. Only those nodes as statically set by the Client_Base administrator will ever be used as "My_Base_Clients" and thus routed for... A command-line only option can set them for the time being. Not elegant, but also not as destructive and much more intentional. The log could spell out those nodes each boot, and perhaps later UI built where those hosts can be shown with an icon in the UI, selected from the node list etc. So: 1_ User enables Client_Base and become a potential router admin. 2_ New router admin sets up to five nodes as My_Base_Clients using their hardware node identifiers via command line. 3_ Favoriting nodes now has nothing to do with routing. The log reminds Client_Base administrators that those nodes are set on each boot. This would carry the feature until a protocol method of handing it is invented, and probably has UI object reuse.

@NomDeTom

Copy link
Copy Markdown
Collaborator

See #8555

@shalberd

Copy link
Copy Markdown

Thank you all for the hard and thoughtful work on this. I am watching your efforts a lot and like how you are willing to alter the behavior of features. In our case here in CH, moving favorites-handling to the late rebroadcast window really helps avoid some of the, probably due to our node density and topography, unwanted side effects of previous early reboradcast window. Thank you, truly.
Also, great to see you are thinking of using a field separate from is_favorite in future potentially for 0-cost-hop and preferred-client_base nodes.

@Hamberthm

Copy link
Copy Markdown

Hi! As far as I understand, this changes apply only to DMs to and from a fav node.
I`ve been losing messages on LongFast that won´t reach my indoor node, because my roof node won´t rebroadcast them for some reason. This makes the function of CLIENT_BASE only valid and useful for DMs.

I propose that in CLIENT_BASE ALL broadcast channel packets should be rebroadcasted at least ONE MORE TIME, so to ensure proper reach of LongFast messages and the like to the indoor nodes.

For packets that the algorithm decided should not be rebroadcasted, I propose to do so BUT after subtracting the remaining hops on the packet (making it 0) so it won´t congest the mesh but ensure reach to the indoor nodes.

@korbinianbauer

Copy link
Copy Markdown
Contributor Author

@Hamberthm

This PR only changes the timing, not if a packet is rebroadcast or not.
Proposals along these lines are out there though, maybe look into the discussion page about that.

@erayd

erayd commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

I propose that in CLIENT_BASE ALL broadcast channel packets should be rebroadcasted at least ONE MORE TIME, so to ensure proper reach of LongFast messages and the like to the indoor nodes.

This would cause congestion problems on many meshes. It's not feasible without significant throttling, and if you're throttling traffic you end up with exactly the same issue (i.e. some broadcast traffic not being rebroadcast). There simply isn't enough bandwidth available to have everybody's roof node rebroadcast every packet.

For packets that the algorithm decided should not be rebroadcasted, I propose to do so BUT after subtracting the remaining hops on the packet (making it 0) so it won´t congest the mesh but ensure reach to the indoor nodes.

Not only would this still congest the mesh (sending a packet as zero-hop still requires just as much airtime to transmit), it actually breaks the mesh by preventing any node that hears it from rebroadcasting. Remember that the nodes inside your house are not the only ones that can hear your CLIENT_BASE; even a very weak signal can still make it halfway across a city fairly easily.

@Hamberthm

Copy link
Copy Markdown

I propose that in CLIENT_BASE ALL broadcast channel packets should be rebroadcasted at least ONE MORE TIME, so to ensure proper reach of LongFast messages and the like to the indoor nodes.

This would cause congestion problems on many meshes. It's not feasible without significant throttling, and if you're throttling traffic you end up with exactly the same issue (i.e. some broadcast traffic not being rebroadcast). There simply isn't enough bandwidth available to have everybody's roof node rebroadcast every packet.

For packets that the algorithm decided should not be rebroadcasted, I propose to do so BUT after subtracting the remaining hops on the packet (making it 0) so it won´t congest the mesh but ensure reach to the indoor nodes.

Not only would this still congest the mesh (sending a packet as zero-hop still requires just as much airtime to transmit), it actually breaks the mesh by preventing any node that hears it from rebroadcasting. Remember that the nodes inside your house are not the only ones that can hear your CLIENT_BASE; even a very weak signal can still make it halfway across a city fairly easily.

Thanks for the detailed answer, got it. The complexity of this system amazes me everytime.

I'm thinking on alternatives like the indoor node sending some type of hash to the roof node to check if it has the same last messages, kind of an S&F server thing. But better I shut up and let the people who know to work on it.

I hope some workaround can be found, as community messages (LongFast) are important, even more on emergency situations.

@shalberd

shalberd commented Feb 5, 2026

Copy link
Copy Markdown

thinking on alternatives

Hi Humberto

personally, I would go with a solution directly connecting to the rooftop node via a special, high-quality bluetooth antenna or even WLAN, depending on the board. That is, not using the indoor node at all. Advantage: that way, you can just configure the rooftop node as CLIENT

For example, I am using this one https://www.data-alliance.net/antenna-2-4ghz-omnidirectional-2-5dbi-weatherproof-rp-sma-thru-hole-mount-wifi-bluetooth/ really just an example, there are so many great antennas for Bluetooth. 50-100m range should be possible, being close to the window, for example, with your smartphone.

and it has much, much better bluetooth range, even when tucked inside the plastic case, not on the outside.

@erayd

erayd commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

I'm thinking on alternatives like the indoor node sending some type of hash to the roof node to check if it has the same last messages, kind of an S&F server thing.

You're describing a feature I've been working on since September 😉. It's not intended for roof nodes though - if you use it that way, it'll throttle fairly aggressively.

Remember that the whole point of CLIENT_BASE is to not relay all broadcast traffic, to prevent the kind of congestion that's seen when people put routers on their roofs. The default LONG_FAST modulation has a data rate equal to roughly 2% of an old dialup modem, and that bandwidth is shared between every node in the same area. The unfortunate consequence of such limited bandwidth is the need to ration it quite aggressively in order to keep everything working effectively, as without such rationing it is very quickly exhausted.

I hope some workaround can be found, as community messages (LongFast) are important, even more on emergency situations.

The workaround that actually scales well is to place the node you want to receive on somewhere that can hear other mesh nodes without needing a roof node to relay to it. Having your phone connected directly to a client node on your roof achieve this quite effectively. I do appreciate that it's cumbersome though.

@Hamberthm

Copy link
Copy Markdown

thinking on alternatives

Hi Humberto

personally, I would go with a solution directly connecting to the rooftop node via a special, high-quality bluetooth antenna or even WLAN, depending on the board. That is, not using the indoor node at all. Advantage: that way, you can just configure the rooftop node as CLIENT

For example, I am using this one https://www.data-alliance.net/antenna-2-4ghz-omnidirectional-2-5dbi-weatherproof-rp-sma-thru-hole-mount-wifi-bluetooth/ really just an example, there are so many great antennas for Bluetooth. 50-100m range should be possible, being close to the window, for example, with your smartphone.

and it has much, much better bluetooth range, even when tucked inside the plastic case, not on the outside.

Indeed, I designed my roof node to be in reach of bluetooth for most of the house, sacrificing some perfomance by using coax to lower the node 2m into a place where I can connect to it. I just discovered by accident that some messages weren't reaching my portable node inside the house. So, even when this is not a problem for me, I was just thinking about people living in apartment buildings and the like who may have roof nodes to serve a bunch of lower nodes.

This may or may not be a real problem, I just got worried by it :)

@shalberd

shalberd commented Feb 5, 2026

Copy link
Copy Markdown

I was just thinking about people living in apartment buildings and the like who may have roof nodes to serve a bunch of lower nodes.

Here is Switzerland, we try to encourage people to use CLIENT_MUTE in the city and then to place their own apartment / client_mute node on the side of the apartment building close to the window that faces a big mountain with a CLIENT node :-) No need for using a rooftop node that way to connect to the mesh.

Thanks to both of you for an interesting discussion, I can relate to what you are worried about / what you mentioned,.

jeek pushed a commit to jeek/Meshtastic-Exploiteers-Hacker-Pager that referenced this pull request Jun 30, 2026
…UTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
jeek pushed a commit to jeek/Meshtastic-Exploiteers-Hacker-Pager that referenced this pull request Jun 30, 2026
…UTER (meshtastic#8567)

* Client_Base - Dont rebroadcast in early (Router) window

Removed early rebroadcast check for CLIENT_BASE role.

* Client_Base - Clamp rebroadcast to late (Router_Late) window on dupe

* Only clamp to Router_Late window if packet from fav'd node

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: CLIENT_BASE with ROUTER_LATE semantics for favorited nodes

10 participants