Devices Guide#
Device Loading at Runtime#
Devices are managed through a set of helper functions available after startup:
# List all available devices (from devices.yml)
find_loadable_devices()
# Filter by label
find_loadable_devices(label="4idg")
find_loadable_devices(name="crl") # substring match
find_loadable_devices(name="kb", exact_name=False)
# Connect a device
load_device("crl")
# Disconnect and remove from baseline
remove_device("crl")
# Reload everything from YAML (useful after devices.yml edits)
reload_all_devices()
reload_all_devices(stations=["core", "4idh"])
These are thin wrappers around
id4_common.utils.device_loader — see the
API reference for full
parameter documentation.
Deferred EPICS Connection Pattern#
make_devices() instantiates every device object from devices.yml without
making EPICS connections. This means startup is fast and does not depend on the
EPICS network being reachable.
Only connect_device() — called internally by load_device() — triggers actual
EPICS interaction via wait_for_connection().
_post_connect_setup() hook#
If your device needs to subscribe to PV values or perform any post-connection work, implement this method:
from ophyd import Device, Component, EpicsSignalRO
class MyDevice(Device):
signal = Component(EpicsSignalRO, "PV:NAME")
def _post_connect_setup(self):
"""Called by connect_device() after EPICS connection is live."""
self.signal.subscribe(self._on_change, run=False)
def _on_change(self, value, **kwargs):
...
connect_device() calls _post_connect_setup() automatically after
wait_for_connection() succeeds. For sub-components (not top-level
devices.yml entries), always use run=False on any subscribe() calls
inside __init__ to avoid fetching PV values before the connection is live.
Factory Pattern for Dynamic Components#
Where a DynamicDeviceComponent must be assembled at class-definition time
(e.g. a variable number of channels), use a factory function that returns a
new class:
def make_crl_class(ioc="4idgSoft:"):
class CRLClass(Device):
lenses = DynamicDeviceComponent(_build_lens_dict(ioc))
...
return CRLClass
# Module-level default (what devices.yml points to)
CRLClass = make_crl_class()
Real examples in the codebase:
Factory |
Module |
|---|---|
|
|
|
|
Notable Device Classes#
Area Detectors#
Class |
Module |
Notes |
|---|---|---|
|
|
Dectris Eiger 1M |
|
|
X-Spectrum Lambda 250k |
|
|
Princeton LightField spectrometer |
|
|
Allied Vision Vimba camera |
Fluorescence Detectors#
Class |
Module |
Notes |
|---|---|---|
|
|
Vortex with XMAP electronics |
|
|
Vortex 7-element with Xspress3 |
|
|
Vortex 4-element with Xspress3 |
|
|
Vortex 1-element with Dante |
|
|
Vortex 4-element with Dante |
Optics and Beam Delivery#
Class |
Module |
Notes |
|---|---|---|
|
|
KB mirror pair (factory-built) |
|
|
Compound refractive lens (factory-built) |
|
|
Si(111) DCM |
|
|
Tracks mono energy; other devices can subscribe |
|
|
Upstream/downstream undulators |
|
|
APS-source XBPM |
|
|
Generic XBPM (used by |
|
|
High-heat-load mirror |
Diffractometer#
Class |
Module |
Notes |
|---|---|---|
|
|
Huber Euler / HP cradles (hklpy2) |
|
|
Companion |
Experiment Utilities#
Class |
Module |
Notes |
|---|---|---|
|
|
2 T electromagnet power supply |
|
|
4IDH 9-Tesla magnet (table + sample + VTI) |
|
|
Time-resolved chopper |
|
|
Local fast shutter (the A/B PSS shutters use |
|
|
Multi-channel scaler (USB-CTR8) |
Counters Class#
CountersClass (from id4_common.utils.counters_class) holds the active
detector and monitor selection used by all scan plans:
# Default counters object is available as `counters` after startup
counters.detectors # list of active detectors
counters.monitor # scaler channel used as monitor
counters.extra_devices # devices read but not plotted
# Change the selection
counters.plotselect(0, 1) # detector index 0, monitor index 1
counters.plotselect(dets=0, mon=1) # equivalent (named args)
counters.plotselect() # interactive prompt
plotselect() accepts integer indices into the scaler channel list,
single device objects, or lists/tuples of either; pass nothing to enter
the interactive prompt. The active selection is auto-snapshotted into
RE.md["session_state"] so a bluesky restart can re-apply it via
restore_session_state() (see Recoverable session
state).
Scan plans automatically read counters.detectors and counters.monitor
unless overridden by explicit arguments.