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/ipin.py CHANGED
@@ -20,7 +20,7 @@ class IPinGain(SubsetEnum):
20
20
 
21
21
 
22
22
  class IPin(StandardReadable):
23
- """Simple device to get the ipin reading"""
23
+ """Simple device to get the ipin reading."""
24
24
 
25
25
  def __init__(self, prefix: str, name: str = "") -> None:
26
26
  with self.add_children_as_readables(
dodal/devices/linkam3.py CHANGED
@@ -14,15 +14,17 @@ class PumpControl(StrictEnum):
14
14
  # TODO: Make use of Status PV:
15
15
  # https://github.com/DiamondLightSource/dodal/issues/338
16
16
  class Linkam3(StandardReadable):
17
- """Device to represent a Linkam3 temperature controller
17
+ """Device to represent a Linkam3 temperature controller.
18
18
 
19
19
  Attributes:
20
- tolerance (float): Deadband around the setpoint within which the position is assumed to have been reached
21
- settle_time (int): The delay between reaching the setpoint and the move being considered complete
20
+ tolerance (float): Deadband around the setpoint within which the position is
21
+ assumed to have been reached.
22
+ settle_time (int): The delay between reaching the setpoint and the move being
23
+ considered complete.
22
24
 
23
25
  Args:
24
- prefix (str): PV prefix for this device
25
- name (str): unique name for this device
26
+ prefix (str): PV prefix for this device.
27
+ name (str): Unique name for this device.
26
28
  """
27
29
 
28
30
  tolerance: float = 0.5
dodal/devices/motors.py CHANGED
@@ -8,29 +8,31 @@ from ophyd_async.epics.motor import Motor
8
8
  _X, _Y, _Z = "X", "Y", "Z"
9
9
 
10
10
  _OMEGA = "OMEGA"
11
+ _POLAR = "POLAR"
12
+ _AZIMUTH = "AZIMUTH"
13
+ _TILT = "TILT"
11
14
 
12
15
 
13
16
  class Stage(StandardReadable, ABC):
14
- """
15
- For these devices, the following co-ordinates are typical but not enforced:
17
+ """For these devices, the following co-ordinates are typical but not enforced:
16
18
  - z is horizontal & parallel to the direction of beam travel
17
19
  - y is vertical and antiparallel to the force of gravity
18
20
  - x is the cross product of y🞬z
19
21
 
20
- Parameters
21
- ----------
22
- prefix:
23
- Common part of the EPICS PV for all motors, including ":".
24
- name:
25
- Name of the stage, each child motor will be named "{name}-{field_name}"
26
- *_infix:
27
- Infix between the common prefix and the EPICS motor record fields for the field.
28
- """
22
+ Attributes:
23
+ prefix (str): Common part of the EPICS PV for all motors, including ":".
24
+ name (str, optional): Name of the stage, each child motor will be named
25
+ "{name}-{field_name}".
26
+ *_infix: Infix between the common prefix and the EPICS motor record fields for
27
+ the field.
28
+ """ # noqa D415
29
29
 
30
30
  ...
31
31
 
32
32
 
33
33
  class XThetaStage(Stage):
34
+ """Two-axis stage with an x and a theta motor."""
35
+
34
36
  def __init__(
35
37
  self, prefix: str, name: str = "", x_infix: str = _X, theta_infix: str = "A"
36
38
  ):
@@ -41,6 +43,8 @@ class XThetaStage(Stage):
41
43
 
42
44
 
43
45
  class XYStage(Stage):
46
+ """A standard two-axis stage with an x and a y motor."""
47
+
44
48
  def __init__(
45
49
  self, prefix: str, name: str = "", x_infix: str = _X, y_infix: str = _Y
46
50
  ):
@@ -51,6 +55,8 @@ class XYStage(Stage):
51
55
 
52
56
 
53
57
  class XYZStage(XYStage):
58
+ """A standard three-axis stage with an x, a y, and a z motor."""
59
+
54
60
  def __init__(
55
61
  self,
56
62
  prefix: str,
@@ -65,6 +71,8 @@ class XYZStage(XYStage):
65
71
 
66
72
 
67
73
  class XYZThetaStage(XYZStage):
74
+ """Four-axis stage with a standard xyz stage and one axis of rotation: theta."""
75
+
68
76
  def __init__(
69
77
  self,
70
78
  prefix: str,
@@ -80,6 +88,8 @@ class XYZThetaStage(XYZStage):
80
88
 
81
89
 
82
90
  class XYZOmegaStage(XYZStage):
91
+ """Four-axis stage with a standard xyz stage and one axis of rotation: omega."""
92
+
83
93
  def __init__(
84
94
  self,
85
95
  prefix: str,
@@ -94,7 +104,69 @@ class XYZOmegaStage(XYZStage):
94
104
  super().__init__(prefix, name, x_infix, y_infix, z_infix)
95
105
 
96
106
 
107
+ class XYZPolarStage(XYZStage):
108
+ """Four-axis stage with a standard xyz stage and one axis of rotation: polar."""
109
+
110
+ def __init__(
111
+ self,
112
+ prefix: str,
113
+ name: str = "",
114
+ x_infix: str = _X,
115
+ y_infix: str = _Y,
116
+ z_infix: str = _Z,
117
+ polar_infix: str = _POLAR,
118
+ ) -> None:
119
+ with self.add_children_as_readables():
120
+ self.polar = Motor(prefix + polar_infix)
121
+ super().__init__(prefix, name, x_infix, y_infix, z_infix)
122
+
123
+
124
+ class XYZPolarAzimuthStage(XYZPolarStage):
125
+ """Five-axis stage with a standard xyz stage and two axis of rotation: polar and
126
+ azimuth.
127
+ """
128
+
129
+ def __init__(
130
+ self,
131
+ prefix: str,
132
+ name: str = "",
133
+ x_infix: str = _X,
134
+ y_infix: str = _Y,
135
+ z_infix: str = _Z,
136
+ polar_infix: str = _POLAR,
137
+ azimuth_infix: str = _AZIMUTH,
138
+ ):
139
+ with self.add_children_as_readables():
140
+ self.azimuth = Motor(prefix + azimuth_infix)
141
+ super().__init__(prefix, name, x_infix, y_infix, z_infix, polar_infix)
142
+
143
+
144
+ class XYZPolarAzimuthTiltStage(XYZPolarAzimuthStage):
145
+ """Six-axis stage with a standard xyz stage and three axis of rotation: polar,
146
+ azimuth and tilt.
147
+ """
148
+
149
+ def __init__(
150
+ self,
151
+ prefix: str,
152
+ name: str = "",
153
+ x_infix: str = _X,
154
+ y_infix: str = _Y,
155
+ z_infix: str = _Z,
156
+ polar_infix: str = _POLAR,
157
+ azimuth_infix: str = _AZIMUTH,
158
+ tilt_infix: str = _TILT,
159
+ ):
160
+ with self.add_children_as_readables():
161
+ self.tilt = Motor(prefix + tilt_infix)
162
+ super().__init__(
163
+ prefix, name, x_infix, y_infix, z_infix, polar_infix, azimuth_infix
164
+ )
165
+
166
+
97
167
  class XYPhiStage(XYStage):
168
+ """Three-axis stage with a standard xy stage and one axis of rotation: phi."""
169
+
98
170
  def __init__(
99
171
  self,
100
172
  prefix: str,
@@ -109,6 +181,8 @@ class XYPhiStage(XYStage):
109
181
 
110
182
 
111
183
  class XYPitchStage(XYStage):
184
+ """Three-axis stage with a standard xy stage and one axis of rotation: pitch."""
185
+
112
186
  def __init__(
113
187
  self,
114
188
  prefix: str,
@@ -123,6 +197,8 @@ class XYPitchStage(XYStage):
123
197
 
124
198
 
125
199
  class XYRollStage(XYStage):
200
+ """Three-axis stage with a standard xy stage and one axis of rotation: roll."""
201
+
126
202
  def __init__(
127
203
  self,
128
204
  prefix: str,
@@ -137,6 +213,10 @@ class XYRollStage(XYStage):
137
213
 
138
214
 
139
215
  class XYZPitchYawStage(XYZStage):
216
+ """Five-axis stage with a standard xyz stage and two axes of rotation: pitch and
217
+ yaw.
218
+ """
219
+
140
220
  def __init__(
141
221
  self,
142
222
  prefix: str,
@@ -154,6 +234,10 @@ class XYZPitchYawStage(XYZStage):
154
234
 
155
235
 
156
236
  class XYZPitchYawRollStage(XYZStage):
237
+ """Five-axis stage with a standard xyz stage and three axes of rotation: pitch, yaw,
238
+ and roll.
239
+ """
240
+
157
241
  def __init__(
158
242
  self,
159
243
  prefix: str,
@@ -173,6 +257,10 @@ class XYZPitchYawRollStage(XYZStage):
173
257
 
174
258
 
175
259
  class SixAxisGonio(XYZOmegaStage):
260
+ """Six-axis goniometer with a standard xyz stage and three axes of rotation:
261
+ kappa, phi and omega.
262
+ """
263
+
176
264
  def __init__(
177
265
  self,
178
266
  prefix: str,
@@ -184,9 +272,6 @@ class SixAxisGonio(XYZOmegaStage):
184
272
  phi_infix: str = "PHI",
185
273
  omega_infix: str = _OMEGA,
186
274
  ):
187
- """Six-axis goniometer with a standard xyz stage and three axes of rotation:
188
- kappa, phi and omega.
189
- """
190
275
  with self.add_children_as_readables():
191
276
  self.kappa = Motor(prefix + kappa_infix)
192
277
  self.phi = Motor(prefix + phi_infix)
@@ -198,6 +283,10 @@ class SixAxisGonio(XYZOmegaStage):
198
283
 
199
284
 
200
285
  class SixAxisGonioKappaPhi(XYZStage):
286
+ """Six-axis goniometer with a standard xyz stage and two axes of rotation:
287
+ kappa and phi.
288
+ """
289
+
201
290
  def __init__(
202
291
  self,
203
292
  prefix: str,
@@ -208,9 +297,6 @@ class SixAxisGonioKappaPhi(XYZStage):
208
297
  kappa_infix: str = "KAPPA",
209
298
  phi_infix: str = "PHI",
210
299
  ):
211
- """Six-axis goniometer with a standard xyz stage and two axes of rotation:
212
- kappa and phi.
213
- """
214
300
  with self.add_children_as_readables():
215
301
  self.kappa = Motor(prefix + kappa_infix)
216
302
  self.phi = Motor(prefix + phi_infix)
@@ -218,6 +304,8 @@ class SixAxisGonioKappaPhi(XYZStage):
218
304
 
219
305
 
220
306
  class YZStage(Stage):
307
+ """Two-axis stage with an x and a z motor."""
308
+
221
309
  def __init__(
222
310
  self, prefix: str, name: str = "", y_infix: str = _Y, z_infix: str = _Z
223
311
  ) -> None:
@@ -244,9 +332,9 @@ def create_axis_perp_to_rotation(motor_theta: Motor, motor_i: Motor, motor_j: Mo
244
332
  Args:
245
333
  motor_theta (Motor): this is the rotation axis of the sample.
246
334
  motor_i (Motor): this is the axis that, when the sample is at 0 deg rotation,
247
- a move here is entirely parallel with the derived axis.
335
+ a move here is entirely parallel with the derived axis.
248
336
  motor_j (Motor): this is the axis that, when the sample is at 90 deg rotation,
249
- a move here is entirely parallel with the derived axis.
337
+ a move here is entirely parallel with the derived axis.
250
338
  """
251
339
 
252
340
  def _get(j_val: float, i_val: float, rot_value: float) -> float:
@@ -14,8 +14,7 @@ _BEAMSTOP_OUT_DELTA_Y_MM = -2
14
14
 
15
15
 
16
16
  class BeamstopPositions(StrictEnum):
17
- """
18
- Beamstop positions.
17
+ """Beamstop positions.
19
18
  GDA supports Standard/High/Low resolution positions, as well as parked and
20
19
  robot load however all 3 resolution positions are the same. We also
21
20
  do not use the robot load position in Hyperion.
@@ -35,8 +34,7 @@ class BeamstopPositions(StrictEnum):
35
34
 
36
35
 
37
36
  class Beamstop(StandardReadable):
38
- """
39
- Beamstop for I03 and I04.
37
+ """Beamstop for I03 and I04.
40
38
 
41
39
  Attributes:
42
40
  x: beamstop x position in mm
@@ -11,19 +11,24 @@ def camera_coordinates_to_xyz_mm(
11
11
  y_vertical_sign: int,
12
12
  z_vertical_sign: int,
13
13
  ) -> np.ndarray:
14
- """
15
- Converts from (horizontal,vertical) pixel measurements from the OAV camera into to (x, y, z) motor coordinates in millimetres.
16
- For an overview of the coordinate system for I03 see https://github.com/DiamondLightSource/hyperion/wiki/Gridscan-Coordinate-System.
14
+ """Converts from (horizontal,vertical) pixel measurements from the OAV camera into
15
+ to (x, y, z) motor coordinates in millimetres.
16
+ For an overview of the coordinate system for I03 see
17
+ https://github.com/DiamondLightSource/hyperion/wiki/Gridscan-Coordinate-System.
17
18
 
18
19
  Args:
19
20
  horizontal (float): A i value from the camera in pixels.
20
21
  vertical (float): A j value from the camera in pixels.
21
- omega (float): The omega angle of the smargon that the horizontal, vertical measurements were obtained at.
22
- microns_per_i_pixel (float): The number of microns per i pixel, adjusted for the zoom level horizontal was measured at.
23
- microns_per_j_pixel (float): The number of microns per j pixel, adjusted for the zoom level vertical was measured at.
24
- x_horizontal_sign (int): Direction mapping for x, positive means the oav and motor are on same direction, default from hyperion
25
- y_vertical_sign (int): Direction mapping for y
26
- z_vertical_sign (int): Direction mapping for z
22
+ omega (float): The omega angle of the smargon that the horizontal, vertical
23
+ measurements were obtained at.
24
+ microns_per_i_pixel (float): The number of microns per i pixel, adjusted for
25
+ the zoom level horizontal was measured at.
26
+ microns_per_j_pixel (float): The number of microns per j pixel, adjusted for
27
+ the zoom level vertical was measured at.
28
+ x_horizontal_sign (int): Direction mapping for x, positive means the oav and
29
+ motor are on same direction, default from hyperion.
30
+ y_vertical_sign (int): Direction mapping for y.
31
+ z_vertical_sign (int): Direction mapping for z.
27
32
  """
28
33
  # Convert the vertical and horizontal into mm.
29
34
  horizontal *= microns_per_i_pixel * 1e-3
@@ -49,15 +54,17 @@ def calculate_beam_distance(
49
54
  horizontal_pixels: int,
50
55
  vertical_pixels: int,
51
56
  ) -> tuple[int, int]:
52
- """
53
- Calculates the distance between the beam centre and the given (horizontal, vertical).
57
+ """Calculates the distance between the beam centre and the given (horizontal,
58
+ vertical).
54
59
 
55
60
  Args:
61
+ beam_centre (tuple[int, int]): The position of the beam in pixels.
56
62
  horizontal_pixels (int): The x (camera coordinates) value in pixels.
57
63
  vertical_pixels (int): The y (camera coordinates) value in pixels.
64
+
58
65
  Returns:
59
- The distance between the beam centre and the (horizontal, vertical) point in pixels as a tuple
60
- (horizontal_distance, vertical_distance).
66
+ tuple: The distance between the beam centre and the (horizontal, vertical) point
67
+ in pixels as a tuple (horizontal_distance, vertical_distance).
61
68
  """
62
69
  beam_x, beam_y = beam_centre
63
70
  return (
@@ -1,13 +1,17 @@
1
+ import asyncio
1
2
  from enum import IntEnum
2
3
 
3
4
  from bluesky.protocols import Movable
4
5
  from ophyd_async.core import (
5
6
  DEFAULT_TIMEOUT,
6
7
  AsyncStatus,
8
+ DeviceMock,
9
+ DeviceVector,
7
10
  LazyMock,
8
11
  SignalR,
9
12
  SignalRW,
10
13
  StandardReadable,
14
+ default_mock_class,
11
15
  derived_signal_r,
12
16
  soft_signal_rw,
13
17
  )
@@ -22,6 +26,7 @@ from dodal.devices.oav.oav_parameters import (
22
26
  )
23
27
  from dodal.devices.oav.snapshots.snapshot import Snapshot
24
28
  from dodal.devices.oav.snapshots.snapshot_with_grid import SnapshotWithGrid
29
+ from dodal.log import LOGGER
25
30
 
26
31
 
27
32
  class Coords(IntEnum):
@@ -56,37 +61,99 @@ class NullZoomController(BaseZoomController):
56
61
  await self.level.set(value, wait=True)
57
62
 
58
63
 
59
- class ZoomController(BaseZoomController):
64
+ class BeamCentreForZoom(StandardReadable):
65
+ """These PVs hold the beam centre on the OAV at each zoom level.
66
+
67
+ When the zoom level is changed the IOC will update the OAV overlay PVs to be at
68
+ these positions.
60
69
  """
61
- Device to control the zoom level. This should be set like
62
- o = OAV(name="oav")
70
+
71
+ def __init__(
72
+ self, prefix: str, level_name_pv_suffix: str, centre_value_pv_suffix: str
73
+ ) -> None:
74
+ self.level_name = epics_signal_r(
75
+ str, f"{prefix}MP:SELECT.{level_name_pv_suffix}"
76
+ )
77
+ self.x_centre = epics_signal_rw(
78
+ float, f"{prefix}PBCX:VAL{centre_value_pv_suffix}"
79
+ )
80
+ self.y_centre = epics_signal_rw(
81
+ float, f"{prefix}PBCY:VAL{centre_value_pv_suffix}"
82
+ )
83
+ super().__init__()
84
+
85
+
86
+ class InstantMovingZoom(DeviceMock["ZoomController"]):
87
+ """Mock behaviour that instantly moves the zoom."""
88
+
89
+ async def connect(self, device: "ZoomController") -> None:
90
+ """Mock signals to do an instant move on setpoint write."""
91
+ device.DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S = 0.001 # type:ignore
92
+
93
+
94
+ @default_mock_class(InstantMovingZoom)
95
+ class ZoomController(BaseZoomController):
96
+ """Device to control the zoom level. This should be set like::
97
+
98
+ oav = OAV(name="oav")
63
99
  oav.zoom_controller.set("1.0x")
64
100
 
65
101
  Note that changing the zoom may change the AD wiring on the associated OAV, as such
66
- you should wait on any zoom changs to finish before changing the OAV wiring.
67
- """
102
+ you should wait on any zoom changes to finish before changing the OAV wiring.
103
+ """ # noqa 415
104
+
105
+ DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S = 2
68
106
 
69
107
  def __init__(self, prefix: str, name: str = "") -> None:
70
108
  self.percentage = epics_signal_rw(float, f"{prefix}ZOOMPOSCMD")
71
109
 
72
110
  # Level is the string description of the zoom level e.g. "1.0x" or "1.0"
73
111
  self.level = epics_signal_rw(str, f"{prefix}MP:SELECT")
112
+
74
113
  super().__init__(name=name)
75
114
 
76
115
  @AsyncStatus.wrap
77
116
  async def set(self, value: str):
78
117
  await self.level.set(value, wait=True)
118
+ LOGGER.info(
119
+ f"Waiting {self.DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S} seconds for zoom to be noticeable"
120
+ )
121
+ await asyncio.sleep(self.DELAY_BETWEEN_MOTORS_AND_IMAGE_UPDATING_S)
79
122
 
80
123
 
81
- class OAV(StandardReadable):
82
- """
83
- Class for oav device
124
+ class ZoomControllerWithBeamCentres(ZoomController):
125
+ def __init__(self, prefix: str, name: str = "") -> None:
126
+ level_to_centre_mapping = [
127
+ ("ZRST", "A"),
128
+ ("ONST", "B"),
129
+ ("TWST", "C"),
130
+ ("THST", "D"),
131
+ ("FRST", "E"),
132
+ ("FVST", "F"),
133
+ ("SXST", "G"),
134
+ ("SVST", "H"),
135
+ ]
136
+
137
+ self.beam_centres = DeviceVector(
138
+ {
139
+ i: BeamCentreForZoom(prefix, *level_to_centre_mapping[i])
140
+ for i in range(len(level_to_centre_mapping))
141
+ }
142
+ )
143
+
144
+ super().__init__(prefix, name)
145
+
84
146
 
85
- x_direction(int): Should only be 1 or -1, with 1 indicating the oav x direction is the same with motor x
86
- y_direction(int): Same with x_direction but for motor y
87
- z_direction(int): Same with x_direction but for motor z
88
- mjpg_x_size_pv(str): PV infix for x_size in mjpg
89
- mjpg_y_size_pv(str): PV infix for y_size in mjpg
147
+ class OAV(StandardReadable):
148
+ """Class for oav device.
149
+
150
+ Attributes:
151
+ x_direction(int, optional): Should only be 1 or -1, with 1 indicating the oav x
152
+ direction is the same with motor x.
153
+ y_direction(int, optional): Same with x_direction but for motor y.
154
+ z_direction(int, optional): Same with x_direction but for motor z.
155
+ mjpg_x_size_pv(str, optional): PV infix for x_size in mjpg.
156
+ mjpg_y_size_pv(str, optional): PV infix for y_size in mjpg.
90
157
  """
91
158
 
92
159
  beam_centre_i: SignalR[int]
@@ -118,6 +185,7 @@ class OAV(StandardReadable):
118
185
  self.zoom_controller = zoom_controller
119
186
 
120
187
  self.cam = Cam(f"{prefix}CAM:", name=name)
188
+
121
189
  with self.add_children_as_readables():
122
190
  self.grid_snapshot = SnapshotWithGrid(
123
191
  f"{prefix}{mjpeg_prefix}:", name, mjpg_x_size_pv, mjpg_y_size_pv
@@ -170,16 +238,17 @@ class OAV(StandardReadable):
170
238
 
171
239
 
172
240
  class OAVBeamCentreFile(OAV):
173
- """
174
- OAV device that reads its beam centre values from a file. The config parameter
241
+ """OAV device that reads its beam centre values from a file. The config parameter
175
242
  must be a OAVConfigBeamCentre object, as this contains a filepath to where the beam
176
243
  centre values are stored.
177
244
 
178
- x_direction(int): Should only be 1 or -1, with 1 indicating the oav x direction is the same with motor x
179
- y_direction(int): Same with x_direction but for motor y
180
- z_direction(int): Same with x_direction but for motor z
181
- mjpg_x_size_pv(str): PV infix for x_size in mjpg
182
- mjpg_y_size_pv(str): PV infix for y_size in mjpg
245
+ Attributes:
246
+ x_direction(int, optional): Should only be 1 or -1, with 1 indicating the oav x
247
+ direction is the same with motor x.
248
+ y_direction(int, optional): Same with x_direction but for motor y.
249
+ z_direction(int, optional): Same with x_direction but for motor z.
250
+ mjpg_x_size_pv(str, optional): PV infix for x_size in mjpg.
251
+ mjpg_y_size_pv(str, optional): PV infix for y_size in mjpg.
183
252
  """
184
253
 
185
254
  def __init__(
@@ -225,8 +294,9 @@ class OAVBeamCentreFile(OAV):
225
294
  self.set_name(self.name)
226
295
 
227
296
  def _get_beam_position(self, zoom_level: str, size: int, coord: int) -> int:
228
- """Extracts the beam location in pixels `xCentre` `yCentre`, for a requested \
229
- zoom level. """
297
+ """Extracts the beam location in pixels `xCentre` `yCentre`, for a requested
298
+ zoom level.
299
+ """
230
300
  _zoom = self._read_current_zoom(zoom_level)
231
301
  value = self.parameters[_zoom].crosshair[coord]
232
302
  return int(value * size / DEFAULT_OAV_WINDOW[coord])
@@ -25,9 +25,7 @@ def _get_element_as_float(node: Element, element_name: str) -> float:
25
25
 
26
26
 
27
27
  class OAVParameters:
28
- """
29
- The parameters to set up the OAV depending on the context.
30
- """
28
+ """The parameters to set up the OAV depending on the context."""
31
29
 
32
30
  def __init__(
33
31
  self,
@@ -45,8 +43,7 @@ class OAVParameters:
45
43
 
46
44
  @staticmethod
47
45
  def load_json(filename: str) -> tuple[dict[str, Any], dict[str, dict]]:
48
- """
49
- Loads the json from the specified file, and returns a dict with all the
46
+ """Loads the json from the specified file, and returns a dict with all the
50
47
  individual top-level k-v pairs, and one with all the subdicts.
51
48
  """
52
49
  with open(filename) as f:
@@ -101,9 +98,7 @@ class OAVParameters:
101
98
  self.max_tip_distance: float = update("max_tip_distance", float, default=300)
102
99
 
103
100
  def get_max_tip_distance_in_pixels(self, microns_per_pixel: float) -> float:
104
- """
105
- Get the maximum tip distance in pixels.
106
- """
101
+ """Get the maximum tip distance in pixels."""
107
102
  return self.max_tip_distance / microns_per_pixel
108
103
 
109
104
 
@@ -154,7 +149,7 @@ class OAVConfig(OAVConfigBase[ZoomParams]):
154
149
 
155
150
 
156
151
  class OAVConfigBeamCentre(OAVConfigBase[ZoomParamsCrosshair]):
157
- """ Read the OAV config files and return a dictionary of {'zoom_level': ZoomParams}\
152
+ """Read the OAV config files and return a dictionary of {'zoom_level': ZoomParams}
158
153
  with information about microns per pixels and crosshairs.
159
154
  """
160
155
 
@@ -45,12 +45,23 @@ class OAVSource(StandardReadable):
45
45
 
46
46
 
47
47
  class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
48
- """Forwards OAV image data to redis. To use call:
48
+ """Forwards OAV image data to redis.
49
49
 
50
- > bps.kickoff(oav_forwarder)
51
- > bps.monitor(oav_forwarder.uuid)
52
- > bps.complete(oav_forwarder)
50
+ To use call::
53
51
 
52
+ bps.kickoff(oav_forwarder)
53
+ bps.monitor(oav_forwarder.uuid)
54
+ bps.complete(oav_forwarder)
55
+
56
+ Reads image data from the MJPEG stream on an OAV and forwards it into a
57
+ redis database. This is currently only used for murko integration.
58
+
59
+ Args:
60
+ prefix (str): The PV prefix of the OAV.
61
+ redis_host (str): The host where the redis database is running.
62
+ redis_password (str): The password for the redis database.
63
+ redis_db (int): Which redis database to connect to, defaults to 0.
64
+ name (str): The name of this device.
54
65
  """
55
66
 
56
67
  DATA_EXPIRY_DAYS = 7
@@ -68,16 +79,6 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
68
79
  redis_db: int = 0,
69
80
  name: str = "",
70
81
  ) -> None:
71
- """Reads image data from the MJPEG stream on an OAV and forwards it into a
72
- redis database. This is currently only used for murko integration.
73
-
74
- Arguments:
75
- prefix: str the PV prefix of the OAV
76
- redis_host: str the host where the redis database is running
77
- redis_password: str the password for the redis database
78
- redis_db: int which redis database to connect to, defaults to 0
79
- name: str the name of this device
80
- """
81
82
  self.counter = epics_signal_r(int, f"{prefix}CAM:ArrayCounter_RBV")
82
83
  self.sources = DeviceVector(
83
84
  {
@@ -109,7 +110,9 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
109
110
  ):
110
111
  """Stores the raw bytes of the jpeg image in redis. Murko ultimately wants a
111
112
  pickled numpy array of pixel values but raw byes are more space efficient. There
112
- may be better ways of doing this, see https://github.com/DiamondLightSource/mx-bluesky/issues/592"""
113
+ may be better ways of doing this, see
114
+ https://github.com/DiamondLightSource/mx-bluesky/issues/592.
115
+ """
113
116
  jpeg_bytes = await get_next_jpeg(response)
114
117
  sample_id = await self.sample_id.get_value()
115
118
  redis_key = f"murko:{sample_id}:raw"
@@ -131,12 +134,13 @@ class OAVToRedisForwarder(StandardReadable, Flyable, Stoppable):
131
134
  await function_to_do(response, source)
132
135
 
133
136
  async def _stream_to_redis(self, response: ClientResponse, source: OAVSource):
134
- """Uses the update of the frame counter as a trigger to pull an image off the OAV
135
- and into redis.
137
+ """Uses the update of the frame counter as a trigger to pull an image off the
138
+ OAV and into redis.
136
139
 
137
140
  The frame counter is continually increasing on the timescales we store data and
138
141
  so can be used as a uuid. If the OAV is updating too quickly we may drop frames
139
- but in this case a best effort on getting as many frames as possible is sufficient.
142
+ but in this case a best effort on getting as many frames as possible is
143
+ sufficient.
140
144
  """
141
145
  done_status = AsyncStatus(
142
146
  asyncio.wait_for(self._stop_flag.wait(), timeout=self.TIMEOUT)