feat(omny): seed realistic values in SimOMNYDewar and SimOMNYTemperatures
CI for csaxs_bec / test (push) Successful in 1m52s

- SimOMNYDewar: patched_device()'s all-zero default read as an alarm
  state (LN2 flow 0.0 l/s trips OMNYDewar.is_flow_low()'s 3.8 l/s
  threshold). Seeded to a healthy/nominal state instead. These values
  are illustrative -- no real dewar-controller reference was available.
- SimOMNYTemperatures: seeded names/units/readings/setpoints for the 29
  real "TEMP" channels, sourced from the real OMNY_tempcontroller/
  tempcontrol.py channel config (name, EGU, ChanHeat, ALARMLIM) and
  cross-referenced against the existing _set_TEMP_default_setpoints()
  (already in this repo, confirmed to cover the same 29 channels).
  Heated channels read at their real setpoint; monitor-only channels get
  a plausible reading below their real alarm limit -- no channel now
  shows a false alarm. Channels not in use are now named "-" (matching
  tempcontrol.py's real default), so show_all() cleanly hides them
  instead of listing 19 fake all-zero rows. temperature_update_time and
  cryo_temperature_update_time are set to now() to avoid a false
  "controller communication is not running" warning.
- The 4 "CRYO" channels are NOT seeded yet -- pending the cryocon
  controller reference (still needed from Mirko).
This commit is contained in:
x01dc
2026-09-01 19:16:35 +02:00
parent da0121216b
commit 7aedac148c
+87 -2
View File
@@ -21,6 +21,7 @@ uses the patched-device pattern with in-memory mock PVs.
from __future__ import annotations
import random
import time
from bec_lib.logger import bec_logger
from ophyd_devices.tests.utils import patched_device
@@ -266,16 +267,100 @@ class SimOMNYSampleStorage(OMNYSampleStorage):
class SimOMNYDewar(OMNYDewar):
"""OMNYDewar with all EPICS PVs replaced by in-memory mock PVs."""
"""OMNYDewar with all EPICS PVs replaced by in-memory mock PVs, seeded to a
healthy/nominal state instead of the all-zero patched_device() default (which
reads as an alarm state: OMNYDewar.is_flow_low() trips below 3.8 l/s). These
values are illustrative -- no real dewar-controller reference was available
when writing this (unlike SimOMNYTemperatures below); adjust if real nominal
values are known.
"""
def __new__(cls, *args, **kwargs):
with patched_device(OMNYDewar, *args, **kwargs) as dewar:
dewar.dewar_press_0.put(1200)
dewar.dewar_refilling.put(0)
dewar.dewar_press_1.put(1500)
dewar.dewar_press_2.put(950)
dewar.dewar_flow_0.put(4.5) # above the 3.8 l/s is_flow_low() threshold
dewar.dewar_valvepos.put(0.35)
dewar.dewar_supply_voltage.put(24.0)
dewar.dewar_uptime_h.put(12)
dewar.dewar_uptime_m.put(30)
dewar.dewar_uptime_s.put(0)
dewar.dewar_valve_movements_h.put(0)
dewar.dewar_valve_movements_m.put(5)
dewar.dewar_valve_movements_s.put(0)
return dewar
# OMNY temperature-controller channels ("TEMP" bank, channels 1-48), sourced from the
# real OMNY_tempcontroller/tempcontrol.py channel config (name, EGU, ChanHeat, ALARMLIM)
# cross-referenced against OMNYTemperatures._set_TEMP_default_setpoints()'s existing
# per-channel setpoints (already in this repo, confirmed to cover exactly the same 29
# channels -- the setpoint value below is copied from that method, not re-derived).
# Sentinel setpoints ("no active control": -199.9 degC / 73.2 K, matching
# tempcontrol.py's configure_device()'s unused-channel convention) mark monitor-only
# channels (ChanHeat=0); those get a plausible physical reading instead of the sentinel.
# channel: (name, EGU, alarm limit, simulated current reading, real setpoint)
_TEMP_CHANNELS = {
8: ("XEye Chamber", "degC", 50, 24.0, -199.9),
9: ("Kuehlsystem RT ZufOSA", "degC", 50, 23.0, 23.0),
10: ("OSA_HaltZul_517", "K", 140, 100.0, 73.2),
16: ("XEye Air", "degC", 50, 24.0, -199.9),
17: ("SampleShield_RT_440", "degC", 50, 23.0, 23.0),
18: ("DeltaA_RT", "degC", 50, 26.0, 26.0),
19: ("DeltaB_RT", "degC", 50, 26.0, 26.0),
20: ("DeltaC_RT", "degC", 50, 26.0, 26.0),
21: ("Haube_ST_RT", "degC", 50, 23.0, 23.0),
22: ("Delta_Basisplatte", "degC", 50, 24.0, -199.9),
23: ("InterfBridge", "degC", 30, 24.0, -199.9),
24: ("XEye Cam", "degC", 50, 24.0, -199.9),
25: ("OSA_HSupp_RT_403", "degC", 50, 25.0, 25.0),
27: ("OSA_Supp_RT_404", "degC", 50, 25.0, 25.0),
28: ("ST_Shield_1", "K", 140, 100.0, 73.2),
29: ("ST_Shield_2", "K", 140, 100.0, 73.2),
30: ("OSA_CoolConn_407", "K", 125, 95.0, 73.2),
31: ("OSA_Holder_406", "K", 115, 90.0, 73.2),
35: ("Gripper_Halter_460", "degC", 5, 25.0, 25.0),
36: ("Gripper_Flex_A", "degC", 5, 25.0, 25.0),
37: ("Gripper_Flex_B", "degC", 5, 25.0, 25.0),
38: ("Gripper_A", "K", 140, 100.0, 73.2),
39: ("Gripper_B", "K", 140, 100.0, 73.2),
41: ("FZP", "degC", 1, 30.0, 30.0),
42: ("Park_RT_A", "degC", 5, 25.0, 25.0),
44: ("Park_RT_B", "degC", 5, 25.0, 25.0),
45: ("BaseBlock", "degC", 50, 24.0, -199.9),
46: ("Park_Cryo_R", "K", 140, 100.0, 73.2),
47: ("Park_Cryo_L", "K", 140, 100.0, 73.2),
}
class SimOMNYTemperatures(OMNYTemperatures):
"""OMNYTemperatures with all EPICS PVs replaced by in-memory mock PVs."""
"""OMNYTemperatures with all EPICS PVs replaced by in-memory mock PVs, seeded
with realistic per-channel names/units/readings/setpoints for the 29 real "TEMP"
channels (see _TEMP_CHANNELS above). The 4 "CRYO" channels are not seeded yet --
pending the cryocon controller reference.
"""
def __new__(cls, *args, **kwargs):
with patched_device(OMNYTemperatures, *args, **kwargs) as temperatures:
now = time.time()
for channel in range(1, 49):
if channel not in _TEMP_CHANNELS:
# matches tempcontrol.py's real ChanName default ('-') for
# channels not in use; show_all() hides these accordingly
getattr(temperatures.temperature_names, f"temperature_name{channel}").put("-")
continue
name, egu, _alarmlim, reading, setpoint = _TEMP_CHANNELS[channel]
getattr(temperatures.temperature_names, f"temperature_name{channel}").put(name)
getattr(temperatures.temperature_unit, f"temperature_unit{channel}").put(egu)
getattr(temperatures.temperature, f"temperature{channel}").put(reading)
getattr(temperatures.temperature_setpoint, f"temperature_setpoint{channel}").put(
setpoint
)
getattr(
temperatures.temperature_alarmstate, f"temperature_alarmstate{channel}"
).put(0)
temperatures.temperature_update_time.put(now)
temperatures.cryo_temperature_update_time.put(now)
return temperatures