From e45e9d81aa986dd6904bd6a08baa6e43ec370122 Mon Sep 17 00:00:00 2001 From: wakonig_k Date: Sun, 10 May 2026 12:17:12 +0200 Subject: [PATCH] feat: add documentation for EPICS put completion and clarify set() vs put() usage --- docs/learn/devices/epics-put-completion.md | 80 +++++++++++++++ docs/learn/devices/set-vs-put.md | 110 +++++++++++++++++++++ zensical.toml | 2 + 3 files changed, 192 insertions(+) create mode 100644 docs/learn/devices/epics-put-completion.md create mode 100644 docs/learn/devices/set-vs-put.md diff --git a/docs/learn/devices/epics-put-completion.md b/docs/learn/devices/epics-put-completion.md new file mode 100644 index 0000000..5376cec --- /dev/null +++ b/docs/learn/devices/epics-put-completion.md @@ -0,0 +1,80 @@ +--- +related: + - title: set() vs put() in ophyd + url: learn/devices/set-vs-put.md + - title: EPICS Signal Variants + url: learn/devices/epics-signals.md +--- + +# EPICS put completion + +`EpicsSignal` supports EPICS put completion, which means EPICS reports back when the write request itself has completed. + +This is an EPICS-specific detail that matters because it changes how `set()` decides that a write is finished. + +## Configuring `put_complete` + +The relevant option is `put_complete`, which is configured on the signal definition. The default value is `False`. + +```python +from ophyd import Component as Cpt, Device, EpicsSignal + + +class MyDevice(Device): + my_signal = Cpt(EpicsSignal, "PV:NAME", put_complete=True) +``` + +## How it changes `set()` + +For `EpicsSignal.set()`, `put_complete` changes the completion condition: + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConfigurationCompletion behaviorWhat the caller gets
put_complete=Falseset() writes the value, then waits until the readback reaches the target.A Status that completes when the readback matches.
put_complete=Trueset() calls put(..., use_complete=True) internally and finishes when EPICS reports put completion.A Status that completes on EPICS put completion.
+ +!!! info "How `put_complete` changes `set()`" + - `put_complete=False`: "wait until the signal value reaches the requested target" + - `put_complete=True`: "wait until EPICS says the write request has completed" + +This can be useful for EPICS signals where the EPICS put-completion callback is the right completion signal for the write. + +## What it does not change + +`put_complete` changes how `set()` finishes, but it does not change the role of `put()`. + +Even when `put_complete=True` is enabled on the signal: + +- `put()` still performs a direct write +- `put()` still returns immediately +- `put()` still does not return a `Status` + +That is why `set()` remains the normal ophyd API when the caller needs structured completion tracking. + +!!! info "What to remember" + - `put_complete` is an `EpicsSignal` option that changes how `set()` decides the write is finished. + - With `put_complete=False`, `set()` waits for the readback to reach the target. + - With `put_complete=True`, `set()` finishes when EPICS reports put completion. + - `put_complete` does not turn `put()` into a completion-tracked API: `put()` still writes directly and returns immediately. diff --git a/docs/learn/devices/set-vs-put.md b/docs/learn/devices/set-vs-put.md new file mode 100644 index 0000000..f61150a --- /dev/null +++ b/docs/learn/devices/set-vs-put.md @@ -0,0 +1,110 @@ +--- +related: + - title: Introduction to ophyd + url: learn/devices/introduction-to-ophyd.md + - title: Change Config Signals from the BEC IPython Client + url: how-to/devices/change-config-signals-from-the-bec-ipython-client.md + - title: EPICS put completion + url: learn/devices/epics-put-completion.md +--- + +# `set()` vs `put()` in `ophyd` + +In ophyd, both `set()` and `put()` can write a new value to a writable signal, but they serve different purposes. + +The short version is: + +- use `put()` for a direct low-level write +- use `set()` when you want a write operation with completion tracking + +That distinction matters in BEC because user-facing device operations often need clear completion semantics, while device-internal helper signals often just need to publish a new value immediately. + +## What `put()` does + +`put()` is the low-level write method on a signal. + +It sends a value to the signal and returns immediately. It does not return a `Status` object and is therefore not the right abstraction when the caller needs to wait for completion in a structured way. + +`put()` is a direct wrapper around the underlying control layer, i.e. in the case of pyepics (default for ophyd_devices), it is calling `epics.PV.put()`. + +Typical uses of `put()` include: + +- updating a soft signal inside device implementation code +- writing trigger-like signals that should be pushed directly +- direct signal writes where completion tracking is not needed or not meaningful + +Example: + +```python +my_signal.put(5) +``` + +## What `set()` does + +`set()` is the higher-level write method. + +It starts a write operation and returns a `Status` object that tells the caller when the operation is considered complete or has failed. This makes `set()` a better fit for coordinated device actions, plans, and user-facing control flows. + +Example: + +```python +status = my_signal.set(5) +status.wait() +``` + +In other words, `set()` is not just about sending a value. It is about sending a value and giving the caller a standard way to observe completion. +Under the hood, `set()` uses `put()` to perform the actual write, but it adds the completion tracking layer on top. + +## The practical difference + +The key difference is the API contract: + + + + + + + + + + + + + + + + + + + + + + +
MethodBehavior
put()Perform a direct write. No Status object is returned.
set()Perform a write operation with completion tracking and return a Status.
+ +That means the choice is usually driven by what the caller needs: + +- If you only need to publish or write a value, `put()` is often enough. +- If the caller needs to wait until the operation is done, use `set()`. + +## How `set()` decides it is done + +For a basic ophyd `Signal`, `set()` uses the lower-level write path and then waits until the signal readback reaches the target value within the configured tolerances. + +This is why `set()` is often described as a write-and-wait operation rather than just a write. + +For `EpicsSignal`, there is one extra detail worth knowing: `put_complete` changes how `set()` decides that the write has finished. That EPICS-specific behavior is covered separately in [EPICS put completion](../../learn/devices/epics-put-completion.md). + + +## Choosing between them + +In practice, the choice is simple: + +- use `put()` when you only need to write a value +- use `set()` when the caller needs a `Status` and clear completion semantics + +!!! info "What to remember" + - `put()` is the low-level write method for directly updating a signal value. + - `set()` is the higher-level write method that returns a `Status` so callers can wait for completion. + - For a basic ophyd `Signal`, `set()` writes the value and waits until the readback reaches the target. + - If you are working with `EpicsSignal`, `put_complete` adds EPICS-specific completion behavior for `set()`. diff --git a/zensical.toml b/zensical.toml index 93e940f..5de82f2 100644 --- a/zensical.toml +++ b/zensical.toml @@ -118,10 +118,12 @@ nav = [ { "Managing YAML Configs" = "learn/devices/managing-yaml-configs.md" }, { "EPICS Motor Variants" = "learn/devices/epics-motors.md" }, { "EPICS Signal Variants" = "learn/devices/epics-signals.md" }, + { "set() vs put()" = "learn/devices/set-vs-put.md" }, ] }, { "Development" = [ { "Pseudo Positioners" = "learn/devices/pseudo-positioners.md" }, { "BEC Signals" = "learn/devices/bec-signals.md" }, + { "EPICS put completion" = "learn/devices/epics-put-completion.md" }, { "Simulated Devices" = "learn/devices/simulated-devices.md" }, ] }, ] },