diff --git a/src/aare/gui/threads/daq_worker.py b/src/aare/gui/threads/daq_worker.py index 33ea2eca..1cbccd4f 100644 --- a/src/aare/gui/threads/daq_worker.py +++ b/src/aare/gui/threads/daq_worker.py @@ -63,6 +63,10 @@ class DAQWorker(QObject): self._smargon_retry_interval_s = 2.0 self._smargon_log_min_interval_s = 10.0 + self._device_error_log_min_interval_s = 10.0 + self._last_device_error_log_ts: dict[str, float] = {"tell": 0.0, "smargon": 0.0} + self._last_device_error_log_key: dict[str, str | None] = {"tell": None, "smargon": None} + self._last_status_error = None self._smargon_error_active = False self._last_smargon_log_ts = 0.0 @@ -105,6 +109,31 @@ class DAQWorker(QObject): self._last_smargon_log_ts = now logger.error(f"Smargon connection error (endpoint={endpoint}): {message}") + def _log_device_error_throttled(self, *, device: str, message: str | None) -> None: + """ + Log device error string immediately if it changes; otherwise at most every N seconds. + Intended for status-poll derived errors like tell_error / smargon_error. + """ + if not message: + return + + device = (device or "unknown").lower() + now = time.monotonic() + key = str(message) + + last_key = self._last_device_error_log_key.get(device) + last_ts = self._last_device_error_log_ts.get(device, 0.0) + + if last_key != key: + self._last_device_error_log_key[device] = key + self._last_device_error_log_ts[device] = now + logger.error(f"{device.upper()} error: {message}") + return + + if now - last_ts >= self._device_error_log_min_interval_s: + self._last_device_error_log_ts[device] = now + logger.error(f"{device.upper()} error: {message}") + @Slot() def regular_update(self): if self.__counter % SPREADHSEET_FREQUENCY == 0: @@ -147,9 +176,16 @@ class DAQWorker(QObject): tell_conn = bool(getattr(parsed_response, "tell_connected", True)) smargon_conn = bool(getattr(parsed_response, "smargon_connected", True)) + tell_err = getattr(parsed_response, "tell_error", None) + smargon_err = getattr(parsed_response, "smargon_error", None) + # Status-bar messages should appear: + # - the first time we *notice* a disconnect + # - again when it reconnects if self._last_tell_connected is None: self._last_tell_connected = tell_conn + if not tell_conn: + self.status_message.emit("TELL connection error, please inform your local contact.", True) elif self._last_tell_connected != tell_conn: self._last_tell_connected = tell_conn if tell_conn: @@ -159,6 +195,8 @@ class DAQWorker(QObject): if self._last_smargon_connected is None: self._last_smargon_connected = smargon_conn + if not smargon_conn: + self.status_message.emit("Smargon connection error, please inform your local contact.", True) elif self._last_smargon_connected != smargon_conn: self._last_smargon_connected = smargon_conn if smargon_conn: @@ -166,6 +204,12 @@ class DAQWorker(QObject): else: self.status_message.emit("Smargon connection error, please inform your local contact.", True) + # Throttled logging of the *error strings* every ~10s while disconnected + if not tell_conn: + self._log_device_error_throttled(device="tell", message=tell_err) + if not smargon_conn: + self._log_device_error_throttled(device="smargon", message=smargon_err) + except Exception as e: # keep your existing throttled logging behavior here if you want logger.error(f"Exception from status response: {e}")