From d8d92b7b71eab51d1c2e88f0251eabf286061709 Mon Sep 17 00:00:00 2001 From: Tom <116762865+NomDeTom@users.noreply.github.com> Date: Sat, 20 Jun 2026 23:08:29 +0100 Subject: [PATCH] Fix/zerohop and hopscale mqtt (#10753) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix for prehopdrop on zerohop packets * hopscaling: exclude MQTT-origin packets from the node histogram The hop-scaling histogram gate only checked transport_mechanism == TRANSPORT_LORA, which excludes packets received from the broker but NOT MQTT-origin packets that a gateway rebroadcasts onto LoRa (those arrive as TRANSPORT_LORA with via_mqtt set). Counting them inflates the local mesh-size/density estimate with nodes that aren't real RF participants — and since the bridged copy usually carries hop_start==0 they land in the hop-0 bucket, the one that pulls getLastRequiredHop() lowest, over- shrinking NodeInfo/position/telemetry hop limits. Add `!mp.via_mqtt` to the gate. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- src/mesh/NodeDB.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 98d6a3f32..5653011fa 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -2821,6 +2821,10 @@ HopStartStatus classifyHopStart(const meshtastic_MeshPacket &p) return HopStartStatus::INVALID; if (p.hop_start == 0) { + // hop_start == hop_limit == 0: intentional zero-hop broadcast (e.g. beacon). Valid by definition — + // the packet was never meant to travel any hops, so no hop_start ambiguity applies. + if (p.hop_limit == 0) + return HopStartStatus::VALID; // Firmware prior to 2.3.0 (585805c) lacked a hop_start field. Firmware version 2.5.0 (bf34329) introduced a // bitfield that is always present. Use the presence of the bitfield to determine if the origin's firmware // version is guaranteed to have hop_start populated. Note that this can only be done for decoded packets as @@ -3161,8 +3165,14 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) mp.via_mqtt); // Store if we received this packet via MQTT #if HAS_VARIABLE_HOPS - // Only sample packets that arrived over LoRa. - if (mp.transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA && hopScalingModule) { + // Only sample genuine RF-origin packets. The transport check excludes packets received + // directly from the broker (TRANSPORT_MQTT), but an MQTT-origin packet rebroadcast onto + // LoRa by a gateway arrives as TRANSPORT_LORA with via_mqtt set — count those would + // inflate the local mesh-size estimate with non-RF nodes (and they usually carry + // hop_start==0, landing in the hop-0 bucket that pulls the recommendation lowest), so + // exclude via_mqtt too. + if (mp.transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA && !mp.via_mqtt && + hopScalingModule) { uint8_t hopCount = std::max(int8_t(0), getHopsAway(mp)); hopScalingModule->samplePacketForHistogram(mp.from, hopCount); }