mx-bluesky 1.4.4__py3-none-any.whl → 1.4.6__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 (74) hide show
  1. mx_bluesky/_version.py +9 -4
  2. mx_bluesky/beamlines/i04/redis_to_murko_forwarder.py +14 -3
  3. mx_bluesky/beamlines/i04/thawing_plan.py +9 -13
  4. mx_bluesky/beamlines/i24/serial/__init__.py +14 -0
  5. mx_bluesky/beamlines/i24/serial/dcid.py +3 -1
  6. mx_bluesky/beamlines/i24/serial/extruder/i24ssx_Extruder_Collect_py3v2.py +1 -1
  7. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Collect_py3v1.py +6 -3
  8. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_Chip_Manager_py3v1.py +11 -11
  9. mx_bluesky/beamlines/i24/serial/fixed_target/i24ssx_moveonclick.py +3 -3
  10. mx_bluesky/beamlines/i24/serial/log.py +0 -1
  11. mx_bluesky/beamlines/i24/serial/parameters/constants.py +1 -1
  12. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_beamline.py +3 -3
  13. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_detector.py +1 -1
  14. mx_bluesky/beamlines/i24/serial/setup_beamline/setup_zebra_plans.py +2 -2
  15. mx_bluesky/beamlines/i24/serial/web_gui_plans/general_plans.py +109 -0
  16. mx_bluesky/beamlines/i24/serial/write_nexus.py +2 -2
  17. mx_bluesky/common/device_setup_plans/setup_panda.py +9 -0
  18. mx_bluesky/common/external_interaction/callbacks/common/plan_reactive_callback.py +2 -2
  19. mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_callback.py +11 -3
  20. mx_bluesky/common/external_interaction/callbacks/xray_centre/ispyb_mapping.py +1 -1
  21. mx_bluesky/common/external_interaction/ispyb/exp_eye_store.py +6 -2
  22. mx_bluesky/common/external_interaction/ispyb/ispyb_store.py +7 -0
  23. mx_bluesky/common/parameters/constants.py +16 -0
  24. mx_bluesky/common/parameters/gridscan.py +36 -1
  25. mx_bluesky/common/plans/do_fgs.py +4 -6
  26. mx_bluesky/common/plans/read_hardware.py +78 -0
  27. mx_bluesky/common/utils/context.py +68 -0
  28. mx_bluesky/common/utils/exceptions.py +2 -1
  29. mx_bluesky/{hyperion/experiment_plans/common → common}/xrc_result.py +16 -0
  30. mx_bluesky/definitions.py +4 -0
  31. mx_bluesky/hyperion/__main__.py +11 -42
  32. mx_bluesky/hyperion/device_setup_plans/setup_oav.py +5 -5
  33. mx_bluesky/hyperion/device_setup_plans/setup_panda.py +9 -8
  34. mx_bluesky/hyperion/device_setup_plans/setup_zebra.py +2 -2
  35. mx_bluesky/hyperion/device_setup_plans/smargon.py +6 -6
  36. mx_bluesky/hyperion/device_setup_plans/utils.py +2 -2
  37. mx_bluesky/hyperion/device_setup_plans/xbpm_feedback.py +14 -4
  38. mx_bluesky/hyperion/experiment_plans/change_aperture_then_move_plan.py +2 -6
  39. mx_bluesky/hyperion/experiment_plans/experiment_registry.py +0 -15
  40. mx_bluesky/hyperion/experiment_plans/flyscan_xray_centre_plan.py +42 -93
  41. mx_bluesky/hyperion/experiment_plans/grid_detect_then_xray_centre_plan.py +14 -6
  42. mx_bluesky/hyperion/experiment_plans/load_centre_collect_full_plan.py +26 -21
  43. mx_bluesky/hyperion/experiment_plans/oav_grid_detection_plan.py +11 -11
  44. mx_bluesky/hyperion/experiment_plans/oav_snapshot_plan.py +5 -9
  45. mx_bluesky/hyperion/experiment_plans/optimise_attenuation_plan.py +1 -1
  46. mx_bluesky/hyperion/experiment_plans/pin_centre_then_xray_centre_plan.py +2 -4
  47. mx_bluesky/hyperion/experiment_plans/pin_tip_centring_plan.py +10 -10
  48. mx_bluesky/hyperion/experiment_plans/robot_load_and_change_energy.py +11 -18
  49. mx_bluesky/hyperion/experiment_plans/robot_load_then_centre_plan.py +2 -4
  50. mx_bluesky/hyperion/experiment_plans/rotation_scan_plan.py +19 -10
  51. mx_bluesky/hyperion/experiment_plans/set_energy_plan.py +2 -0
  52. mx_bluesky/hyperion/external_interaction/agamemnon.py +104 -0
  53. mx_bluesky/hyperion/external_interaction/callbacks/__main__.py +19 -2
  54. mx_bluesky/hyperion/external_interaction/callbacks/rotation/ispyb_callback.py +1 -1
  55. mx_bluesky/hyperion/external_interaction/callbacks/sample_handling/sample_handling_callback.py +14 -9
  56. mx_bluesky/hyperion/external_interaction/config_server.py +13 -2
  57. mx_bluesky/hyperion/parameters/cli.py +1 -9
  58. mx_bluesky/hyperion/parameters/constants.py +6 -1
  59. mx_bluesky/hyperion/parameters/device_composites.py +49 -0
  60. mx_bluesky/hyperion/parameters/gridscan.py +5 -3
  61. mx_bluesky/hyperion/resources/panda/panda-gridscan.yaml +1006 -964
  62. mx_bluesky/hyperion/utils/__init__.py +1 -0
  63. mx_bluesky/hyperion/utils/context.py +0 -65
  64. mx_bluesky/hyperion/utils/validation.py +23 -20
  65. {mx_bluesky-1.4.4.dist-info → mx_bluesky-1.4.6.dist-info}/METADATA +5 -4
  66. {mx_bluesky-1.4.4.dist-info → mx_bluesky-1.4.6.dist-info}/RECORD +71 -66
  67. {mx_bluesky-1.4.4.dist-info → mx_bluesky-1.4.6.dist-info}/WHEEL +1 -1
  68. {mx_bluesky-1.4.4.dist-info → mx_bluesky-1.4.6.dist-info}/entry_points.txt +1 -0
  69. mx_bluesky/common/device_setup_plans/read_hardware_for_setup.py +0 -14
  70. mx_bluesky/hyperion/device_setup_plans/read_hardware_for_setup.py +0 -54
  71. mx_bluesky/hyperion/external_interaction/callbacks/common/callback_util.py +0 -95
  72. /mx_bluesky/{hyperion/external_interaction/callbacks/common → beamlines/i24/serial/web_gui_plans}/__init__.py +0 -0
  73. {mx_bluesky-1.4.4.dist-info → mx_bluesky-1.4.6.dist-info}/LICENSE +0 -0
  74. {mx_bluesky-1.4.4.dist-info → mx_bluesky-1.4.6.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dodal.devices.aperturescatterguard import ApertureValue
4
+ from dodal.devices.detector.det_dim_constants import EIGER2_X_9M_SIZE, EIGER2_X_16M_SIZE
5
+ from dodal.devices.detector.detector import DetectorParams
4
6
  from dodal.devices.fast_grid_scan import (
5
7
  ZebraGridScanParams,
6
8
  )
9
+ from dodal.utils import get_beamline_name
7
10
  from pydantic import Field, PrivateAttr
8
11
  from scanspec.core import Path as ScanPath
9
12
  from scanspec.specs import Line, Static
@@ -18,11 +21,12 @@ from mx_bluesky.common.parameters.components import (
18
21
  XyzStarts,
19
22
  )
20
23
  from mx_bluesky.common.parameters.constants import (
24
+ DetectorParamConstants,
21
25
  GridscanParamConstants,
22
26
  HardwareConstants,
23
27
  )
24
28
 
25
- """Parameter models in this file are abstract. They should be inherited by a top-level model"""
29
+ DETECTOR_SIZE_PER_BEAMLINE = {"i02-1": EIGER2_X_9M_SIZE, "dev": EIGER2_X_16M_SIZE}
26
30
 
27
31
 
28
32
  class GridCommon(
@@ -146,3 +150,34 @@ class SpecifiedThreeDGridScan(
146
150
  @property
147
151
  def num_images(self) -> int:
148
152
  return len(self.scan_points["sam_x"])
153
+
154
+ @property
155
+ def detector_params(self):
156
+ self.det_dist_to_beam_converter_path = (
157
+ self.det_dist_to_beam_converter_path
158
+ or DetectorParamConstants.BEAM_XY_LUT_PATH
159
+ )
160
+ optional_args = {}
161
+ if self.run_number:
162
+ optional_args["run_number"] = self.run_number
163
+ assert self.detector_distance_mm is not None, (
164
+ "Detector distance must be filled before generating DetectorParams"
165
+ )
166
+ return DetectorParams(
167
+ detector_size_constants=DETECTOR_SIZE_PER_BEAMLINE[
168
+ get_beamline_name("dev")
169
+ ],
170
+ expected_energy_ev=self.demand_energy_ev,
171
+ exposure_time=self.exposure_time_s,
172
+ directory=self.storage_directory,
173
+ prefix=self.file_name,
174
+ detector_distance=self.detector_distance_mm,
175
+ omega_start=self.omega_start_deg or 0,
176
+ omega_increment=0,
177
+ num_images_per_trigger=1,
178
+ num_triggers=self.num_images,
179
+ use_roi_mode=self.use_roi_mode,
180
+ det_dist_to_beam_converter_path=self.det_dist_to_beam_converter_path,
181
+ trigger_mode=self.trigger_mode,
182
+ **optional_args,
183
+ )
@@ -14,12 +14,10 @@ from dodal.log import LOGGER
14
14
  from dodal.plan_stubs.check_topup import check_topup_and_wait_if_necessary
15
15
  from scanspec.core import AxesPoints, Axis
16
16
 
17
- from mx_bluesky.common.device_setup_plans.read_hardware_for_setup import (
18
- read_hardware_for_zocalo,
19
- )
20
17
  from mx_bluesky.common.parameters.constants import (
21
18
  PlanNameConstants,
22
19
  )
20
+ from mx_bluesky.common.plans.read_hardware import read_hardware_for_zocalo
23
21
  from mx_bluesky.common.utils.tracing import TRACER
24
22
 
25
23
 
@@ -30,7 +28,7 @@ def _wait_for_zocalo_to_stage_then_do_fgs(
30
28
  during_collection_plan: Callable[[], MsgGenerator] | None = None,
31
29
  ):
32
30
  expected_images = yield from bps.rd(grid_scan_device.expected_images)
33
- exposure_sec_per_image = yield from bps.rd(detector.cam.acquire_time) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
31
+ exposure_sec_per_image = yield from bps.rd(detector.cam.acquire_time) # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
34
32
  LOGGER.info("waiting for topup if necessary...")
35
33
  yield from check_topup_and_wait_if_necessary(
36
34
  synchrotron,
@@ -101,8 +99,8 @@ def kickoff_and_complete_gridscan(
101
99
  }
102
100
  )
103
101
  @bpp.contingency_decorator(
104
- except_plan=lambda e: (yield from bps.stop(detector)), # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
105
- else_plan=lambda: (yield from bps.unstage(detector)), # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
102
+ except_plan=lambda e: (yield from bps.stop(detector)), # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
103
+ else_plan=lambda: (yield from bps.unstage(detector)),
106
104
  )
107
105
  def _decorated_do_fgs():
108
106
  yield from _wait_for_zocalo_to_stage_then_do_fgs(
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ import bluesky.plan_stubs as bps
4
+ from bluesky.protocols import Readable
5
+ from dodal.devices.aperturescatterguard import ApertureScatterguard
6
+ from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
7
+ from dodal.devices.dcm import DCM
8
+ from dodal.devices.eiger import EigerDetector
9
+ from dodal.devices.flux import Flux
10
+ from dodal.devices.s4_slit_gaps import S4SlitGaps
11
+ from dodal.devices.smargon import Smargon
12
+ from dodal.devices.synchrotron import Synchrotron
13
+ from dodal.devices.undulator import Undulator
14
+
15
+ from mx_bluesky.common.parameters.constants import (
16
+ DocDescriptorNames,
17
+ )
18
+ from mx_bluesky.common.utils.log import LOGGER
19
+
20
+
21
+ def read_hardware_plan(
22
+ signals: list[Readable],
23
+ event_name: str,
24
+ ):
25
+ LOGGER.info(f"Reading status of beamline for event, {event_name}")
26
+ yield from bps.create(name=event_name)
27
+ for signal in signals:
28
+ yield from bps.read(signal)
29
+ yield from bps.save()
30
+
31
+
32
+ def read_hardware_for_zocalo(detector: EigerDetector):
33
+ """ "
34
+ If the RunEngine is subscribed to the ZocaloCallback, this plan will also trigger zocalo.
35
+ """
36
+ yield from read_hardware_plan(
37
+ [detector.odin.file_writer.id], # type: ignore
38
+ DocDescriptorNames.ZOCALO_HW_READ,
39
+ )
40
+
41
+
42
+ def standard_read_hardware_pre_collection(
43
+ undulator: Undulator,
44
+ synchrotron: Synchrotron,
45
+ s4_slit_gaps: S4SlitGaps,
46
+ dcm: DCM,
47
+ smargon: Smargon,
48
+ ):
49
+ LOGGER.info("Reading status of beamline for callbacks, pre collection.")
50
+ signals_to_read_pre_flyscan = [
51
+ undulator.current_gap,
52
+ synchrotron.synchrotron_mode,
53
+ s4_slit_gaps,
54
+ smargon,
55
+ dcm.energy_in_kev,
56
+ ]
57
+ yield from read_hardware_plan(
58
+ signals_to_read_pre_flyscan, DocDescriptorNames.HARDWARE_READ_PRE
59
+ )
60
+
61
+
62
+ def standard_read_hardware_during_collection(
63
+ aperture_scatterguard: ApertureScatterguard,
64
+ attenuator: BinaryFilterAttenuator,
65
+ flux: Flux,
66
+ dcm: DCM,
67
+ detector: EigerDetector,
68
+ ):
69
+ signals_to_read_during_collection = [
70
+ aperture_scatterguard,
71
+ attenuator.actual_transmission,
72
+ flux.flux_reading,
73
+ dcm.energy_in_kev,
74
+ detector.bit_depth,
75
+ ]
76
+ yield from read_hardware_plan(
77
+ signals_to_read_during_collection, DocDescriptorNames.HARDWARE_READ_DURING
78
+ )
@@ -0,0 +1,68 @@
1
+ import dataclasses
2
+ from typing import Any, ClassVar, Protocol, TypeVar, get_type_hints
3
+
4
+ from blueapi.core import BlueskyContext
5
+ from blueapi.core.bluesky_types import Device
6
+
7
+ from mx_bluesky.common.utils.log import LOGGER
8
+
9
+ T = TypeVar("T", bound=Device)
10
+
11
+
12
+ class _IsDataclass(Protocol):
13
+ """Protocol followed by any dataclass"""
14
+
15
+ __dataclass_fields__: ClassVar[dict]
16
+
17
+
18
+ DT = TypeVar("DT", bound=_IsDataclass)
19
+
20
+
21
+ def find_device_in_context(
22
+ context: BlueskyContext,
23
+ name: str,
24
+ # Typing in here is wrong (see https://github.com/microsoft/pyright/issues/7228#issuecomment-1934500232)
25
+ # but this whole thing will go away when we do https://github.com/DiamondLightSource/hyperion/issues/868
26
+ expected_type: type[T] = Device, # type: ignore
27
+ ) -> T:
28
+ LOGGER.debug(f"Looking for device {name} of type {expected_type} in context")
29
+
30
+ device = context.find_device(name)
31
+ if device is None:
32
+ raise ValueError(
33
+ f"Cannot find device named '{name}' in bluesky context {context.devices}."
34
+ )
35
+
36
+ if not isinstance(device, expected_type):
37
+ raise ValueError(
38
+ f"Found device named '{name}' and expected it to be a '{expected_type}' but it was a '{device.__class__.__name__}'"
39
+ )
40
+
41
+ LOGGER.debug(f"Found matching device {device}")
42
+ return device
43
+
44
+
45
+ def device_composite_from_context(context: BlueskyContext, dc: type[DT]) -> DT:
46
+ """
47
+ Initializes all of the devices referenced in a given dataclass from a provided
48
+ context, checking that the types of devices returned by the context are compatible
49
+ with the type annotations of the dataclass.
50
+
51
+ Note that if the context was not created with `wait_for_connection=True` devices may
52
+ still be unconnected.
53
+ """
54
+ LOGGER.debug(
55
+ f"Attempting to initialize devices referenced in dataclass {dc} from blueapi context"
56
+ )
57
+
58
+ devices: dict[str, Any] = {}
59
+ dc_type_hints: dict[str, Any] = get_type_hints(dc)
60
+
61
+ for field in dataclasses.fields(dc):
62
+ device = find_device_in_context(
63
+ context, field.name, expected_type=dc_type_hints.get(field.name, Device)
64
+ )
65
+
66
+ devices[field.name] = device
67
+
68
+ return dc(**devices)
@@ -39,7 +39,8 @@ T = TypeVar("T")
39
39
  class CrystalNotFoundException(SampleException):
40
40
  """Raised if grid detection completed normally but no crystal was found."""
41
41
 
42
- pass
42
+ def __init__(self, *args):
43
+ super().__init__("Diffraction not found, skipping sample.")
43
44
 
44
45
 
45
46
  def catch_exception_and_warn(
@@ -5,6 +5,8 @@ from collections.abc import Callable, Sequence
5
5
  from functools import partial
6
6
 
7
7
  import numpy as np
8
+ from bluesky.callbacks import CallbackBase
9
+ from event_model import RunStart
8
10
 
9
11
  from mx_bluesky.common.parameters.components import (
10
12
  MultiXtalSelection,
@@ -12,6 +14,20 @@ from mx_bluesky.common.parameters.components import (
12
14
  )
13
15
 
14
16
 
17
+ class XRayCentreEventHandler(CallbackBase):
18
+ def __init__(self):
19
+ super().__init__()
20
+ self.xray_centre_results: Sequence[XRayCentreResult] | None = None
21
+
22
+ def start(self, doc: RunStart) -> RunStart | None:
23
+ if "xray_centre_results" in doc:
24
+ self.xray_centre_results = [
25
+ XRayCentreResult(**result_dict)
26
+ for result_dict in doc["xray_centre_results"] # type: ignore
27
+ ]
28
+ return doc
29
+
30
+
15
31
  @dataclasses.dataclass
16
32
  class XRayCentreResult:
17
33
  """
@@ -0,0 +1,4 @@
1
+ import os
2
+
3
+ # Change once Python<3.12 is dropped - see https://github.com/DiamondLightSource/mx-bluesky/issues/798
4
+ ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -4,6 +4,7 @@ import threading
4
4
  from collections.abc import Callable
5
5
  from dataclasses import asdict
6
6
  from queue import Queue
7
+ from sys import argv
7
8
  from traceback import format_exception
8
9
  from typing import Any
9
10
 
@@ -37,11 +38,8 @@ from mx_bluesky.hyperion.experiment_plans.experiment_registry import (
37
38
  PLAN_REGISTRY,
38
39
  PlanNotFound,
39
40
  )
40
- from mx_bluesky.hyperion.external_interaction.callbacks.__main__ import (
41
- setup_logging as setup_callback_logging,
42
- )
43
- from mx_bluesky.hyperion.external_interaction.callbacks.common.callback_util import (
44
- CallbacksFactory,
41
+ from mx_bluesky.hyperion.external_interaction.agamemnon import (
42
+ update_params_from_agamemnon,
45
43
  )
46
44
  from mx_bluesky.hyperion.parameters.cli import parse_cli_args
47
45
  from mx_bluesky.hyperion.parameters.constants import CONST
@@ -56,7 +54,6 @@ class Command:
56
54
  devices: Any | None = None
57
55
  experiment: Callable[[Any, Any], MsgGenerator] | None = None
58
56
  parameters: MxBlueskyParameters | None = None
59
- callbacks: CallbacksFactory | None = None
60
57
 
61
58
 
62
59
  @dataclass
@@ -88,7 +85,6 @@ class BlueskyRunner:
88
85
  RE: RunEngine,
89
86
  context: BlueskyContext,
90
87
  skip_startup_connection=False,
91
- use_external_callbacks: bool = False,
92
88
  ) -> None:
93
89
  self.command_queue: Queue[Command] = Queue()
94
90
  self.current_status: StatusAndMessage = StatusAndMessage(Status.IDLE)
@@ -99,15 +95,12 @@ class BlueskyRunner:
99
95
 
100
96
  self.RE = RE
101
97
  self.context = context
102
- self.subscribed_per_plan_callbacks: list[int] = []
103
98
  RE.subscribe(self.aperture_change_callback)
104
99
  RE.subscribe(self.logging_uid_tag_callback)
105
100
 
106
- self.use_external_callbacks = use_external_callbacks
107
- if self.use_external_callbacks:
108
- LOGGER.info("Connecting to external callback ZMQ proxy...")
109
- self.publisher = Publisher(f"localhost:{CONST.CALLBACK_0MQ_PROXY_PORTS[0]}")
110
- RE.subscribe(self.publisher)
101
+ LOGGER.info("Connecting to external callback ZMQ proxy...")
102
+ self.publisher = Publisher(f"localhost:{CONST.CALLBACK_0MQ_PROXY_PORTS[0]}")
103
+ RE.subscribe(self.publisher)
111
104
 
112
105
  if VERBOSE_EVENT_LOGGING:
113
106
  RE.subscribe(VerbosePlanExecutionLoggingCallback())
@@ -123,7 +116,6 @@ class BlueskyRunner:
123
116
  experiment: Callable,
124
117
  parameters: MxBlueskyParameters,
125
118
  plan_name: str,
126
- callbacks: CallbacksFactory | None,
127
119
  ) -> StatusAndMessage:
128
120
  LOGGER.info(f"Started with parameters: {parameters.model_dump_json(indent=2)}")
129
121
 
@@ -142,7 +134,6 @@ class BlueskyRunner:
142
134
  devices=devices,
143
135
  experiment=experiment,
144
136
  parameters=parameters,
145
- callbacks=callbacks,
146
137
  )
147
138
  )
148
139
  return StatusAndMessage(Status.SUCCESS)
@@ -181,17 +172,6 @@ class BlueskyRunner:
181
172
  if command.experiment is None:
182
173
  raise ValueError("No experiment provided for START")
183
174
  try:
184
- if (
185
- not self.use_external_callbacks
186
- and command.callbacks
187
- and (cbs := command.callbacks())
188
- ):
189
- LOGGER.info(
190
- f"Using callbacks for this plan: {not self.use_external_callbacks} - {cbs}"
191
- )
192
- self.subscribed_per_plan_callbacks += [
193
- self.RE.subscribe(cb) for cb in cbs
194
- ]
195
175
  with TRACER.start_span("do_run"):
196
176
  self.RE(command.experiment(command.devices, command.parameters))
197
177
 
@@ -212,11 +192,6 @@ class BlueskyRunner:
212
192
  self.last_run_aborted = False
213
193
  else:
214
194
  self.current_status = make_error_status_and_message(exception)
215
- finally:
216
- [
217
- self.RE.unsubscribe(cb)
218
- for cb in self.subscribed_per_plan_callbacks
219
- ]
220
195
 
221
196
 
222
197
  def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions):
@@ -225,7 +200,6 @@ def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions)
225
200
  raise PlanNotFound(f"Experiment plan '{plan_name}' not found in registry.")
226
201
 
227
202
  experiment_internal_param_type = experiment_registry_entry.get("param_type")
228
- callback_type = experiment_registry_entry.get("callback_collection_type")
229
203
  plan = context.plan_functions.get(plan_name)
230
204
  if experiment_internal_param_type is None:
231
205
  raise PlanNotFound(
@@ -237,13 +211,14 @@ def compose_start_args(context: BlueskyContext, plan_name: str, action: Actions)
237
211
  )
238
212
  try:
239
213
  parameters = experiment_internal_param_type(**json.loads(request.data))
214
+ parameters = update_params_from_agamemnon(parameters)
240
215
  if parameters.model_extra:
241
216
  raise ValueError(f"Extra fields not allowed {parameters.model_extra}")
242
217
  except Exception as e:
243
218
  raise ValueError(
244
219
  f"Supplied parameters don't match the plan for this endpoint {request.data}, for plan {plan_name}"
245
220
  ) from e
246
- return plan, parameters, plan_name, callback_type
221
+ return plan, parameters, plan_name
247
222
 
248
223
 
249
224
  class RunExperiment(Resource):
@@ -256,12 +231,10 @@ class RunExperiment(Resource):
256
231
  status_and_message = StatusAndMessage(Status.FAILED, f"{action} not understood")
257
232
  if action == Actions.START.value:
258
233
  try:
259
- plan, params, plan_name, callback_type = compose_start_args(
234
+ plan, params, plan_name = compose_start_args(
260
235
  self.context, plan_name, action
261
236
  )
262
- status_and_message = self.runner.start(
263
- plan, params, plan_name, callback_type
264
- )
237
+ status_and_message = self.runner.start(plan, params, plan_name)
265
238
  except Exception as e:
266
239
  status_and_message = make_error_status_and_message(e)
267
240
  LOGGER.error(format_exception(e))
@@ -312,7 +285,6 @@ def create_app(
312
285
  test_config=None,
313
286
  RE: RunEngine = RunEngine({}),
314
287
  skip_startup_connection: bool = False,
315
- use_external_callbacks: bool = False,
316
288
  ) -> tuple[Flask, BlueskyRunner]:
317
289
  context = setup_context(
318
290
  wait_for_connection=not skip_startup_connection,
@@ -320,7 +292,6 @@ def create_app(
320
292
  runner = BlueskyRunner(
321
293
  RE,
322
294
  context=context,
323
- use_external_callbacks=use_external_callbacks,
324
295
  skip_startup_connection=skip_startup_connection,
325
296
  )
326
297
  app = Flask(__name__)
@@ -350,11 +321,9 @@ def create_targets():
350
321
  do_default_logging_setup(
351
322
  CONST.LOG_FILE_NAME, CONST.GRAYLOG_PORT, dev_mode=args.dev_mode
352
323
  )
353
- if not args.use_external_callbacks:
354
- setup_callback_logging(args.dev_mode)
324
+ LOGGER.info(f"Hyperion launched with args:{argv}")
355
325
  app, runner = create_app(
356
326
  skip_startup_connection=args.skip_startup_connection,
357
- use_external_callbacks=args.use_external_callbacks,
358
327
  )
359
328
  return app, runner, hyperion_port, args.dev_mode
360
329
 
@@ -55,14 +55,14 @@ def setup_pin_tip_detection_params(
55
55
 
56
56
 
57
57
  def setup_general_oav_params(oav: OAV, parameters: OAVParameters):
58
- yield from set_using_group(oav.cam.color_mode, ColorMode.RGB1) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
59
- yield from set_using_group(oav.cam.acquire_period, parameters.acquire_period) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
60
- yield from set_using_group(oav.cam.acquire_time, parameters.exposure) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
61
- yield from set_using_group(oav.cam.gain, parameters.gain) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
58
+ yield from set_using_group(oav.cam.color_mode, ColorMode.RGB1)
59
+ yield from set_using_group(oav.cam.acquire_period, parameters.acquire_period)
60
+ yield from set_using_group(oav.cam.acquire_time, parameters.exposure)
61
+ yield from set_using_group(oav.cam.gain, parameters.gain)
62
62
 
63
63
  zoom_level_str = f"{float(parameters.zoom)}x"
64
64
  yield from bps.abs_set(
65
- oav.zoom_controller, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
65
+ oav.zoom_controller,
66
66
  zoom_level_str,
67
67
  wait=True,
68
68
  )
@@ -1,6 +1,5 @@
1
1
  from datetime import datetime
2
2
  from enum import Enum
3
- from importlib import resources
4
3
  from pathlib import Path
5
4
 
6
5
  import bluesky.plan_stubs as bps
@@ -8,15 +7,15 @@ from bluesky.utils import MsgGenerator
8
7
  from dodal.common.beamlines.beamline_utils import get_path_provider
9
8
  from dodal.devices.fast_grid_scan import PandAGridScanParams
10
9
  from dodal.devices.smargon import Smargon
11
- from ophyd_async.core import load_device
12
10
  from ophyd_async.fastcs.panda import (
13
11
  HDFPanda,
14
12
  SeqTable,
15
13
  SeqTrigger,
16
14
  )
17
15
 
18
- import mx_bluesky.hyperion.resources.panda as panda_resource
16
+ from mx_bluesky.common.device_setup_plans.setup_panda import load_panda_from_yaml
19
17
  from mx_bluesky.common.utils.log import LOGGER
18
+ from mx_bluesky.hyperion.parameters.constants import DeviceSettingsConstants
20
19
 
21
20
  MM_TO_ENCODER_COUNTS = 200000
22
21
  GENERAL_TIMEOUT = 60
@@ -76,7 +75,8 @@ def _get_seq_table(
76
75
 
77
76
  num_pulses = parameters.x_steps
78
77
 
79
- delay_between_pulses = time_between_steps_ms * TICKS_PER_MS
78
+ # Integer precision here is 1e-6s, so casting is safe
79
+ delay_between_pulses = int(time_between_steps_ms * TICKS_PER_MS)
80
80
 
81
81
  assert delay_between_pulses > PULSE_WIDTH_US
82
82
 
@@ -145,10 +145,11 @@ def setup_panda_for_flyscan(
145
145
 
146
146
  yield from bps.stage(panda, group="panda-config")
147
147
 
148
- with resources.as_file(
149
- resources.files(panda_resource) / "panda-gridscan.yaml"
150
- ) as config_yaml_path:
151
- yield from load_device(panda, str(config_yaml_path))
148
+ yield from load_panda_from_yaml(
149
+ DeviceSettingsConstants.PANDA_FLYSCAN_SETTINGS_DIR,
150
+ DeviceSettingsConstants.PANDA_FLYSCAN_SETTINGS_FILENAME,
151
+ panda,
152
+ )
152
153
 
153
154
  initial_x = yield from bps.rd(smargon.x.user_readback)
154
155
  initial_y = yield from bps.rd(smargon.y.user_readback)
@@ -47,7 +47,7 @@ def bluesky_retry(func: Callable):
47
47
 
48
48
 
49
49
  def arm_zebra(zebra: Zebra):
50
- yield from bps.abs_set(zebra.pc.arm, ArmDemand.ARM, wait=True) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
50
+ yield from bps.abs_set(zebra.pc.arm, ArmDemand.ARM, wait=True)
51
51
 
52
52
 
53
53
  def tidy_up_zebra_after_rotation_scan(
@@ -56,7 +56,7 @@ def tidy_up_zebra_after_rotation_scan(
56
56
  group="tidy_up_zebra_after_rotation",
57
57
  wait=True,
58
58
  ):
59
- yield from bps.abs_set(zebra.pc.arm, ArmDemand.DISARM, group=group) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
59
+ yield from bps.abs_set(zebra.pc.arm, ArmDemand.DISARM, group=group)
60
60
  yield from bps.abs_set(
61
61
  zebra_shutter.control_mode, ZebraShutterControl.MANUAL, group=group
62
62
  )
@@ -16,10 +16,10 @@ def move_smargon_warn_on_out_of_range(
16
16
  "Pin tip centring failed - pin too long/short/bent and out of range"
17
17
  )
18
18
  yield from bps.mv(
19
- smargon.x, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
20
- position[0], # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
21
- smargon.y, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
22
- position[1], # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
23
- smargon.z, # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
24
- position[2], # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
19
+ smargon.x,
20
+ position[0],
21
+ smargon.y,
22
+ position[1],
23
+ smargon.z,
24
+ position[2],
25
25
  )
@@ -44,7 +44,7 @@ def start_preparing_data_collection_then_do_plan(
44
44
  """
45
45
 
46
46
  def wrapped_plan():
47
- yield from bps.abs_set(eiger.do_arm, 1, group=group) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
47
+ yield from bps.abs_set(eiger.do_arm, 1, group=group) # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
48
48
  if detector_distance_mm:
49
49
  yield from set_detector_z_position(
50
50
  detector_motion, detector_distance_mm, group
@@ -55,5 +55,5 @@ def start_preparing_data_collection_then_do_plan(
55
55
  yield from check_beamstop(beamstop)
56
56
  yield from bpp.contingency_wrapper(
57
57
  wrapped_plan(),
58
- except_plan=lambda e: (yield from bps.stop(eiger)), # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
58
+ except_plan=lambda e: (yield from bps.stop(eiger)), # type: ignore # Fix types in ophyd-async (https://github.com/DiamondLightSource/mx-bluesky/issues/855)
59
59
  )
@@ -2,6 +2,8 @@ from bluesky import plan_stubs as bps
2
2
  from bluesky.preprocessors import finalize_wrapper
3
3
  from bluesky.utils import make_decorator
4
4
  from dodal.devices.attenuator.attenuator import BinaryFilterAttenuator
5
+ from dodal.devices.dcm import DCM
6
+ from dodal.devices.undulator import Undulator
5
7
  from dodal.devices.xbpm_feedback import Pause, XBPMFeedback
6
8
 
7
9
  from mx_bluesky.common.utils.log import LOGGER
@@ -23,14 +25,14 @@ def _check_and_pause_feedback(
23
25
  turning XBPM feedback off.
24
26
 
25
27
  """
26
- yield from bps.mv(attenuator, 1.0) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
28
+ yield from bps.mv(attenuator, 1.0)
27
29
  LOGGER.info("Waiting for XBPM feedback to be stable")
28
30
  yield from bps.trigger(xbpm_feedback, wait=True)
29
31
  LOGGER.info(
30
32
  f"XPBM feedback in position, pausing and setting transmission to {desired_transmission_fraction}"
31
33
  )
32
- yield from bps.mv(xbpm_feedback.pause_feedback, Pause.PAUSE) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
33
- yield from bps.mv(attenuator, desired_transmission_fraction) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
34
+ yield from bps.mv(xbpm_feedback.pause_feedback, Pause.PAUSE)
35
+ yield from bps.mv(attenuator, desired_transmission_fraction)
34
36
 
35
37
 
36
38
  def _unpause_xbpm_feedback_and_set_transmission_to_1(
@@ -44,13 +46,15 @@ def _unpause_xbpm_feedback_and_set_transmission_to_1(
44
46
  the beam in position
45
47
  attenuator (BinaryFilterAttenuator): The attenuator used to set transmission
46
48
  """
47
- yield from bps.mv(xbpm_feedback.pause_feedback, Pause.RUN, attenuator, 1.0) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
49
+ yield from bps.mv(xbpm_feedback.pause_feedback, Pause.RUN, attenuator, 1.0)
48
50
 
49
51
 
50
52
  def transmission_and_xbpm_feedback_for_collection_wrapper(
51
53
  plan,
54
+ undulator: Undulator,
52
55
  xbpm_feedback: XBPMFeedback,
53
56
  attenuator: BinaryFilterAttenuator,
57
+ dcm: DCM,
54
58
  desired_transmission_fraction: float,
55
59
  ):
56
60
  """Sets the transmission for the data collection, ensuring the xbpm feedback is valid
@@ -66,6 +70,9 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
66
70
  mostly accounts for slow thermal drift so it is safe to assume that the beam is
67
71
  stable during a collection.
68
72
 
73
+ In the case of a beam dump, undulator gap may not return. Therefore, we check here
74
+ that the undulator gap is correct after XBPM is stable, and before collection.
75
+
69
76
  Args:
70
77
  plan: The plan performing the data collection
71
78
  xbpm_feedback (XBPMFeedback): The XBPM device that is responsible for keeping
@@ -78,6 +85,9 @@ def transmission_and_xbpm_feedback_for_collection_wrapper(
78
85
  yield from _check_and_pause_feedback(
79
86
  xbpm_feedback, attenuator, desired_transmission_fraction
80
87
  )
88
+ # Verify Undulator gap is correct, as may not be after a beam dump
89
+ energy_in_kev = yield from bps.rd(dcm.energy_in_kev.user_readback)
90
+ yield from bps.abs_set(undulator, energy_in_kev, wait=True)
81
91
  return (yield from plan)
82
92
 
83
93
  return (
@@ -6,8 +6,8 @@ from dodal.devices.smargon import Smargon, StubPosition
6
6
 
7
7
  from mx_bluesky.common.utils.log import LOGGER
8
8
  from mx_bluesky.common.utils.tracing import TRACER
9
+ from mx_bluesky.common.xrc_result import XRayCentreResult
9
10
  from mx_bluesky.hyperion.device_setup_plans.manipulate_sample import move_x_y_z
10
- from mx_bluesky.hyperion.experiment_plans.common.xrc_result import XRayCentreResult
11
11
  from mx_bluesky.hyperion.parameters.gridscan import HyperionSpecifiedThreeDGridScan
12
12
 
13
13
 
@@ -43,11 +43,7 @@ def change_aperture_then_move_to_xtal(
43
43
  # https://github.com/DiamondLightSource/mx-bluesky/issues/552
44
44
  if parameters and parameters.FGS_params.set_stub_offsets:
45
45
  LOGGER.info("Recentring smargon co-ordinate system to this point.")
46
- yield from bps.mv(
47
- # See: https://github.com/bluesky/bluesky/issues/1809
48
- smargon.stub_offsets, # type: ignore
49
- StubPosition.CURRENT_AS_CENTER, # type: ignore
50
- )
46
+ yield from bps.mv(smargon.stub_offsets, StubPosition.CURRENT_AS_CENTER)
51
47
 
52
48
 
53
49
  def set_aperture_for_bbox_mm(