Fix/sticky filters #252

Merged
perl_d merged 5 commits from fix/sticky_filters into main 2026-10-20 15:45:30 +02:00
10 changed files with 19 additions and 190 deletions

No files matched your search

-21
View File
@@ -1,21 +0,0 @@
from aarecommon.config.beamline import mx_beamline
from aare.daq.aaredb import AareWrapper
from aare.daq.config import BeamlineConfig
from aare.daq.daq import AareDAQ
from aare.daq.devices import BeamlineDevices
from aare.devices.jfjoch import JFJochWrapper
bl = mx_beamline()
j = JFJochWrapper(bl)
a = AareWrapper(bl)
c = BeamlineConfig(bl)
d = BeamlineDevices(bl)
daq = AareDAQ(bl=bl, cfg=c)
result = j.wait_till_done(60)
a.ingest_scan(
sample=c.current_sample,
result=result,
geom=daq.sample_geometry,
beam_mark_pxl=c.get_beam_mark(d.zoom),
)
@@ -20,17 +20,17 @@ class X10SaBecMacros(BecMacros):
save_and_reload,
save_current_position,
)
from pxii_bec.macros.flux_macros import (
bpm2flux, # pyright: ignore[reportMissingImports, reportMissingModuleSource]
)
from pxii_bec.macros.katscripts import ( # pyright: ignore[reportMissingImports, reportMissingModuleSource]
auto_exposure,
from pxii_bec.macros.flux_macros import ( # pyright: ignore[reportMissingImports, reportMissingModuleSource]
bpm2flux,
)
from pxii_bec.macros.pxii_energy import ( # pyright: ignore[reportMissingImports, reportMissingModuleSource]
bl_energy,
get_current_energy,
mono_pitch_scan,
)
from pxii_bec.macros.pxii_setup import ( # pyright: ignore[reportMissingImports, reportMissingModuleSource]
auto_exposure,
)
from pxii_bec.scripts.init_beamline import ( # pyright: ignore[reportMissingImports, reportMissingModuleSource]
init_beamline_environment,
)
+4 -1
View File
@@ -291,7 +291,7 @@ class AareDAQ:
self.last_time = 0.0
self._dispatch = dispatch
self._cfg = cfg
self._devs = BeamlineDevices(bl, dispatch)
self._devs = BeamlineDevices(bl, dispatch, cfg)
self._mlbox = MlBox(bl)
self._jfjoch = JFJochWrapper(bl)
self._bl = bl.value.upper()
@@ -1978,6 +1978,9 @@ class AareDAQ:
# on completion correctly
logger.debug("Sleeping to ensure transmission set completes due to IOC issues")
time.sleep(2)
if self._devs.transmission == 0:
logger.warning("Transmission move still not completed, sleeping another 2s")
time.sleep(2)
start_pos = getattr(request, "start", None)
if start_pos is not None:
-13
View File
@@ -375,16 +375,3 @@ class BeamlineDevices:
def read_current_state_from_bec(self) -> BeamlineStateEnum:
return self.bec_worker.read_current_state()
if __name__ == "__main__":
from aarecommon.config.beamline import mx_beamline
beamline = mx_beamline()
devs = BeamlineDevices(beamline)
devs.bec_worker.scilog_msg(
message="Testing DAQ hijack of BEC sci log communication channel", color="blue"
)
# devs.aerotech_pos = Coordinate(x=124.0, y=1.0, z=1.0)
# print(devs.aerotech_pos)
# devs.aerotech_omega = 0.0
+2 -1
View File
@@ -3,6 +3,7 @@ import time
from aarecommon.config.logger import setup_logger
from aarecommon.models.models import SampleCameraSettings
from aare.beamline_dispatch.beamline_dispatch import get_beamline_dispatch
from aare.daq.config import ABR_OMEGA_MOUNT, ABR_POS_MOUNT, BeamlineConfig
from aare.daq.devices import BeamlineDevices
from aare.devices.area_detector import AutoEnum
@@ -284,7 +285,7 @@ if __name__ == "__main__":
beamline = mx_beamline()
config = BeamlineConfig(beamline)
devices = BeamlineDevices(beamline)
devices = BeamlineDevices(beamline, get_beamline_dispatch(), config)
common_2rse(devices, config)
time.sleep(10.0)
rse2sa(devices, config)
-20
View File
@@ -876,11 +876,6 @@ class MainWindow(QMainWindow):
for locked_banner in self._locked_beamline_banners:
locked_banner.installEventFilter(self)
self._idle_timer = QTimer(self)
self._idle_timer.setInterval(60_000)
self._idle_timer.timeout.connect(self._check_idle_timeout)
self._idle_timer.start()
self._remote_close_timer = QTimer(self)
self._remote_close_timer.setInterval(1000)
self._remote_close_timer.timeout.connect(self._check_remote_close_deadline)
@@ -3190,18 +3185,3 @@ class MainWindow(QMainWindow):
logger.warning("Closing GUI due to remote close request.")
self.close()
@Slot()
def _check_idle_timeout(self) -> None:
idle_for_s = time.time() - self._last_user_interaction_ts
if idle_for_s < self._idle_close_timeout_s:
return
if not self._can_close_for_idle_or_remote():
logger.info(
"Idle timeout reached, but GUI remains open because beamline is busy or automation is active."
)
return
# TODO deny communication from GUI to DAQ while IDLE for too long rather than kill the GUI
logger.warning("Closing GUI after inactivity timeout.")
self.close()
+4 -4
View File
@@ -110,8 +110,8 @@ class SampleQueuePanel(QFrame):
self.pause_on_conditions_cb.setChecked(True)
self.pause_on_conditions_cb.setToolTip(
"When on, automation refuses to start and pauses between samples if the beam, "
"experiment shutter, hutch doors or robot are not ready, auto-resuming when they "
"recover. Uncheck for testing to run straight through."
"experiment shutter, hutch doors or robot are not ready. Uncheck for testing "
"to run straight through."
)
button_layout.addWidget(self.play_button)
@@ -426,8 +426,8 @@ class SampleQueuePanel(QFrame):
logger.warning(f"Automation paused; beamline not ready: {bad}")
msg = "Automation paused — beamline not ready:\n- " + "\n- ".join(bad)
if conditions_auto_check(self, msg, self._conditions_ok):
logger.debug("Conditions recovered or user chose to continue; resuming automation")
if conditions_auto_check(self, msg):
logger.debug("User chose to continue; resuming automation")
self.table_model.set_running(True)
self._pause = False
self.play_button.setText("⏸ Pause")
+4 -32
View File
@@ -89,40 +89,12 @@ def reply_box(parent, title: str = "Warning", msg: str = "Warning."):
)
def timer_box(
parent, title: str = "Warning", msg: str = "Warning.", condition_func=None
) -> QMessageBox:
def continue_msg_box(parent, title: str = "Warning", msg: str = "Warning.") -> QMessageBox:
box = QMessageBox(parent)
box.setWindowTitle(title)
box.setText(f"{msg} Do you wish to continue?")
box.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
box.show()
timer = QTimer(box)
timer.setInterval(300)
def stop_timer():
if timer.isActive():
timer.stop()
def check():
if not box.isVisible():
stop_timer()
return
try:
if condition_func and condition_func():
# Auto-accept (as if user pressed Yes)
box.done(QMessageBox.StandardButton.Yes)
stop_timer()
except Exception:
# Never let errors in condition_func block UI
logger.exception("Error in condition_func")
box.accepted.connect(stop_timer)
box.rejected.connect(stop_timer)
timer.timeout.connect(check)
timer.start()
return box
@@ -163,10 +135,10 @@ def ring_current_auto_check(parent, ring_current, check_func) -> bool:
if ring_current is None
else f"Ring current is low {round(ring_current, 2)} mA."
)
return conditions_auto_check(parent, msg, check_func, title="Ring current too low")
return conditions_auto_check(parent, msg, title="Ring current too low")
def conditions_auto_check(parent, msg: str, check_func, title: str = "Beamline not ready") -> bool:
def conditions_auto_check(parent, msg: str, title: str = "Beamline not ready") -> bool:
"""Pause-and-wait dialog that auto-resumes when ``check_func()`` becomes True.
Used to hold automation between samples until the beamline recovers. The
@@ -174,7 +146,7 @@ def conditions_auto_check(parent, msg: str, check_func, title: str = "Beamline n
can also click 'Yes' to continue now (override) or 'No' to stop automation.
Returns True to resume, False to stop.
"""
box = timer_box(parent, title=title, msg=msg, condition_func=check_func)
box = continue_msg_box(parent, title=title, msg=msg)
loop = QEventLoop()
def finish(_=None):
-79
View File
@@ -352,85 +352,6 @@ def test_automation_activity_refreshes_idle_timestamp(qtbot, mock_ui_state):
assert win._remote_close_deadline_ts is None
def test_idle_timeout_closes_when_inactive_and_not_running(qtbot, mock_ui_state):
with (
patch("requests.get"),
patch("aare.gui.main_window.DAQWorker"),
patch("aare.gui.main_window.PredictionSubscriber"),
patch("aare.gui.main_window.VideoThread"),
patch("aare.gui.main_window.JFJochDBusClient"),
patch("aare.gui.main_window.jwt.decode") as mock_jwt,
):
mock_jwt.return_value = {
"sub": "testuser",
"staff": True,
"pgroups": ["p123"],
"session": 15,
}
fake_token = "header.payload.signature"
win = MainWindow(
base_url=None,
token=fake_token,
default_image=None,
zmq_addr=None,
pred_zmq_addr=None,
beamline_cam_addr=None,
gonio_cam_addr=None,
gonio_cam_id=None,
)
qtbot.addWidget(win)
win._idle_close_timeout_s = 10
win._last_user_interaction_ts = 100.0
win.close = MagicMock()
with patch("aare.gui.main_window.time.time", return_value=111.0):
win._check_idle_timeout()
win.close.assert_called_once()
def test_idle_timeout_does_not_close_while_automation_active(qtbot, mock_ui_state):
with (
patch("requests.get"),
patch("aare.gui.main_window.DAQWorker"),
patch("aare.gui.main_window.PredictionSubscriber"),
patch("aare.gui.main_window.VideoThread"),
patch("aare.gui.main_window.JFJochDBusClient"),
patch("aare.gui.main_window.jwt.decode") as mock_jwt,
):
mock_jwt.return_value = {
"sub": "testuser",
"staff": True,
"pgroups": ["p123"],
"session": 15,
}
fake_token = "header.payload.signature"
win = MainWindow(
base_url=None,
token=fake_token,
default_image=None,
zmq_addr=None,
pred_zmq_addr=None,
beamline_cam_addr=None,
gonio_cam_addr=None,
gonio_cam_id=None,
)
qtbot.addWidget(win)
win._idle_close_timeout_s = 10
win._last_user_interaction_ts = 100.0
win.job_list_panel.is_running = MagicMock(return_value=True)
win.close = MagicMock()
with patch("aare.gui.main_window.time.time", return_value=111.0):
win._check_idle_timeout()
win.close.assert_not_called()
def _make_window(qtbot):
win = MainWindow(
base_url=None,
-14
View File
@@ -8,7 +8,6 @@ from aare.gui.widgets.message_box import (
reply_box,
ring_current_auto_check,
ring_current_low_check,
timer_box,
)
@@ -21,19 +20,6 @@ def test_reply_box(qtbot):
mock_question.assert_called_once()
def test_timer_box_auto_accept(qtbot):
parent = None
condition_func = MagicMock(return_value=True)
# We need to process events for timer to fire
box = timer_box(parent, condition_func=condition_func)
# Wait until box is closed by check()
qtbot.waitUntil(lambda: not box.isVisible(), timeout=2000)
assert box.result() == QMessageBox.StandardButton.Yes
@pytest.mark.timeout(10)
def test_ring_current_low_check_ok(qtbot):
# Should return True immediately if current is high enough