diff --git a/custom_components/meshcore/logbook.py b/custom_components/meshcore/logbook.py index 567f0e4..9190b17 100644 --- a/custom_components/meshcore/logbook.py +++ b/custom_components/meshcore/logbook.py @@ -106,6 +106,26 @@ async def handle_channel_message(event, coordinator) -> None: channel_idx ) + # path_len semantics for received channel packets mirror the + # direct-contact path (see handle_contact_message for the + # empirical notes against the firmware payload): + # * Direct reception (no repeaters): SDK returns 255 (0xFF) + # — sentinel for "no path bytes processed". -1 also occurs + # in some SDK paths. + # * Multi-hop reception: SDK returns the literal hop count. + # path_hash_mode is a separate field — no bit-mask applied here. + # SNR semantics: V3 CHANNEL_MSG_RECV frames carry SNR directly + # (uppercase "SNR" key from the SDK reader). V2 frames only + # surface SNR via the log_channels lookup when channel decryption + # is enabled, so absence is normal — emit the field only when + # the SDK actually provided it. + path_len_raw = payload.get("path_len", 0) + if not isinstance(path_len_raw, int) or path_len_raw < 0 or path_len_raw == 0xFF: + hop_count = 0 + else: + hop_count = path_len_raw + snr = payload.get("SNR") # V3 channel frames; V2 only via log_channels + # Create event data event_data = { "message": message_text, @@ -115,9 +135,13 @@ async def handle_channel_message(event, coordinator) -> None: "entity_id": entity_id, "domain": DOMAIN, "timestamp": dt_util.utcnow().isoformat(), - "message_type": "channel" # Explicit message type for filtering + "message_type": "channel", # Explicit message type for filtering + "hop_count": hop_count, } + if snr is not None: + event_data["snr"] = snr + # Add sender pubkey if available if sender_pubkey: event_data["pubkey_prefix"] = sender_pubkey diff --git a/docs/docs/events.md b/docs/docs/events.md index 4110e9f..59e09ac 100644 --- a/docs/docs/events.md +++ b/docs/docs/events.md @@ -31,6 +31,8 @@ Fired when any message is received. Ideal for notifications and message logging. - `timestamp` - When received - `message_type` - "channel" - `pubkey_prefix` - Sender's public key prefix +- `hop_count` - Number of repeater hops the packet traversed. `0` indicates direct reception (firmware returns the `0xFF` sentinel, which is normalised to `0`); positive values are the literal hop count from the SDK `path_len` byte. +- `snr` - (Optional) Signal-to-noise ratio in dB for this packet. Present on V3 `CHANNEL_MSG_RECV` frames (carried directly in the SDK payload as `SNR`). On V2 frames the field is only populated when channel decryption is enabled and the SDK matched a `log_channels` entry, so absence is normal. - `rx_log_data` - (Optional) Array of radio reception details when message was received via multiple mesh paths: - `channel_idx` - Channel number - `channel_name` - Channel name