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.0.tar.gz (20.1 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.0-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: capva-0.2.0.tar.gz
  • Upload date:
  • Size: 20.1 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.0.tar.gz
Algorithm Hash digest
SHA256 b22b810b13bc6e44b5a5d4d2231d5de7c5099ade088aa0b44ea131abaf4ec399
MD5 236b8305ee8132c84dfd59bb2d86baa7
BLAKE2b-256 90f3641a06ed4d8ac543d6cc2ea21e8df7b702ae590d05d38ab4f2084d5805c1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: capva-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.5 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4315a4cef62ed332f159e56e6b86404d2de7efee280d331293e6b85fae6ce1b6
MD5 cc1f30de2b58ae4c6a487ebbede1821d
BLAKE2b-256 e480c2fa26905192f903d5f87a945324201fd0bf73598484aa937470f100fa97

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