Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Monitoring changes

Verified · pvmonitor.rs · demo_monitor.py · check docs_verify · docs-verify

The badge reports the whole docs-verify suite, not this chapter alone.

What you'll build

A subscription: one request, then updates pushed by the server for as long as you care to listen. This is what PVAccess is actually for — polling a PV in a loop is almost always the wrong answer.

Rust

#![allow(unused)]
fn main() {
    let client = PvaClient::builder().build();
    let cb = |value: &spvirit_codec::spvd_decode::DecodedValue| {
        println!("{value}");
        ControlFlow::Continue(())
    };
    let refs: Vec<&str> = fields.iter().map(String::as_str).collect();
    if let Some(q) = pipeline {
        client
            .pvmonitor_with_options(&pv, &refs, MonitorOptions::pipelined(q), cb)
            .await?;
    } else if fields.is_empty() {
        client.pvmonitor(&pv, cb).await?;
    } else {
        client.pvmonitor_fields(&pv, &refs, cb).await?;
    }
}

The callback returns a ControlFlow: Continue(()) to keep going, Break(()) to unsubscribe. pvmonitor runs until the callback breaks or the connection drops.

MonitorOptions::pipelined(q) asks the server for flow control with a queue depth of q — useful on high-rate PVs where a slow consumer would otherwise fall behind.

Python

client = spvirit.Client()

seen = 0


def on_update(value):
    global seen
    seen += 1
    print(f"{seen}: {value['value']:.3f}")
    return seen < 5  # returning False ends the monitor


client.monitor("SIM:TEMPERATURE", on_update)

client.monitor(...) blocks until the callback returns False or raises. For a non-blocking version use client.subscribe(...), which returns a Subscription you can close(), and which runs the callback on a background thread:

sub = client.subscribe("SIM:TEMPERATURE", on_update)
...
sub.close()

If a subscription ends on a network error, sub.error holds the message and sub.is_active becomes False — worth checking, because a silently dead subscription looks exactly like a quiet PV.

From the command line

$ spmonitor SIM:TEMPERATURE

What to notice

The first update is the current value. A subscription delivers the present state immediately, then changes. You do not need a GET before a monitor.

Monitors respect the record's MDEL. This is the single most useful thing on this page. A record with mdel=1.0 posts an update only when the value has moved at least 1.0 from the last posted value — not from the last set value. Writing 0.1, 0.2, 0.3, 5.0, 5.1, 5.2, 20.0 to such a PV delivers three updates:

posted to monitor: [0.0, 5.0, 20.0]

0.0 is the initial value on subscribe; 5.0 and 20.0 each cleared the deadband. The intermediate writes landed in the record — a GET would show 5.2 — they just were not broadcast.

MDEL defaults to 0, meaning no deadband. A record you never gave an mdel posts every change. On a 1 kHz PV with a hundred subscribers, that is a decision, so make it deliberately.

Severity changes always get through. The deadband is bypassed when the alarm severity changes, so a PV crossing into MAJOR is never silently swallowed by a large MDEL.

ADEL is not the same thing. ADEL is the archive deadband; it is parsed, stored, and served over field access, but PVAccess monitors use MDEL.

Deadbands are a record-level feature. A raw-NT source posting with put_nt has no MDEL to consult, and every post goes out. See Records vs raw NT.

Run it

# Terminal 1
python spvirit-py/examples/demo_scan.py

# Terminal 2
cargo run -p spvirit-client --example pvmonitor -- SIM:TEMPERATURE
# or
python spvirit-py/examples/demo_monitor.py
# or
spmonitor SIM:TEMPERATURE

demo_scan.py updates ten times a second, so terminal 2 fills immediately:

$ spmonitor SIM:TEMPERATURE
SIM:TEMPERATURE 2026-08-06 09:25:29.221 21.677613
SIM:TEMPERATURE 21.734644
SIM:TEMPERATURE 21.8092
SIM:TEMPERATURE 21.89275
SIM:TEMPERATURE 21.956506
SIM:TEMPERATURE 22.051046
SIM:TEMPERATURE 22.151852
SIM:TEMPERATURE 22.240413
SIM:TEMPERATURE 2026-08-06 09:25:30.028 22.347997
SIM:TEMPERATURE 22.440441
SIM:TEMPERATURE 22.534399
...

spmonitor prints the timestamp only on the first update of each wall-clock second — that is a display convenience, not a change in the data. Every update carries a full timestamp on the wire. Counting the lines between two timestamps is a quick way to see your actual update rate.

Stop it with Ctrl-C.

Next

Discovery and introspection.