Add an Async Signal to a Custom Device¶
Overview
Add an AsyncSignal to a custom ophyd device when the device produces one asynchronous data stream and you want BEC to forward it during a scan.
Prerequisites¶
- You already have a custom device class in Python.
- Your device produces asynchronous data outside the normal
read()path. - You know the dimensionality of the async payload.
- You know how new async updates should be written into the dataset.
1. Declare the signal on the device class¶
Declare one AsyncSignal component on the device.
from ophyd import Component as Cpt, Device
from ophyd_devices import AsyncSignal
class MyDetector(Device):
waveform = Cpt(
AsyncSignal,
name="waveform",
ndim=1,
async_update={"type": "add", "max_shape": [None, 1024]},
max_size=1000,
)
This defines one asynchronous signal named waveform.
ndimdescribes the payload dimensionalityasync_updatetells BEC how incoming updates should be storedmax_sizecontrols how much async data BEC keeps in memory for that signal
2. Define async_update on the signal¶
In normal usage, define async_update once on the signal declaration.
Example for a stream of fixed-length waveforms:
async_update={"type": "add", "max_shape": [None, 1024]}
This means each new update adds one more waveform of length 1024.
When to override it
For add_slice, the slice index may need to change between updates. In that case, pass updated async_update metadata with the individual put(...) call.
Learn about update modes
See BEC Signals for Custom Devices for details on add, add_slice, and replace.
3. Receive the async data first¶
AsyncSignal is meant for data that arrives asynchronously from a callback, subscription, socket, thread, or other background source.
Typical pattern:
def _get_waveform(self):
return [1.0, 2.0, 3.0, 4.0]
values = self._get_waveform()
self.waveform.put(values)
The important sequence is:
- receive one async sample from the hardware or upstream source
- convert it into the payload you want to send
- call
put(...)on theAsyncSignal
4. Handle add_slice if needed¶
If the signal uses add_slice and the slice index changes during runtime, send the updated metadata with the individual update.
Example:
self.waveform.put(
first_chunk,
async_update={"type": "add_slice", "index": 0, "max_shape": [None, 1024]},
)
self.waveform.put(
second_chunk,
async_update={"type": "add_slice", "index": 1, "max_shape": [None, 1024]},
)
If your device naturally emits one complete new waveform, row, or image per update, add is usually simpler than add_slice.
5. Verify the data stream¶
Run a short acquisition and confirm that:
- your callback or background reader is receiving async data
- the payload shape matches the declared signal
- the signal receives updates with
put(...) - the chosen
async_updatemode matches the intended dataset layout
If no async data appears in BEC, first check whether the payload shape and async_update configuration match each other.
Congratulations!
You have successfully added an AsyncSignal to a custom device. BEC can now forward one asynchronous data stream from your device during the scan.