mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-07-07 02:11:29 +02:00
feat(companion): echo injected TX to companion clients as raw RX (0x88)
Push locally-injected TX packets to connected companion frame server clients as PUSH_CODE_LOG_RX_DATA (0x88) with snr=0/rssi=0, so apps that decrypt locally from raw RX (e.g. RemoteTerm) see companion-originated channel traffic. The originating companion is excluded so a node never hears its own transmission, matching physical firmware behavior. inject_packet now takes an origin_hash (threaded per-companion via the packet_injector partial); _on_raw_rx_for_companions gains exclude_hash to skip that companion's frame server. OTA RX is unaffected.
This commit is contained in:
+17
-3
@@ -572,7 +572,12 @@ class RepeaterDaemon:
|
||||
|
||||
bridge = RepeaterCompanionBridge(
|
||||
identity=identity,
|
||||
packet_injector=self.router.inject_packet,
|
||||
# Tag the injector with this companion's hash so inject_packet can
|
||||
# skip its own frame server when echoing TX as raw RX (a node never
|
||||
# hears its own transmission).
|
||||
packet_injector=functools.partial(
|
||||
self.router.inject_packet, origin_hash=companion_hash_str
|
||||
),
|
||||
node_name=node_name,
|
||||
radio_config=radio_config,
|
||||
sqlite_handler=sqlite_handler,
|
||||
@@ -819,12 +824,21 @@ class RepeaterDaemon:
|
||||
f"port={tcp_port}, bind={bind_address}, client_idle_timeout_sec={client_idle_timeout_sec}"
|
||||
)
|
||||
|
||||
async def _on_raw_rx_for_companions(self, data: bytes, rssi: int, snr: float) -> None:
|
||||
"""Raw RX subscriber: push PUSH_CODE_LOG_RX_DATA (0x88) to connected companion clients."""
|
||||
async def _on_raw_rx_for_companions(
|
||||
self, data: bytes, rssi: int, snr: float, exclude_hash: str | None = None
|
||||
) -> None:
|
||||
"""Raw RX subscriber: push PUSH_CODE_LOG_RX_DATA (0x88) to connected companion clients.
|
||||
|
||||
``exclude_hash`` skips the frame server for that companion hash; used when
|
||||
echoing a companion's own injected TX so it never hears its own transmission.
|
||||
OTA RX subscribers leave it unset, so received packets reach every companion.
|
||||
"""
|
||||
servers = getattr(self, "companion_frame_servers", [])
|
||||
if not servers:
|
||||
return
|
||||
for fs in servers:
|
||||
if exclude_hash is not None and getattr(fs, "companion_hash", None) == exclude_hash:
|
||||
continue
|
||||
try:
|
||||
fs.push_rx_raw(snr, rssi, data)
|
||||
except Exception as e:
|
||||
|
||||
@@ -160,7 +160,7 @@ class PacketRouter:
|
||||
pass
|
||||
await self.queue.put(packet)
|
||||
|
||||
async def inject_packet(self, packet, wait_for_ack: bool = False):
|
||||
async def inject_packet(self, packet, wait_for_ack: bool = False, origin_hash=None):
|
||||
try:
|
||||
metadata = {
|
||||
"rssi": getattr(packet, "rssi", 0),
|
||||
@@ -182,6 +182,32 @@ class PacketRouter:
|
||||
# Mark so when this packet is dequeued we don't pass to engine again (avoid double-send / double-count)
|
||||
packet._injected_for_tx = True
|
||||
|
||||
# Echo this local TX to companion frame server clients as raw RX
|
||||
# (PUSH_CODE_LOG_RX_DATA 0x88, snr=0/rssi=0 = local origin) so apps that
|
||||
# decrypt locally from raw RX (e.g. RemoteTerm) see companion-originated
|
||||
# traffic, matching what other mesh nodes would hear off the air. The
|
||||
# originating companion (origin_hash) is excluded so it never hears its own TX.
|
||||
push_rx = getattr(self.daemon, "_on_raw_rx_for_companions", None)
|
||||
if push_rx is not None:
|
||||
try:
|
||||
raw = packet.write_to()
|
||||
await push_rx(raw, 0, 0.0, exclude_hash=origin_hash)
|
||||
servers = getattr(self.daemon, "companion_frame_servers", [])
|
||||
pushed = sum(
|
||||
1
|
||||
for fs in servers
|
||||
if getattr(fs, "companion_hash", None) != origin_hash
|
||||
)
|
||||
logger.debug(
|
||||
"Echoed injected TX as raw RX (0x88) to %d companion client(s) "
|
||||
"(%d bytes, origin=%s excluded)",
|
||||
pushed,
|
||||
len(raw),
|
||||
origin_hash,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("Failed to echo injected TX to companions: %s", e)
|
||||
|
||||
# Enqueue so router can deliver to companion(s): TXT_MSG -> dest bridge, ACK -> all bridges (sender sees ACK)
|
||||
await self.enqueue(packet)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user