Run Multiple Transports Simultaneously#
This guide shows how to expose a fastcs driver through multiple protocols at once.
Basic Setup#
Pass a list of transports to FastCS:
from fastcs.control_system import FastCS
from fastcs.transports import (
EpicsCATransport,
GraphQLTransport,
RestTransport,
)
controller = MyController()
controller.set_path(["DEVICE"]) # PV prefix for EPICS / route prefix for REST
fastcs = FastCS(
controller,
[
EpicsCATransport(),
RestTransport(),
GraphQLTransport(),
]
)
fastcs.run()
All transports run concurrently, exposing the same controller API.
Choosing controller ids across transports#
Each transport derives its addressing from the controller’s id (the PV prefix for EPICS, the URL prefix for REST, the top-level Query field for GraphQL), and each enforces its own charset at startup.
Transport |
Allowed id charset |
|---|---|
EPICS CA |
|
EPICS PVA |
|
REST |
|
Tango |
|
GraphQL |
|
If you serve the same controller through multiple transports, use the
intersection — a leading letter or underscore followed by letters, digits and
underscores. GraphQL is the lowest common denominator: an id like dev-01
will start an EPICS or REST transport happily but fail fast when GraphQL is
added.
Available Transports#
Transport |
Protocol |
Install Extra |
Primary Use Case |
|---|---|---|---|
|
EPICS Channel Access |
|
Control system integration |
|
EPICS PV Access |
|
Modern EPICS with structured data |
|
Tango |
|
Tango control system |
|
HTTP REST |
|
Web applications, debugging |
|
GraphQL |
|
Flexible queries, web clients |
Install extras as needed:
pip install "fastcs[epicsca,rest,graphql]"
Transport Configuration#
Each transport has its own options:
EPICS Channel Access#
The PV prefix is the first segment of the controller’s path (set via
controller.set_path([...]) or auto-seeded by launch() from the YAML
entry’s id:).
from pathlib import Path
from fastcs.transports import (
EpicsCATransport,
EpicsDocsOptions,
EpicsGUIOptions,
)
epics_ca = EpicsCATransport(
gui=EpicsGUIOptions(
output_dir=Path("./opis"),
title="Device Control",
),
docs=EpicsDocsOptions(
output_dir=Path("./reference"),
),
)
EPICS PV Access#
from fastcs.transports import EpicsPVATransport
epics_pva = EpicsPVATransport()
REST#
from fastcs.transports import RestTransport
from fastcs.transports.rest import RestServerOptions
rest = RestTransport(
rest=RestServerOptions(
host="0.0.0.0",
port=8080,
log_level="info",
)
)
GraphQL#
from fastcs.transports import GraphQLTransport
from fastcs.transports.graphql import GraphQLServerOptions
graphql = GraphQLTransport(
graphql=GraphQLServerOptions(
host="localhost",
port=8081,
)
)
Tango#
from fastcs.transports import TangoTransport, TangoDSROptions
tango = TangoTransport(
tango=TangoDSROptions(
dsr_instance="MY_SERVER_INSTANCE",
),
)
The Tango device name for each controller is derived from its id —
{id}/{dev_class}/{dsr_instance}. The id forms the leading device-name
segment, so multiple controllers in one DSR get distinct device names.
EPICS CA + PVA Together#
Run both EPICS protocols simultaneously:
from pathlib import Path
from fastcs.transports import (
EpicsCATransport,
EpicsGUIOptions,
EpicsPVATransport,
)
controller.set_path(["DEVICE"])
fastcs = FastCS(
controller,
[
EpicsCATransport(
gui=EpicsGUIOptions(output_dir=Path("./opis")),
),
EpicsPVATransport(),
]
)
Both transports derive the same PV prefix from the controller’s id and expose identical PVs.
YAML Configuration#
When using the launch() framework, configure transports in YAML.
See Using the Launch Framework for details.