diff --git a/src/aare/daq/daq.py b/src/aare/daq/daq.py index ccde41d3..14aa8042 100644 --- a/src/aare/daq/daq.py +++ b/src/aare/daq/daq.py @@ -3608,6 +3608,20 @@ class AareDAQ: finally: self.__cfg.state_busy = False + def mono_pitch_scan(self, plot: bool = False) -> None: + self.__cfg.try_set_busy(timeout=360) + try: + self.__devs.bec_worker.mono_pitch_scan_runner(plot=plot) + finally: + self.__cfg.state_busy = False + + def change_energy(self, value: float, plot: bool = False) -> None: + self.__cfg.try_set_busy(timeout=360) + try: + self.__devs.bec_worker.change_energy(value=value, plot=plot) + finally: + self.__cfg.state_busy = False + def fluorimeter_take_spectrum(self, fm: FluorescenceSpectrumParameterModel) -> FluorescenceSpectrumOutputModel: self.__cfg.try_set_busy(timeout=360) diff --git a/src/aare/daq/server.py b/src/aare/daq/server.py index 15398bc6..df828759 100644 --- a/src/aare/daq/server.py +++ b/src/aare/daq/server.py @@ -424,6 +424,43 @@ async def zoom(val: float, token: str = Depends(oauth2_scheme)): return "OK" +@app.post("/beamline/mono_pitch_scan") +async def mono_pitch_scan(plot: bool = False, token: str = Depends(oauth2_scheme)): + """ + Run a monochromator pitch scan. Staff only. + + Args: + plot: Whether to enable plotting in the BEC worker. + token: OAuth2 access token. + + Returns: + "OK" on success. + """ + logger.debug(f"Running mono pitch scan (plot={plot})") + auth.check_jwt_staff(cfg, auth.parse_token(token)) + daq.mono_pitch_scan(plot=plot) + return "OK" + + +@app.put("/beamline/change_energy") +async def change_energy(value: float, plot: bool = False, token: str = Depends(oauth2_scheme)): + """ + Change monochromator energy. Staff only. + + Args: + value: Target energy. + plot: Whether to enable plotting in the BEC worker. + token: OAuth2 access token. + + Returns: + "OK" on success. + """ + logger.debug(f"Changing energy to {value} (plot={plot})") + auth.check_jwt_staff(cfg, auth.parse_token(token)) + daq.change_energy(value=value, plot=plot) + return "OK" + + @app.put("/beamline/smargon") async def smargon(val: SmargonCoordinate, token: str = Depends(oauth2_scheme)): """ diff --git a/src/aare/gui/main_window.py b/src/aare/gui/main_window.py index fc7133c2..22f96e88 100644 --- a/src/aare/gui/main_window.py +++ b/src/aare/gui/main_window.py @@ -92,6 +92,8 @@ class MainWindow(QMainWindow): self._cleanup_done = False self._default_window_state = None + self._show_beamline_state_panel_for_users = True + self._waiting_for_baton_response: bool = False self._baton_request_dialog: BatonRequestDialog | None = None self._baton_pending_dialog: BatonPendingDialog | None = None @@ -187,10 +189,16 @@ class MainWindow(QMainWindow): self.loop_centering = LoopCenteringPanel(parent=self.left_column) self.beamline_state_panel = BeamlineStatePanel(parent=self.left_column) + self._beamline_state_panel_enabled = bool( + self.__decoded_token.staff or self._show_beamline_state_panel_for_users + ) self.left_column_layout.addWidget(self.data_collection) self.left_column_layout.addWidget(self.loop_centering) - self.left_column_layout.addWidget(self.beamline_state_panel) + if self._beamline_state_panel_enabled: + self.left_column_layout.addWidget(self.beamline_state_panel) + else: + self.beamline_state_panel.hide() self.left_column_layout.addStretch() top_widget_layout.addWidget(collection_controls_scroll) @@ -456,6 +464,8 @@ class MainWindow(QMainWindow): self.beamline.illumination_panel.back_light.connect(self.daq.back_light) if self.__decoded_token.staff: + self.beamline.monochromator_panel.mono_pitch_scan.connect(self.daq.mono_pitch_scan) + self.beamline.monochromator_panel.change_energy.connect(self.daq.change_energy) self.beamline.abr_tweak.abr_tweak.connect(self.daq.abr_tweak) self.beamline.abr_tweak.abr_save.connect(self.daq.abr_save) self.beamline.abr_tweak.abr_goto_meas.connect(self.daq.abr_goto_meas) @@ -613,6 +623,7 @@ class MainWindow(QMainWindow): self.daq.update.connect(self.camera_thread.update_daq_status) if self.__decoded_token.staff: + self.daq.update.connect(self.beamline.monochromator_panel.update_daq_status) self.daq.update.connect(self.beamline.beam_size.update_daq_status) self.daq.update.connect(self.beamline.beam_center.update_daq_status) self.daq.update.connect(self.beamline.abr_tweak.update_daq_status) @@ -823,6 +834,15 @@ class MainWindow(QMainWindow): view_menu = menu_bar.addMenu("View") + if self._beamline_state_panel_enabled: + self._show_beamline_state_action = QAction("Show Beamline State Panel", self) + self._show_beamline_state_action.setCheckable(True) + self._show_beamline_state_action.setChecked(self.beamline_state_panel.isVisible()) + self._show_beamline_state_action.triggered.connect( + lambda checked: self.beamline_state_panel.setVisible(checked) + ) + view_menu.addAction(self._show_beamline_state_action) + show_samples_action = QAction("Show Sample List", self) show_samples_action.setCheckable(True) show_samples_action.setChecked(True) @@ -973,6 +993,12 @@ class MainWindow(QMainWindow): self.job_list_dock.setVisible(True) self.manual_sample_dock.setVisible(True) + if self._beamline_state_panel_enabled: + self.beamline_state_panel.setVisible(True) + self.beamline_state_panel.set_collapsed(False) + if hasattr(self, "_show_beamline_state_action"): + self._show_beamline_state_action.setChecked(True) + self.face_panel_dock.setVisible(False) self.fluor_panel_dock.setVisible(False) self.smargon_trace_dock.setVisible(False) diff --git a/src/aare/gui/panels/beamline_controls.py b/src/aare/gui/panels/beamline_controls.py index 22ddce87..6b4c2155 100644 --- a/src/aare/gui/panels/beamline_controls.py +++ b/src/aare/gui/panels/beamline_controls.py @@ -5,6 +5,7 @@ from aare.gui.panels.beam_center_panel import BeamCenterWidget from aare.gui.panels.beam_mark_panel import BeamMarkWidget from aare.gui.panels.beam_size_panel import BeamSizeWidget from aare.gui.panels.illumination_panel import IlluminationPanel +from aare.gui.panels.monochromator_panel import MonochromatorPanel from aare.gui.panels.omega_panel import OmegaPanel from aare.gui.panels.samcam_panel import SamcamPanel from aare.gui.panels.smargon_panel import SmargonPanel @@ -37,11 +38,13 @@ class BeamlineControls(QFrame): self.v_layout.addWidget(self.samcam) if staff: + self.monochromator_panel = MonochromatorPanel(self) self.abr_tweak = AbrTweakWidget(self) self.beam_mark = BeamMarkWidget(self) self.beam_center = BeamCenterWidget(self) self.beam_size = BeamSizeWidget(self) + self.v_layout.addWidget(self.monochromator_panel) self.v_layout.addWidget(self.abr_tweak) self.v_layout.addWidget(self.beam_mark) self.v_layout.addWidget(self.beam_center) @@ -49,4 +52,3 @@ class BeamlineControls(QFrame): self.v_layout.addStretch() self.setLayout(self.v_layout) - diff --git a/src/aare/gui/panels/beamline_state_panel.py b/src/aare/gui/panels/beamline_state_panel.py index ffaf6ac7..ddafb216 100644 --- a/src/aare/gui/panels/beamline_state_panel.py +++ b/src/aare/gui/panels/beamline_state_panel.py @@ -56,6 +56,8 @@ class BeamlineStatePanel(QFrame): set_width = 400 map_height = 470 + title_height = 50 + collapsed_height = 50 station_radius = 8 def __init__(self, parent=None): @@ -63,7 +65,9 @@ class BeamlineStatePanel(QFrame): self.setFrameShape(QFrame.Shape.StyledPanel) self.setFrameShadow(QFrame.Shadow.Raised) self.setFixedWidth(self.set_width) + self._is_collapsed = False self.setMinimumHeight(self.map_height) + self.setMaximumHeight(self.map_height) self._current_state: BeamlineStateEnum | None = None self._hovered_state: BeamlineStateEnum | None = None @@ -134,8 +138,27 @@ class BeamlineStatePanel(QFrame): self.title.setText("