dls-dodal 1.68.0__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/METADATA +1 -31
  2. dls_dodal-2.0.0.dist-info/RECORD +354 -0
  3. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/WHEEL +1 -1
  4. dodal/_version.py +2 -2
  5. dodal/beamlines/__init__.py +10 -17
  6. dodal/beamlines/adsim.py +40 -33
  7. dodal/beamlines/b01_1.py +11 -0
  8. dodal/beamlines/b07.py +17 -21
  9. dodal/beamlines/b07_1.py +20 -22
  10. dodal/beamlines/b07_shared.py +12 -0
  11. dodal/beamlines/b16.py +1 -1
  12. dodal/beamlines/b21.py +15 -6
  13. dodal/beamlines/i02_1.py +17 -45
  14. dodal/beamlines/i02_2.py +6 -12
  15. dodal/beamlines/i03.py +8 -5
  16. dodal/beamlines/i03_supervisor.py +19 -0
  17. dodal/beamlines/i04.py +87 -184
  18. dodal/beamlines/i05.py +9 -39
  19. dodal/beamlines/i05_1.py +4 -13
  20. dodal/beamlines/i05_shared.py +51 -0
  21. dodal/beamlines/i06_1.py +26 -0
  22. dodal/beamlines/{i06.py → i06_shared.py} +25 -14
  23. dodal/beamlines/i07.py +14 -16
  24. dodal/beamlines/i09.py +76 -29
  25. dodal/beamlines/i09_1.py +25 -56
  26. dodal/beamlines/i09_1_shared.py +61 -0
  27. dodal/beamlines/i09_2.py +6 -100
  28. dodal/beamlines/i09_2_shared.py +110 -0
  29. dodal/beamlines/i10.py +60 -54
  30. dodal/beamlines/i10_1.py +99 -10
  31. dodal/beamlines/{i10_optics.py → i10_shared.py} +80 -66
  32. dodal/beamlines/i11.py +31 -18
  33. dodal/beamlines/i13_1.py +1 -1
  34. dodal/beamlines/i15.py +6 -6
  35. dodal/beamlines/i15_1.py +6 -6
  36. dodal/beamlines/i16.py +11 -0
  37. dodal/beamlines/i17.py +37 -28
  38. dodal/beamlines/i18.py +3 -4
  39. dodal/beamlines/i19_1.py +95 -34
  40. dodal/beamlines/i19_2.py +68 -52
  41. dodal/beamlines/i19_optics.py +26 -13
  42. dodal/beamlines/i20_1.py +17 -11
  43. dodal/beamlines/i21.py +44 -29
  44. dodal/beamlines/i22.py +19 -4
  45. dodal/beamlines/i23.py +20 -27
  46. dodal/beamlines/i24.py +64 -113
  47. dodal/beamlines/k07.py +99 -5
  48. dodal/beamlines/p38.py +3 -3
  49. dodal/beamlines/p60.py +35 -14
  50. dodal/beamlines/p99.py +16 -15
  51. dodal/beamlines/training_rig.py +20 -12
  52. dodal/cli.py +36 -2
  53. dodal/common/__init__.py +2 -1
  54. dodal/common/beamlines/beamline_parameters.py +2 -1
  55. dodal/common/beamlines/beamline_utils.py +11 -9
  56. dodal/common/beamlines/commissioning_mode.py +6 -3
  57. dodal/common/coordination.py +12 -14
  58. dodal/common/crystal_metadata.py +5 -8
  59. dodal/common/device_utils.py +4 -3
  60. dodal/common/maths.py +87 -19
  61. dodal/common/udc_directory_provider.py +13 -8
  62. dodal/common/visit.py +18 -21
  63. dodal/common/watcher_utils.py +13 -12
  64. dodal/device_manager.py +94 -54
  65. dodal/devices/aperturescatterguard.py +26 -27
  66. dodal/devices/areadetector/plugins/cam.py +1 -3
  67. dodal/devices/areadetector/plugins/mjpg.py +6 -5
  68. dodal/devices/attenuator/attenuator.py +12 -11
  69. dodal/devices/beamlines/b07/__init__.py +3 -0
  70. dodal/devices/{b07_1 → beamlines/b07_1}/__init__.py +2 -2
  71. dodal/devices/{b07_1 → beamlines/b07_1}/ccmc.py +5 -10
  72. dodal/devices/{b16 → beamlines/b16}/detector.py +2 -3
  73. dodal/devices/{i02_1 → beamlines/i02_1}/fast_grid_scan.py +2 -3
  74. dodal/devices/{i02_1 → beamlines/i02_1}/sample_motors.py +1 -1
  75. dodal/devices/{i03 → beamlines/i03}/beamsize.py +11 -7
  76. dodal/devices/{i03 → beamlines/i03}/dcm.py +1 -2
  77. dodal/devices/{i03 → beamlines/i03}/undulator_dcm.py +4 -5
  78. dodal/devices/beamlines/i04/beam_centre.py +151 -0
  79. dodal/devices/{i04 → beamlines/i04}/beamsize.py +11 -7
  80. dodal/devices/beamlines/i04/max_pixel.py +25 -0
  81. dodal/devices/{i04 → beamlines/i04}/murko_results.py +23 -8
  82. dodal/devices/{i04 → beamlines/i04}/transfocator.py +10 -15
  83. dodal/devices/beamlines/i05/__init__.py +3 -0
  84. dodal/devices/beamlines/i06_shared/__init__.py +3 -0
  85. dodal/devices/beamlines/i06_shared/i06_enum.py +7 -0
  86. dodal/devices/{i07 → beamlines/i07}/dcm.py +2 -3
  87. dodal/devices/{i07 → beamlines/i07}/id.py +8 -9
  88. dodal/devices/beamlines/i09/__init__.py +3 -0
  89. dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_energy.py +5 -6
  90. dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/hard_undulator_functions.py +19 -16
  91. dodal/devices/{i10 → beamlines/i10}/diagnostics.py +4 -3
  92. dodal/devices/{i10 → beamlines/i10}/i10_apple2.py +37 -51
  93. dodal/devices/{i10 → beamlines/i10}/rasor/rasor_current_amp.py +1 -24
  94. dodal/devices/{i10 → beamlines/i10}/rasor/rasor_motors.py +2 -2
  95. dodal/devices/{i10 → beamlines/i10}/slits.py +5 -3
  96. dodal/devices/beamlines/i10_1/__init__.py +9 -0
  97. dodal/devices/beamlines/i10_1/electromagnet/magnet.py +16 -0
  98. dodal/devices/beamlines/i10_1/electromagnet/stages.py +14 -0
  99. dodal/devices/beamlines/i10_1/scaler_cards.py +13 -0
  100. dodal/devices/{i11 → beamlines/i11}/cyberstar_blower.py +1 -1
  101. dodal/devices/{i11 → beamlines/i11}/diff_stages.py +4 -6
  102. dodal/devices/{i11 → beamlines/i11}/mythen.py +3 -4
  103. dodal/devices/{i11 → beamlines/i11}/nx100robot.py +6 -6
  104. dodal/devices/{i11 → beamlines/i11}/spinner.py +1 -1
  105. dodal/devices/{i13_1 → beamlines/i13_1}/merlin.py +1 -1
  106. dodal/devices/{i15 → beamlines/i15}/dcm.py +1 -2
  107. dodal/devices/{i15 → beamlines/i15}/focussing_mirror.py +5 -5
  108. dodal/devices/{i15 → beamlines/i15}/jack.py +2 -2
  109. dodal/devices/{i15 → beamlines/i15}/multilayer_mirror.py +1 -1
  110. dodal/devices/{i17 → beamlines/i17}/i17_apple2.py +16 -22
  111. dodal/devices/{i18 → beamlines/i18}/diode.py +1 -1
  112. dodal/devices/{i19 → beamlines/i19}/access_controlled/attenuator_motor_squad.py +12 -8
  113. dodal/devices/{i19 → beamlines/i19}/access_controlled/blueapi_device.py +16 -15
  114. dodal/devices/beamlines/i19/access_controlled/piezo_control.py +72 -0
  115. dodal/devices/{i19 → beamlines/i19}/access_controlled/shutter.py +11 -9
  116. dodal/devices/{i19 → beamlines/i19}/backlight.py +3 -1
  117. dodal/devices/{i19 → beamlines/i19}/mapt_configuration.py +2 -1
  118. dodal/devices/{i19 → beamlines/i19}/pin_col_stages.py +11 -8
  119. dodal/devices/beamlines/i19/pin_tip.py +32 -0
  120. dodal/devices/beamlines/i21/__init__.py +3 -0
  121. dodal/devices/{i22 → beamlines/i22}/dcm.py +1 -2
  122. dodal/devices/{i22 → beamlines/i22}/fswitch.py +1 -3
  123. dodal/devices/{i22 → beamlines/i22}/nxsas.py +5 -4
  124. dodal/devices/{i24 → beamlines/i24}/beam_center.py +1 -1
  125. dodal/devices/{i24 → beamlines/i24}/beamstop.py +2 -2
  126. dodal/devices/{i24 → beamlines/i24}/commissioning_jungfrau.py +12 -12
  127. dodal/devices/{i24 → beamlines/i24}/dcm.py +1 -3
  128. dodal/devices/{i24 → beamlines/i24}/dual_backlight.py +3 -3
  129. dodal/devices/{i24 → beamlines/i24}/pmac.py +9 -7
  130. dodal/devices/{p60 → beamlines/p60}/lab_xray_source.py +1 -1
  131. dodal/devices/beamlines/p99/__init__.py +0 -0
  132. dodal/devices/{p99 → beamlines/p99}/andor2_point.py +11 -15
  133. dodal/devices/bimorph_mirror.py +22 -20
  134. dodal/devices/collimation_table.py +3 -2
  135. dodal/devices/common_dcm.py +30 -20
  136. dodal/devices/controllers.py +2 -2
  137. dodal/devices/cryostream.py +8 -0
  138. dodal/devices/current_amplifiers/current_amplifier.py +16 -18
  139. dodal/devices/current_amplifiers/current_amplifier_detector.py +9 -10
  140. dodal/devices/current_amplifiers/femto.py +8 -9
  141. dodal/devices/current_amplifiers/sr570.py +16 -16
  142. dodal/devices/current_amplifiers/struck_scaler_counter.py +5 -5
  143. dodal/devices/detector/det_resolution.py +9 -8
  144. dodal/devices/detector/detector.py +4 -2
  145. dodal/devices/diamond_filter.py +3 -4
  146. dodal/devices/eiger.py +32 -17
  147. dodal/devices/eiger_odin.py +1 -1
  148. dodal/devices/electron_analyser/base/__init__.py +3 -3
  149. dodal/devices/electron_analyser/base/base_controller.py +32 -21
  150. dodal/devices/electron_analyser/base/base_detector.py +15 -20
  151. dodal/devices/electron_analyser/base/base_driver_io.py +39 -46
  152. dodal/devices/electron_analyser/base/base_enums.py +0 -5
  153. dodal/devices/electron_analyser/base/base_region.py +29 -31
  154. dodal/devices/electron_analyser/base/base_util.py +18 -16
  155. dodal/devices/electron_analyser/base/energy_sources.py +35 -40
  156. dodal/devices/electron_analyser/specs/specs_detector.py +7 -6
  157. dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +7 -6
  158. dodal/devices/eurotherm.py +3 -2
  159. dodal/devices/fast_grid_scan.py +31 -34
  160. dodal/devices/fast_shutter.py +125 -39
  161. dodal/devices/flux.py +1 -1
  162. dodal/devices/focusing_mirror.py +29 -11
  163. dodal/devices/hutch_shutter.py +6 -6
  164. dodal/devices/insertion_device/__init__.py +20 -8
  165. dodal/devices/insertion_device/apple2_controller.py +371 -0
  166. dodal/devices/insertion_device/apple2_undulator.py +184 -587
  167. dodal/devices/insertion_device/apple_knot_controller.py +222 -0
  168. dodal/devices/insertion_device/energy.py +161 -0
  169. dodal/devices/insertion_device/energy_motor_lookup.py +21 -28
  170. dodal/devices/insertion_device/lookup_table_models.py +47 -52
  171. dodal/devices/insertion_device/polarisation.py +36 -0
  172. dodal/devices/ipin.py +1 -1
  173. dodal/devices/linkam3.py +7 -5
  174. dodal/devices/motors.py +107 -19
  175. dodal/devices/mx_phase1/beamstop.py +2 -4
  176. dodal/devices/oav/oav_calculations.py +20 -13
  177. dodal/devices/oav/oav_detector.py +92 -22
  178. dodal/devices/oav/oav_parameters.py +4 -9
  179. dodal/devices/oav/oav_to_redis_forwarder.py +22 -18
  180. dodal/devices/oav/pin_image_recognition/__init__.py +4 -6
  181. dodal/devices/oav/pin_image_recognition/manual_test.py +1 -2
  182. dodal/devices/oav/pin_image_recognition/utils.py +30 -32
  183. dodal/devices/oav/snapshots/grid_overlay.py +10 -9
  184. dodal/devices/oav/snapshots/snapshot_image_processing.py +15 -13
  185. dodal/devices/oav/utils.py +20 -6
  186. dodal/devices/p45.py +3 -9
  187. dodal/devices/pgm.py +8 -14
  188. dodal/devices/pressure_jump_cell.py +93 -32
  189. dodal/devices/qbpm.py +1 -3
  190. dodal/devices/robot.py +45 -20
  191. dodal/devices/s4_slit_gaps.py +1 -1
  192. dodal/devices/selectable_source.py +41 -0
  193. dodal/devices/slits.py +2 -5
  194. dodal/devices/smargon.py +2 -3
  195. dodal/devices/temperture_controller/lakeshore/lakeshore.py +38 -64
  196. dodal/devices/temperture_controller/lakeshore/lakeshore_io.py +21 -35
  197. dodal/devices/tetramm.py +7 -7
  198. dodal/devices/turbo_slit.py +8 -7
  199. dodal/devices/undulator.py +42 -56
  200. dodal/devices/util/adjuster_plans.py +2 -3
  201. dodal/devices/util/epics_util.py +10 -10
  202. dodal/devices/util/lookup_tables.py +17 -18
  203. dodal/devices/v2f.py +2 -3
  204. dodal/devices/watsonmarlow323_pump.py +1 -1
  205. dodal/devices/xbpm_feedback.py +3 -2
  206. dodal/devices/xspress3/xspress3.py +8 -11
  207. dodal/devices/xspress3/xspress3_channel.py +3 -6
  208. dodal/devices/zebra/zebra.py +21 -7
  209. dodal/devices/zebra/zebra_constants_mapping.py +12 -7
  210. dodal/devices/zebra/zebra_controlled_shutter.py +2 -1
  211. dodal/devices/zocalo/zocalo_interaction.py +14 -14
  212. dodal/devices/zocalo/zocalo_results.py +33 -33
  213. dodal/log.py +23 -20
  214. dodal/plan_stubs/check_topup.py +15 -15
  215. dodal/plan_stubs/data_session.py +6 -6
  216. dodal/plan_stubs/motor_utils.py +22 -18
  217. dodal/plan_stubs/pressure_jump_cell.py +18 -0
  218. dodal/plan_stubs/wrapped.py +40 -55
  219. dodal/plans/bimorph.py +63 -52
  220. dodal/plans/configure_arm_trigger_and_disarm_detector.py +0 -1
  221. dodal/plans/device_setup_plans/__init__.py +5 -0
  222. dodal/plans/device_setup_plans/setup_pin_tip_params.py +63 -0
  223. dodal/plans/preprocessors/verify_undulator_gap.py +10 -8
  224. dodal/plans/spec_path.py +3 -5
  225. dodal/plans/verify_undulator_gap.py +1 -2
  226. dodal/plans/wrapped.py +4 -3
  227. dodal/testing/__init__.py +0 -0
  228. dodal/testing/electron_analyser/device_factory.py +5 -7
  229. dodal/testing/fixtures/devices/apple2.py +38 -0
  230. dodal/testing/fixtures/run_engine.py +3 -7
  231. dodal/testing/fixtures/utils.py +1 -2
  232. dodal/utils.py +60 -58
  233. dls_dodal-1.68.0.dist-info/RECORD +0 -330
  234. dodal/beamline_specific_utils/i05_shared.py +0 -14
  235. dodal/devices/b07/__init__.py +0 -3
  236. dodal/devices/i04/max_pixel.py +0 -38
  237. dodal/devices/i05/__init__.py +0 -3
  238. dodal/devices/i09/__init__.py +0 -3
  239. dodal/devices/i21/__init__.py +0 -5
  240. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/entry_points.txt +0 -0
  241. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/licenses/LICENSE +0 -0
  242. {dls_dodal-1.68.0.dist-info → dls_dodal-2.0.0.dist-info}/top_level.txt +0 -0
  243. /dodal/{beamline_specific_utils → devices/beamlines}/__init__.py +0 -0
  244. /dodal/devices/{b07 → beamlines/b07}/enums.py +0 -0
  245. /dodal/devices/{b07_1 → beamlines/b07_1}/enums.py +0 -0
  246. /dodal/devices/{b16 → beamlines/b16}/__init__.py +0 -0
  247. /dodal/devices/{i02_1 → beamlines/i02_1}/__init__.py +0 -0
  248. /dodal/devices/{i02_2 → beamlines/i02_2}/__init__.py +0 -0
  249. /dodal/devices/{i03 → beamlines/i03}/__init__.py +0 -0
  250. /dodal/devices/{i03 → beamlines/i03}/constants.py +0 -0
  251. /dodal/devices/{i04 → beamlines/i04}/__init__.py +0 -0
  252. /dodal/devices/{i04 → beamlines/i04}/constants.py +0 -0
  253. /dodal/devices/{i05 → beamlines/i05}/enums.py +0 -0
  254. /dodal/devices/{i07 → beamlines/i07}/__init__.py +0 -0
  255. /dodal/devices/{i09 → beamlines/i09}/enums.py +0 -0
  256. /dodal/devices/{i09_1 → beamlines/i09_1}/__init__.py +0 -0
  257. /dodal/devices/{i09_1 → beamlines/i09_1}/enums.py +0 -0
  258. /dodal/devices/{i09_1_shared → beamlines/i09_1_shared}/__init__.py +0 -0
  259. /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/__init__.py +0 -0
  260. /dodal/devices/{i09_2_shared → beamlines/i09_2_shared}/i09_apple2.py +0 -0
  261. /dodal/devices/{i10 → beamlines/i10}/__init__.py +0 -0
  262. /dodal/devices/{i10 → beamlines/i10}/i10_setting_data.py +0 -0
  263. /dodal/devices/{i10 → beamlines/i10}/mirrors.py +0 -0
  264. /dodal/devices/{i10 → beamlines/i10}/rasor/__init__.py +0 -0
  265. /dodal/devices/{i10 → beamlines/i10}/rasor/rasor_scaler_cards.py +0 -0
  266. /dodal/devices/{i11 → beamlines/i10_1/electromagnet}/__init__.py +0 -0
  267. /dodal/devices/{i13_1 → beamlines/i11}/__init__.py +0 -0
  268. /dodal/devices/{i15 → beamlines/i13_1}/__init__.py +0 -0
  269. /dodal/devices/{i13_1 → beamlines/i13_1}/merlin_controller.py +0 -0
  270. /dodal/devices/{i17 → beamlines/i15}/__init__.py +0 -0
  271. /dodal/devices/{i15 → beamlines/i15}/laue.py +0 -0
  272. /dodal/devices/{i15 → beamlines/i15}/motors.py +0 -0
  273. /dodal/devices/{i15 → beamlines/i15}/rail.py +0 -0
  274. /dodal/devices/{i18 → beamlines/i17}/__init__.py +0 -0
  275. /dodal/devices/{i19 → beamlines/i18}/__init__.py +0 -0
  276. /dodal/devices/{i18 → beamlines/i18}/kb_mirror.py +0 -0
  277. /dodal/devices/{i19/access_controlled → beamlines/i19}/__init__.py +0 -0
  278. /dodal/devices/{i20_1 → beamlines/i19/access_controlled}/__init__.py +0 -0
  279. /dodal/devices/{i19 → beamlines/i19}/access_controlled/hutch_access.py +0 -0
  280. /dodal/devices/{i19 → beamlines/i19}/beamstop.py +0 -0
  281. /dodal/devices/{i19 → beamlines/i19}/diffractometer.py +0 -0
  282. /dodal/devices/{i22 → beamlines/i20_1}/__init__.py +0 -0
  283. /dodal/devices/{i21 → beamlines/i21}/enums.py +0 -0
  284. /dodal/devices/{i24 → beamlines/i22}/__init__.py +0 -0
  285. /dodal/devices/{p99 → beamlines/i24}/__init__.py +0 -0
  286. /dodal/devices/{i24 → beamlines/i24}/aperture.py +0 -0
  287. /dodal/devices/{i24 → beamlines/i24}/focus_mirrors.py +0 -0
  288. /dodal/devices/{i24 → beamlines/i24}/vgonio.py +0 -0
  289. /dodal/devices/{p60 → beamlines/p60}/__init__.py +0 -0
  290. /dodal/devices/{p60 → beamlines/p60}/enums.py +0 -0
  291. /dodal/devices/{p99 → beamlines/p99}/sample_stage.py +0 -0
  292. /dodal/devices/insertion_device/{id_enum.py → enum.py} +0 -0
dodal/devices/robot.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  from asyncio import FIRST_COMPLETED, CancelledError, Task, wait_for
3
3
  from dataclasses import dataclass
4
+ from enum import IntEnum
4
5
 
5
6
  from bluesky.protocols import Movable
6
7
  from ophyd_async.core import (
@@ -21,8 +22,8 @@ from ophyd_async.epics.core import (
21
22
 
22
23
  from dodal.log import LOGGER
23
24
 
24
- WAIT_FOR_OLD_PIN_MSG = "Waiting on old pin unloaded"
25
- WAIT_FOR_NEW_PIN_MSG = "Waiting on new pin loaded"
25
+ WAIT_FOR_BEAMLINE_DISABLE_MSG = "Waiting on beamline disable"
26
+ WAIT_FOR_BEAMLINE_ENABLE_MSG = "Waiting on beamline enable"
26
27
 
27
28
 
28
29
  class RobotLoadError(Exception):
@@ -43,11 +44,19 @@ class SampleLocation:
43
44
  pin: int
44
45
 
45
46
 
47
+ SAMPLE_LOCATION_EMPTY = SampleLocation(-1, -1)
48
+
49
+
46
50
  class PinMounted(StrictEnum):
47
51
  NO_PIN_MOUNTED = "No Pin Mounted"
48
52
  PIN_MOUNTED = "Pin Mounted"
49
53
 
50
54
 
55
+ class BeamlineStatus(IntEnum):
56
+ ENABLED = 0
57
+ DISABLED = 1
58
+
59
+
51
60
  class ErrorStatus(Device):
52
61
  def __init__(self, prefix: str) -> None:
53
62
  self.str = epics_signal_r(str, prefix + "_ERR_MSG")
@@ -61,7 +70,7 @@ class ErrorStatus(Device):
61
70
  raise RobotLoadError(int(error_code), error_string) from raise_from
62
71
 
63
72
 
64
- class BartRobot(StandardReadable, Movable[SampleLocation | None]):
73
+ class BartRobot(StandardReadable, Movable[SampleLocation]):
65
74
  """The sample changing robot."""
66
75
 
67
76
  # How long to wait for the robot if it is busy soaking/drying
@@ -78,6 +87,11 @@ class BartRobot(StandardReadable, Movable[SampleLocation | None]):
78
87
  # How far the gonio position can be out before loading will fail
79
88
  LOAD_TOLERANCE_MM = 0.02
80
89
 
90
+ # mode constants for CRYO_MODE - TODO when https://jira.diamond.ac.uk/browse/I03-1056
91
+ # is completed these should be made into a proper enum
92
+ CRYO_MODE_WARM = 0.0
93
+ CRYO_MODE_CRYO = 1.0
94
+
81
95
  def __init__(self, prefix: str, name: str = "") -> None:
82
96
  with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
83
97
  self.barcode = epics_signal_r(str, prefix + "BARCODE")
@@ -86,6 +100,8 @@ class BartRobot(StandardReadable, Movable[SampleLocation | None]):
86
100
  self.current_puck = epics_signal_r(float, prefix + "CURRENT_PUCK_RBV")
87
101
  self.current_pin = epics_signal_r(float, prefix + "CURRENT_PIN_RBV")
88
102
 
103
+ self.beamline_disabled = epics_signal_r(int, prefix + "ROBOT_OP_16_BITS.B8")
104
+
89
105
  self.next_pin = epics_signal_rw_rbv(float, prefix + "NEXT_PIN")
90
106
  self.next_puck = epics_signal_rw_rbv(float, prefix + "NEXT_PUCK")
91
107
 
@@ -116,8 +132,8 @@ class BartRobot(StandardReadable, Movable[SampleLocation | None]):
116
132
  )
117
133
  super().__init__(name=name)
118
134
 
119
- async def pin_state_or_error(self, expected_state=PinMounted.PIN_MOUNTED):
120
- """This co-routine will finish when either the pin sensor reaches the specified
135
+ async def beamline_status_or_error(self, expected_state: BeamlineStatus):
136
+ """This co-routine will finish when either the beamline reaches the specified
121
137
  state or the robot gives an error (whichever happens first). In the case where
122
138
  there is an error a RobotLoadError error is raised.
123
139
  """
@@ -130,12 +146,12 @@ class BartRobot(StandardReadable, Movable[SampleLocation | None]):
130
146
  error_msg = await self.prog_error.str.get_value()
131
147
  raise RobotLoadError(error_code, error_msg)
132
148
 
133
- async def wfv():
134
- await wait_for_value(self.gonio_pin_sensor, expected_state, None)
149
+ async def wait_for_expected_state():
150
+ await wait_for_value(self.beamline_disabled, expected_state.value, None)
135
151
 
136
152
  tasks = [
137
153
  (Task(raise_if_error())),
138
- (Task(wfv())),
154
+ (Task(wait_for_expected_state())),
139
155
  ]
140
156
  try:
141
157
  finished, unfinished = await asyncio.wait(
@@ -171,31 +187,40 @@ class BartRobot(StandardReadable, Movable[SampleLocation | None]):
171
187
  set_and_wait_for_value(self.next_pin, sample_location.pin),
172
188
  )
173
189
  await self.load.trigger()
174
- if await self.gonio_pin_sensor.get_value() == PinMounted.PIN_MOUNTED:
175
- LOGGER.info(WAIT_FOR_OLD_PIN_MSG)
176
- await self.pin_state_or_error(PinMounted.NO_PIN_MOUNTED)
177
- LOGGER.info(WAIT_FOR_NEW_PIN_MSG)
190
+ await self._wait_for_beamline_enabled_after_load_or_unload()
191
+
192
+ async def _wait_for_beamline_enabled_after_load_or_unload(self):
193
+ if await self.beamline_disabled.get_value() == BeamlineStatus.ENABLED.value:
194
+ LOGGER.info(WAIT_FOR_BEAMLINE_DISABLE_MSG)
195
+ await self.beamline_status_or_error(BeamlineStatus.DISABLED)
178
196
 
179
- await self.pin_state_or_error()
197
+ LOGGER.info(WAIT_FOR_BEAMLINE_ENABLE_MSG)
198
+ await self.beamline_status_or_error(BeamlineStatus.ENABLED)
180
199
 
181
200
  @AsyncStatus.wrap
182
- async def set(self, value: SampleLocation | None):
183
- """
184
- Perform a sample load from the specified sample location
201
+ async def set(self, value: SampleLocation):
202
+ """Perform a sample load from the specified sample location.
203
+
185
204
  Args:
186
- value: The pin and puck to load, or None to unload the sample.
205
+ value (SampleLocation): The pin and puck to load, or SAMPLE_LOCATION_EMPTY
206
+ to unload the sample.
207
+
187
208
  Raises:
188
- RobotLoadError if a timeout occurs, or if an error occurs loading the smaple.
209
+ RobotLoadError: If a timeout occurs, or if an error occurs loading the
210
+ sample.
189
211
  """
190
212
  try:
191
- if value is not None:
213
+ if value != SAMPLE_LOCATION_EMPTY:
192
214
  await wait_for(
193
215
  self._load_pin_and_puck(value),
194
216
  timeout=self.LOAD_TIMEOUT + self.NOT_BUSY_TIMEOUT,
195
217
  )
196
218
  else:
197
219
  await self.unload.trigger(timeout=self.LOAD_TIMEOUT)
198
- await wait_for_value(self.program_running, False, self.NOT_BUSY_TIMEOUT)
220
+ await wait_for(
221
+ self._wait_for_beamline_enabled_after_load_or_unload(),
222
+ timeout=self.LOAD_TIMEOUT + self.NOT_BUSY_TIMEOUT,
223
+ )
199
224
  except TimeoutError as e:
200
225
  await self.prog_error.raise_if_error(e)
201
226
  await self.controller_error.raise_if_error(e)
@@ -3,7 +3,7 @@ from ophyd_async.epics.motor import Motor
3
3
 
4
4
 
5
5
  class S4SlitGaps(StandardReadable):
6
- """Note that the S4 slits have a different PV fromat to other beamline slits"""
6
+ """Note that the S4 slits have a different PV fromat to other beamline slits."""
7
7
 
8
8
  def __init__(self, prefix: str, name="") -> None:
9
9
  with self.add_children_as_readables():
@@ -0,0 +1,41 @@
1
+ from typing import TypeVar
2
+
3
+ from bluesky.protocols import Movable
4
+ from ophyd_async.core import AsyncStatus, StandardReadable, StrictEnum, soft_signal_rw
5
+
6
+
7
+ class SelectedSource(StrictEnum):
8
+ SOURCE1 = "source1"
9
+ SOURCE2 = "source2"
10
+
11
+
12
+ T = TypeVar("T")
13
+
14
+
15
+ def get_obj_from_selected_source(selected_source: SelectedSource, s1: T, s2: T) -> T:
16
+ """Util function that maps enum values for SelectedSource to two objects. It then
17
+ returns one of the objects that corrosponds to the selected_source value.
18
+ """
19
+ match selected_source:
20
+ case SelectedSource.SOURCE1:
21
+ return s1
22
+ case SelectedSource.SOURCE2:
23
+ return s2
24
+
25
+
26
+ class SourceSelector(StandardReadable, Movable[SelectedSource]):
27
+ """Device that holds a selected_source signal enum of SelectedSource. Useful for
28
+ beamlines with multiple sources to coordinate which energy source or shutter to
29
+ use.
30
+ """
31
+
32
+ def __init__(self, name: str = ""):
33
+ with self.add_children_as_readables():
34
+ self.selected_source = soft_signal_rw(
35
+ SelectedSource, SelectedSource.SOURCE1
36
+ )
37
+ super().__init__(name)
38
+
39
+ @AsyncStatus.wrap
40
+ async def set(self, value: SelectedSource):
41
+ await self.selected_source.set(value)
dodal/devices/slits.py CHANGED
@@ -19,8 +19,7 @@ class MinimalSlits(StandardReadable):
19
19
 
20
20
 
21
21
  class Slits(MinimalSlits):
22
- """
23
- Representation of a 4-blade set of slits. Allows control/readout of the gap
22
+ """Representation of a 4-blade set of slits. Allows control/readout of the gap
24
23
  between each pair of blades.
25
24
  """
26
25
 
@@ -40,9 +39,7 @@ class Slits(MinimalSlits):
40
39
 
41
40
 
42
41
  class SlitsY(StandardReadable):
43
- """
44
- Representation of a 2-blade slits.
45
- """
42
+ """Representation of a 2-blade slits."""
46
43
 
47
44
  def __init__(
48
45
  self,
dodal/devices/smargon.py CHANGED
@@ -68,7 +68,7 @@ class DeferMoves(StrictEnum):
68
68
 
69
69
 
70
70
  class CombinedMove(TypedDict, total=False):
71
- """A move on multiple axes at once using a deferred move"""
71
+ """A move on multiple axes at once using a deferred move."""
72
72
 
73
73
  x: float | None
74
74
  y: float | None
@@ -79,8 +79,7 @@ class CombinedMove(TypedDict, total=False):
79
79
 
80
80
 
81
81
  class Smargon(XYZOmegaStage, Movable):
82
- """
83
- Real motors added to allow stops following pin load (e.g. real_x1.stop() )
82
+ """Real motors added to allow stops following pin load (e.g. real_x1.stop() )
84
83
  X1 and X2 real motors provide compound chi motion as well as the compound X travel,
85
84
  increasing the gap between x1 and x2 changes chi, moving together changes virtual x.
86
85
  Robot loading can nudge these and lead to errors.
@@ -24,31 +24,28 @@ class Heater336Settings(StrictEnum):
24
24
 
25
25
 
26
26
  class Lakeshore(LakeshoreBaseIO, StandardReadable, Movable[float]):
27
- """
28
- Device for controlling and reading from a Lakeshore temperature controller.
27
+ """Device for controlling and reading from a Lakeshore temperature controller.
29
28
  It supports multiple channels and PID control.
30
29
 
31
- Attributes
32
- ----------
33
- temperature : LakeshoreBaseIO
34
- Temperature IO interface.
35
- PID : PIDBaseIO
36
- PID IO interface.
37
- control_channel : derived_signal_rw
38
- Signal for selecting the control channel,
39
- optional readback as hinted signal
40
- (default readback channel is the same as control channel).
41
-
42
- temperature_high_limit: soft_signal_rw
43
- Signal to store the soft high temperature limit.
44
- temperature_low_limit: soft_signal_rw
45
- Signal to store the soft low temperature limit.
46
-
47
-
48
- Methods
49
- -------
50
- set(value: float)
51
- Set the temperature setpoint for the selected control channel.
30
+ Attributes:
31
+ temperature (LakeshoreBaseIO): Temperature IO interface.
32
+ PID (PIDBaseIO): PID IO interface.
33
+ control_channel (derived_signal_rw): Signal for selecting the control channel,
34
+ optional readback as hinted signal (default readback channel is the same
35
+ as control channel).
36
+ temperature_high_limit (soft_signal_rw): Signal to store the soft high
37
+ temperature limit.
38
+ temperature_low_limit (soft_signal_rw): Signal to store the soft low
39
+ temperature limit.
40
+
41
+ Args:
42
+ prefix (str): The EPICS prefix for the device.
43
+ no_channels (int): Number of temperature channels.
44
+ heater_setting (type[SignalDatatypeT]): Enum type for heater settings.
45
+ control_channel (int, optional): The initial control channel (default is 1).
46
+ single_control_channel (bool, optional): Whether to use a single control
47
+ channel (default is False).
48
+ name (str, optional): Name of the device.
52
49
  """
53
50
 
54
51
  def __init__(
@@ -60,22 +57,6 @@ class Lakeshore(LakeshoreBaseIO, StandardReadable, Movable[float]):
60
57
  single_control_channel: bool = False,
61
58
  name: str = "",
62
59
  ):
63
- """
64
- Parameters
65
- ----------
66
- prefix : str
67
- The EPICS prefix for the device.
68
- no_channels : int
69
- Number of temperature channels.
70
- heater_setting : type[SignalDatatypeT]
71
- Enum type for heater settings.
72
- control_channel : int, optional
73
- The initial control channel (default is 1).
74
- single_control_channel : bool, optional
75
- Whether to use a single control channel (default is False).
76
- name : str, optional
77
- Name of the device.
78
- """
79
60
  self._control_channel = soft_signal_rw(int, initial_value=control_channel)
80
61
  self.temperature_high_limit = soft_signal_rw(float, initial_value=400)
81
62
  self.temperature_low_limit = soft_signal_rw(float, initial_value=0)
@@ -113,9 +94,7 @@ class Lakeshore(LakeshoreBaseIO, StandardReadable, Movable[float]):
113
94
 
114
95
  @AsyncStatus.wrap
115
96
  async def set(self, value: float) -> None:
116
- """
117
- Set the temperature setpoint for the active control channel.
118
- """
97
+ """Set the temperature setpoint for the active control channel."""
119
98
  high, low = await gather(
120
99
  self.temperature_high_limit.get_value(),
121
100
  self.temperature_low_limit.get_value(),
@@ -149,22 +128,20 @@ class Lakeshore(LakeshoreBaseIO, StandardReadable, Movable[float]):
149
128
 
150
129
 
151
130
  class Lakeshore336(Lakeshore):
131
+ """Lakeshore 336 temperature controller. With 4 readback and control channels.
132
+ Heater settings are: Off, Low, Medium, High.
133
+
134
+ Args:
135
+ prefix (str): The EPICS prefix for the device.
136
+ control_channel (int, optional): The initial control channel (default is 1).
137
+ """
138
+
152
139
  def __init__(
153
140
  self,
154
141
  prefix: str,
155
142
  control_channel: int = 1,
156
143
  name: str = "",
157
144
  ):
158
- """
159
- Lakeshore 336 temperature controller. With 4 readback and control channels.
160
- Heater settings are: Off, Low, Medium, High.
161
- Parameters
162
- ----------
163
- prefix : str
164
- The EPICS prefix for the device.
165
- control_channel : int, optional
166
- The initial control channel (default is 1).
167
- """
168
145
  super().__init__(
169
146
  prefix=prefix,
170
147
  num_readback_channel=4,
@@ -176,24 +153,21 @@ class Lakeshore336(Lakeshore):
176
153
 
177
154
 
178
155
  class Lakeshore340(Lakeshore):
156
+ """Lakeshore 340 temperature controller. With 4 readback channels and a single
157
+ control channel.
158
+ Heater settings are in power from 0 to 5. 0 is 0 watt, 5 is 50 watt.
159
+
160
+ Args:
161
+ prefix (str): The EPICS prefix for the device.
162
+ control_channel (int, optional): The initial control channel (default is 1).
163
+ """
164
+
179
165
  def __init__(
180
166
  self,
181
167
  prefix: str,
182
168
  control_channel: int = 1,
183
169
  name: str = "",
184
170
  ):
185
- """Lakeshore 340 temperature controller. With 4 readback channels and a single
186
- control channel.
187
- Heater settings are in power from 0 to 5. 0 is 0 watt, 5 is 50 watt.
188
-
189
- Parameters
190
- ----------
191
- prefix : str
192
- The EPICS prefix for the device.
193
- control_channel : int, optional
194
- The initial control channel (default is 1).
195
- """
196
-
197
171
  super().__init__(
198
172
  prefix=prefix,
199
173
  num_readback_channel=4,
@@ -3,11 +3,16 @@ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
3
3
 
4
4
 
5
5
  class LakeshoreControlChannel(Device):
6
- """
7
- Single control channel for a Lakeshore temperature controller.
6
+ """Single control channel for a Lakeshore temperature controller.
7
+
8
+ Provides access to setpoint, ramp rate, ramp enable, heater output, heater output
9
+ range, PID parameters (P, I, D), and manual output for the channel.
8
10
 
9
- Provides access to setpoint, ramp rate, ramp enable, heater output, heater output range,
10
- PID parameters (P, I, D), and manual output for the channel.
11
+ Args:
12
+ prefix (str): The EPICS prefix for the Lakeshore device.
13
+ suffix (str): Suffix for the channel, used to differentiate multiple channels.
14
+ heater_type (SignalDatatypeT): Type of the heater output range.
15
+ name (str, optional): Name for the device.
11
16
  """
12
17
 
13
18
  def __init__(
@@ -17,19 +22,6 @@ class LakeshoreControlChannel(Device):
17
22
  heater_type: type[SignalDatatypeT],
18
23
  name: str = "",
19
24
  ):
20
- """Initialize the LakeshoreControlChannel device.
21
- Parameters
22
- ----------
23
- prefix: str
24
- The EPICS prefix for the Lakeshore device.
25
- suffix: str
26
- Suffix for the channel, used to differentiate multiple channels.
27
- heater_type: SignalDatatypeT
28
- Type of the heater output range.
29
- name: str
30
- Optional name for the device.
31
- """
32
-
33
25
  def channel_rw(channel_type, pv_name):
34
26
  return epics_signal_rw(
35
27
  channel_type,
@@ -53,11 +45,21 @@ class LakeshoreControlChannel(Device):
53
45
  class LakeshoreBaseIO(Device):
54
46
  """Base class for Lakeshore temperature controller IO.
55
47
 
56
- Provides access to control channels and readback channels for setpoint, ramp rate, heater output,
57
- and PID parameters. Supports both single and multiple control channel configurations.
48
+ Provides access to control channels and readback channels for setpoint, ramp rate,
49
+ heater output, and PID parameters. Supports both single and multiple control channel
50
+ configurations.
51
+
58
52
  Note:
59
53
  Almost all models have a controller for each readback channel but some models
60
54
  only has a single controller for multiple readback channels.
55
+
56
+ Args:
57
+ prefix (str): The EPICS prefix for the Lakeshore device.
58
+ num_readback_channel (int): Number of readback channels to create.
59
+ heater_setting (SignalDatatypeT): Type of the heater setting.
60
+ name (str, optional): Name for the device.
61
+ single_control_channel (bool): If True, use a single control channel for
62
+ all readback.
61
63
  """
62
64
 
63
65
  def __init__(
@@ -68,22 +70,6 @@ class LakeshoreBaseIO(Device):
68
70
  name: str = "",
69
71
  single_control_channel: bool = False,
70
72
  ):
71
- """Initialize the LakeshoreBaseIO device.
72
-
73
- Parameters
74
- -----------
75
- prefix: str
76
- The EPICS prefix for the Lakeshore device.
77
- num_readback_channel: int
78
- Number of readback channels to create.
79
- heater_setting: SignalDatatypeT
80
- Type of the heater setting.
81
- name: str
82
- Optional name for the device.
83
- single_control_channel: bool
84
- If True, use a single control channel for all readback.
85
- """
86
-
87
73
  suffixes = (
88
74
  [""]
89
75
  if single_control_channel
dodal/devices/tetramm.py CHANGED
@@ -75,7 +75,7 @@ class TetrammDriver(NDArrayBaseIO):
75
75
 
76
76
 
77
77
  class TetrammController(DetectorController):
78
- """Controller for a TetrAMM current monitor"""
78
+ """Controller for a TetrAMM current monitor."""
79
79
 
80
80
  _supported_trigger_types = {
81
81
  DetectorTrigger.EDGE_TRIGGER: TetrammTrigger.EXT_TRIGGER,
@@ -164,9 +164,8 @@ class TetrammController(DetectorController):
164
164
  sample rate, it will be lowered to the prior multiple ot ensure triggers
165
165
  are not missed.
166
166
 
167
- :param exposure: Desired exposure time.
168
- :type exposure: How long to wait for the exposure time and acquire
169
- period to be set.
167
+ Args:
168
+ exposure (float): Desired exposure time.
170
169
  """
171
170
  sample_time = await self.driver.sample_time.get_value()
172
171
  minimum_samples = self._minimal_values_per_reading[
@@ -189,9 +188,10 @@ class TetrammController(DetectorController):
189
188
  Then, it checks that the DetectorState PV is in DEFAULT_GOOD_STATES,
190
189
  and otherwise raises a ValueError.
191
190
 
192
- :returns AsyncStatus:
193
- An AsyncStatus that can be awaited to set driver.acquire to True and perform
194
- subsequent raising (if applicable) due to detector state.
191
+ Returns:
192
+ AsyncStatus: An AsyncStatus that can be awaited to set driver.acquire to
193
+ True and perform subsequent raising (if applicable) due to detector
194
+ state.
195
195
  """
196
196
  status = await set_and_wait_for_value(
197
197
  self.driver.acquire,
@@ -4,18 +4,19 @@ from ophyd_async.epics.motor import Motor
4
4
 
5
5
 
6
6
  class TurboSlit(StandardReadable, Movable[float]):
7
- """
8
- This collection of motors coordinates time resolved XAS experiments.
7
+ """This collection of motors coordinates time resolved XAS experiments.
9
8
  It selects a beam out of the polychromatic fan.
10
9
  There is a 0.1 degrees beam that can move along a 90-ish degree arc.
11
10
  A turboslit device moves after the beam, so that the gap aligns with the beam.
12
11
  The turboslit gap can be made smaller to increase energy resolution.
13
- The xfine motor can move the slit in x direction at high frequencies for different scans.
12
+ The xfine motor can move the slit in x direction at high frequencies for different
13
+ scans.
14
14
  These slits can be scanned continously or in step mode.
15
15
  The relationship between the three motors is as follows:
16
- - arc - position of the middle of the gap in degrees (coarse/ macro) extension
17
- - gap - width in mm, provides energy resolution
18
- - xfine - main scanning axis in mm, selects the energy as part of the high frequency scan
16
+ - arc - position of the middle of the gap in degrees (coarse/ macro) extension.
17
+ - gap - width in mm, provides energy resolution.
18
+ - xfine - main scanning axis in mm, selects the energy as part of the high
19
+ frequency scan.
19
20
  """
20
21
 
21
22
  def __init__(self, prefix: str, name: str = ""):
@@ -27,5 +28,5 @@ class TurboSlit(StandardReadable, Movable[float]):
27
28
 
28
29
  @AsyncStatus.wrap
29
30
  async def set(self, value: float):
30
- """This will move the default XFINE"""
31
+ """This will move the default XFINE."""
31
32
  await self.xfine.set(value)