mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-06-13 18:24:46 +02:00
fix(channels): honor device path_hash_mode when building raw_packet
Resends were building raw_packet with the default 1-byte path-hash size,
ignoring the device's actual path_hash_mode. When path_hash_mode=1 (2-byte
hashes) the original send produced 2-byte path entries in repeater echoes,
but the resend's path_len byte said "1-byte" — so post-resend echoes
appended 1-byte hashes, mixing into the badge as inconsistent tokens
(e.g. "44D8, D103, E7" — the trailing E7 was a 1-byte fragment).
Cache path_hash_mode from DEVICE_INFO at connect (fw_ver_code >= 10) and
expose path_hash_size = max(1, mode+1). Pass it through to
_build_grp_txt_raw_packet in send_channel_message and the clock-drift
refresh path. Keep cache in sync with set_param('path_hash_mode', N).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+26
-2
@@ -205,6 +205,7 @@ class DeviceManager:
|
||||
self._channel_secrets = {} # {channel_idx: secret_hex} for pkt_payload
|
||||
self._max_channels = 8 # updated from device_info at connect
|
||||
self._fw_ver_code = None # FIRMWARE_VER_CODE from DEVICE_INFO; gates feature support
|
||||
self._path_hash_mode = 0 # 0=1B, 1=2B, 2=3B per hop hash; refreshed on set_param
|
||||
self._pending_echo = None # {'timestamp': float, 'channel_idx': int, 'msg_id': int, 'pkt_payload': str|None}
|
||||
self._echo_lock = threading.Lock()
|
||||
self._send_lock = threading.Lock() # serialize set-scope + send-channel-message pair (used in PR #4)
|
||||
@@ -402,8 +403,15 @@ class DeviceManager:
|
||||
dev_info = dev_info_event.payload or {}
|
||||
self._max_channels = dev_info.get('max_channels', 8)
|
||||
self._fw_ver_code = dev_info.get('fw ver')
|
||||
# path_hash_mode in DEVICE_INFO requires fw_ver_code >= 10
|
||||
# (companion-v1.14+); older firmware omits it, leaving 0
|
||||
# (= 1-byte hashes) which is also the legacy default.
|
||||
phm = dev_info.get('path_hash_mode')
|
||||
if isinstance(phm, int) and phm >= 0:
|
||||
self._path_hash_mode = phm
|
||||
logger.info(f"Device max_channels={self._max_channels}, "
|
||||
f"fw_ver_code={self._fw_ver_code}")
|
||||
f"fw_ver_code={self._fw_ver_code}, "
|
||||
f"path_hash_mode={self._path_hash_mode}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not fetch device_info: {e}")
|
||||
|
||||
@@ -1710,6 +1718,7 @@ class DeviceManager:
|
||||
raw_packet = _build_grp_txt_raw_packet(
|
||||
guess_pkt_payload,
|
||||
scope_key_hex=scope['key_hex'] if scope else None,
|
||||
path_hash_size=self.path_hash_size,
|
||||
)
|
||||
if raw_packet:
|
||||
self.db.update_message_raw_packet(msg_id, raw_packet)
|
||||
@@ -1758,6 +1767,17 @@ class DeviceManager:
|
||||
def supports_raw_resend(self) -> bool:
|
||||
return (self._fw_ver_code or 0) >= self._MIN_FW_VER_RAW_RESEND
|
||||
|
||||
@property
|
||||
def path_hash_size(self) -> int:
|
||||
"""Bytes per path-hop hash, derived from cached _path_hash_mode.
|
||||
|
||||
Matches firmware's `_prefs.path_hash_mode + 1` used by sendFlood —
|
||||
so raw_packet snapshots have the same path_len byte the firmware
|
||||
would have produced, and post-resend repeater echoes use the same
|
||||
hash size as the original (no mixed 1B/2B entries on the badge).
|
||||
"""
|
||||
return max(1, (self._path_hash_mode or 0) + 1)
|
||||
|
||||
def resend_channel_message(self, msg_id: int) -> Dict:
|
||||
"""Re-broadcast an own channel message verbatim so repeaters can dedupe.
|
||||
|
||||
@@ -3589,7 +3609,11 @@ class DeviceManager:
|
||||
# Lib's internal default_timeout is 15s; give the outer wrapper
|
||||
# enough headroom so we don't surface a bare TimeoutError when
|
||||
# the device just needs a moment to acknowledge.
|
||||
self.execute(self.mc.commands.set_path_hash_mode(int(value)), timeout=20)
|
||||
phm = int(value)
|
||||
self.execute(self.mc.commands.set_path_hash_mode(phm), timeout=20)
|
||||
# Keep cache in sync so subsequent raw_packet snapshots use
|
||||
# the new hash size without needing a reconnect.
|
||||
self._path_hash_mode = phm
|
||||
return {'success': True, 'message': f'Path hash mode set to: {value}'}
|
||||
elif param == 'help':
|
||||
return {'success': True, 'help': 'set'}
|
||||
|
||||
Reference in New Issue
Block a user