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 longcaput
orcaget
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 (intime.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 unlessthrow=False
has been set.throw
This parameter determines the behaviour of
caget
,caput
, andconnect
when an error occurs. Ifthrow=True
(the default) is set then an exception is raised, otherwise ifFalse
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 typewait – 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:
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:
- 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 formatdatatype – Override
Datatype
to a non-native typeformat – Request extra
Format
fieldscount – Request a specific element
Count
in an arrayall_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 routineconnect_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.
- 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.
- 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.
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
- 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 valuesok
is always set toTrue
.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:
- 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 associateddtype
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 fromcaget
, and may be raised as an exception to report a data error on caget or caput with wait.
The following ECA error codes from epicscorelibs.ca.cadef
are worth noting:
ECA_SUCCESS
Success error code. In this case
.ok
isTrue
. Returned by successfulcaput
andconnect
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
andcamonitor
this controls the format of the data that will be requested, while forcaput
the data will be coerced into the requested format.datatype
can be any of the following:None
(the default). In this case the “native” datatype provided by the channel will be returned.A
Dbr
value. See items 5 onwards for details of the special values.A python type compatible with any of the above values, such as
int
,float
orstr
. These correspond toDBR_LONG
,DBR_DOUBLE
andDBR_STRING
respectively.Any
numpy.dtype
compatible with any of the above values.One of the special values
DBR_CHAR_STR
,DBR_CHAR_UNICODE
, orDBR_CHAR_BYTES
. This is used to request a char array which is then converted to a Pythonstr
orbytes
string on receipt. It is not sensible to specifycount
with this option. The optionsDBR_CHAR_BYTES
andDBR_CHAR_UNICODE
are meaningless and not supported forcaput
.Note that if the PV name ends in
$
anddatatype
is not specified thenDBR_CHAR_STR
will be used.The special value
DBR_ENUM_STR
, only forcaget
andcamonitor
. In this case the “native” channel datatype is used unless the channel is an enumeration, in which case the corresponding string is returned.For
caget
andcamonitor
two further special values are supported. In both of these casesformat
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 andDBR_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
orcamonitor
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
andDatatype
of the pv, and if the operation was successful.Every value has the
ok
andname
fields.If
ok
is False thenerrorcode
is set to the appropriate ECA error code and str(value) will return an appropriate error message.If
ok
is True thendatatype
andelement_count
will be present.If FORMAT_TIME is requested then
status
,severity
,timestamp
andraw_stamp
will be presentIf FORMAT_CTRL is requested then
status
andseverity
will be present, along with otherDbr
specific fields:DBR_SHORT, DBR_CHAR, DBR_LONG will also have
units
,upper_disp_limit
,lower_disp_limit
,upper_alarm_limit
,lower_alarm_limit
,upper_warning_limit
,lower_warning_limit
,upper_ctrl_limit
,lower_ctrl_limit
DBR_FLOAT, DBR_DOUBLE will have the DBR_LONG fiels together with a
precision
fieldDBR_ENUM will have
enums
DBR_STRING does not support FORMAT_CTRL, so FORMAT_TIME data is returned instead
- 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).
- datetime: datetime#
This is a dynamic property which returns
timestamp
as adatetime
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.
- 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.
- 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
- 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
valueTo 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
- 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]