Skip to main content

A generic bridge between EPICS IOCs and Python logic.

Project description

EPICS Bridge

Python License

EPICS Bridge is a high-availability Python framework designed for implementing a robust EPICS-Python interface. It provides a structured environment for bridging external control logic with the EPICS control system, emphasizing synchronous execution, fault tolerance, and strict process monitoring.

This library addresses the common reliability challenges like preventing silent stalls ("zombie processes") and handling network IO failures deterministically.

System Architecture

The core of epics-bridge relies on a Twin-Thread Architecture that decouples the control logic from the monitoring signal.

1. Synchronous Control Loop (Main Thread)

The primary thread executes the user-defined logic in a strict, synchronous cycle:

  1. Trigger: Waits for an input event or timer.
  2. Run Task: Executes user-defined task
  3. Acknowledge: Updates the task status and completes the handshake.

2. Isolated Heartbeat Monitor (Daemon Thread)

A separate, isolated thread acts as an internal watchdog. It monitors the activity timestamp of the Main Thread.

  • Operational: Pulses the Heartbeat PV as long as the Main Thread is active.
  • Stalled (Zombie Protection): If the Main Thread hangs (e.g., infinite loop, deadlocked IO) for longer than the defined tolerance, the Heartbeat thread ceases pulsing immediately. This alerts external watchdogs (e.g., the IOC or alarm handler) that the process is unresponsive.

3. Automatic Recovery ("Suicide Pact")

To support containerized environments (Docker, Kubernetes) or systemd supervisors, the daemon implements a fail-fast mechanism. If network connectivity is lost or IO errors persist beyond a configurable threshold (max_stuck_cycles), the process voluntarily terminates (exit(0)). This allows the external supervisor to perform a clean restart of the service.

4. Logger

Output important messages in the daemon shell to a configured log file.

Installation

# Install the package
pip install .

# Install test dependencies
pip install -r requirements-test.txt

Project Structure

  • epics_bridge.daemon Main control loop, heartbeat logic, and failure handling

  • epics_bridge.io Synchronous P4P client wrapper with strict error handling

  • epics_bridge.base_pv_interface PV template definitions and prefix validation

  • epics_bridge.utils Utilities for converting P4P data into native Python types


Quick Start

1. EPICS Interface

There should be a standard epics db to handle the basic functionalities of the daemon and any amount of specialized dbs to fulfill the intended functionality.

The standard db should always be loaded by the IOC that interfaces with the daemon. These are its contents:

record(bo, "$(P)Trigger") {
    field(DESC, "Start Task")
    field(ZNAM, "Idle")
    field(ONAM, "Run")
}

record(bi, "$(P)Busy") {
    field(DESC, "Task Running Status")
    field(ZNAM, "Idle")
    field(ONAM, "Busy")
}

record(bi, "$(P)Heartbeat") {
    field(DESC, "Daemon Heartbeat")
}

record(mbbi, "$(P)TaskStatus") {
    field(DESC, "Last Cycle Result")
    field(DTYP, "Raw Soft Channel")

    # State 0: Success (Green)
    field(ZRVL, "0")
    field(ZRST, "Success")
    field(ZRSV, "NO_ALARM")

    # State 1: Logic Failure (Yellow - e.g. Interlock)
    field(ONVL, "1")
    field(ONST, "Task Fail")
    field(ONSV, "MINOR")

    # State 2: EPICS IO Failure (Yellow - e.g. PV Read/Write Error)
    field(TWVL, "2")
    field(TWST, "IO Failure")
    field(TWSV, "MINOR")

    # State 3: Exception (Red - Software/Hardware Crash)
    field(THVL, "3")
    field(THST, "Code Crash")
    field(THSV, "MAJOR")
}

record(ai, "$(P)TaskDuration") {
    field(DESC, "Task duration")
    field(PREC, "2")
    field(EGU,  "s")
}

2. Define a Python PV Interface

Use a dataclass to define EPICS PV templates. Standard PVs (trigger, busy, heartbeat, task_status) are provided automatically.

from dataclasses import dataclass
from epics_bridge.base_pv_interface import BasePVInterface

@dataclass
class MotorInterface(BasePVInterface):
    position_rbv: str = "{main}Pos:RBV"
    velocity_sp: str  = "{main}Vel:SP"
    temperature: str  = "{sys}Temp:Mon"

3. Implement Control Logic

Subclass BridgeDaemon and implement the synchronous execute() method.

from epics_bridge.daemon import BridgeDaemon, TaskStatus

class MotorControlDaemon(BridgeDaemon):
    def run_task(self, inputs=None) -> TaskStatus:
        velocity = self.io.pvget(self.interface.velocity_sp)

        if velocity is None:
            return TaskStatus.ERROR

        new_position = velocity * 0.5

        self.io.pvput({
            self.interface.position_rbv: new_position
        })

        return TaskStatus.DONE

4. Run the Daemon

def main():

    prefixes = {
        "main": "IOC:MOTOR:01:",
        "sys": "IOC:SYS:"
    }

    interface = MotorInterface(prefixes=prefixes)

    daemon = MotorControlDaemon(
        interface=interface,
    )

    daemon.start()

if __name__ == "__main__":
    main()

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

epics_bridge-1.0.1.tar.gz (15.3 kB view details)

Uploaded Source

Built Distribution

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

epics_bridge-1.0.1-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file epics_bridge-1.0.1.tar.gz.

File metadata

  • Download URL: epics_bridge-1.0.1.tar.gz
  • Upload date:
  • Size: 15.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for epics_bridge-1.0.1.tar.gz
Algorithm Hash digest
SHA256 dbda68b2a3de2c61e68c888d6cddf5562d45d3be317fef2724ff50118d0d5e1b
MD5 23e4c2c0fa0edbb27cdbe0f2efcc59d7
BLAKE2b-256 be8c1a3a19ad306e4a0631428915fa098bfdb6ddbcea7215bdda991fbdc3b68e

See more details on using hashes here.

File details

Details for the file epics_bridge-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: epics_bridge-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for epics_bridge-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e467c8f24c466642f2001cdad19b9e82b58ff41a3d4ca941959ba98cc60d7e1b
MD5 8f5a3a56a2c71e88e54029d2eff3fd28
BLAKE2b-256 1efcc178e10f07c24e1348566e7ce5333f3d1f7dcd29ca92a9b4fc373c38bd8a

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