Skip to main content

EPICS PV client supporting both Channel Access and PV Access

Project description

capva

Unified Python client for EPICS PVs over Channel Access (CA) and PV Access (PVA).

capva wraps pyepics and p4p behind one API. Reads and monitors return a structured PVData model; JSON/Web payloads are built with PVData.to_dict() (optional base64 array encoding).

Developed from the weiss project — capva builds on that codebase and refactors the PV client layer into a standalone Python library with a unified CA/PVA API and structured PVData.

flowchart TB
  subgraph capva["capva — standalone PV client library"]
    api["PV, PVPool, tools"]
    prov["CA_PV, PVA_PV"]
    data["pv_parser, PVData"]
  end

  subgraph drivers["protocol drivers"]
    direction LR
    pyepics["pyepics (CA)"]
    p4p["p4p (PVA)"]
  end

  epics["EPICS IOC"]

  prov --> pyepics
  prov --> p4p
  pyepics --> epics
  p4p --> epics

Features

  • Single API for CA and PVA — One client for Channel Access and PV Access; capva picks the backend from the PV name so application code does not split into separate CA/PVA paths.
  • Unified PVData model — Every read returns the same structured snapshot (value, alarm, timeStamp, display, control, …). Monitor callbacks return value, alarm, and timeStamp by default.
  • Raw monitormonitor_raw() delivers a RawMonitorEvent with the driver payload unchanged (no parsing in the EPICS callback thread). Parse later with parse_raw_monitor_to_pvdata(), parse_raw_monitor_to_update_dict(), or parse_raw_monitor_to_metadata_dict() when your application is ready (ideal for high-concurrency gateways).
  • Public parser APIparse_raw_monitor_to_* helpers for deferred parsing from RawMonitorEvent. Lower-level CA/PVA parsers live in capva.pv_parser.
  • Public interfaces: PV, PVPool, and procedural tools — Use the object API for multi-step work on one connection, PVPool when several callers share a PV, or one-shot pvget / pvput / pvinfo / pvmonitor / pvmonitor_raw when a script only needs a single operation.
  • Reference-counted PVPoolgetPV / releasePV reuse one connection per PV name; the channel closes when the last reference is released.
  • Protocol prefixesca://… for Channel Access, pva://… for PV Access, or no prefix to default to CA.

Requirements

  • Python ≥ 3.10

Installation

From PyPI:

pip install capva

From a checkout (development):

pip install -e .

Quick start

Examples use pva://calcExample; switch to ca://… or a bare name (CA default) as needed.

Procedural API

import time

from capva import PVData, pvget, pvmonitor

PV_NAME = "pva://calcExample"

data = pvget(PV_NAME)
print(data.value)

def on_update(data: PVData) -> None:
    if data.is_disconnected():
        print(f"{data.pvName} disconnected")
    else:
        print(data.value)

session = pvmonitor(PV_NAME, on_update)
try:
    time.sleep(30)
finally:
    session.close()

Object API

import time

from capva import PV, PVData

PV_NAME = "pva://calcExample"

pv = PV(PV_NAME)
handle = None
try:
    data = pv.get()
    print(data.value)

    def on_update(data: PVData) -> None:
        if data.is_disconnected():
            print(f"{data.pvName} disconnected")
        else:
            print(data.value)

    handle = pv.monitor(on_update)
    time.sleep(30)
finally:
    if handle is not None:
        pv.clear_monitor(handle)
    pv.close()

Raw monitor (deferred parsing)

import time

from capva import PV, RawMonitorEvent, parse_raw_monitor_to_update_dict, parse_raw_monitor_to_metadata_dict

PV_NAME = "pva://calcExample"

pending = None

def on_raw(event: RawMonitorEvent):
    global pending
    pending = event

pv = PV(PV_NAME)
handle = pv.monitor_raw(on_raw)
try:
    time.sleep(1.0)
finally:
    pv.clear_monitor(handle)
    pv.close()

if pending is not None and not pending.disconnected:
    update = parse_raw_monitor_to_update_dict(pending)
    metadata = parse_raw_monitor_to_metadata_dict(pending)
    print(update["value"], metadata.get("display"))

PVPool

from capva import PVPool

PV_NAME = "pva://calcExample"

pv1 = PVPool.getPV(PV_NAME)
pv2 = PVPool.getPV(PV_NAME)
try:
    print(pv1 is pv2)  # same pooled instance
    print(pv1.get().value)
finally:
    PVPool.releasePV(pv1)
    PVPool.releasePV(pv2)

PVData.to_dict modes

mode Use case
"full" Complete snapshot (value, alarm, timeStamp, display, control, …)
"update" Monitor/Web push (value, alarm, timeStamp; metadata from parse_raw_monitor_to_metadata_dict when needed)
"metadata" display / control / valueAlarm only

Set base64_encode=True on "full" or "update" to emit b64arr / b64dtype instead of a numeric array value.

Project layout

src/capva/
  pv.py, pv_data.py      # Public PV + PVData model
  pv_parser.py           # CA/PVA → PVData
  monitor_raw.py         # RawMonitorEvent, parse_raw_monitor_to_* helpers
  tools.py               # pvget, pvput, pvinfo, pvmonitor
  pool.py                # PVPool
  providers/             # ca_pv, pva_pv
examples/
  tool_*.py              # Procedural tools (one-shot)
  pv_*.py                # PV class API
  pool_*.py              # PVPool (shared connections)
tests/                   # Unit tests (mocked; no IOC required)

Examples

Edit PV_NAME at the top of each script, then run against a real IOC:

# Procedural tools
python examples/tool_get.py
python examples/tool_info.py
python examples/tool_put.py
python examples/tool_monitor.py

# PV class
python examples/pv_get.py
python examples/pv_info.py
python examples/pv_put.py
python examples/pv_monitor.py
python examples/pv_monitor_raw.py

# PVPool
python examples/pool_get.py
python examples/pool_info.py
python examples/pool_put.py
python examples/pool_monitor.py

# Web JSON payload (wfExample waveform PV + Node.js)
python examples/encode_array.py
node examples/decode_array.js

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

capva-0.2.1.tar.gz (20.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

capva-0.2.1-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file capva-0.2.1.tar.gz.

File metadata

  • Download URL: capva-0.2.1.tar.gz
  • Upload date:
  • Size: 20.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.1

File hashes

Hashes for capva-0.2.1.tar.gz
Algorithm Hash digest
SHA256 c9e378a9e0d13e484eaf13a203e38fcec8d8f6636efedfb9c5ccd90b29f35ee6
MD5 d22d636d7138525f486ca43fae3f7168
BLAKE2b-256 64d24899cc55d39cf9760a48e87c5b148fc0d47cce06d73758f480905732fb82

See more details on using hashes here.

File details

Details for the file capva-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: capva-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.1

File hashes

Hashes for capva-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ae401e37a339bc374c2195904c95134dc20e45e387bea6e328150ecfd8e580fa
MD5 73dcd0d199cb3261d2bf69bbbc757d01
BLAKE2b-256 67cc1f74eacbc3b0443c4b38214826622ff82d681dbdfa164d36ca2b4234a501

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page