From f6c9c65a51849a248e7ed5153ba1fa9893c0f582 Mon Sep 17 00:00:00 2001 From: MarekWo Date: Tue, 31 Mar 2026 20:48:35 +0200 Subject: [PATCH] fix(channels): refresh channel secret cache after join/create After set_channel(), read back the actual secret from the device and update both _channel_secrets in-memory cache and the DB. This fixes newly-joined # channels (where firmware auto-generates the key) having no repeater info, missing Analyzer URLs, and incorrect route data until container restart. Also clean up _channel_secrets on channel removal. Co-Authored-By: Claude Opus 4.6 --- app/device_manager.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/device_manager.py b/app/device_manager.py index 895c9a0..6583faf 100644 --- a/app/device_manager.py +++ b/app/device_manager.py @@ -1955,11 +1955,35 @@ class DeviceManager: try: self.execute(self.mc.commands.set_channel(idx, name, secret)) self.db.upsert_channel(idx, name, secret.hex() if secret else None) + + # Read back the actual secret from device (firmware may have + # generated it for # channels) and update in-memory cache + DB. + self._refresh_channel_secret(idx, name) + return {'success': True, 'message': f'Channel {idx} set'} except Exception as e: logger.error(f"Failed to set channel: {e}") return {'success': False, 'error': str(e)} + def _refresh_channel_secret(self, idx: int, name: str = ''): + """Read back a channel's secret from device and update cache + DB.""" + try: + event = self.execute(self.mc.commands.get_channel(idx)) + if event: + data = getattr(event, 'payload', None) or {} + secret = data.get('channel_secret', data.get('secret', b'')) + if isinstance(secret, bytes): + secret = secret.hex() + if secret and len(secret) == 32: + self._channel_secrets[idx] = secret + ch_name = data.get('channel_name', data.get('name', '')) + if isinstance(ch_name, str): + ch_name = ch_name.strip('\x00').strip() + self.db.upsert_channel(idx, ch_name or name, secret) + logger.info(f"Refreshed channel {idx} secret into cache") + except Exception as e: + logger.warning(f"Failed to refresh channel {idx} secret: {e}") + def remove_channel(self, idx: int) -> Dict: """Remove a channel from the device.""" if not self.is_connected: @@ -1969,6 +1993,7 @@ class DeviceManager: # Set channel with empty name removes it self.execute(self.mc.commands.set_channel(idx, '', None)) self.db.delete_channel(idx) + self._channel_secrets.pop(idx, None) return {'success': True, 'message': f'Channel {idx} removed'} except Exception as e: logger.error(f"Failed to remove channel: {e}")