Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility with ophyd-async v0.3a4 #525

Merged
merged 8 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ classifiers = [
description = "Ophyd devices and other utils that could be used across DLS beamlines"
dependencies = [
"ophyd",
"ophyd-async>=0.3a3",
"ophyd-async>=0.3a4",
"bluesky",
"pyepics",
"dataclasses-json",
Expand Down
11 changes: 5 additions & 6 deletions src/dodal/beamlines/beamline_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,16 @@ def active_device_is_same_type(


def _wait_for_connection(
device: AnyDevice, timeout: float = DEFAULT_CONNECTION_TIMEOUT, sim: bool = False
device: AnyDevice,
timeout: float = DEFAULT_CONNECTION_TIMEOUT,
mock: bool = False,
) -> None:
if isinstance(device, OphydV1Device):
device.wait_for_connection(timeout=timeout)
elif isinstance(device, OphydV2Device):
call_in_bluesky_event_loop(
v2_device_wait_for_connection(
coros=device.connect(
sim=sim,
timeout=timeout,
)
coros=device.connect(mock=mock, timeout=timeout)
),
)
else:
Expand Down Expand Up @@ -110,7 +109,7 @@ def device_instantiation(
)
ACTIVE_DEVICES[name] = device_instance
if wait:
_wait_for_connection(device_instance, sim=fake)
_wait_for_connection(device_instance, mock=fake)

else:
if not active_device_is_same_type(already_existing_device, device_factory):
Expand Down
6 changes: 4 additions & 2 deletions src/dodal/devices/aperturescatterguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from bluesky.protocols import Movable
from ophyd_async.core import AsyncStatus, SignalR, StandardReadable
from ophyd_async.core.sim_signal_backend import SimSignalBackend
from ophyd_async.core.soft_signal_backend import SoftSignalBackend

from dodal.devices.aperture import Aperture
from dodal.devices.scatterguard import Scatterguard
Expand Down Expand Up @@ -94,7 +94,9 @@ def __init__(self, prefix: str = "", name: str = "") -> None:
self.aperture_positions: AperturePositions | None = None
self.TOLERANCE_STEPS = 3 # Number of MRES steps
self.selected_aperture = self.SelectedAperture(
backend=SimSignalBackend(SingleAperturePosition, AperturePositions.UNKNOWN),
backend=SoftSignalBackend(
SingleAperturePosition, AperturePositions.UNKNOWN
),
)
self.set_readable_signals(
read=[
Expand Down
4 changes: 2 additions & 2 deletions src/dodal/devices/focusing_mirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ophyd import Component, Device, EpicsSignal
from ophyd.status import Status, StatusBase
from ophyd_async.core import StandardReadable
from ophyd_async.core.signal import soft_signal_r_and_backend
from ophyd_async.core.signal import soft_signal_r_and_setter
from ophyd_async.epics.motion import Motor
from ophyd_async.epics.signal import (
epics_signal_rw,
Expand Down Expand Up @@ -139,7 +139,7 @@ def __init__(
self.translation1_mm = Motor(prefix + "X1")
self.translation2_mm = Motor(prefix + "X2")

self.type, _ = soft_signal_r_and_backend(MirrorType, MirrorType.SINGLE)
self.type, _ = soft_signal_r_and_setter(MirrorType, MirrorType.SINGLE)
# The device is in the beamline co-ordinate system so pitch is the incident angle
# regardless of orientation of the mirror
self.incident_angle = Motor(prefix + "PITCH")
Expand Down
61 changes: 19 additions & 42 deletions src/dodal/devices/oav/pin_image_recognition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import numpy as np
from numpy.typing import NDArray
from ophyd_async.core import (
DEFAULT_TIMEOUT,
AsyncStatus,
StandardReadable,
observe_value,
soft_signal_r_and_setter,
soft_signal_rw,
)
from ophyd_async.epics.signal import epics_signal_r

Expand All @@ -18,7 +19,6 @@
ScanDirections,
identity,
)
from dodal.devices.ophyd_async_utils import create_soft_signal_r, create_soft_signal_rw
from dodal.log import LOGGER

Tip = tuple[int | None, int | None]
Expand Down Expand Up @@ -50,38 +50,30 @@ def __init__(self, prefix: str, name: str = ""):
self._prefix: str = prefix
self._name = name

self.triggered_tip = create_soft_signal_r(Tip, "triggered_tip", self.name)
self.triggered_top_edge = create_soft_signal_r(
NDArray[np.uint32], "triggered_top_edge", self.name
self.triggered_tip, _ = soft_signal_r_and_setter(Tip, name="triggered_tip")
self.triggered_top_edge, _ = soft_signal_r_and_setter(
NDArray[np.uint32], name="triggered_top_edge"
)
self.triggered_bottom_edge = create_soft_signal_r(
NDArray[np.uint32], "triggered_bottom_edge", self.name
self.triggered_bottom_edge, _ = soft_signal_r_and_setter(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, we can make a separate issue to make sure these signals use their setters rather than the backends in order to set values. Also, there may be scope to have a regular soft_signal_r function in ophyd-async

NDArray[np.uint32], name="triggered_bottom_edge"
)
self.array_data = epics_signal_r(NDArray[np.uint8], f"pva://{prefix}PVA:ARRAY")

# Soft parameters for pin-tip detection.
self.preprocess_operation = create_soft_signal_rw(int, "preprocess", self.name)
self.preprocess_ksize = create_soft_signal_rw(
int, "preprocess_ksize", self.name
self.preprocess_operation = soft_signal_rw(int, 10, name="preprocess")
self.preprocess_ksize = soft_signal_rw(int, 5, name="preprocess_ksize")
self.preprocess_iterations = soft_signal_rw(
int, 5, name="preprocess_iterations"
)
self.preprocess_iterations = create_soft_signal_rw(
int, "preprocess_iterations", self.name
)
self.canny_upper_threshold = create_soft_signal_rw(
int, "canny_upper", self.name
)
self.canny_lower_threshold = create_soft_signal_rw(
int, "canny_lower", self.name
)
self.close_ksize = create_soft_signal_rw(int, "close_ksize", self.name)
self.close_iterations = create_soft_signal_rw(
int, "close_iterations", self.name
)
self.scan_direction = create_soft_signal_rw(int, "scan_direction", self.name)
self.min_tip_height = create_soft_signal_rw(int, "min_tip_height", self.name)
self.validity_timeout = create_soft_signal_rw(
float, "validity_timeout", self.name
self.canny_upper_threshold = soft_signal_rw(int, 100, name="canny_upper")
self.canny_lower_threshold = soft_signal_rw(int, 50, name="canny_lower")
self.close_ksize = soft_signal_rw(int, 5, name="close_ksize")
self.close_iterations = soft_signal_rw(int, 5, name="close_iterations")
self.scan_direction = soft_signal_rw(
int, ScanDirections.FORWARD.value, name="scan_direction"
)
self.min_tip_height = soft_signal_rw(int, 5, name="min_tip_height")
self.validity_timeout = soft_signal_rw(float, 5.0, name="validity_timeout")

self.set_readable_signals(
read=[
Expand Down Expand Up @@ -146,21 +138,6 @@ async def _get_tip_and_edge_data(
)
return location

async def connect(self, sim: bool = False, timeout: float = DEFAULT_TIMEOUT):
await super().connect(sim, timeout)

# Set defaults for soft parameters
await self.validity_timeout.set(5.0)
await self.canny_upper_threshold.set(100)
await self.canny_lower_threshold.set(50)
await self.close_iterations.set(5)
await self.close_ksize.set(5)
await self.scan_direction.set(ScanDirections.FORWARD.value)
await self.min_tip_height.set(5)
await self.preprocess_operation.set(10) # Identity function
await self.preprocess_iterations.set(5)
await self.preprocess_ksize.set(5)

@AsyncStatus.wrap
async def trigger(self):
async def _set_triggered_tip():
Expand Down
17 changes: 0 additions & 17 deletions src/dodal/devices/ophyd_async_utils.py

This file was deleted.

29 changes: 15 additions & 14 deletions src/dodal/devices/tetramm.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
StandardDetector,
set_and_wait_for_value,
)
from ophyd_async.epics.areadetector.utils import ad_r, ad_rw, stop_busy_record
from ophyd_async.epics.areadetector.utils import stop_busy_record
from ophyd_async.epics.areadetector.writers import HDFWriter, NDFileHDF
from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv


class TetrammRange(str, Enum):
Expand Down Expand Up @@ -53,25 +54,25 @@ def __init__(
name: str = "",
):
self._prefix = prefix
self.range = ad_rw(TetrammRange, prefix + "Range")
self.sample_time = ad_r(float, prefix + "SampleTime")
self.range = epics_signal_rw_rbv(TetrammRange, prefix + "Range")
self.sample_time = epics_signal_r(float, prefix + "SampleTime_RBV")

self.values_per_reading = ad_rw(int, prefix + "ValuesPerRead")
self.averaging_time = ad_rw(float, prefix + "AveragingTime")
self.to_average = ad_r(int, prefix + "NumAverage")
self.averaged = ad_r(int, prefix + "NumAveraged")
self.values_per_reading = epics_signal_rw_rbv(int, prefix + "ValuesPerRead")
self.averaging_time = epics_signal_rw_rbv(float, prefix + "AveragingTime")
self.to_average = epics_signal_r(int, prefix + "NumAverage_RBV")
self.averaged = epics_signal_r(int, prefix + "NumAveraged_RBV")

self.acquire = ad_rw(bool, prefix + "Acquire")
self.acquire = epics_signal_rw_rbv(bool, prefix + "Acquire")

# this PV is special, for some reason it doesn't have a _RBV suffix...
self.overflows = epics_signal_r(int, prefix + "RingOverflows")

self.num_channels = ad_rw(TetrammChannels, prefix + "NumChannels")
self.resolution = ad_rw(TetrammResolution, prefix + "Resolution")
self.trigger_mode = ad_rw(TetrammTrigger, prefix + "TriggerMode")
self.bias = ad_rw(bool, prefix + "BiasState")
self.bias_volts = ad_rw(float, prefix + "BiasVoltage")
self.geometry = ad_rw(TetrammGeometry, prefix + "Geometry")
self.num_channels = epics_signal_rw_rbv(TetrammChannels, prefix + "NumChannels")
self.resolution = epics_signal_rw_rbv(TetrammResolution, prefix + "Resolution")
self.trigger_mode = epics_signal_rw_rbv(TetrammTrigger, prefix + "TriggerMode")
self.bias = epics_signal_rw_rbv(bool, prefix + "BiasState")
self.bias_volts = epics_signal_rw_rbv(float, prefix + "BiasVoltage")
self.geometry = epics_signal_rw_rbv(TetrammGeometry, prefix + "Geometry")
self.nd_attributes_file = epics_signal_rw(str, prefix + "NDAttributesFile")

super().__init__(name=name)
Expand Down
9 changes: 4 additions & 5 deletions src/dodal/devices/webcam.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
import aiofiles
from aiohttp import ClientSession
from bluesky.protocols import Triggerable
from ophyd_async.core import AsyncStatus, StandardReadable
from ophyd_async.core import AsyncStatus, StandardReadable, soft_signal_rw

from dodal.devices.ophyd_async_utils import create_soft_signal_rw
from dodal.log import LOGGER


class Webcam(StandardReadable, Triggerable):
def __init__(self, name, prefix, url):
self.url = url
self.filename = create_soft_signal_rw(str, "filename", "webcam")
self.directory = create_soft_signal_rw(str, "directory", "webcam")
self.last_saved_path = create_soft_signal_rw(str, "last_saved_path", "webcam")
self.filename = soft_signal_rw(str, name="filename")
self.directory = soft_signal_rw(str, name="directory")
self.last_saved_path = soft_signal_rw(str, name="last_saved_path")

self.set_readable_signals([self.last_saved_path])
super().__init__(name=name)
Expand Down
15 changes: 7 additions & 8 deletions src/dodal/devices/zocalo/zocalo_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@
import workflows.transport
from bluesky.protocols import Descriptor, Triggerable
from numpy.typing import NDArray
from ophyd_async.core import StandardReadable
from ophyd_async.core import StandardReadable, soft_signal_r_and_setter
from ophyd_async.core.async_status import AsyncStatus
from workflows.transport.common_transport import CommonTransport

from dodal.devices.ophyd_async_utils import create_soft_signal_r
from dodal.devices.zocalo.zocalo_interaction import _get_zocalo_connection
from dodal.log import LOGGER

Expand Down Expand Up @@ -80,15 +79,15 @@ def __init__(
self._raw_results_received: Queue = Queue()
self.transport: CommonTransport | None = None

self.results = create_soft_signal_r(list[XrcResult], "results", self.name)
self.centres_of_mass = create_soft_signal_r(
NDArray[np.uint64], "centres_of_mass", self.name
self.results, _ = soft_signal_r_and_setter(list[XrcResult], name="results")
self.centres_of_mass, _ = soft_signal_r_and_setter(
NDArray[np.uint64], name="centres_of_mass"
)
self.bbox_sizes = create_soft_signal_r(
self.bbox_sizes, _ = soft_signal_r_and_setter(
NDArray[np.uint64], "bbox_sizes", self.name
)
self.ispyb_dcid = create_soft_signal_r(int, "ispyb_dcid", self.name)
self.ispyb_dcgid = create_soft_signal_r(int, "ispyb_dcgid", self.name)
self.ispyb_dcid, _ = soft_signal_r_and_setter(int, name="ispyb_dcid")
self.ispyb_dcgid, _ = soft_signal_r_and_setter(int, name="ispyb_dcgid")
self.set_readable_signals(
read=[
self.results,
Expand Down
5 changes: 2 additions & 3 deletions tests/beamlines/unit_tests/test_beamline_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from ophyd.sim import FakeEpicsSignal
from ophyd_async.core import Device as OphydV2Device
from ophyd_async.core import StandardReadable
from ophyd_async.core.sim_signal_backend import SimSignalBackend

from dodal.beamlines import beamline_utils, i03
from dodal.devices.aperturescatterguard import ApertureScatterguard
Expand Down Expand Up @@ -65,7 +64,7 @@ def test_instantiate_v2_function_fake_makes_fake():
i03.Zebra, "zebra", "", True, True, None
)
assert isinstance(fake_zeb, StandardReadable)
assert isinstance(fake_zeb.pc.arm.armed._backend, SimSignalBackend)
assert fake_zeb.pc.arm.armed.source.startswith("mock+ca")


def test_clear_devices(RE):
Expand Down Expand Up @@ -116,6 +115,6 @@ def test_wait_for_v2_device_connection_passes_through_timeout(
beamline_utils._wait_for_connection(device, **kwargs)

device.connect.assert_called_once_with(
sim=ANY,
mock=ANY,
timeout=expected_timeout,
)
10 changes: 5 additions & 5 deletions tests/devices/i22/test_fswitch.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
from unittest import mock

import pytest
from ophyd_async.core import DeviceCollector, set_sim_value
from ophyd_async.core import DeviceCollector, set_mock_value

from dodal.devices.i22.fswitch import FilterState, FSwitch


@pytest.fixture
async def fswitch() -> FSwitch:
async with DeviceCollector(sim=True):
async with DeviceCollector(mock=True):
fswitch = FSwitch("DEMO-FSWT-01:")

return fswitch


async def test_reading_fswitch(fswitch: FSwitch):
set_sim_value(fswitch.filters.get(0), FilterState.OUT_BEAM)
set_sim_value(fswitch.filters.get(1), FilterState.OUT_BEAM)
set_sim_value(fswitch.filters.get(2), FilterState.OUT_BEAM)
set_mock_value(fswitch.filters.get(0), FilterState.OUT_BEAM)
set_mock_value(fswitch.filters.get(1), FilterState.OUT_BEAM)
set_mock_value(fswitch.filters.get(2), FilterState.OUT_BEAM)

reading = await fswitch.read()
assert reading == {
Expand Down
19 changes: 12 additions & 7 deletions tests/devices/unit_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
from unittest.mock import AsyncMock, patch

import pytest
from ophyd_async.core import DirectoryInfo, DirectoryProvider, StaticDirectoryProvider
from ophyd_async.core import (
DirectoryInfo,
DirectoryProvider,
StaticDirectoryProvider,
set_mock_value,
)
from ophyd_async.epics.motion import Motor


Expand All @@ -13,16 +18,16 @@ async def mock_good_coroutine():


def mock_move(motor: Motor, val, *args, **kwargs):
motor.user_setpoint._backend._set_value(val) # type: ignore
motor.user_readback._backend._set_value(val) # type: ignore
set_mock_value(motor.user_setpoint, val)
set_mock_value(motor.user_readback, val)
return mock_good_coroutine() # type: ignore


def patch_motor(motor: Motor, initial_position=0):
motor.user_setpoint._backend._set_value(initial_position) # type: ignore
motor.user_readback._backend._set_value(initial_position) # type: ignore
motor.deadband._backend._set_value(0.001) # type: ignore
motor.motor_done_move._backend._set_value(1) # type: ignore
set_mock_value(motor.user_setpoint, initial_position)
set_mock_value(motor.user_readback, initial_position)
set_mock_value(motor.deadband, 0.001)
set_mock_value(motor.motor_done_move, 1)
return patch.object(
motor, "_move", AsyncMock(side_effect=partial(mock_move, motor))
)
Expand Down
Loading
Loading