From 0ae0e77814e86bc503cae9e81365ebc74e37af6a Mon Sep 17 00:00:00 2001 From: Username Date: Tue, 24 Feb 2026 16:45:30 +0100 Subject: [PATCH] app: deduplicate config detection, suppress hold-mode PTT spam --- src/tuimble/app.py | 70 ++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/src/tuimble/app.py b/src/tuimble/app.py index 6d37a79..f7c8e78 100644 --- a/src/tuimble/app.py +++ b/src/tuimble/app.py @@ -2,6 +2,7 @@ from __future__ import annotations +import dataclasses import html import logging from html.parser import HTMLParser @@ -737,39 +738,32 @@ class TuimbleApp(App): safe: list[str] = [] restart: list[str] = [] - if old.ptt.key != new.ptt.key: - safe.append(f"ptt key: {old.ptt.key} -> {new.ptt.key}") - if old.ptt.mode != new.ptt.mode: - safe.append(f"ptt mode: {old.ptt.mode} -> {new.ptt.mode}") - if old.ptt.backend != new.ptt.backend: - safe.append( - f"ptt backend: {old.ptt.backend} -> {new.ptt.backend}" - ) - if old.audio.input_gain != new.audio.input_gain: - safe.append( - f"input gain: {old.audio.input_gain} -> " - f"{new.audio.input_gain}" - ) - if old.audio.output_gain != new.audio.output_gain: - safe.append( - f"output gain: {old.audio.output_gain} -> " - f"{new.audio.output_gain}" - ) + # PTT: all fields are safe to hot-reload + old_ptt = dataclasses.asdict(old.ptt) + new_ptt = dataclasses.asdict(new.ptt) + for key in old_ptt: + if old_ptt[key] != new_ptt[key]: + safe.append(f"ptt {key}: {old_ptt[key]} -> {new_ptt[key]}") - o_srv, n_srv = old.server, new.server - for attr in ("host", "port", "username", "password", - "certfile", "keyfile"): - ov, nv = getattr(o_srv, attr), getattr(n_srv, attr) - if ov != nv: - label = "password" if attr == "password" else attr + # Audio: gains are safe; hardware settings require restart + safe_audio = {"input_gain", "output_gain"} + old_aud = dataclasses.asdict(old.audio) + new_aud = dataclasses.asdict(new.audio) + for key in old_aud: + if old_aud[key] != new_aud[key]: + if key in safe_audio: + safe.append(f"{key}: {old_aud[key]} -> {new_aud[key]}") + else: + restart.append(f"audio.{key} changed") + + # Server: all changes require restart + old_srv = dataclasses.asdict(old.server) + new_srv = dataclasses.asdict(new.server) + for key in old_srv: + if old_srv[key] != new_srv[key]: + label = "password" if key == "password" else key restart.append(f"server.{label} changed") - o_aud, n_aud = old.audio, new.audio - for attr in ("input_device", "output_device", "sample_rate"): - ov, nv = getattr(o_aud, attr), getattr(n_aud, attr) - if ov != nv: - restart.append(f"audio.{attr} changed") - return safe, restart def _apply_safe_changes(self, new: Config) -> None: @@ -791,17 +785,11 @@ class TuimbleApp(App): old = self._config server_changed = ( - old.server.host != new.server.host - or old.server.port != new.server.port - or old.server.username != new.server.username - or old.server.password != new.server.password - or old.server.certfile != new.server.certfile - or old.server.keyfile != new.server.keyfile + dataclasses.asdict(old.server) != dataclasses.asdict(new.server) ) - audio_hw_changed = ( - old.audio.input_device != new.audio.input_device - or old.audio.output_device != new.audio.output_device - or old.audio.sample_rate != new.audio.sample_rate + audio_hw_changed = any( + getattr(old.audio, a) != getattr(new.audio, a) + for a in ("input_device", "output_device", "sample_rate") ) if server_changed: @@ -929,6 +917,8 @@ class TuimbleApp(App): self._audio.capturing = transmitting status = self.query_one("#status", StatusBar) status.ptt_active = transmitting + if self._config.ptt.mode == "hold": + return chatlog = self.query_one("#chatlog", ChatLog) if transmitting: chatlog.write("[#e0af68]● transmitting[/]")