dls-dodal 1.33.0__py3-none-any.whl → 1.35.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 (89) hide show
  1. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/METADATA +3 -3
  2. dls_dodal-1.35.0.dist-info/RECORD +147 -0
  3. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/WHEEL +1 -1
  4. dodal/__init__.py +8 -0
  5. dodal/_version.py +2 -2
  6. dodal/beamline_specific_utils/i03.py +6 -2
  7. dodal/beamlines/__init__.py +2 -3
  8. dodal/beamlines/i03.py +41 -9
  9. dodal/beamlines/i04.py +26 -4
  10. dodal/beamlines/i10.py +257 -0
  11. dodal/beamlines/i22.py +25 -13
  12. dodal/beamlines/i24.py +11 -11
  13. dodal/beamlines/p38.py +24 -13
  14. dodal/common/beamlines/beamline_utils.py +1 -2
  15. dodal/common/crystal_metadata.py +61 -0
  16. dodal/common/signal_utils.py +10 -14
  17. dodal/common/types.py +2 -7
  18. dodal/devices/CTAB.py +1 -1
  19. dodal/devices/aperture.py +1 -1
  20. dodal/devices/aperturescatterguard.py +20 -8
  21. dodal/devices/apple2_undulator.py +603 -0
  22. dodal/devices/areadetector/plugins/CAM.py +29 -0
  23. dodal/devices/areadetector/plugins/MJPG.py +51 -106
  24. dodal/devices/attenuator.py +1 -1
  25. dodal/devices/backlight.py +11 -11
  26. dodal/devices/cryostream.py +3 -5
  27. dodal/devices/dcm.py +26 -2
  28. dodal/devices/detector/detector_motion.py +3 -5
  29. dodal/devices/diamond_filter.py +46 -0
  30. dodal/devices/eiger.py +6 -2
  31. dodal/devices/eiger_odin.py +48 -39
  32. dodal/devices/fast_grid_scan.py +1 -1
  33. dodal/devices/fluorescence_detector_motion.py +5 -7
  34. dodal/devices/focusing_mirror.py +26 -19
  35. dodal/devices/hutch_shutter.py +4 -5
  36. dodal/devices/i10/i10_apple2.py +399 -0
  37. dodal/devices/i10/i10_setting_data.py +7 -0
  38. dodal/devices/i22/dcm.py +50 -83
  39. dodal/devices/i22/fswitch.py +5 -5
  40. dodal/devices/i24/aperture.py +3 -5
  41. dodal/devices/i24/beamstop.py +3 -5
  42. dodal/devices/i24/dcm.py +1 -1
  43. dodal/devices/i24/dual_backlight.py +9 -11
  44. dodal/devices/i24/pmac.py +35 -46
  45. dodal/devices/i24/vgonio.py +16 -0
  46. dodal/devices/ipin.py +5 -3
  47. dodal/devices/linkam3.py +7 -7
  48. dodal/devices/oav/oav_calculations.py +22 -0
  49. dodal/devices/oav/oav_detector.py +118 -83
  50. dodal/devices/oav/oav_parameters.py +50 -104
  51. dodal/devices/oav/oav_to_redis_forwarder.py +77 -35
  52. dodal/devices/oav/pin_image_recognition/__init__.py +9 -7
  53. dodal/devices/oav/{grid_overlay.py → snapshots/grid_overlay.py} +16 -59
  54. dodal/devices/oav/snapshots/snapshot_with_beam_centre.py +64 -0
  55. dodal/devices/oav/snapshots/snapshot_with_grid.py +57 -0
  56. dodal/devices/oav/utils.py +28 -27
  57. dodal/devices/p99/sample_stage.py +3 -5
  58. dodal/devices/pgm.py +40 -0
  59. dodal/devices/qbpm.py +18 -0
  60. dodal/devices/robot.py +5 -5
  61. dodal/devices/smargon.py +3 -3
  62. dodal/devices/synchrotron.py +9 -4
  63. dodal/devices/tetramm.py +9 -9
  64. dodal/devices/thawer.py +13 -7
  65. dodal/devices/undulator.py +7 -6
  66. dodal/devices/util/adjuster_plans.py +1 -1
  67. dodal/devices/util/epics_util.py +1 -1
  68. dodal/devices/util/lookup_tables.py +4 -5
  69. dodal/devices/watsonmarlow323_pump.py +45 -0
  70. dodal/devices/webcam.py +9 -2
  71. dodal/devices/xbpm_feedback.py +3 -5
  72. dodal/devices/xspress3/xspress3.py +8 -9
  73. dodal/devices/xspress3/xspress3_channel.py +3 -5
  74. dodal/devices/zebra.py +12 -8
  75. dodal/devices/zebra_controlled_shutter.py +5 -6
  76. dodal/devices/zocalo/__init__.py +2 -2
  77. dodal/devices/zocalo/zocalo_constants.py +3 -0
  78. dodal/devices/zocalo/zocalo_interaction.py +2 -1
  79. dodal/devices/zocalo/zocalo_results.py +105 -89
  80. dodal/plans/data_session_metadata.py +2 -2
  81. dodal/plans/motor_util_plans.py +11 -9
  82. dodal/utils.py +11 -0
  83. dls_dodal-1.33.0.dist-info/RECORD +0 -136
  84. dodal/beamlines/i04_1.py +0 -140
  85. dodal/devices/i24/i24_vgonio.py +0 -17
  86. dodal/devices/oav/oav_errors.py +0 -35
  87. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/LICENSE +0 -0
  88. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/entry_points.txt +0 -0
  89. {dls_dodal-1.33.0.dist-info → dls_dodal-1.35.0.dist-info}/top_level.txt +0 -0
dodal/beamlines/i22.py CHANGED
@@ -11,9 +11,13 @@ from dodal.common.beamlines.beamline_utils import (
11
11
  )
12
12
  from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
13
13
  from dodal.common.beamlines.device_helpers import numbered_slits
14
+ from dodal.common.crystal_metadata import (
15
+ MaterialsEnum,
16
+ make_crystal_metadata_from_material,
17
+ )
14
18
  from dodal.common.visit import RemoteDirectoryServiceClient, StaticVisitPathProvider
15
19
  from dodal.devices.focusing_mirror import FocusingMirror
16
- from dodal.devices.i22.dcm import CrystalMetadata, DoubleCrystalMonochromator
20
+ from dodal.devices.i22.dcm import DoubleCrystalMonochromator
17
21
  from dodal.devices.i22.fswitch import FSwitch
18
22
  from dodal.devices.i22.nxsas import NXSasMetadataHolder, NXSasOAV, NXSasPilatus
19
23
  from dodal.devices.linkam3 import Linkam3
@@ -21,6 +25,7 @@ from dodal.devices.slits import Slits
21
25
  from dodal.devices.synchrotron import Synchrotron
22
26
  from dodal.devices.tetramm import TetrammDetector
23
27
  from dodal.devices.undulator import Undulator
28
+ from dodal.devices.watsonmarlow323_pump import WatsonMarlow323Pump
24
29
  from dodal.log import set_beamline as set_log_beamline
25
30
  from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device
26
31
 
@@ -165,23 +170,17 @@ def dcm(
165
170
  return device_instantiation(
166
171
  DoubleCrystalMonochromator,
167
172
  "dcm",
168
- "",
173
+ f"{BeamlinePrefix(BL).beamline_prefix}-MO-DCM-01:",
169
174
  wait_for_connection,
170
175
  fake_with_ophyd_sim,
171
176
  bl_prefix=False,
172
- motion_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-MO-DCM-01:",
173
177
  temperature_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-DI-DCM-01:",
174
- crystal_1_metadata=CrystalMetadata(
175
- usage="Bragg",
176
- type="silicon",
177
- reflection=(1, 1, 1),
178
- d_spacing=(3.13475, "nm"),
178
+ crystal_1_metadata=make_crystal_metadata_from_material(
179
+ MaterialsEnum.Si, (1, 1, 1)
179
180
  ),
180
- crystal_2_metadata=CrystalMetadata(
181
- usage="Bragg",
182
- type="silicon",
183
- reflection=(1, 1, 1),
184
- d_spacing=(3.13475, "nm"),
181
+ crystal_2_metadata=make_crystal_metadata_from_material(
182
+ MaterialsEnum.Si,
183
+ (1, 1, 1),
185
184
  ),
186
185
  )
187
186
 
@@ -378,3 +377,16 @@ def linkam(
378
377
  wait_for_connection,
379
378
  fake_with_ophyd_sim,
380
379
  )
380
+
381
+
382
+ def ppump(
383
+ wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
384
+ ) -> WatsonMarlow323Pump:
385
+ """Sample Environment Peristaltic Pump"""
386
+ return device_instantiation(
387
+ WatsonMarlow323Pump,
388
+ "ppump",
389
+ "-EA-PUMP-01:",
390
+ wait_for_connection,
391
+ fake_with_ophyd_sim,
392
+ )
dodal/beamlines/i24.py CHANGED
@@ -1,4 +1,7 @@
1
- from dodal.common.beamlines.beamline_utils import BL, device_instantiation
1
+ from dodal.common.beamlines.beamline_utils import (
2
+ BL,
3
+ device_instantiation,
4
+ )
2
5
  from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
3
6
  from dodal.devices.detector import DetectorParams
4
7
  from dodal.devices.eiger import EigerDetector
@@ -8,10 +11,10 @@ from dodal.devices.i24.beamstop import Beamstop
8
11
  from dodal.devices.i24.dcm import DCM
9
12
  from dodal.devices.i24.dual_backlight import DualBacklight
10
13
  from dodal.devices.i24.i24_detector_motion import DetectorMotion
11
- from dodal.devices.i24.i24_vgonio import VGonio
12
14
  from dodal.devices.i24.pmac import PMAC
15
+ from dodal.devices.i24.vgonio import VerticalGoniometer
13
16
  from dodal.devices.oav.oav_detector import OAV
14
- from dodal.devices.oav.oav_parameters import OAVConfigParams
17
+ from dodal.devices.oav.oav_parameters import OAVConfig
15
18
  from dodal.devices.zebra import Zebra
16
19
  from dodal.log import set_beamline as set_log_beamline
17
20
  from dodal.utils import get_beamline_name, skip_device
@@ -138,28 +141,25 @@ def pmac(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) ->
138
141
 
139
142
  @skip_device(lambda: BL == "s24")
140
143
  def oav(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -> OAV:
141
- """Get the i24 OAV device, instantiate it if it hasn't already been.
142
- If this is called when already instantiated in i24, it will return the existing object.
143
- """
144
144
  return device_instantiation(
145
145
  OAV,
146
146
  "oav",
147
- "",
147
+ "-DI-OAV-01:",
148
148
  wait_for_connection,
149
149
  fake_with_ophyd_sim,
150
- params=OAVConfigParams(ZOOM_PARAMS_FILE, DISPLAY_CONFIG),
150
+ config=OAVConfig(ZOOM_PARAMS_FILE, DISPLAY_CONFIG),
151
151
  )
152
152
 
153
153
 
154
154
  @skip_device(lambda: BL == "s24")
155
155
  def vgonio(
156
156
  wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
157
- ) -> VGonio:
158
- """Get the i24 vgonio device, instantiate it if it hasn't already been.
157
+ ) -> VerticalGoniometer:
158
+ """Get the i24 vertical goniometer device, instantiate it if it hasn't already been.
159
159
  If this is called when already instantiated, it will return the existing object.
160
160
  """
161
161
  return device_instantiation(
162
- VGonio,
162
+ VerticalGoniometer,
163
163
  "vgonio",
164
164
  "-MO-VGON-01:",
165
165
  wait_for_connection,
dodal/beamlines/p38.py CHANGED
@@ -10,14 +10,19 @@ from dodal.common.beamlines.beamline_utils import (
10
10
  )
11
11
  from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline
12
12
  from dodal.common.beamlines.device_helpers import numbered_slits
13
+ from dodal.common.crystal_metadata import (
14
+ MaterialsEnum,
15
+ make_crystal_metadata_from_material,
16
+ )
13
17
  from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider
14
18
  from dodal.devices.focusing_mirror import FocusingMirror
15
- from dodal.devices.i22.dcm import CrystalMetadata, DoubleCrystalMonochromator
19
+ from dodal.devices.i22.dcm import DoubleCrystalMonochromator
16
20
  from dodal.devices.i22.fswitch import FSwitch
17
21
  from dodal.devices.linkam3 import Linkam3
18
22
  from dodal.devices.slits import Slits
19
23
  from dodal.devices.tetramm import TetrammDetector
20
24
  from dodal.devices.undulator import Undulator
25
+ from dodal.devices.watsonmarlow323_pump import WatsonMarlow323Pump
21
26
  from dodal.log import set_beamline as set_log_beamline
22
27
  from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device
23
28
 
@@ -222,23 +227,16 @@ def dcm(
222
227
  return device_instantiation(
223
228
  DoubleCrystalMonochromator,
224
229
  "dcm",
225
- "",
230
+ f"{BeamlinePrefix(BL).beamline_prefix}-MO-DCM-01:",
226
231
  wait_for_connection,
227
232
  fake_with_ophyd_sim,
228
233
  bl_prefix=False,
229
- motion_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-MO-DCM-01:",
230
234
  temperature_prefix=f"{BeamlinePrefix(BL).beamline_prefix}-DI-DCM-01:",
231
- crystal_1_metadata=CrystalMetadata(
232
- usage="Bragg",
233
- type="silicon",
234
- reflection=(1, 1, 1),
235
- d_spacing=(3.13475, "nm"),
235
+ crystal_1_metadata=make_crystal_metadata_from_material(
236
+ MaterialsEnum.Si, (1, 1, 1)
236
237
  ),
237
- crystal_2_metadata=CrystalMetadata(
238
- usage="Bragg",
239
- type="silicon",
240
- reflection=(1, 1, 1),
241
- d_spacing=(3.13475, "nm"),
238
+ crystal_2_metadata=make_crystal_metadata_from_material(
239
+ MaterialsEnum.Si, (1, 1, 1)
242
240
  ),
243
241
  )
244
242
 
@@ -318,3 +316,16 @@ def linkam(
318
316
  wait_for_connection,
319
317
  fake_with_ophyd_sim,
320
318
  )
319
+
320
+
321
+ def ppump(
322
+ wait_for_connection: bool = True, fake_with_ophyd_sim: bool = True
323
+ ) -> WatsonMarlow323Pump:
324
+ """Peristaltic Pump"""
325
+ return device_instantiation(
326
+ WatsonMarlow323Pump,
327
+ "ppump",
328
+ "-EA-PUMP-01:",
329
+ wait_for_connection,
330
+ fake_with_ophyd_sim,
331
+ )
@@ -90,8 +90,7 @@ def device_instantiation(
90
90
  fake: bool whether to fake with ophyd.sim
91
91
  post_create: Callable (optional) a function to be run on the device after
92
92
  creation
93
- bl_prefix: bool if true, add the beamline prefix when instantiating, if
94
- false the complete PV prefix must be supplied.
93
+ bl_prefix: bool if true, add the beamline prefix when instantiating
95
94
  Returns:
96
95
  The instance of the device.
97
96
  """
@@ -0,0 +1,61 @@
1
+ import math
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+ from typing import Literal
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class Material:
9
+ """
10
+ Class representing a crystalline material with a specific lattice parameter.
11
+ """
12
+
13
+ name: str
14
+ lattice_parameter: float # Lattice parameter in meters
15
+
16
+
17
+ class MaterialsEnum(Enum):
18
+ Si = Material(name="silicon", lattice_parameter=5.4310205e-10)
19
+ Ge = Material(name="germanium", lattice_parameter=5.6575e-10)
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class CrystalMetadata:
24
+ """
25
+ Metadata used in the NeXus format,
26
+ see https://manual.nexusformat.org/classes/base_classes/NXcrystal.html
27
+ """
28
+
29
+ usage: Literal["Bragg", "Laue"]
30
+ type: str
31
+ reflection: tuple[int, int, int]
32
+ d_spacing: tuple[float, str]
33
+
34
+ @staticmethod
35
+ def calculate_default_d_spacing(
36
+ lattice_parameter: float, reflection: tuple[int, int, int]
37
+ ) -> tuple[float, str]:
38
+ """
39
+ Calculates the d-spacing value in nanometers based on the given lattice parameter and reflection indices.
40
+ """
41
+ h_index, k_index, l_index = reflection
42
+ d_spacing_m = lattice_parameter / math.sqrt(
43
+ h_index**2 + k_index**2 + l_index**2
44
+ )
45
+ d_spacing_nm = d_spacing_m * 1e9 # Convert meters to nanometers
46
+ return round(d_spacing_nm, 5), "nm"
47
+
48
+
49
+ def make_crystal_metadata_from_material(
50
+ material: MaterialsEnum,
51
+ reflection_plane: tuple[int, int, int],
52
+ usage: Literal["Bragg", "Laue"] = "Bragg",
53
+ d_spacing_param: tuple[float, str] | None = None,
54
+ ):
55
+ d_spacing = d_spacing_param or CrystalMetadata.calculate_default_d_spacing(
56
+ material.value.lattice_parameter, reflection_plane
57
+ )
58
+ assert all(
59
+ isinstance(i, int) and i > 0 for i in reflection_plane
60
+ ), "Reflection plane indices must be positive integers"
61
+ return CrystalMetadata(usage, material.value.name, reflection_plane, d_spacing)
@@ -1,17 +1,14 @@
1
1
  from collections.abc import Callable, Coroutine
2
- from typing import Any, TypeVar
2
+ from typing import Any
3
3
 
4
4
  from bluesky.protocols import Reading
5
- from ophyd_async.core import SignalR, SoftSignalBackend
6
- from ophyd_async.core._soft_signal_backend import SignalMetadata
5
+ from ophyd_async.core import SignalDatatypeT, SignalR, SoftSignalBackend
7
6
 
8
- T = TypeVar("T")
9
7
 
10
-
11
- class HarwareBackedSoftSignalBackend(SoftSignalBackend[T]):
8
+ class HardwareBackedSoftSignalBackend(SoftSignalBackend[SignalDatatypeT]):
12
9
  def __init__(
13
10
  self,
14
- get_from_hardware_func: Callable[[], Coroutine[Any, Any, T]],
11
+ get_from_hardware_func: Callable[[], Coroutine[Any, Any, SignalDatatypeT]],
15
12
  *args,
16
13
  **kwargs,
17
14
  ) -> None:
@@ -20,20 +17,20 @@ class HarwareBackedSoftSignalBackend(SoftSignalBackend[T]):
20
17
 
21
18
  async def _update_value(self):
22
19
  new_value = await self.get_from_hardware_func()
23
- await self.put(new_value)
20
+ await self.put(new_value, True)
24
21
 
25
22
  async def get_reading(self) -> Reading:
26
23
  await self._update_value()
27
24
  return await super().get_reading()
28
25
 
29
- async def get_value(self) -> T:
26
+ async def get_value(self) -> SignalDatatypeT:
30
27
  await self._update_value()
31
28
  return await super().get_value()
32
29
 
33
30
 
34
31
  def create_hardware_backed_soft_signal(
35
- datatype: type[T],
36
- get_from_hardware_func: Callable[[], Coroutine[Any, Any, T]],
32
+ datatype: type[SignalDatatypeT],
33
+ get_from_hardware_func: Callable[[], Coroutine[Any, Any, SignalDatatypeT]],
37
34
  units: str | None = None,
38
35
  precision: int | None = None,
39
36
  ):
@@ -45,9 +42,8 @@ def create_hardware_backed_soft_signal(
45
42
  the signal is currently read only. See https://github.com/bluesky/ophyd-async/issues/525
46
43
  for a more full solution.
47
44
  """
48
- metadata = SignalMetadata(units=units, precision=precision)
49
45
  return SignalR(
50
- backend=HarwareBackedSoftSignalBackend(
51
- get_from_hardware_func, datatype, metadata=metadata
46
+ backend=HardwareBackedSoftSignalBackend(
47
+ get_from_hardware_func, datatype, units=units, precision=precision
52
48
  )
53
49
  )
dodal/common/types.py CHANGED
@@ -1,16 +1,11 @@
1
1
  from abc import ABC, abstractmethod
2
- from collections.abc import Callable, Generator
3
- from typing import (
4
- Any,
5
- )
2
+ from collections.abc import Callable
6
3
 
7
- from bluesky.utils import Msg
4
+ from bluesky.utils import MsgGenerator
8
5
  from ophyd_async.core import PathProvider
9
6
 
10
7
  # String identifier used by 'wait' or stubs that await
11
8
  Group = str
12
- # A true 'plan', usually the output of a generator function
13
- MsgGenerator = Generator[Msg, Any, None]
14
9
  # A function that generates a plan
15
10
  PlanGenerator = Callable[..., MsgGenerator]
16
11
 
dodal/devices/CTAB.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.core import epics_signal_r
2
3
  from ophyd_async.epics.motor import Motor
3
- from ophyd_async.epics.signal import epics_signal_r
4
4
 
5
5
 
6
6
  class CTAB(StandardReadable):
dodal/devices/aperture.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from ophyd_async.core import StandardReadable
2
+ from ophyd_async.epics.core import epics_signal_r
2
3
  from ophyd_async.epics.motor import Motor
3
- from ophyd_async.epics.signal import epics_signal_r
4
4
 
5
5
 
6
6
  class Aperture(StandardReadable):
@@ -1,13 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- from enum import Enum
5
4
 
6
5
  from bluesky.protocols import Movable
7
6
  from ophyd_async.core import (
8
7
  AsyncStatus,
9
- HintedSignal,
10
8
  StandardReadable,
9
+ StandardReadableFormat,
10
+ StrictEnum,
11
11
  )
12
12
  from pydantic import BaseModel, Field
13
13
 
@@ -22,12 +22,24 @@ class InvalidApertureMove(Exception):
22
22
 
23
23
 
24
24
  class AperturePosition(BaseModel):
25
+ """
26
+ Represents one of the available positions for the Aperture-Scatterguard.
27
+ Attributes:
28
+ aperture_x: The x position of the aperture component in mm
29
+ aperture_y: The y position of the aperture component in mm
30
+ aperture_z: The z position of the aperture component in mm
31
+ scatterguard_x: The x position of the scatterguard component in mm
32
+ scatterguard_y: The y position of the scatterguard component in mm
33
+ radius: Radius of the selected aperture. When in the Robot Load position, the
34
+ radius is defined to be 0
35
+ """
36
+
25
37
  aperture_x: float
26
38
  aperture_y: float
27
39
  aperture_z: float
28
40
  scatterguard_x: float
29
41
  scatterguard_y: float
30
- radius: float | None = Field(json_schema_extra={"units": "µm"}, default=None)
42
+ radius: float = Field(json_schema_extra={"units": "µm"}, default=0.0)
31
43
 
32
44
  @property
33
45
  def values(self) -> tuple[float, float, float, float, float]:
@@ -54,7 +66,7 @@ class AperturePosition(BaseModel):
54
66
  @staticmethod
55
67
  def from_gda_params(
56
68
  name: ApertureValue,
57
- radius: float | None,
69
+ radius: float,
58
70
  params: GDABeamlineParameters,
59
71
  ) -> AperturePosition:
60
72
  return AperturePosition(
@@ -67,7 +79,7 @@ class AperturePosition(BaseModel):
67
79
  )
68
80
 
69
81
 
70
- class ApertureValue(str, Enum):
82
+ class ApertureValue(StrictEnum):
71
83
  """Maps from a short usable name to the value name in the GDA Beamline parameters"""
72
84
 
73
85
  ROBOT_LOAD = "ROBOT_LOAD"
@@ -81,7 +93,7 @@ def load_positions_from_beamline_parameters(
81
93
  ) -> dict[ApertureValue, AperturePosition]:
82
94
  return {
83
95
  ApertureValue.ROBOT_LOAD: AperturePosition.from_gda_params(
84
- ApertureValue.ROBOT_LOAD, None, params
96
+ ApertureValue.ROBOT_LOAD, 0, params
85
97
  ),
86
98
  ApertureValue.SMALL: AperturePosition.from_gda_params(
87
99
  ApertureValue.SMALL, 20, params
@@ -120,7 +132,7 @@ class ApertureScatterguard(StandardReadable, Movable):
120
132
  self.radius,
121
133
  ],
122
134
  )
123
- with self.add_children_as_readables(HintedSignal):
135
+ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
124
136
  self.selected_aperture = create_hardware_backed_soft_signal(
125
137
  ApertureValue, self._get_current_aperture_position
126
138
  )
@@ -172,7 +184,7 @@ class ApertureScatterguard(StandardReadable, Movable):
172
184
 
173
185
  raise InvalidApertureMove("Current aperture/scatterguard state unrecognised")
174
186
 
175
- async def _get_current_radius(self) -> float | None:
187
+ async def _get_current_radius(self) -> float:
176
188
  current_value = await self._get_current_aperture_position()
177
189
  return self._loaded_positions[current_value].radius
178
190