dls-dodal 1.41.0__py3-none-any.whl → 1.42.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 (42) hide show
  1. {dls_dodal-1.41.0.dist-info → dls_dodal-1.42.0.dist-info}/METADATA +3 -3
  2. {dls_dodal-1.41.0.dist-info → dls_dodal-1.42.0.dist-info}/RECORD +42 -35
  3. {dls_dodal-1.41.0.dist-info → dls_dodal-1.42.0.dist-info}/WHEEL +1 -1
  4. dodal/_version.py +2 -2
  5. dodal/beamlines/__init__.py +1 -0
  6. dodal/beamlines/adsim.py +1 -1
  7. dodal/beamlines/aithre.py +9 -0
  8. dodal/beamlines/i04.py +1 -1
  9. dodal/beamlines/i19_optics.py +34 -0
  10. dodal/beamlines/p45.py +28 -67
  11. dodal/common/visit.py +1 -1
  12. dodal/devices/aithre_lasershaping/goniometer.py +15 -0
  13. dodal/devices/aperturescatterguard.py +1 -1
  14. dodal/devices/apple2_undulator.py +8 -10
  15. dodal/devices/attenuator/attenuator.py +1 -1
  16. dodal/devices/backlight.py +1 -1
  17. dodal/devices/bimorph_mirror.py +2 -2
  18. dodal/devices/detector/detector.py +1 -1
  19. dodal/devices/eiger.py +2 -2
  20. dodal/devices/hutch_shutter.py +1 -1
  21. dodal/devices/i10/i10_apple2.py +3 -3
  22. dodal/devices/i19/hutch_access.py +8 -0
  23. dodal/devices/i19/shutter.py +1 -1
  24. dodal/devices/i24/pmac.py +2 -2
  25. dodal/devices/oav/oav_detector.py +1 -1
  26. dodal/devices/oav/snapshots/snapshot_with_grid.py +4 -3
  27. dodal/devices/p45.py +8 -8
  28. dodal/devices/pressure_jump_cell.py +3 -7
  29. dodal/devices/robot.py +1 -1
  30. dodal/devices/thawer.py +4 -4
  31. dodal/devices/undulator.py +1 -1
  32. dodal/devices/undulator_dcm.py +1 -1
  33. dodal/devices/util/epics_util.py +1 -1
  34. dodal/devices/zebra/zebra.py +3 -4
  35. dodal/devices/zebra/zebra_controlled_shutter.py +1 -1
  36. dodal/plan_stubs/wrapped.py +12 -10
  37. dodal/plans/preprocessors/__init__.py +0 -0
  38. dodal/plans/preprocessors/verify_undulator_gap.py +49 -0
  39. dodal/plans/verify_undulator_gap.py +19 -0
  40. {dls_dodal-1.41.0.dist-info → dls_dodal-1.42.0.dist-info}/LICENSE +0 -0
  41. {dls_dodal-1.41.0.dist-info → dls_dodal-1.42.0.dist-info}/entry_points.txt +0 -0
  42. {dls_dodal-1.41.0.dist-info → dls_dodal-1.42.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dls-dodal
3
- Version: 1.41.0
3
+ Version: 1.42.0
4
4
  Summary: Ophyd devices and other utils that could be used across DLS beamlines
5
5
  Author-email: Dominic Oram <dominic.oram@diamond.ac.uk>
6
6
  License: Apache License
@@ -217,7 +217,7 @@ License-File: LICENSE
217
217
  Requires-Dist: click
218
218
  Requires-Dist: ophyd
219
219
  Requires-Dist: ophyd-async>=0.9.0a2
220
- Requires-Dist: bluesky
220
+ Requires-Dist: bluesky==1.13.0
221
221
  Requires-Dist: pyepics
222
222
  Requires-Dist: dataclasses-json
223
223
  Requires-Dist: pillow
@@ -246,7 +246,7 @@ Requires-Dist: pipdeptree; extra == "dev"
246
246
  Requires-Dist: pre-commit; extra == "dev"
247
247
  Requires-Dist: psutil; extra == "dev"
248
248
  Requires-Dist: pydata-sphinx-theme>=0.12; extra == "dev"
249
- Requires-Dist: pyright==1.1.394; extra == "dev"
249
+ Requires-Dist: pyright; extra == "dev"
250
250
  Requires-Dist: pytest; extra == "dev"
251
251
  Requires-Dist: pytest-asyncio; extra == "dev"
252
252
  Requires-Dist: pytest-cov; extra == "dev"
@@ -1,29 +1,31 @@
1
1
  dodal/__init__.py,sha256=Ksms_WJF8LTkbm38gEpm1jBpGqcQ8NGvmb2ZJlOE1j8,198
2
2
  dodal/__main__.py,sha256=kP2S2RPitnOWpNGokjZ1Yq-1umOtp5sNOZk2B3tBPLM,111
3
- dodal/_version.py,sha256=vzwCPJLAKjDDFO5dFLzh88htG2LcsTvkffw3I3imiBo,513
3
+ dodal/_version.py,sha256=ovREbwPKWGv5kafSj2cj_y_IxXNlgemp5GRlT3e-7yQ,513
4
4
  dodal/cli.py,sha256=NieWNUgLUxyck1rHoFAPJjX1xXLzHNdQ-s4wvxYFfps,3757
5
5
  dodal/log.py,sha256=ry8WMq1S4WMIAPqtqGeKuegMRN7Jy3qdVTJlkpKXkL8,9503
6
6
  dodal/utils.py,sha256=nZ_gilv1KErYKnTmknFYaE-JnCC-RxZWQ975cchklFA,19790
7
7
  dodal/beamline_specific_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  dodal/beamline_specific_utils/i03.py,sha256=P6Ls4FoVtcacH0RJM3v6ZwwGx27oMppcBdW0la-ohTY,377
9
9
  dodal/beamlines/README.md,sha256=K9MkL_GomxlsoTB7Mz-_dJA5NNSbmCfMiutchGg3C8o,404
10
- dodal/beamlines/__init__.py,sha256=VJOFt2N6Ge-kvKzpiGee8so2Qs1BLO4k7SYFaF3lG8U,3118
11
- dodal/beamlines/adsim.py,sha256=_LMMjPou7r-T8Jt9ZSj2SGFLuDUju_WNtF5ID6xiZJU,1925
10
+ dodal/beamlines/__init__.py,sha256=dTmVSfeEVUHgxOTQO94lbQQiJHfFcvK2RAwVeTpCqxo,3150
11
+ dodal/beamlines/adsim.py,sha256=uOmFYZIGyput93XHk9R5ydZdxnTrS_wA2zSEm62UCVU,1930
12
+ dodal/beamlines/aithre.py,sha256=1q7zeMYunOBIWCm203NIkCl5tgVl_-jMWc0f5af-W_E,263
12
13
  dodal/beamlines/b01_1.py,sha256=-NYuJv6FhOgJvNYqDtpYb5HucI5_0HS4uDphRXUWzl4,1807
13
14
  dodal/beamlines/i02_1.py,sha256=d2IyqFMgeaSEyZYm7GMSjTKr7_02SakyC_oARx-XwnY,1204
14
15
  dodal/beamlines/i03.py,sha256=q0dMF0W44kCNXiXOUENaUv3nmAfxyOSr5C1zPonCbvk,14856
15
- dodal/beamlines/i04.py,sha256=IwZOnRPL1PC0Oe8m_L4xwXVW2IYJBo0wSbADLWBupyg,12128
16
+ dodal/beamlines/i04.py,sha256=V0fgXfEJnkh0spDXelK6zwjFChN6VaV9_CtrxJLZx2E,12100
16
17
  dodal/beamlines/i10.py,sha256=lkn_xg0pt-vFuWkUGyl62A0xT-Rzs71JztJ1EeQkMi0,11487
17
18
  dodal/beamlines/i13_1.py,sha256=EgnBzsJ55BmsBtq2sDHD6pKnWZsqqAtL0ZM-JP908zE,2467
18
19
  dodal/beamlines/i18.py,sha256=Y5qLniqUkbYHcGGLPdBbiMILQHonPT2oz5M1hKMGqzs,3434
19
20
  dodal/beamlines/i19_1.py,sha256=I5vz64UsVUkDDT7itdpGVFuYq8zkmPECB0rCbCVUkAY,2325
20
21
  dodal/beamlines/i19_2.py,sha256=DihbYZ27rCdF7fvBclyhZ6Rf0YRSs2rc7hmDNtEr6cA,1939
22
+ dodal/beamlines/i19_optics.py,sha256=TAl2ZNVveRGSbdxRjZC_vW8XFrCZlFB648Bkz7g-8oM,1148
21
23
  dodal/beamlines/i20_1.py,sha256=7ZZhPfjjKAhGjdXOI6mu2FPbMbsSjFHJOPa1toZRa0U,1725
22
24
  dodal/beamlines/i22.py,sha256=XCAVBkZxN9cmxfpGoWaCvo77lu8hVIJ_e3BUc_qxdu0,7664
23
25
  dodal/beamlines/i23.py,sha256=Qnu3Rk9gb2BD3YolMqUXiupt0ehxw5rVnfPJXBWFoCU,973
24
26
  dodal/beamlines/i24.py,sha256=9rBQMCWGdKiRnFbcVvmjiBWiC9WJIJCtLh5m6LkHUtU,7096
25
27
  dodal/beamlines/p38.py,sha256=MwxBqYe_rUIj-MCRIFZpHJmR0JtA22bSFKfBpoDI9P0,5777
26
- dodal/beamlines/p45.py,sha256=0mQ_AEURczc7yzfJzR9QK9i-b6rBGIjGZ4xCIdLNfdI,3031
28
+ dodal/beamlines/p45.py,sha256=2snO895TGwf4LbNIvg4BkvAGSfvZcevdpv_82MRpXKo,2129
27
29
  dodal/beamlines/p99.py,sha256=k24QhYpoOHBd0188Fu3wvmpT6dsu8okiIVqVVckdBkw,1063
28
30
  dodal/beamlines/training_rig.py,sha256=8u1TulTFgvu28sfo6vFY-uo_VBAYKT66ENXTqegw3y0,1940
29
31
  dodal/common/__init__.py,sha256=ZC4ICKUDB0BDxRaVy8nmqclVmDBne-dPtk6UJsoFq6I,258
@@ -33,7 +35,7 @@ dodal/common/maths.py,sha256=K9x7iL3xXLtWYTV-xlFHDNSTIL9a2UP3Ws7wr6Dm2rQ,1803
33
35
  dodal/common/signal_utils.py,sha256=-p4h7xtGPp13t6HTjgFGcs5nN22kVArlkfCPVjpLuRU,1728
34
36
  dodal/common/types.py,sha256=fkL7UOwDbe3v2_VJ5f1W5RxR98Wx-Ra-LxUZWkNDtls,486
35
37
  dodal/common/udc_directory_provider.py,sha256=v5OBaCUwjtQZAsRQUw6LlVL58UvwwDO1l2MKlilXjdk,2403
36
- dodal/common/visit.py,sha256=2UbbCmgOjZWSCxFzE9RYiTJhA_IoVOegma-Jv-PJqps,5787
38
+ dodal/common/visit.py,sha256=BLpr3GrP7Ij95V135hRJLgg7gWtBKXVxyOibWtcO8RE,5782
37
39
  dodal/common/beamlines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
40
  dodal/common/beamlines/beamline_parameters.py,sha256=oIPHooqu5vTAwfqZutsKbzwdi9nvFF8568Mz7jrK5rI,3618
39
41
  dodal/common/beamlines/beamline_utils.py,sha256=-FEBuz4fYBclgifAODKaaBB5GIQFhPHPaktGS5c5lWc,5236
@@ -42,29 +44,29 @@ dodal/devices/CTAB.py,sha256=5_261Ox6NG2cJIzzwnjWz289BG0nZoE0wKOaI5V5jqM,1998
42
44
  dodal/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
45
  dodal/devices/adsim.py,sha256=vCexraF4zLssHdjfPod-XuQGJE_sWoCttFdx__HDS8w,488
44
46
  dodal/devices/aperture.py,sha256=yyw2ei3gM_lmZWDQ6VTbydB58RCDTen_nqBZyoTP2IM,583
45
- dodal/devices/aperturescatterguard.py,sha256=kkBAS10HjZG0tOLM1R2ciaNJxdMGk_Mg5HJaFXDEWEU,12422
46
- dodal/devices/apple2_undulator.py,sha256=R4KDgA4HcFj9zg1rPAEP9E0mKVzE06bhyxNRUrsi3Sw,20826
47
- dodal/devices/backlight.py,sha256=RcgeA1hE3Z_5jA-jH8S8uLMpBfZjenRLz1lx6HTYeAo,1653
48
- dodal/devices/bimorph_mirror.py,sha256=D5PkrOggJRVAnv38lTdy8rErKLu_O2juLEvSqwcotxY,4825
47
+ dodal/devices/aperturescatterguard.py,sha256=Md5dDlA8Ua6GpQ0kTwDtz14Y3wKtLUW7Xh-4_7VYgGU,12407
48
+ dodal/devices/apple2_undulator.py,sha256=WUmaBAMv1xVDHDUk7sTFb5tobl5BnJlEaS7ZlJBXS-g,20731
49
+ dodal/devices/backlight.py,sha256=nQIr3J-I-OXnOUoWmr3ruy3nhq_q2US1KXC4NrGG_2U,1634
50
+ dodal/devices/bimorph_mirror.py,sha256=kG9waIdTkKglUrvY_wD9w533oKPqa7fct1-wa_GCFW0,4797
49
51
  dodal/devices/cryostream.py,sha256=K-ldpredpeDTzNt4qtQMg99nKJNjBYoXBbK0WJGexzw,656
50
52
  dodal/devices/dcm.py,sha256=JbyxLnrS68nnnv39l9XEWgJgXUBqxX6aFo19MZnL36E,2574
51
53
  dodal/devices/diamond_filter.py,sha256=A--RHd7WuH-IBhvCyENcRCTP4K-mm_Kqpa0pojpHZow,1098
52
- dodal/devices/eiger.py,sha256=n9-rCrIdRnmDNdAz6sCKTYLhiglwlDTmKuMkLUdIWZg,15832
54
+ dodal/devices/eiger.py,sha256=RN3klVASvdTT_jer2HJHUCZWZBKoOUQQdTpsKdgTPfo,15836
53
55
  dodal/devices/eiger_odin.py,sha256=ytUH_18YuM1nJDhplS6OTdtADloYvHpO6ppENjVd4jU,7411
54
56
  dodal/devices/fast_grid_scan.py,sha256=SJTolz-LHlkxWA3Fb0lHa90CH8IjyJ1v2vkaaCURGpU,12044
55
57
  dodal/devices/fluorescence_detector_motion.py,sha256=-1qCSvW0PdT0m6BcoLxrtc0OJ5UDIBsEe11EOLr-gFw,501
56
58
  dodal/devices/flux.py,sha256=1CDsq9yU2-ho8MfYBl50Tl9ABZwpUBHnV486PQXKNoQ,462
57
59
  dodal/devices/focusing_mirror.py,sha256=vdUPkwyCAZBSR3LQ-EojDOoxVy1ZmOaD_nevETbj7BA,6592
58
- dodal/devices/hutch_shutter.py,sha256=UvGpsiIQcNW8IGd8ZA8Omus30bSNcVFE1poqO3yK9TE,3859
60
+ dodal/devices/hutch_shutter.py,sha256=oEYrV9V6HLk51_z4bl7H0JYlxrAAZIFF67Fq3lfzI-k,3844
59
61
  dodal/devices/ipin.py,sha256=eq5jlKw7WGQi8VLrAWpaAIsZmfiVf-5Q0td_B22H6A4,473
60
62
  dodal/devices/linkam3.py,sha256=2sf-_heIsDg4qmqae-w9C2Py8pG8bPB3mT0TFPQIzd0,3869
61
63
  dodal/devices/logging_ophyd_device.py,sha256=dUVE-XhWA56WUXez0mrc4sf322CXY3MVLreTycO5j_A,668
62
64
  dodal/devices/motors.py,sha256=K1df9Pn1ThvsW-g7LrfKWOFaiaQXXUAf2BtbRehzUc4,1108
63
- dodal/devices/p45.py,sha256=hNCfWb8xubuHO8uJ5MpHPurp-r1ss7JMgbZQwHVJg-w,1743
65
+ dodal/devices/p45.py,sha256=hoBPpnj3b-njKqmhjAUFb79AyM4qFbWC9tuN6Aa47Rk,1703
64
66
  dodal/devices/pgm.py,sha256=am-AST9iTqma1PkGOKLozqAokZWbJUbM3TNcqXzB-6A,1132
65
- dodal/devices/pressure_jump_cell.py,sha256=h5nMNtr2PMG_AKM6nOB7qNTYT70GRuiGBwC-Ol2Yby0,10548
67
+ dodal/devices/pressure_jump_cell.py,sha256=QYU3BTA6O8lvWdg8UX81Ya0BCbGz4dirjt0xp2ez7O0,10423
66
68
  dodal/devices/qbpm.py,sha256=FfrWWAHHtYv3fGRT1qljyPpAwoHJYfbooT9CfKg-oXI,465
67
- dodal/devices/robot.py,sha256=4jiWZnPBz3DmvJJdEG6mKIrrWHty2a6bdbCv8KOn1HE,6009
69
+ dodal/devices/robot.py,sha256=5Y5lNkAbXooIAkSWHwDKyeKKzlqMeH3TuLHzCsw2FPI,5993
68
70
  dodal/devices/s4_slit_gaps.py,sha256=4KdarIQoRqX4ry3LUS1Km7fkjUFahA0VuTd2DvYEqQ8,446
69
71
  dodal/devices/scatterguard.py,sha256=jx03in9QgaThWxD4t1S8_Llent2kWrn_hThJ9KkUWTk,330
70
72
  dodal/devices/scintillator.py,sha256=PlD6cnJ39PTB_e7QrRspPliLYE4kL_K7ziJURzuxgdA,365
@@ -73,16 +75,17 @@ dodal/devices/smargon.py,sha256=tOHb9fjI8ZCIrboiC4OzS2j1QJDOKkAlQ2SORbBmaGo,4708
73
75
  dodal/devices/status.py,sha256=hVrJS1yooQo6PRumRACoIEh-SKBUKxvBlQl-MtLFUMQ,327
74
76
  dodal/devices/synchrotron.py,sha256=wLfClZ1lYQWA_D--UsM3NnKLG8bY8mvVsRYER6ob-Ew,2026
75
77
  dodal/devices/tetramm.py,sha256=1lNXtWlmq0Pc_gVGD77XrV3ECe38TornDJUXkq3H1i0,8524
76
- dodal/devices/thawer.py,sha256=mYrO9klUPYcSbpoUuJ4ZuZZEPcHWWaZ2px5jh8XNQ9Y,1675
78
+ dodal/devices/thawer.py,sha256=4t4yF4VDIrT_tQ8RwjmXe_hDMwVjR8A-4rDkPx19b28,1672
77
79
  dodal/devices/turbo_slit.py,sha256=2k5ipQOFpDG-E_bYv4Mf7lOUJg0eIBJXEYNsFU6SV7g,1209
78
- dodal/devices/undulator.py,sha256=ZTjdD0bGp4gkfh0uZmA8FsATLCOsGt14gwPwqLezh1M,5302
79
- dodal/devices/undulator_dcm.py,sha256=olg8FrIKWqGmhJMuzuvJXH-LQTGhKytvXHPso3Br7C0,2398
80
+ dodal/devices/undulator.py,sha256=rQjDhrvgf4uXUEO17CiLopNDEagWOgkmpa02BarozDE,5295
81
+ dodal/devices/undulator_dcm.py,sha256=zulVn1wvu4-WEpf0BgLiDet58IsaKV7KW6qruAdRR_s,2391
80
82
  dodal/devices/watsonmarlow323_pump.py,sha256=rwU94YE6esgGLYdh-pe8nBo_3tvgp6brrrbPDrqp5_M,1406
81
83
  dodal/devices/webcam.py,sha256=mef075ynDbzZ4pNAjfxR_9tdTTqF_rM7hAOVEEOV-Do,2408
82
84
  dodal/devices/xbpm_feedback.py,sha256=j8MHhhE0feoe6R54zPKqS5EbQ0bEDR-nOpLHzHhnHHQ,1156
85
+ dodal/devices/aithre_lasershaping/goniometer.py,sha256=YEl0DEXW4Dl9b3nsyfwrM7FDiwEZCXK-evGxlyOJr8k,512
83
86
  dodal/devices/areadetector/plugins/CAM.py,sha256=sZzJm5Ez3eWfXZi_EB67wluhZmMQm1UyOc2bJFfzd1U,964
84
87
  dodal/devices/areadetector/plugins/MJPG.py,sha256=QTsxCoWbofNpLMGPoOR2hWoM33KyntuLepbF0YmX0KE,3031
85
- dodal/devices/attenuator/attenuator.py,sha256=Vq9Zsyf56S5fePHGeluImTUtxdwEqttBa2YBIdU5tJU,3993
88
+ dodal/devices/attenuator/attenuator.py,sha256=eHJpM-E4XQfzy1mxGRk754y3n9q6i3youkCqQg_6SUM,3986
86
89
  dodal/devices/attenuator/filter.py,sha256=ZoPsTWXjllyMtKBdSIFLB7Cbc88rGof5k3ymL13VczE,422
87
90
  dodal/devices/attenuator/filter_selections.py,sha256=lcmTprCXgSggp2L6uQ6YU0xLMljXvbspAug-WWKCXks,1410
88
91
  dodal/devices/current_amplifiers/__init__.py,sha256=-MhT-t-GJ83rrvTDBCoWub_NKYkRtu4sEj8-y5XZBP0,782
@@ -95,12 +98,12 @@ dodal/devices/detector/__init__.py,sha256=-RdACL3tzc3lLArWOoGNje48UUlv2fElOmGOz9
95
98
  dodal/devices/detector/det_dim_constants.py,sha256=arBWvzMwybatdSiCMAiwB4Bq1dX-wkLi54xPPfTfQhY,2772
96
99
  dodal/devices/detector/det_dist_to_beam_converter.py,sha256=7keoqZYfvgayePVx97lHYpcFRTJnQOfAk_PYP4EZTZQ,1951
97
100
  dodal/devices/detector/det_resolution.py,sha256=aQkKp24LpRGiwzPAQM3wLVa4ANw32HdrKc2kftHfKQA,3253
98
- dodal/devices/detector/detector.py,sha256=syzkl52kGaMINXCXEviFuYPbgNatm5tioVPDmjgro8s,4768
101
+ dodal/devices/detector/detector.py,sha256=sIOGwkixbJTYPdNiwZjDiY7DfYuYzRomKltO2EztDZE,4770
99
102
  dodal/devices/detector/detector_motion.py,sha256=UGDQriDWRluDZOZh1mDX9w_fPjMD-_BGe11kA36Kezs,1616
100
103
  dodal/devices/i03/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
104
  dodal/devices/i03/beamstop.py,sha256=D1-QeGNpNlUE1qtFz-XxgzQGZbvM5bdb09f69yDB7U0,2802
102
105
  dodal/devices/i04/transfocator.py,sha256=sVI4Bgv-2-DH4-F1nIXMp5Aktevrm3agZnCA-WgjmW8,3780
103
- dodal/devices/i10/i10_apple2.py,sha256=ErObNNE59NuYssde6ojWJb8wo3SVohkQsvK0Bjnf1T8,13192
106
+ dodal/devices/i10/i10_apple2.py,sha256=pEZes8wVCPHiOOcuVhEtqPvtnyphMxqbdp39mDp6xXQ,13165
104
107
  dodal/devices/i10/i10_setting_data.py,sha256=69XWgE-YNTiW7C3t67MNcTL5JDDhOo7h-X7DCTpFE5g,164
105
108
  dodal/devices/i10/mirrors.py,sha256=E0M5keGI3LGaDHyXQkCCyj6xmixNY1xTSkIaaYwtnP8,794
106
109
  dodal/devices/i10/slits.py,sha256=4X50bGiJhTIHxhsOrv-8DATBkQPwQgEaFMNa2OsPrFY,1201
@@ -116,7 +119,8 @@ dodal/devices/i18/diode.py,sha256=q8ddVYT7yDXwURzxw5gfXlGT1tFirNfHBmiKnpvvXHk,40
116
119
  dodal/devices/i18/table.py,sha256=f6OtVSqCFIpXyoHX97CPLpaVDVXUNc2EvgSFP3qVFKo,446
117
120
  dodal/devices/i18/thor_labs_stage.py,sha256=I9JSKY-UqTjN-yBxQWL4CycTNNkUj3vknRrXjA6KZR8,364
118
121
  dodal/devices/i19/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
- dodal/devices/i19/shutter.py,sha256=RASOmpVaFBPVkCfPR0fddqrGTEWK-VLPIrqJcObHwNE,2211
122
+ dodal/devices/i19/hutch_access.py,sha256=K8hYi5gYg46XPw03qFgwoInapYzNGjf4Fgf9Ifi0gAI,308
123
+ dodal/devices/i19/shutter.py,sha256=9KmS4NBwvifgJ4FF_FeXIfSEAV7ZkBAfutiu_0SLrAs,2196
120
124
  dodal/devices/i20_1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
125
  dodal/devices/i22/dcm.py,sha256=SQDh-Sj1OvplHZ9yTWblJwv8PJrUqxseDPupZOWmcLo,4701
122
126
  dodal/devices/i22/fswitch.py,sha256=LSMoo9aDkH0SLcojbUh2NxTWIpUXHZxauTqThc3XtSk,3073
@@ -130,12 +134,12 @@ dodal/devices/i24/dual_backlight.py,sha256=CbQ9mYUNhhozVdNXqR5ac73tEIAWT2RnEpRwX
130
134
  dodal/devices/i24/focus_mirrors.py,sha256=HO3B4yjV-HMvjkgFd2xTvXft75Qj4lN8d0RNg6HJ4Lo,1857
131
135
  dodal/devices/i24/i24_detector_motion.py,sha256=_HgdsZqFYY0tKqUgMzViHaPEUFXL3WlXXioGvDehRUw,364
132
136
  dodal/devices/i24/pilatus_metadata.py,sha256=fV8AQSBYGx1Qc91Rqj8VhcFPqPLqLCePNpDdmhcrTYM,1827
133
- dodal/devices/i24/pmac.py,sha256=pghm0jM24N1GZ1EOazPEoSxcn6zyizp6E4H28jnUn1s,6862
137
+ dodal/devices/i24/pmac.py,sha256=lz9FYU_8YN8cC51ddTzdxcUA7MCVTA_ho3P0CHJ9zCo,6837
134
138
  dodal/devices/i24/vgonio.py,sha256=sxSmcYZayVJPJz_D_91j9PmNor7Tbl1RGQFRrdtESlw,533
135
139
  dodal/devices/oav/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
140
  dodal/devices/oav/microns_for_zoom_levels.json,sha256=kJTkbu2v6_Ccc_cDy7FRTX-gRhXxfYskjVqwBCZIqCQ,1209
137
141
  dodal/devices/oav/oav_calculations.py,sha256=tr3Z2pFT7v_enAiNuSZV0esPsiHfRGrj7t0-g_Ix5Do,2363
138
- dodal/devices/oav/oav_detector.py,sha256=uF-5OAoFZYJwBUJkTTQtB89k3g7nj-XKU8IgheP2I0Q,4330
142
+ dodal/devices/oav/oav_detector.py,sha256=jdlgXuxEi0Ojjpt-Bz1KOjYlyQyaWfm0XLRw6-MxsFQ,4325
139
143
  dodal/devices/oav/oav_parameters.py,sha256=gGN73TQGUiRzlIO5YKiqCRkjpTKsV6LFGo7Eu4Vs82g,6074
140
144
  dodal/devices/oav/oav_to_redis_forwarder.py,sha256=pfhaW6Uo_1wDNfywyPkS5UTrY8yhkerhjgJfRMqrJRA,6259
141
145
  dodal/devices/oav/utils.py,sha256=3IvSTw6Ygkaz4Hzoz0eU2l6mljpq0NO57M15e-K4jOE,3182
@@ -144,23 +148,23 @@ dodal/devices/oav/pin_image_recognition/manual_test.py,sha256=h1Rto6ZDCB3jWhjSy9
144
148
  dodal/devices/oav/pin_image_recognition/utils.py,sha256=L9ypluYqeOFoS7gQuws-vTNc8LqaKl2ZIDNeQ2JaNpg,8592
145
149
  dodal/devices/oav/snapshots/grid_overlay.py,sha256=CdvCdTKMCiwMwxm2lV28KpcIUSXlscZmWxb73_KKmiI,3694
146
150
  dodal/devices/oav/snapshots/snapshot_with_beam_centre.py,sha256=J77RfE3AGTLNdWc6hvsRn2DUdupzuk_FTDGvdP0jqbU,1962
147
- dodal/devices/oav/snapshots/snapshot_with_grid.py,sha256=EBoCtr1NmOKye2yQHqbTBxSg-DsEKFeyBtMFmOeGPRs,2269
151
+ dodal/devices/oav/snapshots/snapshot_with_grid.py,sha256=KAM7KjF0BzhGxx-MXd4Zc16IBbi1BF8S_VT8T84_2OY,2309
148
152
  dodal/devices/p99/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
153
  dodal/devices/p99/sample_stage.py,sha256=DvHU556Gp0wFiufZiwY3o2W4xmsCL5uSwNnhd8HPAnc,528
150
154
  dodal/devices/training_rig/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
155
  dodal/devices/training_rig/sample_stage.py,sha256=jktTp837ij8wor5LidE3AajCk95L7DebJotMlO7QwTE,355
152
156
  dodal/devices/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
157
  dodal/devices/util/adjuster_plans.py,sha256=XpJ1YJKoOCFzj2sonkZYJAdewi3jRaok_2gOmNsfeS0,956
154
- dodal/devices/util/epics_util.py,sha256=3_d0m7BTvN19WIKvz2XSMvoPdTdccg9Z2gOAL-52q4s,4692
158
+ dodal/devices/util/epics_util.py,sha256=A8iNL79PnxntuxPTKA9oLGaDRKhnXaaeAVJwS6FNAWA,4687
155
159
  dodal/devices/util/lookup_tables.py,sha256=3gU9cOBhHBu1S6XqXHWNjCNkV7F4Z-eDlDfesvKbMg4,2185
156
160
  dodal/devices/util/motor_utils.py,sha256=pNY-aUk9LxaIWeDr5rpMS6udiB9j19wcCXkNDLp1uA0,257
157
161
  dodal/devices/util/test_utils.py,sha256=x0QVKVeST4T-wpsVSSm-169MyNRXlmybVWnPTefv1as,565
158
162
  dodal/devices/xspress3/xspress3.py,sha256=75RdPuHpES4Xi-Lcywz0XUhaN2G3vZSoc-dzgcxfNvs,4636
159
163
  dodal/devices/xspress3/xspress3_channel.py,sha256=w8tAx2lz5kJ_LeJ_eb_4o--Dtt8MRijsYNgDG6oEIVg,1626
160
164
  dodal/devices/zebra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
161
- dodal/devices/zebra/zebra.py,sha256=UPryxnhvEb9Y2hefYWbTZShmVKULghftHyO1LVJRLpI,9248
165
+ dodal/devices/zebra/zebra.py,sha256=_OA34T9CcgwXxyajVKai2jz4nHVDaEvMkb5eG5eAYKw,9192
162
166
  dodal/devices/zebra/zebra_constants_mapping.py,sha256=DCWMvBFvmN90rBpZ4aOVF_hbKm4K6QWubsG811R-MK8,4170
163
- dodal/devices/zebra/zebra_controlled_shutter.py,sha256=tcBq2WQxST9g2VrjVWu-tOomFX-zGLHLNDhYhL0DtHc,1871
167
+ dodal/devices/zebra/zebra_controlled_shutter.py,sha256=5-SH5HoXp_6P-xAtfDFJKQq6mBDwreubuCULSz78fgw,1852
164
168
  dodal/devices/zocalo/__init__.py,sha256=dRAZ9o7B9TACqyE7aanT3yzvqWtt019YgV5ZJY7Ylso,517
165
169
  dodal/devices/zocalo/zocalo_constants.py,sha256=vu7Xjz7UNEpBUWEEBxDvP4bVFkZIN6NLGfQDpWbCjH8,98
166
170
  dodal/devices/zocalo/zocalo_interaction.py,sha256=GFukU9xqagQtVSDg5BrL23jxl1w8wjs4b4NLLqdFfpk,3584
@@ -170,14 +174,17 @@ dodal/plan_stubs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
170
174
  dodal/plan_stubs/check_topup.py,sha256=3gyLHfHNQBCgEWuAg4QE-ONx7y2Do1vVv5HP8ss0Z1I,5371
171
175
  dodal/plan_stubs/data_session.py,sha256=33wPwbs0mtMnle0H76mH_RNTc5omld7gNSJ9BvRdUnM,1570
172
176
  dodal/plan_stubs/motor_utils.py,sha256=4c93U_WgjfmX12uNiztVW2oKxGVWa_SKQdJYCUNmsGU,4653
173
- dodal/plan_stubs/wrapped.py,sha256=kC8HH7bx3-sLYu2oieY_502tAdT2OECF8n-fqoL5Bfc,4266
177
+ dodal/plan_stubs/wrapped.py,sha256=nriHKX4BF010CmrhdoUhY3-txClW5W8TPLz64kE_AXU,4533
174
178
  dodal/plans/__init__.py,sha256=nH1jNxw3DzDMg9O8Uda0kqKIalRVEWBrq07OLY6Ey38,93
175
179
  dodal/plans/save_panda.py,sha256=1fumH7Ih8uDIv8ahAtgQ_vUuR3dz0sfUs4n9TEtEbSs,3053
176
180
  dodal/plans/scanspec.py,sha256=Q0AcvTKRT401iGMRDSqK-D523UX5_ofiVMZ_rNXKOx8,2074
181
+ dodal/plans/verify_undulator_gap.py,sha256=mq2fHtc5o5rSgdTM2xhULOImfjwa6x29tPpeoLw4GcU,553
177
182
  dodal/plans/wrapped.py,sha256=BPMw__RcWvk9v5XnhMsi9_k4KsDEbmXogzD2n1ecbUg,2098
178
- dls_dodal-1.41.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
179
- dls_dodal-1.41.0.dist-info/METADATA,sha256=0xKqobHJQk4qTg-57eXoXfkBm1Sgh63jVo4ePiQr2OU,16792
180
- dls_dodal-1.41.0.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
181
- dls_dodal-1.41.0.dist-info/entry_points.txt,sha256=bycw_EKUzup_rxfCetOwcauXV4kLln_OPpPT8jEnr-I,94
182
- dls_dodal-1.41.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
183
- dls_dodal-1.41.0.dist-info/RECORD,,
183
+ dodal/plans/preprocessors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
184
+ dodal/plans/preprocessors/verify_undulator_gap.py,sha256=cBZEGq8TW1jrXFXB00iClQVXSEaE_jP_rHMY9WTgYyY,1813
185
+ dls_dodal-1.42.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
186
+ dls_dodal-1.42.0.dist-info/METADATA,sha256=z74PYCHBK1Fi9i9jqxo4P2ss7NEXj5rBn2oRmXg4NH0,16791
187
+ dls_dodal-1.42.0.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
188
+ dls_dodal-1.42.0.dist-info/entry_points.txt,sha256=bycw_EKUzup_rxfCetOwcauXV4kLln_OPpPT8jEnr-I,94
189
+ dls_dodal-1.42.0.dist-info/top_level.txt,sha256=xIozdmZk_wmMV4wugpq9-6eZs0vgADNUKz3j2UAwlhc,6
190
+ dls_dodal-1.42.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (76.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
dodal/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.41.0'
21
- __version_tuple__ = version_tuple = (1, 41, 0)
20
+ __version__ = version = '1.42.0'
21
+ __version_tuple__ = version_tuple = (1, 42, 0)
@@ -13,6 +13,7 @@ _BEAMLINE_NAME_OVERRIDES = {
13
13
  "i20-1": "i20_1",
14
14
  "i19-1": "i19_1",
15
15
  "i19-2": "i19_2",
16
+ "i19-optics": "i19_optics",
16
17
  "s03": "i03",
17
18
  "p46": "training_rig",
18
19
  "p47": "training_rig",
dodal/beamlines/adsim.py CHANGED
@@ -40,7 +40,7 @@ https://epics-containers.github.io/main/tutorials/launch_example.html
40
40
  And ensure that the signals are visible:
41
41
 
42
42
  ```sh
43
- export EPICS_CA_ADDR_LIST=127.0.0.1
43
+ export EPICS_CA_ADDR_LIST=127.0.0.1:5094
44
44
  ```
45
45
 
46
46
  How to use the devices in a plan:
@@ -0,0 +1,9 @@
1
+ from dodal.common.beamlines.beamline_utils import device_factory
2
+ from dodal.devices.aithre_lasershaping.goniometer import Goniometer
3
+
4
+ PREFIX = "LA18L"
5
+
6
+
7
+ @device_factory()
8
+ def goniometer() -> Goniometer:
9
+ return Goniometer(f"{PREFIX}-MO-LSR-01:", "goniometer")
dodal/beamlines/i04.py CHANGED
@@ -46,7 +46,7 @@ ZOOM_PARAMS_FILE = (
46
46
  DISPLAY_CONFIG = "/dls_sw/i04/software/gda_versions/var/display.configuration"
47
47
  DAQ_CONFIGURATION_PATH = "/dls_sw/i04/software/daq_configuration"
48
48
 
49
- REDIS_HOST = os.environ.get("VALKEY_PROD_SVC_SERVICE_HOST", "test_redis")
49
+ REDIS_HOST = "i04-valkey-murko.diamond.ac.uk"
50
50
  REDIS_PASSWORD = os.environ.get("VALKEY_PASSWORD", "test_redis_password")
51
51
  MURKO_REDIS_DB = 7
52
52
 
@@ -0,0 +1,34 @@
1
+ from dodal.common.beamlines.beamline_utils import (
2
+ device_factory,
3
+ )
4
+ from dodal.common.beamlines.beamline_utils import (
5
+ set_beamline as set_utils_beamline,
6
+ )
7
+ from dodal.devices.hutch_shutter import HutchShutter
8
+ from dodal.devices.i19.hutch_access import HutchAccessControl
9
+ from dodal.log import set_beamline as set_log_beamline
10
+ from dodal.utils import BeamlinePrefix
11
+
12
+ BL = "i19-optics"
13
+ PREFIX = BeamlinePrefix("i19", "I")
14
+ set_log_beamline(BL)
15
+ set_utils_beamline(BL)
16
+
17
+
18
+ @device_factory()
19
+ def shutter() -> HutchShutter:
20
+ """Get the i19 hutch shutter device, instantiate it if it hasn't already been.
21
+ If this is called when already instantiated, it will return the existing object.
22
+ """
23
+ return HutchShutter(
24
+ f"{PREFIX.beamline_prefix}-PS-SHTR-01:",
25
+ "shutter",
26
+ )
27
+
28
+
29
+ @device_factory()
30
+ def access_control() -> HutchAccessControl:
31
+ """Get a device that checks the active hutch for i19, instantiate it if it hasn't already been.
32
+ If this is called when already instantiated, it will return the existing object.
33
+ """
34
+ return HutchAccessControl(f"{PREFIX.beamline_prefix}-OP-STAT-01:", "access_control")
dodal/beamlines/p45.py CHANGED
@@ -4,7 +4,7 @@ from ophyd_async.epics.adaravis import AravisDetector
4
4
  from ophyd_async.fastcs.panda import HDFPanda
5
5
 
6
6
  from dodal.common.beamlines.beamline_utils import (
7
- device_instantiation,
7
+ device_factory,
8
8
  get_path_provider,
9
9
  set_path_provider,
10
10
  )
@@ -13,11 +13,13 @@ from dodal.common.beamlines.device_helpers import DET_SUFFIX, HDF5_SUFFIX
13
13
  from dodal.common.visit import StaticVisitPathProvider
14
14
  from dodal.devices.p45 import Choppers, TomoStageWithStretchAndSkew
15
15
  from dodal.log import set_beamline as set_log_beamline
16
- from dodal.utils import get_beamline_name, skip_device
16
+ from dodal.utils import BeamlinePrefix, get_beamline_name
17
17
 
18
18
  BL = get_beamline_name("p45")
19
+ PREFIX = BeamlinePrefix(BL)
19
20
  set_log_beamline(BL)
20
21
  set_utils_beamline(BL)
22
+
21
23
  set_path_provider(
22
24
  StaticVisitPathProvider(
23
25
  BL,
@@ -26,92 +28,51 @@ set_path_provider(
26
28
  )
27
29
 
28
30
 
29
- def sample(
30
- wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
31
- ) -> TomoStageWithStretchAndSkew:
32
- return device_instantiation(
33
- TomoStageWithStretchAndSkew,
34
- "sample_stage",
35
- "-MO-STAGE-01:",
36
- wait_for_connection,
37
- fake_with_ophyd_sim,
38
- )
31
+ @device_factory()
32
+ def sample() -> TomoStageWithStretchAndSkew:
33
+ return TomoStageWithStretchAndSkew(f"{PREFIX.beamline_prefix}-MO-STAGE-01:")
39
34
 
40
35
 
41
- def choppers(
42
- wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
43
- ) -> Choppers:
44
- return device_instantiation(
45
- Choppers,
46
- "chopper",
47
- "-MO-CHOP-01:",
48
- wait_for_connection,
49
- fake_with_ophyd_sim,
50
- )
36
+ @device_factory()
37
+ def choppers() -> Choppers:
38
+ return Choppers(f"{PREFIX.beamline_prefix}-MO-CHOP-01:")
51
39
 
52
40
 
53
41
  # Disconnected
54
- @skip_device()
55
- def det(
56
- wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
57
- ) -> AravisDetector:
58
- return device_instantiation(
59
- AravisDetector,
60
- "det",
61
- "-EA-MAP-01:",
62
- wait_for_connection,
63
- fake_with_ophyd_sim,
42
+ @device_factory(skip=True)
43
+ def det() -> AravisDetector:
44
+ return AravisDetector(
45
+ f"{PREFIX.beamline_prefix}-EA-MAP-01:",
46
+ path_provider=get_path_provider(),
64
47
  drv_suffix=DET_SUFFIX,
65
48
  fileio_suffix=HDF5_SUFFIX,
66
- path_provider=get_path_provider(),
67
49
  )
68
50
 
69
51
 
70
52
  # Disconnected
71
- @skip_device()
72
- def diff(
73
- wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
74
- ) -> AravisDetector:
75
- return device_instantiation(
76
- AravisDetector,
77
- "diff",
78
- "-EA-DIFF-01:",
79
- wait_for_connection,
80
- fake_with_ophyd_sim,
53
+ @device_factory(skip=True)
54
+ def diff() -> AravisDetector:
55
+ return AravisDetector(
56
+ f"{PREFIX.beamline_prefix}-EA-DIFF-01:",
57
+ path_provider=get_path_provider(),
81
58
  drv_suffix=DET_SUFFIX,
82
59
  fileio_suffix=HDF5_SUFFIX,
83
- path_provider=get_path_provider(),
84
60
  )
85
61
 
86
62
 
87
- # Must find which PandA IOC(s) are compatible
88
63
  # Must document what PandAs are physically connected to
89
64
  # See: https://github.com/bluesky/ophyd-async/issues/284
90
- @skip_device()
91
- def panda1(
92
- wait_for_connection: bool = True,
93
- fake_with_ophyd_sim: bool = False,
94
- ) -> HDFPanda:
95
- return device_instantiation(
96
- HDFPanda,
97
- "panda1",
98
- "-MO-PANDA-01:",
99
- wait_for_connection,
100
- fake_with_ophyd_sim,
65
+ @device_factory(skip=True)
66
+ def panda1() -> HDFPanda:
67
+ return HDFPanda(
68
+ f"{PREFIX.beamline_prefix}-MO-PANDA-01:",
101
69
  path_provider=get_path_provider(),
102
70
  )
103
71
 
104
72
 
105
- @skip_device()
106
- def panda2(
107
- wait_for_connection: bool = True,
108
- fake_with_ophyd_sim: bool = False,
109
- ) -> HDFPanda:
110
- return device_instantiation(
111
- HDFPanda,
112
- "panda2",
113
- "-MO-PANDA-02:",
114
- wait_for_connection,
115
- fake_with_ophyd_sim,
73
+ @device_factory(skip=True)
74
+ def panda2() -> HDFPanda:
75
+ return HDFPanda(
76
+ f"{PREFIX.beamline_prefix}-MO-PANDA-02:",
116
77
  path_provider=get_path_provider(),
117
78
  )
dodal/common/visit.py CHANGED
@@ -78,7 +78,7 @@ class RemoteDirectoryServiceClient(DirectoryServiceClient):
78
78
  ):
79
79
  response.raise_for_status()
80
80
  json = await response.json()
81
- return DataCollectionIdentifier.model_validate_json(json)
81
+ return DataCollectionIdentifier.model_validate(json)
82
82
 
83
83
 
84
84
  class LocalDirectoryServiceClient(DirectoryServiceClient):
@@ -0,0 +1,15 @@
1
+ from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.motor import Motor
3
+
4
+
5
+ class Goniometer(StandardReadable):
6
+ """Goniometer and the stages it sits on"""
7
+
8
+ def __init__(self, prefix: str, name: str = "") -> None:
9
+ self.x = Motor(prefix + "X")
10
+ self.y = Motor(prefix + "Y")
11
+ self.z = Motor(prefix + "Z")
12
+ self.sampy = Motor(prefix + "SAMPY")
13
+ self.sampz = Motor(prefix + "SAMPZ")
14
+ self.omega = Motor(prefix + "OMEGA")
15
+ super().__init__(name)
@@ -123,7 +123,7 @@ def load_positions_from_beamline_parameters(
123
123
  }
124
124
 
125
125
 
126
- class ApertureScatterguard(StandardReadable, Movable[ApertureValue], Preparable):
126
+ class ApertureScatterguard(StandardReadable, Movable, Preparable):
127
127
  """Move the aperture and scatterguard assembly in a safe way. There are two ways to
128
128
  interact with the device depending on if you want simplicity or move flexibility.
129
129
 
@@ -1,7 +1,7 @@
1
1
  import abc
2
2
  import asyncio
3
3
  from dataclasses import dataclass
4
- from typing import Any, Generic, TypeVar
4
+ from typing import Any
5
5
 
6
6
  import numpy as np
7
7
  from bluesky.protocols import Movable
@@ -21,8 +21,6 @@ from pydantic import BaseModel, ConfigDict, RootModel
21
21
 
22
22
  from dodal.log import LOGGER
23
23
 
24
- T = TypeVar("T")
25
-
26
24
 
27
25
  class UndulatorGateStatus(StrictEnum):
28
26
  OPEN = "Open"
@@ -101,7 +99,7 @@ async def estimate_motor_timeout(
101
99
  return abs((target_pos - cur_pos) * 2.0 / vel) + 1
102
100
 
103
101
 
104
- class SafeUndulatorMover(StandardReadable, Movable[T], Generic[T]):
102
+ class SafeUndulatorMover(StandardReadable, Movable):
105
103
  """A device that will check it's safe to move the undulator before moving it and
106
104
  wait for the undulator to be safe again before calling the move complete.
107
105
  """
@@ -117,7 +115,7 @@ class SafeUndulatorMover(StandardReadable, Movable[T], Generic[T]):
117
115
  super().__init__(name)
118
116
 
119
117
  @AsyncStatus.wrap
120
- async def set(self, value: T) -> None:
118
+ async def set(self, value) -> None:
121
119
  LOGGER.info(f"Setting {self.name} to {value}")
122
120
  await self.raise_if_cannot_move()
123
121
  await self._set_demand_positions(value)
@@ -127,7 +125,7 @@ class SafeUndulatorMover(StandardReadable, Movable[T], Generic[T]):
127
125
  await wait_for_value(self.gate, UndulatorGateStatus.CLOSE, timeout=timeout)
128
126
 
129
127
  @abc.abstractmethod
130
- async def _set_demand_positions(self, value: T) -> None:
128
+ async def _set_demand_positions(self, value) -> None:
131
129
  """Set the demand positions on the device without actually hitting move."""
132
130
 
133
131
  @abc.abstractmethod
@@ -141,7 +139,7 @@ class SafeUndulatorMover(StandardReadable, Movable[T], Generic[T]):
141
139
  raise RuntimeError(f"{self.name} is already in motion.")
142
140
 
143
141
 
144
- class UndulatorGap(SafeUndulatorMover[float]):
142
+ class UndulatorGap(SafeUndulatorMover):
145
143
  """A device with a collection of epics signals to set Apple 2 undulator gap motion.
146
144
  Only PV used by beamline are added the full list is here:
147
145
  /dls_sw/work/R3.14.12.7/support/insertionDevice/db/IDGapVelocityControl.template
@@ -187,7 +185,7 @@ class UndulatorGap(SafeUndulatorMover[float]):
187
185
  self.user_readback = epics_signal_r(float, prefix + "CURRGAPD")
188
186
  super().__init__(self.set_move, prefix, name)
189
187
 
190
- async def _set_demand_positions(self, value: float) -> None:
188
+ async def _set_demand_positions(self, value) -> None:
191
189
  await self.user_setpoint.set(str(value))
192
190
 
193
191
  async def get_timeout(self) -> float:
@@ -236,7 +234,7 @@ class UndulatorPhaseMotor(StandardReadable):
236
234
  super().__init__(name=name)
237
235
 
238
236
 
239
- class UndulatorPhaseAxes(SafeUndulatorMover[Apple2PhasesVal]):
237
+ class UndulatorPhaseAxes(SafeUndulatorMover):
240
238
  """
241
239
  A collection of 4 phase Motor to make up the full id phase motion. We are using the diamond pv convention.
242
240
  e.g. top_outer == Q1
@@ -292,7 +290,7 @@ class UndulatorPhaseAxes(SafeUndulatorMover[Apple2PhasesVal]):
292
290
  return np.max(timeouts)
293
291
 
294
292
 
295
- class UndulatorJawPhase(SafeUndulatorMover[float]):
293
+ class UndulatorJawPhase(SafeUndulatorMover):
296
294
  """
297
295
  A JawPhase movable, this is use for moving the jaw phase which is use to control the
298
296
  linear arbitrary polarisation but only one some of the beamline.
@@ -29,7 +29,7 @@ class ReadOnlyAttenuator(StandardReadable):
29
29
  super().__init__(name)
30
30
 
31
31
 
32
- class BinaryFilterAttenuator(ReadOnlyAttenuator, Movable[float]):
32
+ class BinaryFilterAttenuator(ReadOnlyAttenuator, Movable):
33
33
  """The attenuator will insert filters into the beam to reduce its transmission.
34
34
  In this attenuator, each filter can be in one of two states: IN or OUT
35
35
 
@@ -15,7 +15,7 @@ class BacklightPosition(StrictEnum):
15
15
  OUT = "Out"
16
16
 
17
17
 
18
- class Backlight(StandardReadable, Movable[BacklightPosition]):
18
+ class Backlight(StandardReadable, Movable):
19
19
  """Simple device to trigger the pneumatic in/out."""
20
20
 
21
21
  TIME_TO_MOVE_S = 1.0 # Tested using a stopwatch on the beamline 09/2024
@@ -41,7 +41,7 @@ class BimorphMirrorStatus(StrictEnum):
41
41
  ERROR = "Error"
42
42
 
43
43
 
44
- class BimorphMirrorChannel(StandardReadable, Movable[float], EpicsDevice):
44
+ class BimorphMirrorChannel(StandardReadable, Movable, EpicsDevice):
45
45
  """Collection of PVs comprising a single bimorph channel.
46
46
 
47
47
  Attributes:
@@ -66,7 +66,7 @@ class BimorphMirrorChannel(StandardReadable, Movable[float], EpicsDevice):
66
66
  await self.output_voltage.set(value)
67
67
 
68
68
 
69
- class BimorphMirror(StandardReadable, Movable[Mapping[int, float]]):
69
+ class BimorphMirror(StandardReadable, Movable):
70
70
  """Class to represent CAENels Bimorph Mirrors.
71
71
 
72
72
  Attributes:
@@ -32,7 +32,7 @@ class DetectorParams(BaseModel):
32
32
  # Must use model_dump(by_alias=True) if serialising!
33
33
 
34
34
  expected_energy_ev: float | None = None
35
- exposure_time: float
35
+ exposure_time_s: float
36
36
  directory: str # : Path https://github.com/DiamondLightSource/dodal/issues/774
37
37
  prefix: str
38
38
  detector_distance: float
dodal/devices/eiger.py CHANGED
@@ -221,11 +221,11 @@ class EigerDetector(Device, Stageable):
221
221
  def set_cam_pvs(self) -> AndStatus:
222
222
  assert self.detector_params is not None
223
223
  status = self.cam.acquire_time.set(
224
- self.detector_params.exposure_time,
224
+ self.detector_params.exposure_time_s,
225
225
  timeout=self.timeouts.general_status_timeout,
226
226
  )
227
227
  status &= self.cam.acquire_period.set(
228
- self.detector_params.exposure_time,
228
+ self.detector_params.exposure_time_s,
229
229
  timeout=self.timeouts.general_status_timeout,
230
230
  )
231
231
  status &= self.cam.num_exposures.set(
@@ -55,7 +55,7 @@ class HutchInterlock(StandardReadable):
55
55
  return interlock_state == HUTCH_SAFE_FOR_OPERATIONS
56
56
 
57
57
 
58
- class HutchShutter(StandardReadable, Movable[ShutterDemand]):
58
+ class HutchShutter(StandardReadable, Movable):
59
59
  """Device to operate the hutch shutter.
60
60
 
61
61
  When a demand is sent, the device should first check the hutch status \
@@ -175,7 +175,7 @@ class I10Apple2(Apple2):
175
175
  self._available_pol = list(self.lookup_tables["Gap"].keys())
176
176
 
177
177
 
178
- class I10Apple2PGM(StandardReadable, Movable[float]):
178
+ class I10Apple2PGM(StandardReadable, Movable):
179
179
  """
180
180
  Compound device to set both ID and PGM energy at the sample time,poly_deg
181
181
 
@@ -211,7 +211,7 @@ class I10Apple2PGM(StandardReadable, Movable[float]):
211
211
  )
212
212
 
213
213
 
214
- class I10Apple2Pol(StandardReadable, Movable[str]):
214
+ class I10Apple2Pol(StandardReadable, Movable):
215
215
  """
216
216
  Compound device to set polorisation of ID.
217
217
  """
@@ -240,7 +240,7 @@ class I10Apple2Pol(StandardReadable, Movable[str]):
240
240
  ) # Move id to new polarisation
241
241
 
242
242
 
243
- class LinearArbitraryAngle(StandardReadable, Movable[SupportsFloat]):
243
+ class LinearArbitraryAngle(StandardReadable, Movable):
244
244
  """
245
245
  Device to set polorisation angle of the ID. Linear Arbitrary Angle (laa)
246
246
  is the direction of the magnetic field which can be change by varying the jaw_phase
@@ -0,0 +1,8 @@
1
+ from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.core import epics_signal_r
3
+
4
+
5
+ class HutchAccessControl(StandardReadable):
6
+ def __init__(self, prefix: str, name: str = "") -> None:
7
+ self.active_hutch = epics_signal_r(str, f"{prefix}EHStatus.VALA")
8
+ super().__init__(name)
@@ -18,7 +18,7 @@ class HutchState(str, Enum):
18
18
  INVALID = "INVALID"
19
19
 
20
20
 
21
- class HutchConditionalShutter(StandardReadable, Movable[ShutterDemand]):
21
+ class HutchConditionalShutter(StandardReadable, Movable):
22
22
  """ I19-specific device to operate the hutch shutter.
23
23
 
24
24
  This device evaluates the hutch state value to work out which of the two I19 \
dodal/devices/i24/pmac.py CHANGED
@@ -71,7 +71,7 @@ class PMACStringMove(Triggerable):
71
71
  await self.signal_ref().set(self.cmd_string, wait=True)
72
72
 
73
73
 
74
- class PMACStringLaser(Device, Movable[LaserSettings]):
74
+ class PMACStringLaser(Device, Movable):
75
75
  """Set the pmac_string to control the laser."""
76
76
 
77
77
  def __init__(
@@ -90,7 +90,7 @@ class PMACStringLaser(Device, Movable[LaserSettings]):
90
90
  await self._signal_ref().set(value.value)
91
91
 
92
92
 
93
- class PMACStringEncReset(Device, Movable[EncReset]):
93
+ class PMACStringEncReset(Device, Movable):
94
94
  """Set a pmac_string to control the encoder channels in the controller."""
95
95
 
96
96
  def __init__(
@@ -29,7 +29,7 @@ def _get_correct_zoom_string(zoom: str) -> str:
29
29
  return zoom
30
30
 
31
31
 
32
- class ZoomController(StandardReadable, Movable[str]):
32
+ class ZoomController(StandardReadable, Movable):
33
33
  """
34
34
  Device to control the zoom level. This should be set like
35
35
  o = OAV(name="oav")
@@ -34,9 +34,10 @@ class SnapshotWithGrid(MJPG):
34
34
  box_width = await self.box_width.get_value()
35
35
  num_boxes_x = await self.num_boxes_x.get_value()
36
36
  num_boxes_y = await self.num_boxes_y.get_value()
37
-
38
- assert isinstance(filename_str := await self.filename.get_value(), str)
39
- assert isinstance(directory_str := await self.directory.get_value(), str)
37
+ filename_str = await self.filename.get_value()
38
+ assert isinstance(filename_str, str)
39
+ directory_str = await self.directory.get_value()
40
+ assert isinstance(directory_str, str)
40
41
 
41
42
  add_grid_border_overlay_to_image(
42
43
  image, int(top_left_x), int(top_left_y), box_width, num_boxes_x, num_boxes_y
dodal/devices/p45.py CHANGED
@@ -7,13 +7,13 @@ class SampleY(StandardReadable):
7
7
  Motors for controlling the sample's y position and stretch in the y axis.
8
8
  """
9
9
 
10
- def __init__(self, prefix: str, name="") -> None:
10
+ def __init__(self, prefix: str, name: str = ""):
11
11
  with self.add_children_as_readables():
12
12
  self.base = Motor(prefix + "CS:Y")
13
13
  self.stretch = Motor(prefix + "CS:Y:STRETCH")
14
14
  self.top = Motor(prefix + "Y:TOP")
15
15
  self.bottom = Motor(prefix + "Y:BOT")
16
- super().__init__(name=name)
16
+ super().__init__(name)
17
17
 
18
18
 
19
19
  class SampleTheta(StandardReadable):
@@ -21,13 +21,13 @@ class SampleTheta(StandardReadable):
21
21
  Motors for controlling the sample's theta position and skew
22
22
  """
23
23
 
24
- def __init__(self, prefix: str, name="") -> None:
24
+ def __init__(self, prefix: str, name: str = ""):
25
25
  with self.add_children_as_readables():
26
26
  self.base = Motor(prefix + "THETA:POS")
27
27
  self.skew = Motor(prefix + "THETA:SKEW")
28
28
  self.top = Motor(prefix + "THETA:TOP")
29
29
  self.bottom = Motor(prefix + "THETA:BOT")
30
- super().__init__(name=name)
30
+ super().__init__(name)
31
31
 
32
32
 
33
33
  class TomoStageWithStretchAndSkew(StandardReadable):
@@ -35,12 +35,12 @@ class TomoStageWithStretchAndSkew(StandardReadable):
35
35
  Grouping of motors for the P45 tomography stage
36
36
  """
37
37
 
38
- def __init__(self, prefix: str, name="") -> None:
38
+ def __init__(self, prefix: str, name: str = ""):
39
39
  with self.add_children_as_readables():
40
40
  self.x = Motor(prefix + "X")
41
41
  self.y = SampleY(prefix)
42
42
  self.theta = SampleTheta(prefix)
43
- super().__init__(name=name)
43
+ super().__init__(name)
44
44
 
45
45
 
46
46
  class Choppers(StandardReadable):
@@ -48,8 +48,8 @@ class Choppers(StandardReadable):
48
48
  Grouping for the P45 chopper motors
49
49
  """
50
50
 
51
- def __init__(self, prefix: str, name="") -> None:
51
+ def __init__(self, prefix: str, name: str = ""):
52
52
  with self.add_children_as_readables():
53
53
  self.x = Motor(prefix + "ENDAT")
54
54
  self.y = Motor(prefix + "BISS")
55
- super().__init__(name=name)
55
+ super().__init__(name)
@@ -76,7 +76,7 @@ class AllValvesControlState:
76
76
  valve_6: FastValveControlRequest | None = None
77
77
 
78
78
 
79
- class AllValvesControl(StandardReadable, Movable[AllValvesControlState]):
79
+ class AllValvesControl(StandardReadable, Movable):
80
80
  """
81
81
  valves 2, 4, 7, 8 are not controlled by the IOC,
82
82
  as they are under manual control.
@@ -151,9 +151,7 @@ class AllValvesControl(StandardReadable, Movable[AllValvesControlState]):
151
151
  )
152
152
 
153
153
 
154
- class ValveControl(
155
- StandardReadable, Movable[ValveControlRequest | ValveOpenSeqRequest]
156
- ):
154
+ class ValveControl(StandardReadable, Movable):
157
155
  def __init__(self, prefix: str, name: str = "") -> None:
158
156
  with self.add_children_as_readables():
159
157
  self.close = epics_signal_rw(ValveControlRequest, prefix + ":CON")
@@ -172,9 +170,7 @@ class ValveControl(
172
170
  return set_status
173
171
 
174
172
 
175
- class FastValveControl(
176
- StandardReadable, Movable[FastValveControlRequest | ValveOpenSeqRequest]
177
- ):
173
+ class FastValveControl(StandardReadable, Movable):
178
174
  def __init__(self, prefix: str, name: str = "") -> None:
179
175
  with self.add_children_as_readables():
180
176
  self.close = epics_signal_rw(FastValveControlRequest, prefix + ":CON")
dodal/devices/robot.py CHANGED
@@ -52,7 +52,7 @@ class ErrorStatus(Device):
52
52
  raise RobotLoadFailed(int(error_code), error_string) from raise_from
53
53
 
54
54
 
55
- class BartRobot(StandardReadable, Movable[SampleLocation]):
55
+ class BartRobot(StandardReadable, Movable):
56
56
  """The sample changing robot."""
57
57
 
58
58
  # How long to wait for the robot if it is busy soaking/drying
dodal/devices/thawer.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from asyncio import Task, create_task, sleep
2
2
 
3
- from bluesky.protocols import Movable, Stoppable
3
+ from bluesky.protocols import Stoppable
4
4
  from ophyd_async.core import (
5
5
  AsyncStatus,
6
6
  Device,
@@ -21,18 +21,18 @@ class ThawerStates(StrictEnum):
21
21
  ON = "On"
22
22
 
23
23
 
24
- class ThawingTimer(Device, Stoppable, Movable[float]):
24
+ class ThawingTimer(Device, Stoppable):
25
25
  def __init__(self, control_signal: SignalRW[ThawerStates]) -> None:
26
26
  self._control_signal_ref = Reference(control_signal)
27
27
  self._thawing_task: Task | None = None
28
28
  super().__init__("thaw_for_time_s")
29
29
 
30
30
  @AsyncStatus.wrap
31
- async def set(self, value: float):
31
+ async def set(self, time_to_thaw_for: float):
32
32
  await self._control_signal_ref().set(ThawerStates.ON)
33
33
  if self._thawing_task and not self._thawing_task.done():
34
34
  raise ThawingException("Thawing task already in progress")
35
- self._thawing_task = create_task(sleep(value))
35
+ self._thawing_task = create_task(sleep(time_to_thaw_for))
36
36
  try:
37
37
  await self._thawing_task
38
38
  finally:
@@ -46,7 +46,7 @@ def _get_closest_gap_for_energy(
46
46
  return table[1][idx]
47
47
 
48
48
 
49
- class Undulator(StandardReadable, Movable[float]):
49
+ class Undulator(StandardReadable, Movable):
50
50
  """
51
51
  An Undulator-type insertion device, used to control photon emission at a given
52
52
  beam energy.
@@ -12,7 +12,7 @@ from .undulator import Undulator
12
12
  ENERGY_TIMEOUT_S: float = 30.0
13
13
 
14
14
 
15
- class UndulatorDCM(StandardReadable, Movable[float]):
15
+ class UndulatorDCM(StandardReadable, Movable):
16
16
  """
17
17
  Composite device to handle changing beamline energies, wraps the Undulator and the
18
18
  DCM. The DCM has a motor which controls the beam energy, when it moves, the
@@ -114,7 +114,7 @@ def call_func(func: Callable[[], StatusBase]) -> StatusBase:
114
114
  return func()
115
115
 
116
116
 
117
- class SetWhenEnabled(OphydAsyncDevice, Movable[int]):
117
+ class SetWhenEnabled(OphydAsyncDevice, Movable):
118
118
  """A device that sets the proc field of a PV when it becomes enabled."""
119
119
 
120
120
  def __init__(self, name: str = "", prefix: str = ""):
@@ -4,7 +4,6 @@ import asyncio
4
4
  from enum import Enum
5
5
  from functools import partialmethod
6
6
 
7
- from bluesky.protocols import Movable
8
7
  from ophyd_async.core import (
9
8
  AsyncStatus,
10
9
  DeviceVector,
@@ -75,7 +74,7 @@ class SoftInState(StrictEnum):
75
74
  NO = "No"
76
75
 
77
76
 
78
- class ArmingDevice(StandardReadable, Movable[ArmDemand]):
77
+ class ArmingDevice(StandardReadable):
79
78
  """A useful device that can abstract some of the logic of arming.
80
79
  Allows a user to just call arm.set(ArmDemand.ARM)"""
81
80
 
@@ -95,8 +94,8 @@ class ArmingDevice(StandardReadable, Movable[ArmDemand]):
95
94
  return
96
95
 
97
96
  @AsyncStatus.wrap
98
- async def set(self, value: ArmDemand):
99
- await asyncio.wait_for(self._set_armed(value), timeout=self.TIMEOUT)
97
+ async def set(self, demand: ArmDemand):
98
+ await asyncio.wait_for(self._set_armed(demand), timeout=self.TIMEOUT)
100
99
 
101
100
 
102
101
  class PositionCompare(StandardReadable):
@@ -19,7 +19,7 @@ class ZebraShutterControl(StrictEnum):
19
19
  AUTO = "Auto"
20
20
 
21
21
 
22
- class ZebraShutter(StandardReadable, Movable[ZebraShutterState]):
22
+ class ZebraShutter(StandardReadable, Movable):
23
23
  """The shutter on most MX beamlines is controlled by the zebra.
24
24
 
25
25
  Internally in the zebra there are two AND gates, one for manual control and one for
@@ -1,6 +1,6 @@
1
1
  import itertools
2
2
  from collections.abc import Mapping
3
- from typing import Annotated, TypeVar
3
+ from typing import Annotated, Any
4
4
 
5
5
  import bluesky.plan_stubs as bps
6
6
  from bluesky.protocols import Movable
@@ -12,17 +12,17 @@ Wrappers for Bluesky built-in plan stubs with type hinting
12
12
 
13
13
  Group = Annotated[str, "String identifier used by 'wait' or stubs that await"]
14
14
 
15
- T = TypeVar("T")
16
-
17
15
 
16
+ # After bluesky 1.14, bounds for stubs that move can be narrowed
17
+ # https://github.com/bluesky/bluesky/issues/1821
18
18
  def set_absolute(
19
- movable: Movable[T], value: T, group: Group | None = None, wait: bool = False
19
+ movable: Movable, value: Any, group: Group | None = None, wait: bool = False
20
20
  ) -> MsgGenerator:
21
21
  """
22
22
  Set a device, wrapper for `bp.abs_set`.
23
23
 
24
24
  Args:
25
- movable (Movable[T]): The device to set
25
+ movable (Movable): The device to set
26
26
  value (T): The new value
27
27
  group (Group | None, optional): The message group to associate with the
28
28
  setting, for sequencing. Defaults to None.
@@ -39,7 +39,7 @@ def set_absolute(
39
39
 
40
40
 
41
41
  def set_relative(
42
- movable: Movable[T], value: T, group: Group | None = None, wait: bool = False
42
+ movable: Movable, value: Any, group: Group | None = None, wait: bool = False
43
43
  ) -> MsgGenerator:
44
44
  """
45
45
  Change a device, wrapper for `bp.rel_set`.
@@ -62,7 +62,7 @@ def set_relative(
62
62
  return (yield from bps.rel_set(movable, value, group=group, wait=wait))
63
63
 
64
64
 
65
- def move(moves: Mapping[Movable[T], T], group: Group | None = None) -> MsgGenerator:
65
+ def move(moves: Mapping[Movable, Any], group: Group | None = None) -> MsgGenerator:
66
66
  """
67
67
  Move a device, wrapper for `bp.mv`.
68
68
 
@@ -79,12 +79,13 @@ def move(moves: Mapping[Movable[T], T], group: Group | None = None) -> MsgGenera
79
79
  """
80
80
 
81
81
  return (
82
- yield from bps.mv(*itertools.chain.from_iterable(moves.items()), group=group)
82
+ # type ignore until https://github.com/bluesky/bluesky/issues/1809
83
+ yield from bps.mv(*itertools.chain.from_iterable(moves.items()), group=group) # type: ignore
83
84
  )
84
85
 
85
86
 
86
87
  def move_relative(
87
- moves: Mapping[Movable[T], T], group: Group | None = None
88
+ moves: Mapping[Movable, Any], group: Group | None = None
88
89
  ) -> MsgGenerator:
89
90
  """
90
91
  Move a device relative to its current position, wrapper for `bp.mvr`.
@@ -102,7 +103,8 @@ def move_relative(
102
103
  """
103
104
 
104
105
  return (
105
- yield from bps.mvr(*itertools.chain.from_iterable(moves.items()), group=group)
106
+ # type ignore until https://github.com/bluesky/bluesky/issues/1809
107
+ yield from bps.mvr(*itertools.chain.from_iterable(moves.items()), group=group) # type: ignore
106
108
  )
107
109
 
108
110
 
File without changes
@@ -0,0 +1,49 @@
1
+ from bluesky.preprocessors import plan_mutator
2
+ from bluesky.utils import Msg, MsgGenerator, make_decorator
3
+
4
+ from dodal.plans.verify_undulator_gap import CheckUndulatorDevices, verify_undulator_gap
5
+
6
+
7
+ def verify_undulator_gap_before_run_wrapper(
8
+ plan: MsgGenerator,
9
+ devices: CheckUndulatorDevices,
10
+ run_key_to_wrap: str | None = None,
11
+ ):
12
+ """
13
+ Modifies the wrapped plan so that it checks the undulator gap before the specified run is opened and sets it to the correct value if needed.
14
+
15
+ After a beam dump, the undulator gap may not return correctly, scientists have often requested that this check is done before collections.
16
+
17
+ Args:
18
+ plan: The plan performing the run.
19
+ devices (CheckUndulatorDevices): Any device composite including the DCM and undulator
20
+ run_key_to_wrap: (str | None): The plan to verify the undulator gap is inserted after the 'open_run' message is seen with
21
+ the matching run key. If not specified, instead wrap the first run encountered.
22
+ """
23
+
24
+ # If no run_key specified, make sure we only do check on first run encountered
25
+ _wrapped_run_name: None | str = None
26
+
27
+ def head(msg: Msg):
28
+ yield from verify_undulator_gap(devices)
29
+ yield msg
30
+
31
+ def insert_plans(msg: Msg):
32
+ nonlocal _wrapped_run_name
33
+
34
+ match msg.command:
35
+ case "open_run":
36
+ if (
37
+ not (run_key_to_wrap or _wrapped_run_name)
38
+ or run_key_to_wrap is msg.run
39
+ ):
40
+ _wrapped_run_name = msg.run if msg.run else "unnamed_run"
41
+ return head(msg), None
42
+ return None, None
43
+
44
+ return plan_mutator(plan, insert_plans)
45
+
46
+
47
+ verify_undulator_gap_before_run_decorator = make_decorator(
48
+ verify_undulator_gap_before_run_wrapper
49
+ )
@@ -0,0 +1,19 @@
1
+ from typing import Protocol, runtime_checkable
2
+
3
+ from bluesky import plan_stubs as bps
4
+
5
+ from dodal.devices.dcm import DCM
6
+ from dodal.devices.undulator import Undulator
7
+
8
+
9
+ @runtime_checkable
10
+ class CheckUndulatorDevices(Protocol):
11
+ undulator: Undulator
12
+ dcm: DCM
13
+
14
+
15
+ def verify_undulator_gap(devices: CheckUndulatorDevices):
16
+ """Verify Undulator gap is correct - it may not be after a beam dump"""
17
+
18
+ energy_in_kev = yield from bps.rd(devices.dcm.energy_in_kev.user_readback)
19
+ yield from bps.abs_set(devices.undulator, energy_in_kev, wait=True)