dls-dodal 1.34.1__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 (71) hide show
  1. {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/METADATA +2 -2
  2. {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/RECORD +70 -67
  3. {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/WHEEL +1 -1
  4. dodal/_version.py +2 -2
  5. dodal/beamlines/i22.py +24 -11
  6. dodal/beamlines/i24.py +4 -4
  7. dodal/beamlines/p38.py +23 -11
  8. dodal/common/beamlines/beamline_utils.py +1 -2
  9. dodal/common/crystal_metadata.py +61 -0
  10. dodal/common/signal_utils.py +10 -14
  11. dodal/devices/CTAB.py +1 -1
  12. dodal/devices/aperture.py +1 -1
  13. dodal/devices/aperturescatterguard.py +20 -8
  14. dodal/devices/apple2_undulator.py +30 -29
  15. dodal/devices/areadetector/plugins/CAM.py +3 -5
  16. dodal/devices/areadetector/plugins/MJPG.py +1 -1
  17. dodal/devices/attenuator.py +1 -1
  18. dodal/devices/backlight.py +4 -5
  19. dodal/devices/cryostream.py +3 -5
  20. dodal/devices/dcm.py +26 -2
  21. dodal/devices/detector/detector_motion.py +3 -5
  22. dodal/devices/diamond_filter.py +3 -4
  23. dodal/devices/fast_grid_scan.py +1 -1
  24. dodal/devices/fluorescence_detector_motion.py +5 -7
  25. dodal/devices/focusing_mirror.py +12 -11
  26. dodal/devices/hutch_shutter.py +4 -5
  27. dodal/devices/i10/i10_apple2.py +20 -19
  28. dodal/devices/i10/i10_setting_data.py +2 -2
  29. dodal/devices/i22/dcm.py +43 -75
  30. dodal/devices/i22/fswitch.py +5 -5
  31. dodal/devices/i24/aperture.py +3 -5
  32. dodal/devices/i24/beamstop.py +3 -5
  33. dodal/devices/i24/dcm.py +1 -1
  34. dodal/devices/i24/dual_backlight.py +4 -6
  35. dodal/devices/i24/pmac.py +35 -46
  36. dodal/devices/i24/vgonio.py +16 -0
  37. dodal/devices/ipin.py +5 -3
  38. dodal/devices/linkam3.py +7 -7
  39. dodal/devices/oav/oav_detector.py +3 -3
  40. dodal/devices/oav/oav_to_redis_forwarder.py +8 -7
  41. dodal/devices/oav/pin_image_recognition/__init__.py +9 -7
  42. dodal/devices/oav/snapshots/grid_overlay.py +16 -16
  43. dodal/devices/oav/snapshots/snapshot_with_beam_centre.py +5 -5
  44. dodal/devices/oav/snapshots/snapshot_with_grid.py +6 -6
  45. dodal/devices/oav/utils.py +2 -2
  46. dodal/devices/p99/sample_stage.py +3 -5
  47. dodal/devices/pgm.py +5 -6
  48. dodal/devices/qbpm.py +1 -1
  49. dodal/devices/robot.py +3 -3
  50. dodal/devices/smargon.py +1 -1
  51. dodal/devices/synchrotron.py +9 -4
  52. dodal/devices/tetramm.py +7 -7
  53. dodal/devices/thawer.py +13 -7
  54. dodal/devices/undulator.py +5 -5
  55. dodal/devices/util/epics_util.py +1 -1
  56. dodal/devices/watsonmarlow323_pump.py +45 -0
  57. dodal/devices/webcam.py +9 -2
  58. dodal/devices/xbpm_feedback.py +3 -5
  59. dodal/devices/xspress3/xspress3.py +8 -9
  60. dodal/devices/xspress3/xspress3_channel.py +3 -5
  61. dodal/devices/zebra.py +7 -6
  62. dodal/devices/zebra_controlled_shutter.py +5 -6
  63. dodal/devices/zocalo/__init__.py +2 -2
  64. dodal/devices/zocalo/zocalo_constants.py +3 -0
  65. dodal/devices/zocalo/zocalo_interaction.py +2 -1
  66. dodal/devices/zocalo/zocalo_results.py +92 -79
  67. dodal/utils.py +4 -0
  68. dodal/devices/i24/i24_vgonio.py +0 -17
  69. {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/LICENSE +0 -0
  70. {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/entry_points.txt +0 -0
  71. {dls_dodal-1.34.1.dist-info → dls_dodal-1.35.0.dist-info}/top_level.txt +0 -0
@@ -1,26 +1,26 @@
1
1
  import abc
2
2
  import asyncio
3
3
  from dataclasses import dataclass
4
- from enum import Enum
5
4
  from typing import Any
6
5
 
7
6
  import numpy as np
8
7
  from bluesky.protocols import Movable
9
8
  from ophyd_async.core import (
10
9
  AsyncStatus,
11
- ConfigSignal,
12
- HintedSignal,
10
+ Reference,
13
11
  StandardReadable,
12
+ StandardReadableFormat,
13
+ StrictEnum,
14
14
  soft_signal_r_and_setter,
15
15
  wait_for_value,
16
16
  )
17
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw, epics_signal_w
17
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_w
18
18
  from pydantic import BaseModel, ConfigDict, RootModel
19
19
 
20
20
  from dodal.log import LOGGER
21
21
 
22
22
 
23
- class UndulatorGateStatus(str, Enum):
23
+ class UndulatorGateStatus(StrictEnum):
24
24
  open = "Open"
25
25
  close = "Closed"
26
26
 
@@ -128,12 +128,12 @@ class UndulatorGap(StandardReadable, Movable):
128
128
  )
129
129
  # This is calculated acceleration from speed
130
130
  self.acceleration_time = epics_signal_r(float, prefix + "IDGSETACC")
131
- with self.add_children_as_readables(ConfigSignal):
131
+ with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
132
132
  # Unit
133
133
  self.motor_egu = epics_signal_r(str, prefix + "BLGAPMTR.EGU")
134
134
  # Gap velocity
135
135
  self.velocity = epics_signal_rw(float, prefix + "BLGSETVEL")
136
- with self.add_children_as_readables(HintedSignal):
136
+ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
137
137
  # Gap readback value
138
138
  self.user_readback = epics_signal_r(float, prefix + "CURRGAPD")
139
139
  super().__init__(name)
@@ -187,10 +187,10 @@ class UndulatorPhaseMotor(StandardReadable):
187
187
  self.user_setpoint_demand_readback = epics_signal_r(float, fullPV + "DMD")
188
188
 
189
189
  fullPV = fullPV + "MTR"
190
- with self.add_children_as_readables(HintedSignal):
190
+ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
191
191
  self.user_setpoint_readback = epics_signal_r(float, fullPV + ".RBV")
192
192
 
193
- with self.add_children_as_readables(ConfigSignal):
193
+ with self.add_children_as_readables(StandardReadableFormat.CONFIG_SIGNAL):
194
194
  self.motor_egu = epics_signal_r(str, fullPV + ".EGU")
195
195
  self.velocity = epics_signal_rw(float, fullPV + ".VELO")
196
196
 
@@ -388,10 +388,10 @@ class Apple2(StandardReadable, Movable):
388
388
 
389
389
  # Attributes are set after super call so they are not renamed to
390
390
  # <name>-undulator, etc.
391
- with self.add_children_as_readables():
392
- self.gap = id_gap
393
- self.phase = id_phase
394
- with self.add_children_as_readables(HintedSignal):
391
+ self.gap = Reference(id_gap)
392
+ self.phase = Reference(id_phase)
393
+
394
+ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
395
395
  # Store the polarisation for readback.
396
396
  self.polarisation, self._polarisation_set = soft_signal_r_and_setter(
397
397
  str, initial_value=None
@@ -437,16 +437,16 @@ class Apple2(StandardReadable, Movable):
437
437
  """
438
438
 
439
439
  # Only need to check gap as the phase motors share both fault and gate with gap.
440
- await self.gap.check_id_status()
440
+ await self.gap().check_id_status()
441
441
  await asyncio.gather(
442
- self.phase.top_outer.user_setpoint.set(value=value.top_outer),
443
- self.phase.top_inner.user_setpoint.set(value=value.top_inner),
444
- self.phase.btm_inner.user_setpoint.set(value=value.btm_inner),
445
- self.phase.btm_outer.user_setpoint.set(value=value.btm_outer),
446
- self.gap.user_setpoint.set(value=value.gap),
442
+ self.phase().top_outer.user_setpoint.set(value=value.top_outer),
443
+ self.phase().top_inner.user_setpoint.set(value=value.top_inner),
444
+ self.phase().btm_inner.user_setpoint.set(value=value.btm_inner),
445
+ self.phase().btm_outer.user_setpoint.set(value=value.btm_outer),
446
+ self.gap().user_setpoint.set(value=value.gap),
447
447
  )
448
448
  timeout = np.max(
449
- await asyncio.gather(self.gap.get_timeout(), self.phase.get_timeout())
449
+ await asyncio.gather(self.gap().get_timeout(), self.phase().get_timeout())
450
450
  )
451
451
  LOGGER.info(
452
452
  f"Moving f{self.name} energy and polorisation to {energy}, {self.pol}"
@@ -454,10 +454,12 @@ class Apple2(StandardReadable, Movable):
454
454
  )
455
455
 
456
456
  await asyncio.gather(
457
- self.gap.set_move.set(value=1, timeout=timeout),
458
- self.phase.set_move.set(value=1, timeout=timeout),
457
+ self.gap().set_move.set(value=1, timeout=timeout),
458
+ self.phase().set_move.set(value=1, timeout=timeout),
459
+ )
460
+ await wait_for_value(
461
+ self.gap().gate, UndulatorGateStatus.close, timeout=timeout
459
462
  )
460
- await wait_for_value(self.gap.gate, UndulatorGateStatus.close, timeout=timeout)
461
463
  self._energy_set(energy) # Update energy for after move for readback.
462
464
 
463
465
  def _get_id_gap_phase(self, energy: float) -> tuple[float, float]:
@@ -522,12 +524,11 @@ class Apple2(StandardReadable, Movable):
522
524
  (May be for future one can use the inverse poly to work out the energy and try to match it with the current energy
523
525
  to workout the polarisation but during my test the inverse poly is too unstable for general use.)
524
526
  """
525
- cur_loc = await self.read()
526
- top_outer = cur_loc[self.phase.top_outer.user_setpoint_readback.name]["value"]
527
- top_inner = cur_loc[self.phase.top_inner.user_setpoint_readback.name]["value"]
528
- btm_inner = cur_loc[self.phase.btm_inner.user_setpoint_readback.name]["value"]
529
- btm_outer = cur_loc[self.phase.btm_outer.user_setpoint_readback.name]["value"]
530
- gap = cur_loc[self.gap.user_readback.name]["value"]
527
+ top_outer = await self.phase().top_outer.user_setpoint_readback.get_value()
528
+ top_inner = await self.phase().top_inner.user_setpoint_readback.get_value()
529
+ btm_inner = await self.phase().btm_inner.user_setpoint_readback.get_value()
530
+ btm_outer = await self.phase().btm_outer.user_setpoint_readback.get_value()
531
+ gap = await self.gap().user_readback.get_value()
531
532
  if gap > MAXIMUM_GAP_MOTOR_POSITION:
532
533
  raise RuntimeError(
533
534
  f"{self.name} is not in use, close gap or set polarisation to use this ID"
@@ -1,10 +1,8 @@
1
- from enum import Enum
1
+ from ophyd_async.core import StandardReadable, StrictEnum
2
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
2
3
 
3
- from ophyd_async.core import StandardReadable
4
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
5
4
 
6
-
7
- class ColorMode(str, Enum):
5
+ class ColorMode(StrictEnum):
8
6
  """
9
7
  Enum to store the various color modes of the camera. We use RGB1.
10
8
  """
@@ -6,7 +6,7 @@ import aiofiles
6
6
  from aiohttp import ClientSession
7
7
  from bluesky.protocols import Triggerable
8
8
  from ophyd_async.core import AsyncStatus, StandardReadable, soft_signal_rw
9
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
9
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
10
10
  from PIL import Image
11
11
 
12
12
  from dodal.log import LOGGER
@@ -9,7 +9,7 @@ from ophyd_async.core import (
9
9
  StandardReadable,
10
10
  wait_for_value,
11
11
  )
12
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw, epics_signal_x
12
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x
13
13
 
14
14
  from dodal.log import LOGGER
15
15
 
@@ -1,17 +1,16 @@
1
1
  from asyncio import sleep
2
- from enum import Enum
3
2
 
4
3
  from bluesky.protocols import Movable
5
- from ophyd_async.core import AsyncStatus, StandardReadable
6
- from ophyd_async.epics.signal import epics_signal_rw
4
+ from ophyd_async.core import AsyncStatus, StandardReadable, StrictEnum
5
+ from ophyd_async.epics.core import epics_signal_rw
7
6
 
8
7
 
9
- class BacklightPower(str, Enum):
8
+ class BacklightPower(StrictEnum):
10
9
  ON = "On"
11
10
  OFF = "Off"
12
11
 
13
12
 
14
- class BacklightPosition(str, Enum):
13
+ class BacklightPosition(StrictEnum):
15
14
  IN = "In"
16
15
  OUT = "Out"
17
16
 
@@ -1,10 +1,8 @@
1
- from enum import Enum
1
+ from ophyd_async.core import StandardReadable, StrictEnum
2
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
2
3
 
3
- from ophyd_async.core import StandardReadable
4
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
5
4
 
6
-
7
- class InOut(str, Enum):
5
+ class InOut(StrictEnum):
8
6
  IN = "In"
9
7
  OUT = "Out"
10
8
 
dodal/devices/dcm.py CHANGED
@@ -1,6 +1,14 @@
1
- from ophyd_async.core import StandardReadable
1
+ import numpy as np
2
+ from numpy.typing import NDArray
3
+ from ophyd_async.core import StandardReadable, soft_signal_r_and_setter
4
+ from ophyd_async.epics.core import epics_signal_r
2
5
  from ophyd_async.epics.motor import Motor
3
- from ophyd_async.epics.signal import epics_signal_r
6
+
7
+ from dodal.common.crystal_metadata import (
8
+ CrystalMetadata,
9
+ MaterialsEnum,
10
+ make_crystal_metadata_from_material,
11
+ )
4
12
 
5
13
 
6
14
  class DCM(StandardReadable):
@@ -17,7 +25,11 @@ class DCM(StandardReadable):
17
25
  self,
18
26
  prefix: str,
19
27
  name: str = "",
28
+ crystal_metadata: CrystalMetadata | None = None,
20
29
  ) -> None:
30
+ cm = crystal_metadata or make_crystal_metadata_from_material(
31
+ MaterialsEnum.Si, (1, 1, 1)
32
+ )
21
33
  with self.add_children_as_readables():
22
34
  self.bragg_in_degrees = Motor(prefix + "BRAGG")
23
35
  self.roll_in_mrad = Motor(prefix + "ROLL")
@@ -36,4 +48,16 @@ class DCM(StandardReadable):
36
48
  self.perp_temp = epics_signal_r(float, prefix + "TEMP6")
37
49
  self.perp_sub_assembly_temp = epics_signal_r(float, prefix + "TEMP7")
38
50
 
51
+ self.crystal_metadata_usage, _ = soft_signal_r_and_setter(
52
+ str, initial_value=cm.usage
53
+ )
54
+ self.crystal_metadata_type, _ = soft_signal_r_and_setter(
55
+ str, initial_value=cm.type
56
+ )
57
+ reflection_array = np.array(cm.reflection)
58
+ self.crystal_metadata_reflection, _ = soft_signal_r_and_setter(
59
+ NDArray[np.uint64],
60
+ initial_value=reflection_array,
61
+ )
62
+ self.crystal_metadata_d_spacing = epics_signal_r(float, "DSPACING:RBV")
39
63
  super().__init__(name)
@@ -1,11 +1,9 @@
1
- from enum import Enum
2
-
3
- from ophyd_async.core import Device
1
+ from ophyd_async.core import Device, StrictEnum
2
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
4
3
  from ophyd_async.epics.motor import Motor
5
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
6
4
 
7
5
 
8
- class ShutterState(str, Enum):
6
+ class ShutterState(StrictEnum):
9
7
  CLOSED = "Closed"
10
8
  OPEN = "Open"
11
9
 
@@ -1,12 +1,11 @@
1
- from enum import Enum
2
1
  from typing import Generic, TypeVar
3
2
 
4
- from ophyd_async.core import StandardReadable
3
+ from ophyd_async.core import StandardReadable, StrictEnum
4
+ from ophyd_async.epics.core import epics_signal_rw
5
5
  from ophyd_async.epics.motor import Motor
6
- from ophyd_async.epics.signal import epics_signal_rw
7
6
 
8
7
 
9
- class _Filters(str, Enum):
8
+ class _Filters(StrictEnum):
10
9
  pass
11
10
 
12
11
 
@@ -15,7 +15,7 @@ from ophyd_async.core import (
15
15
  StandardReadable,
16
16
  wait_for_value,
17
17
  )
18
- from ophyd_async.epics.signal import (
18
+ from ophyd_async.epics.core import (
19
19
  epics_signal_r,
20
20
  epics_signal_rw,
21
21
  epics_signal_rw_rbv,
@@ -1,12 +1,10 @@
1
- from enum import Enum
1
+ from ophyd_async.core import StandardReadable, StrictEnum
2
+ from ophyd_async.epics.core import epics_signal_r
2
3
 
3
- from ophyd_async.core import StandardReadable
4
- from ophyd_async.epics.signal import epics_signal_r
5
4
 
6
-
7
- class FluorescenceDetectorControlState(Enum):
8
- OUT = 0
9
- IN = 1
5
+ class FluorescenceDetectorControlState(StrictEnum):
6
+ OUT = "Out"
7
+ IN = "In"
10
8
 
11
9
 
12
10
  class FluorescenceDetector(StandardReadable):
@@ -1,21 +1,19 @@
1
- from enum import Enum
2
-
3
1
  from ophyd_async.core import (
4
2
  AsyncStatus,
5
- ConfigSignal,
6
3
  Device,
7
4
  DeviceVector,
8
- HintedSignal,
9
5
  StandardReadable,
6
+ StandardReadableFormat,
7
+ StrictEnum,
10
8
  observe_value,
11
9
  soft_signal_r_and_setter,
12
10
  )
13
- from ophyd_async.epics.motor import Motor
14
- from ophyd_async.epics.signal import (
11
+ from ophyd_async.epics.core import (
15
12
  epics_signal_r,
16
13
  epics_signal_rw,
17
14
  epics_signal_x,
18
15
  )
16
+ from ophyd_async.epics.motor import Motor
19
17
 
20
18
  from dodal.log import LOGGER
21
19
 
@@ -25,20 +23,20 @@ VOLTAGE_POLLING_DELAY_S = 0.5
25
23
  DEFAULT_SETTLE_TIME_S = 60
26
24
 
27
25
 
28
- class MirrorType(str, Enum):
26
+ class MirrorType(StrictEnum):
29
27
  """See https://manual.nexusformat.org/classes/base_classes/NXmirror.html"""
30
28
 
31
29
  SINGLE = "single"
32
30
  MULTI = "multi"
33
31
 
34
32
 
35
- class MirrorStripe(str, Enum):
33
+ class MirrorStripe(StrictEnum):
36
34
  RHODIUM = "Rhodium"
37
35
  BARE = "Bare"
38
36
  PLATINUM = "Platinum"
39
37
 
40
38
 
41
- class MirrorVoltageDemand(str, Enum):
39
+ class MirrorVoltageDemand(StrictEnum):
42
40
  N_A = "N/A"
43
41
  OK = "OK"
44
42
  FAIL = "FAIL"
@@ -151,8 +149,11 @@ class FocusingMirror(StandardReadable):
151
149
  # regardless of orientation of the mirror
152
150
  self.incident_angle = Motor(prefix + "PITCH")
153
151
 
154
- self.add_readables([self.incident_angle.user_readback], wrapper=HintedSignal)
155
- self.add_readables([self.type], wrapper=ConfigSignal)
152
+ self.add_readables(
153
+ [self.incident_angle.user_readback],
154
+ format=StandardReadableFormat.HINTED_SIGNAL,
155
+ )
156
+ self.add_readables([self.type], format=StandardReadableFormat.CONFIG_SIGNAL)
156
157
  super().__init__(name)
157
158
 
158
159
 
@@ -1,13 +1,12 @@
1
- from enum import Enum
2
-
3
1
  from bluesky.protocols import Movable
4
2
  from ophyd_async.core import (
5
3
  DEFAULT_TIMEOUT,
6
4
  AsyncStatus,
7
5
  StandardReadable,
6
+ StrictEnum,
8
7
  wait_for_value,
9
8
  )
10
- from ophyd_async.epics.signal import epics_signal_r, epics_signal_w
9
+ from ophyd_async.epics.core import epics_signal_r, epics_signal_w
11
10
 
12
11
  HUTCH_SAFE_FOR_OPERATIONS = 0 # Hutch is locked and can't be entered
13
12
 
@@ -16,13 +15,13 @@ class ShutterNotSafeToOperateError(Exception):
16
15
  pass
17
16
 
18
17
 
19
- class ShutterDemand(str, Enum):
18
+ class ShutterDemand(StrictEnum):
20
19
  OPEN = "Open"
21
20
  CLOSE = "Close"
22
21
  RESET = "Reset"
23
22
 
24
23
 
25
- class ShutterState(str, Enum):
24
+ class ShutterState(StrictEnum):
26
25
  FAULT = "Fault"
27
26
  OPEN = "Open"
28
27
  OPENING = "Opening"
@@ -2,14 +2,15 @@ import asyncio
2
2
  import csv
3
3
  from dataclasses import dataclass
4
4
  from pathlib import Path
5
- from typing import Any
5
+ from typing import Any, SupportsFloat
6
6
 
7
7
  import numpy as np
8
8
  from bluesky.protocols import Movable
9
9
  from ophyd_async.core import (
10
10
  AsyncStatus,
11
- HintedSignal,
11
+ Reference,
12
12
  StandardReadable,
13
+ StandardReadableFormat,
13
14
  soft_signal_r_and_setter,
14
15
  soft_signal_rw,
15
16
  )
@@ -118,14 +119,15 @@ class I10Apple2(Apple2):
118
119
  name=name,
119
120
  )
120
121
  with self.add_children_as_readables():
121
- self.id_jaw_phase = id_jaw_phase
122
+ self.id_jaw_phase = Reference(id_jaw_phase)
122
123
 
123
124
  @AsyncStatus.wrap
124
- async def set(self, value: float) -> None:
125
+ async def set(self, value: SupportsFloat) -> None:
125
126
  """
126
127
  Check polarisation state and use it together with the energy(value)
127
128
  to calculate the required gap and phases before setting it.
128
129
  """
130
+ value = float(value)
129
131
  if self.pol is None:
130
132
  LOGGER.warning("Polarisation not set attempting to read from hardware")
131
133
  pol, phase = await self.determinePhaseFromHardware()
@@ -146,8 +148,8 @@ class I10Apple2(Apple2):
146
148
  LOGGER.info(f"Setting polarisation to {self.pol}, with {id_set_val}")
147
149
  await self._set(value=id_set_val, energy=value)
148
150
  if self.pol != "la":
149
- await self.id_jaw_phase.set(0)
150
- await self.id_jaw_phase.set_move.set(1)
151
+ await self.id_jaw_phase().set(0)
152
+ await self.id_jaw_phase().set_move.set(1)
151
153
 
152
154
  def update_lookuptable(self):
153
155
  """
@@ -195,18 +197,17 @@ class I10Apple2PGM(StandardReadable, Movable):
195
197
  New device name.
196
198
  """
197
199
  super().__init__(name=name)
198
- with self.add_children_as_readables():
199
- self.id = id
200
- self.pgm = pgm
201
- with self.add_children_as_readables(HintedSignal):
200
+ self.id_ref = Reference(id)
201
+ self.pgm_ref = Reference(pgm)
202
+ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
202
203
  self.energy_offset = soft_signal_rw(float, initial_value=0)
203
204
 
204
205
  @AsyncStatus.wrap
205
206
  async def set(self, value: float) -> None:
206
207
  LOGGER.info(f"Moving f{self.name} energy to {value}.")
207
208
  await asyncio.gather(
208
- self.id.set(value=value + await self.energy_offset.get_value()),
209
- self.pgm.energy.set(value),
209
+ self.id_ref().set(value=value + await self.energy_offset.get_value()),
210
+ self.pgm_ref().energy.set(value),
210
211
  )
211
212
 
212
213
 
@@ -273,22 +274,22 @@ class LinearArbitraryAngle(StandardReadable, Movable):
273
274
  polynomial parameters highest power first.
274
275
  """
275
276
  super().__init__(name=name)
276
- with self.add_children_as_readables():
277
- self.id = id
277
+ self.id_ref = Reference(id)
278
278
  self.jaw_phase_from_angle = np.poly1d(jaw_phase_poly_param)
279
279
  self.angle_threshold_deg = angle_threshold_deg
280
280
  self.jaw_phase_limit = jaw_phase_limit
281
- with self.add_children_as_readables(HintedSignal):
281
+ with self.add_children_as_readables(StandardReadableFormat.HINTED_SIGNAL):
282
282
  self.angle, self._angle_set = soft_signal_r_and_setter(
283
283
  float, initial_value=None
284
284
  )
285
285
 
286
286
  @AsyncStatus.wrap
287
- async def set(self, value: float) -> None:
288
- pol = self.id.pol
287
+ async def set(self, value: SupportsFloat) -> None:
288
+ value = float(value)
289
+ pol = self.id_ref().pol
289
290
  if pol != "la":
290
291
  raise RuntimeError(
291
- f"Angle control is not available in polarisation {pol} with {self.id.name}"
292
+ f"Angle control is not available in polarisation {pol} with {self.id_ref().name}"
292
293
  )
293
294
  # Moving to real angle which is 210 to 30.
294
295
  alpha_real = value if value > self.angle_threshold_deg else value + ALPHA_OFFSET
@@ -298,7 +299,7 @@ class LinearArbitraryAngle(StandardReadable, Movable):
298
299
  f"jaw_phase position for angle ({value}) is outside permitted range"
299
300
  f" [-{self.jaw_phase_limit}, {self.jaw_phase_limit}]"
300
301
  )
301
- await self.id.id_jaw_phase.set(jaw_phase)
302
+ await self.id_ref().id_jaw_phase().set(jaw_phase)
302
303
  self._angle_set(value)
303
304
 
304
305
 
@@ -1,7 +1,7 @@
1
- from enum import Enum
1
+ from ophyd_async.core import StrictEnum
2
2
 
3
3
 
4
- class I10Grating(str, Enum):
4
+ class I10Grating(StrictEnum):
5
5
  Au400 = "400 line/mm Au"
6
6
  Si400 = "400 line/mm Si"
7
7
  Au1200 = "1200 line/mm Au"