Skip to content

Commit ec5fc8d

Browse files
authored
Add WatchableAsyncStatus support to the xbpm_feedback status (#1928)
* Add WatchableAsyncStatus support to the xbpm_feedback status
1 parent 004332f commit ec5fc8d

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

src/dodal/devices/xbpm_feedback.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
from bluesky.protocols import Triggerable
2-
from ophyd_async.core import AsyncStatus, Device, Reference, StrictEnum, observe_value
2+
from ophyd_async.core import (
3+
Device,
4+
Reference,
5+
StrictEnum,
6+
WatchableAsyncStatus,
7+
WatcherUpdate,
8+
observe_value,
9+
)
310
from ophyd_async.epics.core import epics_signal_r, epics_signal_rw
411

512
from dodal.common.device_utils import periodic_reminder
@@ -24,12 +31,21 @@ def __init__(self, prefix: str, name: str = "", baton: Baton | None = None) -> N
2431
self.baton_ref = Reference(baton) if baton else None
2532
super().__init__(name=name)
2633

27-
@AsyncStatus.wrap
34+
@WatchableAsyncStatus.wrap
2835
async def trigger(self):
2936
if self.baton_ref and await self.baton_ref().commissioning.get_value():
3037
LOGGER.warning("Commissioning mode enabled, ignoring feedback")
3138
else:
3239
async with periodic_reminder("Waiting for XBPM"):
40+
initial = None
3341
async for value in observe_value(self.pos_stable):
42+
if initial is None:
43+
initial = value
44+
yield WatcherUpdate(
45+
current=value,
46+
initial=initial,
47+
target=1,
48+
name=self.pos_stable.name,
49+
)
3450
if value:
3551
return

tests/devices/test_xbpm_feedback.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pytest
66
from bluesky import plan_stubs as bps
77
from bluesky.run_engine import RunEngine
8-
from ophyd_async.core import init_devices, set_mock_value
8+
from ophyd_async.core import WatchableAsyncStatus, init_devices, set_mock_value
99

1010
from dodal.devices.baton import Baton
1111
from dodal.devices.xbpm_feedback import XBPMFeedback
@@ -15,7 +15,7 @@
1515
async def fake_xbpm_feedback() -> XBPMFeedback:
1616
async with init_devices(mock=True):
1717
baton = Baton("BATON-01:")
18-
xbpm_feedback = XBPMFeedback("", baton=baton)
18+
xbpm_feedback = XBPMFeedback("", baton=baton, name="xbpm_feedback")
1919
return xbpm_feedback
2020

2121

@@ -108,3 +108,33 @@ def test_xbpm_feedback_does_not_wait_if_commissioning_mode_enabled(
108108
run_engine(bps.trigger(xbpm_feedback_in_commissioning_mode, wait=True))
109109
mock_periodic_reminder.assert_not_called()
110110
mock_observe_value.assert_not_called()
111+
112+
113+
async def test_xbpm_feedback_trigger_is_watchable(
114+
fake_xbpm_feedback: XBPMFeedback,
115+
run_engine: RunEngine,
116+
):
117+
set_mock_value(fake_xbpm_feedback.pos_stable, False)
118+
received_events = []
119+
120+
def on_event(**kwargs):
121+
received_events.append(kwargs)
122+
if kwargs.get("current") == 0:
123+
set_mock_value(fake_xbpm_feedback.pos_stable, True)
124+
125+
def wait_for_feedback():
126+
status = yield from bps.trigger(fake_xbpm_feedback, wait=False)
127+
assert isinstance(status, WatchableAsyncStatus)
128+
status.watch(on_event) # type: ignore
129+
yield from bps.wait(timeout=1)
130+
131+
run_engine(wait_for_feedback())
132+
133+
assert received_events[0]["name"] == "xbpm_feedback-pos_stable"
134+
assert received_events[0]["current"] == 0
135+
assert received_events[0]["initial"] == 0
136+
assert received_events[0]["target"] == 1
137+
assert received_events[1]["name"] == "xbpm_feedback-pos_stable"
138+
assert received_events[1]["current"] == 1
139+
assert received_events[1]["initial"] == 0
140+
assert received_events[1]["target"] == 1

0 commit comments

Comments
 (0)