aioca API#

Common Notes#

All four functions take an argument pv which can specify the name of a single PV or can be a list of PVs. In all cases the returned result has the same “shape” as the pv argument, in other words, if pv is a single string then a single value (error code, value, or subscription) is returned, and if pv is a list then a list of exactly the same length is returned.

In general there are advantages to calling caput, caget or connect on a list of PVs, as in this case the channel connection and access delays will occur in parallel.

Several arguments are common through this API: throw determines how errors are handled, timeout determines timeouts, and finally datatype, format and count determine data formats and are documented in Augmented Values.

timeout

The timeout argument specified how long caput or caget will wait for the entire operation to complete. This timeout is in seconds, and can be one of several formats: a timeout interval in seconds, an absolute deadline (in time.time format) as a single element tuple, or None to specify that no timeout will occur. Note that a timeout of 0 will timeout immediately if any waiting is required.

If a timeout occurs then a CANothing will be raised unless throw=False has been set.

throw

This parameter determines the behaviour of caget, caput, and connect when an error occurs. If throw=True (the default) is set then an exception is raised, otherwise if False is specified an error code value is returned for each failing PV.

Functions#

async aioca.caput(pv: str, value, datatype: Datatype = None, wait: bool = False, timeout: Timeout = 5.0, throw: bool = True) CANothing[source]#
async aioca.caput(pvs: List[str] | Tuple[str, ...], values, repeat_value: bool = ..., datatype: Datatype = None, wait: bool = False, timeout: Timeout = 5.0, throw: bool = True) List[CANothing]

Writes values to one or more PVs

If a list of PVs is given, then normally value will have the same length and value[i] is written to pv[i]. If value is a scalar or repeat_value=True then the same value is written to all PVs.

Parameters:
  • repeat_value – If True and a list of PVs is given, write the same value to every PV.

  • datatype – Override Datatype to a non-native type

  • wait – Do a caput with callback, waiting for completion

  • timeout – After how long should a caput with wait=True Timeout

  • throw – If False then return CANothing instead of raising an exception

Returns:

CANothing for single PV or [CANothing] for a list of PVs

The return value from caput is either a list or a single value, depending on the shape of pv. For each PV a CANothing success code is returned on success, otherwise either an exception is raised or an appropriate error code is returned for each failing PV if throw=True is set. The return code can be tested for boolean success, so for example it is possible to write:

if not caput(pv, value, throw=False):
    # process caput error

If all the PVs listed in pv have already been connected, through a successful call to any aioca method, then the library guarantees that the puts for each PV will occur strictly in sequence. For any PVs which need a connection to be established the order of execution of puts is completely undefined.

async aioca.caget(pv: str, datatype: Datatype = None, format: Format = 0, count: Count = 0, timeout: Timeout = 5.0, throw: bool = True) AugmentedValue[source]#
async aioca.caget(pvs: List[str] | Tuple[str, ...], datatype: Datatype = None, format: Format = 0, count: Count = 0, timeout: Timeout = 5.0, throw: bool = True) List[AugmentedValue]

Retrieves an AugmentedValue from one or more PVs.

Parameters:
  • datatype – Override Datatype to a non-native type

  • format – Request extra Format fields

  • count – Request a specific element Count in an array

  • timeout – After how long should caget Timeout

  • throw – If False then return CANothing instead of raising an exception

Returns:

AugmentedValue for single PV or [AugmentedValue] for a list of PVs

The various arguments control the behaviour of caget as follows:

datatype, format, count

See documentation for Augmented Values below.

timeout, throw

Documented in Common Notes above. If a value cannot be retrieved and throw=False is set then for each failing PV an empty value with .ok==False is returned.

The format of values returned depends on the number of values requested for each PV. If only one value is requested then the value is returned as a scalar, otherwise as a numpy array.

aioca.camonitor(pv: str, callback: Callable[[Any], None | Awaitable], events: Dbe = None, datatype: Datatype = None, format: Format = 0, count: Count = 0, all_updates: bool = False, notify_disconnect: bool = False, connect_timeout: Timeout = None) Subscription[source]#
aioca.camonitor(pv: List[str] | Tuple[str, ...], callback: Callable[[Any, int], None | Awaitable], events: Dbe = None, datatype: Datatype = None, format: Format = 0, count: Count = 0, all_updates: bool = False, notify_disconnect: bool = False, connect_timeout: Timeout = None) List[Subscription]

Create a subscription to one or more PVs

Parameters:
  • callback – Regular function or async function

  • events – Bit-wise or of Dbe types to notify about. If not given the default mask depends on the requested format

  • datatype – Override Datatype to a non-native type

  • format – Request extra Format fields

  • count – Request a specific element Count in an array

  • all_updates – If True then every update received from channel access will trigger a callback, otherwise any updates received during the previous callback will be merged into the most recent value, incrementing Subscription.dropped_callbacks

  • notify_disconnect – If True then IOC disconnect events will be reported by calling the callback with a CANothing error with .ok False, otherwise only valid values will be passed to the callback routine

  • connect_timeout – If specified then the camonitor will report a disconnection event after the specified interval if connection has not completed by this time. Note that this notification will be made even if notify_disconnect is False, and that if the PV subsequently connects it will update as normal.

Returns:

Subscription for single PV or [Subscription] for a list of PVs

For a single pv callbacks will be called as:

callback(value)

for each update where value is an AugmentedValue. For a list of pvs then each update is called as:

callback(value, index)

where index is the position in the original array of pvs of the name generating this update.

If an async function as passed as a callback, then it will be awaited and no further callbacks will be run for this particular Subscription until this completes. This can be useful in conjunction with the default all_updates=False for running periodic updating code like:

async def about_once_a_second(value):
    do_something_with(value)
    await asyncio.sleep(1)

camonitor(pv, callback=about_once_a_second)

Note

If you have the choice between sync and async functions (like asyncio.Queue.put_nowait vs asyncio.Queue.put on an unbounded Queue) then choose the sync option for better performance

Subscriptions will remain active until the close() method is called on the returned subscription object:

class aioca.Subscription[source]#

A Subscription object wraps a single channel access subscription, and notifies all updates through an event queue.

dropped_callbacks: int#

The number of updates that have been dropped as they happened while another callback was in progress

close(exc_info=None) None[source]#

Closes the subscription and releases any associated resources. Note that no further callbacks will occur on a closed subscription, not even callbacks currently queued for execution.

async aioca.connect(pv: str, wait: bool = True, timeout: Timeout = 5.0, throw: bool = True) CANothing[source]#
async aioca.connect(pv: List[str] | Tuple[str, ...], wait: bool = True, timeout: Timeout = 5.0, throw: bool = True) List[CANothing]

Establishes a connection to one or more PVs

A single PV or a list of PVs can be given. This does not normally need to be called, as the ca…() routines will establish their own connections as required, but after a successful connection we can guarantee that caput(…, wait=False) will complete immediately without suspension.

This routine can safely be called repeatedly without any extra side effects.

Parameters:
  • wait – If False then queue a connection without waiting for completion

  • timeout – After how long should the connect with wait=True Timeout

  • throw – If False then return CANothing instead of raising an exception

Returns:

CANothing for single PV or [CANothing] for a list of PVs

async aioca.cainfo(pv: str, wait: bool = True, timeout: Timeout = 5.0, throw: bool = True) CAInfo[source]#
async aioca.cainfo(pv: List[str] | Tuple[str, ...], wait: bool = True, timeout: Timeout = 5.0, throw: bool = True) List[CAInfo]

Returns a CAInfo structure for the given PVs.

See the documentation for connect() for details of arguments.

class aioca.CAInfo[source]#

Object representing the information returned from cainfo

state_strings = ['never connected', 'previously connected', 'connected', 'closed']#

Converts state into a printable description of the connection state.

datatype_strings = ['string', 'short', 'float', 'enum', 'char', 'long', 'double', 'no access']#

Textual descriptions of the possible channel data types, can be used to convert datatype into a printable string

ok: bool#

True iff the channel was successfully connected

name: str#

The name of the PV

state: int#

State of channel as an integer. Look up state_strings[state] for textual description.

host: str#

Host name and port of server providing this PV

read: bool#

True iff read access to this PV

write: bool#

True iff write access to this PV

count: int#

Data count of this channel

datatype: int#

Underlying channel datatype as Dbr value. Look up datatype_strings[datatype] for textual description.

The str representation of this structure can be printed to produce output similar to that produced by the cainfo command line tool.

It is possible to test whether a channel has successfully connected without provoking suspension by calling cainfo(pv, wait=False) and testing the .state attribute of the result.

All of the above functions will make a connection to a channel which is cached for future calls. If you need to clear this cache (e.g. in tests) you can call:

aioca.purge_channel_caches()#

Remove cached channel connections. This will close all subscriptions

All the async functions in the aioca interface can be run under the asyncio event loop. A convenience function is provided to do this:

aioca.run(coro, forever=False)[source]#

Convenience function that makes an event loop and runs the async function within it.

Parameters:

forever – If True then run the event loop forever, otherwise return on completion of the coro

class aioca.ChannelInfo[source]#

Information about a particular Channel

name#

Process Variable name the Channel is targeting

Type:

str

connected#

True if the Channel is currently connected

Type:

bool

subscriber_count#

Number of clients subscribed to this Channel

Type:

int

aioca.get_channel_infos() List[ChannelInfo][source]#

Return information about all Channels

Working with Values#

There are two types of values returned by aioca functions: Augmented Values and Error Code Values. The caput function only returns an error code value (which may indicate success), while caget and camonitor will normally return (or deliver) augmented values, but will return (or deliver) an error code on failure.

The following fields are common to both types of value. This means that is is always safe to test value.ok for a value returned by caget or caput or delivered by camonitor.

ok

Set to True if the data is good, False if there was an error. For augmented values ok is always set to True.

name

Name of the pv.

Values and their Types#

The type of values returned by caget or delivered by camonitor callbacks is determined by the requested datatype in the original caget or camonitor call together with the underlying length of the requested EPICS field.

If the underlying length (element_count) of the EPICS value is 1 then the value will be returned as a Python scalar, and will be one of the three basic scalar types (string, integer or floating point number), but wrapped as an augmented type.

If on the other hand element_count is not 1 then the value is treated as an array and is always returned as a numpy array, again wrapped as an augmented type. Note that this means that even if caget(pv, count=1) is used to fetch a value with one element, if the underlying PV is an array then the result returned will be an array.

The table below enumerates the possibilities:

aioca type

Derived from

For these values

ca_str

str

String value

ca_int

int

Integral value

ca_float

float

Floating point value

ca_array

ndarray

Any array value

class aioca.ca_str#
class aioca.ca_int#
class aioca.ca_float#

Scalar types derived from basic Python types.

class aioca.ca_array#

Array type derived from numpy.ndarray. The associated dtype will be as close a fit to the underlying data as possible.

Error Code Values#

class aioca.CANothing(name: str, errorcode=1)[source]#

This value is returned as a success or failure indicator from caput, as a failure indicator from caget, and may be raised as an exception to report a data error on caget or caput with wait.

name: str#

Name of the PV

ok: int#

True for successful completion, False for error code

errorcode: int#

ECA error code

The following ECA error codes from epicscorelibs.ca.cadef are worth noting:

ECA_SUCCESS

Success error code. In this case .ok is True. Returned by successful caput and connect calls.

ECA_DISCONN

Channel disconnected. This is used by camonitor to report channel disconnect events.

ECA_TIMEOUT

Channel timed out. Reported if user specified timeout ocurred before completion and if throw=False specified.

Augmented Values#

Augmented values are normally Python or numpy values with extra fields: the .ok and .name fields are already mentioned above, and further extra fields will be present depending on format requested for the data. As pointed out above, .ok is always True for valid data.

Four different types of augmented value are returned: strings, integers, floating point numbers or arrays, depending on the length of the data requested – an array is only used when the data length is >1.

In almost all circumstances an augmented value will behave exactly like a normal value, but there are a few rare cases where differences in behaviour are observed (these are mostly bugs). If this occurs the augumentation can be stripped from an augmented value value by writing +value – this returns the underlying value.

The type of augmented values is determined both by parameters passed to caget and camonitor and by the underlying datatype. Both of these functions share parameters datatype, format and count which can be used to control the type of the data returned:

datatype

For caget and camonitor this controls the format of the data that will be requested, while for caput the data will be coerced into the requested format. datatype can be any of the following:

  1. None (the default). In this case the “native” datatype provided by the channel will be returned.

  2. A Dbr value. See items 5 onwards for details of the special values.

  3. A python type compatible with any of the above values, such as int, float or str. These correspond to DBR_LONG, DBR_DOUBLE and DBR_STRING respectively.

  4. Any numpy.dtype compatible with any of the above values.

  5. One of the special values DBR_CHAR_STR, DBR_CHAR_UNICODE, or DBR_CHAR_BYTES. This is used to request a char array which is then converted to a Python str or bytes string on receipt. It is not sensible to specify count with this option. The options DBR_CHAR_BYTES and DBR_CHAR_UNICODE are meaningless and not supported for caput.

    Note that if the PV name ends in $ and datatype is not specified then DBR_CHAR_STR will be used.

  6. The special value DBR_ENUM_STR, only for caget and camonitor. In this case the “native” channel datatype is used unless the channel is an enumeration, in which case the corresponding string is returned.

  7. For caget and camonitor two further special values are supported. In both of these cases format is ignored:

    aioca.DBR_STSACK_STRING#

    Returns the current value as a string together with extra fields status, severity, ackt, acks.

    aioca.DBR_CLASS_NAME#

    Returns the name of the “enclosing interface”, typically the record type, and typically the same as the EPICS .RTYP field.

    For caput also two further values are supported:

    aioca.DBR_PUT_ACKT#
    aioca.DBR_PUT_ACKS#

    These are used for global alarm acknowledgement, where DBR_PUT_ACKT configures whether alarms need to be acknowleged and DBR_PUT_ACKS acknowledges alarms of a particular severity.

format

The Format controls how much auxilliary information will be returned with the retrieved data.

count

The Count determines how many elements to fetch for arrays

class aioca.types.AugmentedValue(*args, **kwargs)[source]#

Protocol representing a value returned from caget or camonitor

The value itself depends on the number of values requested for the PV. If only one value is requested then the value is returned as a scalar, otherwise as a numpy array.

The value will also be “augmented” with extra fields depending on the Format and Datatype of the pv, and if the operation was successful.

Every value has the ok and name fields.

If ok is False then errorcode is set to the appropriate ECA error code and str(value) will return an appropriate error message.

If ok is True then datatype and element_count will be present.

If FORMAT_TIME is requested then status, severity, timestamp and raw_stamp will be present

If FORMAT_CTRL is requested then status and severity will be present, along with other Dbr specific fields:

acks: int#

Used for global alarm acknowledgement. The highest alarm severity to acknowledge. If the current alarm severity is less then or equal to this value the alarm is acknowledged.

ackt: int#

Used for global alarm acknowledgement. Do transient alarms have to be acknowledged? (0,1) means (no, yes).

datatype: int#

Underlying Dbr code

datetime: datetime#

This is a dynamic property which returns timestamp as a datetime value, taking local time into account

element_count: int#

Number of elements in the underlying EPICS value. If this is not 1 then the value is treated as an array, otherwise up to this many elements may be present in the value.

enums: List[str]#

Enumeration strings for ENUM type

errorcode: int#

ECA error code

lower_alarm_limit: float#

Below this limit value in alarm

lower_ctrl_limit: float#

Lower limit for puts to this value

lower_disp_limit: float#

Lower limit for displaying value

lower_warning_limit: float#

Below this limit is a warning

name: str#

Name of the PV used to create this value

ok: bool#

True for normal data, False for error code

precision: int#

Display precision for floating point values

raw_stamp: Tuple[int, int]#

Record timestamp in raw format as provided by EPICS (but in the local Unix epoch, not the EPICS epoch). Is a tuple of the form (secs, nsec) with integer seconds and nanosecond values, provided in case full ns timestamp precision is required.

severity: int#

EPICS alarm severity, normally one of the values listed below.

0

No alarm

1

Alarm condition, minor severity

2

Alarm condition, major severity.

3

Invalid value.

status: int#

CA status code, the reason for severity

timestamp: float#

Timestamp in seconds in format compatible with time.time() rounded to the nearest microsecond: for nanosecond precision use raw_stamp instead.

units: str#

Units for display

upper_alarm_limit: float#

Above this limit value in alarm

upper_ctrl_limit: float#

Upper limit for puts to this value

upper_disp_limit: float#

Upper limit for displaying value

upper_warning_limit: float#

Above this limit is a warning

aioca.types.Count#

How many array elements to retrieve from the server. One of the following

0

Server and data dependent waveform length

-1

The full data length

+ve int

A maximum of this number of elements

alias of Literal[0, -1] | int

aioca.types.Datatype#

The format of the requested data can be one of the following

None (the default)

In this case the “native” datatype provided by the channel will be returned

A Dbr value

To request this type from the IOC

A python type

Compatible with any of the above values, such as int, float or str

A numpy dtype

Compatible with any of the above values

alias of None | Literal[0, 1, 2, 3, 4, 5, 6, 35, 36, 37, 38, 996, 997, 998, 999] | Type

aioca.types.Dbe#

A bitwise or of DBE event codes from epicscorelibs.ca.dbr

DBE_VALUE

Trigger an event when a significant change in the channel’s value occurs. Relies on the monitor deadband field on the server

DBE_LOG

Trigger an event when an archive significant change in the channel’s value occurs. Relies on the archiver monitor deadband field on the server

DBE_ALARM

Trigger an event when the alarm state changes

DBE_PROPERTY

Trigger an event when a property change (control limit, graphical limit, status string, enum string …) occurs.

If not specified then the default value depends on the requested Format

Format

Default value for events

FORMAT_RAW

DBE_VALUE

FORMAT_TIME

DBE_VALUE | DBE_ALARM

FORMAT_CTRL

DBE_VALUE | DBE_ALARM | DBE_PROPERTY

alias of None | int

aioca.types.Dbr#

A DBR request code from epicscorelibs.ca.dbr. One of

DBR_STRING

40 character strings

DBR_SHORT

16 bit signed

DBR_FLOAT

32 bit float

DBR_ENUM

16 bit unsigned

DBR_CHAR

8 bit unsigned

DBR_LONG

32 bit signed

DBR_DOUBLE

64 bit float

DBR_PUT_ACKT

Configure global alarm acknowledgement

DBR_PUT_ACKS

Acknowledge global alarm

DBR_STSACK_STRING

Returns status ack structure

DBR_CLASS_NAME

Returns record type (same as .RTYP)

DBR_ENUM_STR

Enums as strings, default otherwise

DBR_CHAR_BYTES

Long byte strings as char arrays

DBR_CHAR_UNICODE

Long unicode strings as char arrays

DBR_CHAR_STR

Long strings as char arrays

alias of Literal[0, 1, 2, 3, 4, 5, 6, 35, 36, 37, 38, 996, 997, 998, 999]

aioca.types.Format#

How much auxilliary information will be returned with the retrieved data. From epicscorelibs.ca.dbr, one of the following

FORMAT_RAW

The data is returned unaugmented except for the .name field

FORMAT_TIME

The data is augmented by the data timestamp together with .alarm .status and .severity fields.

FORMAT_CTRL

The data is augmented by channel access “control” fields. This set of fields depends on the underlying datatype

alias of Literal[0, 1, 2]

aioca.types.Timeout#

A timeout is represented by one of the following

None

A timeout that never expires

0

Timeout immediately if any waiting is required

float

A relative timeout interval in seconds

(float,)

An absolute deadline in seconds past epoch

alias of None | Tuple[float] | float