Skip to content

Commit e45e9d8

Browse files
committed
feat: add documentation for EPICS put completion and clarify set() vs put() usage
1 parent 51a917c commit e45e9d8

3 files changed

Lines changed: 192 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
related:
3+
- title: set() vs put() in ophyd
4+
url: learn/devices/set-vs-put.md
5+
- title: EPICS Signal Variants
6+
url: learn/devices/epics-signals.md
7+
---
8+
9+
# EPICS put completion
10+
11+
`EpicsSignal` supports EPICS put completion, which means EPICS reports back when the write request itself has completed.
12+
13+
This is an EPICS-specific detail that matters because it changes how `set()` decides that a write is finished.
14+
15+
## Configuring `put_complete`
16+
17+
The relevant option is `put_complete`, which is configured on the signal definition. The default value is `False`.
18+
19+
```python
20+
from ophyd import Component as Cpt, Device, EpicsSignal
21+
22+
23+
class MyDevice(Device):
24+
my_signal = Cpt(EpicsSignal, "PV:NAME", put_complete=True)
25+
```
26+
27+
## How it changes `set()`
28+
29+
For `EpicsSignal.set()`, `put_complete` changes the completion condition:
30+
31+
<table>
32+
<colgroup>
33+
<col style="width: 22%;">
34+
<col style="width: 48%;">
35+
<col style="width: 30%;">
36+
</colgroup>
37+
<thead>
38+
<tr>
39+
<th>Configuration</th>
40+
<th>Completion behavior</th>
41+
<th>What the caller gets</th>
42+
</tr>
43+
</thead>
44+
<tbody>
45+
<tr>
46+
<td><code>put_complete=False</code></td>
47+
<td><code>set()</code> writes the value, then waits until the readback reaches the target.</td>
48+
<td>A <code>Status</code> that completes when the readback matches.</td>
49+
</tr>
50+
<tr>
51+
<td><code>put_complete=True</code></td>
52+
<td><code>set()</code> calls <code>put(..., use_complete=True)</code> internally and finishes when EPICS reports put completion.</td>
53+
<td>A <code>Status</code> that completes on EPICS put completion.</td>
54+
</tr>
55+
</tbody>
56+
</table>
57+
58+
!!! info "How `put_complete` changes `set()`"
59+
- `put_complete=False`: "wait until the signal value reaches the requested target"
60+
- `put_complete=True`: "wait until EPICS says the write request has completed"
61+
62+
This can be useful for EPICS signals where the EPICS put-completion callback is the right completion signal for the write.
63+
64+
## What it does not change
65+
66+
`put_complete` changes how `set()` finishes, but it does not change the role of `put()`.
67+
68+
Even when `put_complete=True` is enabled on the signal:
69+
70+
- `put()` still performs a direct write
71+
- `put()` still returns immediately
72+
- `put()` still does not return a `Status`
73+
74+
That is why `set()` remains the normal ophyd API when the caller needs structured completion tracking.
75+
76+
!!! info "What to remember"
77+
- `put_complete` is an `EpicsSignal` option that changes how `set()` decides the write is finished.
78+
- With `put_complete=False`, `set()` waits for the readback to reach the target.
79+
- With `put_complete=True`, `set()` finishes when EPICS reports put completion.
80+
- `put_complete` does not turn `put()` into a completion-tracked API: `put()` still writes directly and returns immediately.

docs/learn/devices/set-vs-put.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
related:
3+
- title: Introduction to ophyd
4+
url: learn/devices/introduction-to-ophyd.md
5+
- title: Change Config Signals from the BEC IPython Client
6+
url: how-to/devices/change-config-signals-from-the-bec-ipython-client.md
7+
- title: EPICS put completion
8+
url: learn/devices/epics-put-completion.md
9+
---
10+
11+
# `set()` vs `put()` in `ophyd`
12+
13+
In ophyd, both `set()` and `put()` can write a new value to a writable signal, but they serve different purposes.
14+
15+
The short version is:
16+
17+
- use `put()` for a direct low-level write
18+
- use `set()` when you want a write operation with completion tracking
19+
20+
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.
21+
22+
## What `put()` does
23+
24+
`put()` is the low-level write method on a signal.
25+
26+
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.
27+
28+
`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()`.
29+
30+
Typical uses of `put()` include:
31+
32+
- updating a soft signal inside device implementation code
33+
- writing trigger-like signals that should be pushed directly
34+
- direct signal writes where completion tracking is not needed or not meaningful
35+
36+
Example:
37+
38+
```python
39+
my_signal.put(5)
40+
```
41+
42+
## What `set()` does
43+
44+
`set()` is the higher-level write method.
45+
46+
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.
47+
48+
Example:
49+
50+
```python
51+
status = my_signal.set(5)
52+
status.wait()
53+
```
54+
55+
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.
56+
Under the hood, `set()` uses `put()` to perform the actual write, but it adds the completion tracking layer on top.
57+
58+
## The practical difference
59+
60+
The key difference is the API contract:
61+
62+
<table>
63+
<colgroup>
64+
<col style="width: 20%;">
65+
<col style="width: 80%;">
66+
</colgroup>
67+
<thead>
68+
<tr>
69+
<th>Method</th>
70+
<th>Behavior</th>
71+
</tr>
72+
</thead>
73+
<tbody>
74+
<tr>
75+
<td style="white-space: nowrap;"><code>put()</code></td>
76+
<td>Perform a direct write. No <code>Status</code> object is returned.</td>
77+
</tr>
78+
<tr>
79+
<td style="white-space: nowrap;"><code>set()</code></td>
80+
<td>Perform a write operation with completion tracking and return a <code>Status</code>.</td>
81+
</tr>
82+
</tbody>
83+
</table>
84+
85+
That means the choice is usually driven by what the caller needs:
86+
87+
- If you only need to publish or write a value, `put()` is often enough.
88+
- If the caller needs to wait until the operation is done, use `set()`.
89+
90+
## How `set()` decides it is done
91+
92+
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.
93+
94+
This is why `set()` is often described as a write-and-wait operation rather than just a write.
95+
96+
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).
97+
98+
99+
## Choosing between them
100+
101+
In practice, the choice is simple:
102+
103+
- use `put()` when you only need to write a value
104+
- use `set()` when the caller needs a `Status` and clear completion semantics
105+
106+
!!! info "What to remember"
107+
- `put()` is the low-level write method for directly updating a signal value.
108+
- `set()` is the higher-level write method that returns a `Status` so callers can wait for completion.
109+
- For a basic ophyd `Signal`, `set()` writes the value and waits until the readback reaches the target.
110+
- If you are working with `EpicsSignal`, `put_complete` adds EPICS-specific completion behavior for `set()`.

zensical.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,12 @@ nav = [
118118
{ "Managing YAML Configs" = "learn/devices/managing-yaml-configs.md" },
119119
{ "EPICS Motor Variants" = "learn/devices/epics-motors.md" },
120120
{ "EPICS Signal Variants" = "learn/devices/epics-signals.md" },
121+
{ "set() vs put()" = "learn/devices/set-vs-put.md" },
121122
] },
122123
{ "Development" = [
123124
{ "Pseudo Positioners" = "learn/devices/pseudo-positioners.md" },
124125
{ "BEC Signals" = "learn/devices/bec-signals.md" },
126+
{ "EPICS put completion" = "learn/devices/epics-put-completion.md" },
125127
{ "Simulated Devices" = "learn/devices/simulated-devices.md" },
126128
] },
127129
] },

0 commit comments

Comments
 (0)