Skip to content

Commit

Permalink
Merge branch 'main' into mx_bluesky_521_expand_voltages
Browse files Browse the repository at this point in the history
  • Loading branch information
dperl-dls authored Oct 21, 2024
2 parents baae65e + 32d252c commit ccfcce1
Show file tree
Hide file tree
Showing 34 changed files with 1,121 additions and 322 deletions.
28 changes: 28 additions & 0 deletions docs/explanations/decisions/0003-make-devices-factory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 3. Add device factory decorator with lazy connect support

Date: 2024-04-26

## Status

Accepted

## Context

Device instances should be capable of being created without necessarily connecting, so long as they are connected prior to being utilised to collect data. The current method puts requirements on the init method of device classes, and does not expose all options for connecting to ophyd-async devices.

## Decision

DAQ members led us to this proposal:

- ophyd-async: make Device.connect(mock, timeout, force=False) idempotent
- ophyd-async: make ensure_connected(\*devices) plan stub
- dodal: make device_factory() decorator that may construct, name, cache and connect a device
- dodal: collect_factories() returns all device factories
- blueapi: call collect_factories(), instantiate and connect Devices appropriately, log those that fail
- blueapi: when plan is called, run ensure_connected on all plan args and defaults that are Devices

We can then iterate on this if the parallel connect causes a broadcast storm. We could also in future add a monitor to a heartbeat PV per device in Device.connect so that it would reconnect next time it was called.

## Consequences

Beamlines will be converted to use the decorator, and default arguments to plans should be replaced with a non-eagerly connecting call to the initializer controlling device.
37 changes: 37 additions & 0 deletions docs/how-to/include-devices-in-plans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Include Devices in Plans

There are two main ways to include dodal devices in plans

## 1. Pass as Argument

```python
import bluesky.plans as bp

from bluesky.protocols import Readable
from bluesky.utils import MsgGenerator
from dodal.beamlines import i22

def my_plan(detector: Readable) -> MsgGenerator:
yield from bp.count([detector])

RE(my_plan(i22.saxs()))
```

This is useful for generic plans that can run on a variety of devices and are not designed with any specific device in mind.

## 2. Pass as Default Argument

```python
import bluesky.plans as bp

from bluesky.protocols import Readable
from bluesky.utils import MsgGenerator
from dodal.beamlines import i22

def my_plan(detector: Readable = i22.saxs(connect_immediately=False)) -> MsgGenerator:
yield from bp.count([detector])

RE(my_plan()))
```

This is useful for plans that will usually, but not exclusively, use the same device or that are designed to only ever work with a specific device.
31 changes: 31 additions & 0 deletions src/dodal/beamlines/i03.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
from dodal.devices.dcm import DCM
from dodal.devices.detector import DetectorParams
from dodal.devices.detector.detector_motion import DetectorMotion
from dodal.devices.diamond_filter import DiamondFilter, I03Filters
from dodal.devices.eiger import EigerDetector
from dodal.devices.fast_grid_scan import PandAFastGridScan, ZebraFastGridScan
from dodal.devices.flux import Flux
from dodal.devices.focusing_mirror import FocusingMirrorWithStripes, MirrorVoltages
from dodal.devices.motors import XYZPositioner
from dodal.devices.oav.oav_detector import OAV, OAVConfigParams
from dodal.devices.oav.pin_image_recognition import PinTipDetection
from dodal.devices.qbpm import QBPM
from dodal.devices.robot import BartRobot
from dodal.devices.s4_slit_gaps import S4SlitGaps
from dodal.devices.smargon import Smargon
Expand Down Expand Up @@ -516,3 +518,32 @@ def cryo_stream(
wait_for_connection,
fake_with_ophyd_sim,
)


def diamond_filter(
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
) -> DiamondFilter[I03Filters]:
"""Get the i03 diamond filter device, instantiate it if it hasn't already been.
If this is called when already instantiated in i03, it will return the existing object.
"""
return device_instantiation(
DiamondFilter[I03Filters],
"diamond_filter",
"-MO-FLTR-01:",
wait_for_connection,
fake_with_ophyd_sim,
data_type=I03Filters,
)


def qbpm(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -> QBPM:
"""Get the i03 qbpm device, instantiate it if it hasn't already been.
If this is called when already instantiated in i03, it will return the existing object.
"""
return device_instantiation(
QBPM,
"qbpm",
"-DI-QBPM-01:",
wait_for_connection,
fake_with_ophyd_sim,
)
17 changes: 17 additions & 0 deletions src/dodal/beamlines/i04.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from dodal.devices.dcm import DCM
from dodal.devices.detector import DetectorParams
from dodal.devices.detector.detector_motion import DetectorMotion
from dodal.devices.diamond_filter import DiamondFilter, I04Filters
from dodal.devices.eiger import EigerDetector
from dodal.devices.fast_grid_scan import ZebraFastGridScan
from dodal.devices.flux import Flux
Expand Down Expand Up @@ -419,3 +420,19 @@ def oav_to_redis_forwarder(
redis_password=REDIS_PASSWORD,
redis_db=7,
)


def diamond_filter(
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
) -> DiamondFilter[I04Filters]:
"""Get the i04 diamond filter device, instantiate it if it hasn't already been.
If this is called when already instantiated in i03, it will return the existing object.
"""
return device_instantiation(
DiamondFilter[I04Filters],
"diamond_filter",
"-MO-FLTR-01:",
wait_for_connection,
fake_with_ophyd_sim,
data_type=I04Filters,
)
Loading

0 comments on commit ccfcce1

Please sign in to comment.