From 2efaa4dd88b4d8bdd51e198a3745e35702c217bd Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 25 Jun 2025 11:26:10 +0200 Subject: [PATCH] DAQ: Add spreadsheetupdater.py --- daq/src/aaredaq/config.py | 143 +++++++++++++------------- daq/src/aaredaq/spreadsheetupdater.py | 18 ++++ 2 files changed, 90 insertions(+), 71 deletions(-) create mode 100644 daq/src/aaredaq/spreadsheetupdater.py diff --git a/daq/src/aaredaq/config.py b/daq/src/aaredaq/config.py index db8fa935..ba700046 100644 --- a/daq/src/aaredaq/config.py +++ b/daq/src/aaredaq/config.py @@ -125,10 +125,6 @@ class BeamlineConfig: self.__client.set(f"{self.__bl}:active_session", session) self.__client.expire(f"{self.__bl}:active_session", expiry_sec) - @property - def tell_mount_count(self) -> int: - return int(self.__client.incr(f"{self.__bl}:tell_mount_count")) - @property def pgroup(self) -> str | None: tmp = self.__client.get(f"{self.__bl}:pgroup") @@ -141,6 +137,70 @@ class BeamlineConfig: else: self.__client.set(f"{self.__bl}:pgroup", pgroup) + + # Beamline state management + # Atomic check if beamline is busy and if not set state to busy + def try_set_busy(self, timeout: int | None = None): + with redis_lock.Lock(self.__client, f"{self.__bl}:move_state_lock", expire=10): + if self.state_busy: + raise BeamlineBusyException("Beamline is busy") + self.state_busy = True + if timeout is not None: + self.__client.expire(f"{self.__bl}:busy", timeout) + + def set_busy(self, target: BeamlineStateEnum, timeout: int | None = None): + self.try_set_busy(timeout=timeout) + curr_state = self.state + if curr_state != target: + self.state_busy = False + raise Exception("Beamline is not in a proper state") + + def start_moving( + self, target: BeamlineStateEnum, timeout: int | None = None + ) -> BeamlineStateEnum: + self.try_set_busy(timeout=timeout) + curr_state = self.state + if target == curr_state: + self.state_busy = False + else: + self.state = BeamlineStateEnum.Moving + return curr_state + + @property + def state(self) -> BeamlineStateEnum: + raw_value = self.__client.get(f"{self.__bl}:state") + + if raw_value is None: + return BeamlineStateEnum.Maintenance + try: + int_value = int(raw_value) # Ensure it's an integer + return BeamlineStateEnum(int_value) # Convert to BeamlineStateEnum + except (ValueError, KeyError): + raise ValueError( + f"Invalid 'mx_state' value: {raw_value}. Expected integer corresponding to a BeamlineStateEnum." + ) + + @state.setter + def state(self, state: BeamlineStateEnum): + self.__client.set(f"{self.__bl}:state", state.value) + + @property + def state_busy(self) -> bool: + return self.__client.get(f"{self.__bl}:busy") is not None + + @state_busy.setter + def state_busy(self, i: bool): + if i: + self.__client.set(f"{self.__bl}:busy", "1") + else: + self.__client.delete(f"{self.__bl}:busy") + + # Other beamline settings + + @property + def tell_mount_count(self) -> int: + return int(self.__client.incr(f"{self.__bl}:tell_mount_count")) + def pixel_to_mm(self, zoom: float) -> float: cfg = self.settings return 1.0 / ( @@ -162,7 +222,6 @@ class BeamlineConfig: val_y = 0 return val_x, val_y - @beam_center.setter def beam_center(self, data: Tuple[float, float]): self.__client.set(f"{self.__bl}:beam_center_x", data[0]) @@ -214,38 +273,9 @@ class BeamlineConfig: def put_alc_bkg(self, zoom: float, data: np.ndarray): self.__client.set(f"{self.__bl}:bkg{zoom:.1f}", numpy_to_base64(data)) - @property - def state(self) -> BeamlineStateEnum: - raw_value = self.__client.get(f"{self.__bl}:state") - - if raw_value is None: - return BeamlineStateEnum.Maintenance - try: - int_value = int(raw_value) # Ensure it's an integer - return BeamlineStateEnum(int_value) # Convert to BeamlineStateEnum - except (ValueError, KeyError): - raise ValueError( - f"Invalid 'mx_state' value: {raw_value}. Expected integer corresponding to a BeamlineStateEnum." - ) - - @state.setter - def state(self, state: BeamlineStateEnum): - self.__client.set(f"{self.__bl}:state", state.value) - - @property - def state_busy(self) -> bool: - return self.__client.get(f"{self.__bl}:busy") is not None - - @state_busy.setter - def state_busy(self, i: bool): - if i: - self.__client.set(f"{self.__bl}:busy", "1") - else: - self.__client.delete(f"{self.__bl}:busy") - @property def spreadsheet(self) -> SampleShortInfoList: - tmp = self.__client.get(f"{self.__bl}:spreadsheet") + tmp = self.__client.get(f"{self.__bl}:sample_spreadsheet") if tmp is None: return SampleShortInfoList(s=[]) @@ -259,7 +289,13 @@ class BeamlineConfig: @spreadsheet.setter def spreadsheet(self, data: SampleShortInfoList): - self.__client.set(f"{self.__bl}:spreadsheet", data.model_dump_json()) + self.__client.set(f"{self.__bl}:sample_spreadsheet", data.model_dump_json()) + + def listen_changes_spreadsheet(self) -> redis.client.PubSub: + self.__client.config_set("notify-keyspace-events", "KEA") + pubsub = self.__client.pubsub() + pubsub.psubscribe(f"__keyspace@0__:{self.__bl}:sample_spreadsheet") + return pubsub @property def current_sample(self) -> SampleShortInfo | None: @@ -316,7 +352,6 @@ class BeamlineConfig: def abr_meas_pos(self, data: Coordinate): self.__client.set(f"{self.__bl}:abr_meas_pos", data.model_dump_json()) - @property def dtz(self) -> float | None: tmp = self.__client.get(f"{self.__bl}:dtz") @@ -328,39 +363,6 @@ class BeamlineConfig: def dtz(self, dtz: float): self.__client.set(f"{self.__bl}:dtz", dtz) - def listen_changes(self) -> redis.client.PubSub: - self.__client.config_set("notify-keyspace-events", "KEA") - pubsub = self.__client.pubsub() - pubsub.psubscribe(f"__keyspace@0__:{self.__bl}:*") - return pubsub - - # Atomic check if beamline is busy and if not set state to busy - def try_set_busy(self, timeout: int | None = None): - with redis_lock.Lock(self.__client, f"{self.__bl}:move_state_lock", expire=10): - if self.state_busy: - raise BeamlineBusyException("Beamline is busy") - self.state_busy = True - if timeout is not None: - self.__client.expire(f"{self.__bl}:busy", timeout) - - def set_busy(self, target: BeamlineStateEnum, timeout: int | None = None): - self.try_set_busy(timeout=timeout) - curr_state = self.state - if curr_state != target: - self.state_busy = False - raise Exception("Beamline is not in a proper state") - - def start_moving( - self, target: BeamlineStateEnum, timeout: int | None = None - ) -> BeamlineStateEnum: - self.try_set_busy(timeout=timeout) - curr_state = self.state - if target == curr_state: - self.state_busy = False - else: - self.state = BeamlineStateEnum.Moving - return curr_state - def clear_mark_beam(self): self.__client.delete(f"{self.__bl}:beam_mark") @@ -391,4 +393,3 @@ class BeamlineConfig: x_pxl = np.polyval(model.coeff_x, zoom) y_pxl = np.polyval(model.coeff_y, zoom) return float(x_pxl), float(y_pxl) - diff --git a/daq/src/aaredaq/spreadsheetupdater.py b/daq/src/aaredaq/spreadsheetupdater.py new file mode 100644 index 00000000..c6bd7eb4 --- /dev/null +++ b/daq/src/aaredaq/spreadsheetupdater.py @@ -0,0 +1,18 @@ +import time + +from aaredaqlib.beamline import MXBeamline +from config import BeamlineConfig + +from aaredaq.aaredb import AareWrapper + +config = BeamlineConfig(MXBeamline.X06DA) +aaredb = AareWrapper(MXBeamline.X06DA) + + +while True: + try: + samples = aaredb.get_sample_info() + config.spreadsheet = samples + except Exception as e: + print(f"Error in spreadsheet updater: {e}") + time.sleep(10)