Main Page | Features | Central Services | csv-Files | Types | Transfer | Access | API-C | API-.NET | API-Java | Examples | Downloads
page generated on 21.11.2024 - 04:45
Python API

The client and server interfaces for Python applications follow the Buffered Client and the Buffered Server paradigms. In addition, several utilities for browsing and for retrieving archived data, etc. are also available. These will be covered in the sections which follow.

Specifically these are:

Note that you should install the python tine library to the correct location for the python installed on your host machine. On a windows machine, make sure that PyTine.pyd is copied into the Python34\DLLs directory or possibly the Continuum\Anaconda3\DLLs directory. On Linux systems this will be a PyTine.so library (possibly PyTine.cpython-34m.so if you have an anacondo installation) and on MAC this will be a PyTine.dylib library. An up-to-date TINE installation on the relevant platform is also necessary.

Client API

On the client side, dedicated 'get' and 'set' calls generally allow for easy access to control system variables from python.
In their most basic forms, the calls appear to be 'transactional', which in fact they are for 'write' commands. 'get' calls generally start an asynchronous static listener (i.e. a local monitor) on the desired variable, which is then stored in a local buffer, thereby locally 'reflecting' the associated memory for the value(s) in question at the remote server. Thus, repeated 'get' calls merely retrieve the most recent updated value from the local buffer. The update rate can of course be influenced by the calling parameters. A 'get' call can likewise be constructed to in fact issue a synchronous transactional read request.

We shall expore these get calls in some detail below.

List of API Calls (details below)

  • PyTine.get gets the current value of the target address and property.
  • PyTine.stop_get will stop any underlying listening monitor associated with the given address and property.
  • PyTine.set sets value of the target address and property
  • PyTine.call will send the given input and retrieve the designated output to/from the target address and property in an atomic call.
  • PyTine.attach monitors the current value of the target address and property and calls the assocated callable Python function when an update arrives.
  • PyTine.detach detaches the monitor assocated with the given attached link handle.

PyTine.get (see also PyTine.attach)

With 'PyTine.get' you can access the current readback value of any targeted endpoint which contains readback data. If you import PyTine at the python command prompt and Simply type 'PyTine.get()' you will generate a syntax error exception, whose error message will remind you of the calling parameters.

>>> import PyTine
>>> PyTine.get()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.get(address='str',property='str'[,format='str',size=val,timeout=val,mode='str')
>>>

One sees that the API support 'key-value' input and that there is are only two required arguments, namely the target 'address' and target 'property'. Actually if you provide the property in the target address (appended inside brackets) then you can make the call with a single parameter. That is address = '/TEST/SineServer/SineGen0[Sine]' will suffice, in lieu of address = '/TEST/SineServer/SineGen0', property = 'Sine', although the latter makes a clearer distinction between 'where' and 'what'. If you use a GUI variant, then helper text is also available:

The parameter description is given in more detail below:

Parameters
addressis the initial parameter and must be a string of the form /<context>/<server>/<device>. This essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (for the target property as established by the targeted server) will be acquired. See below.
propertyis a string giving the desired property to be obtained from the target address. If the property is not 'static' then an asynchronous listener will be established updating the value every 1000 msec. No 'callbacks' events will be issued. It is assumed that the application will continue to issue the same read requests for its life cycle. If this is not the case, then after an idle period of 5 minutes without any subsequent 'read' requests on the same parameter will cause the listener to be canceled, thereby notifying the corresonding server that this client is no longer interested in the parameter.
format(string) is optional. If used it can specify the desired data acquisition format. If this is omitted, then the call will try to ascertain the default data output format. Make use of this parameter to override the default data type. Additionally, if it is known that a property has been multiply exported with different data types (i.e. overloaded) then this parameter can be used to determine which specific call is intended. This is often true in the case of structures. If a structure is wished for and the structure tag is known, then the property form of this parameter follows the paradigm: 'STRUCT.<tag>' (see example below. If the canonical data type is a structure, this parameter may be omitted, in which case the data structure will be 'discovered'.
size(optional integer) is the requested data size. Many servers prefer by default to deliver 'multi-channel' arrays of all elements of the desired property (for instance an array containing ALL vacuum pressures beginning at the index determined by the 'device name' input). If the application only needs a single value (or subset), the size can be used to specify the precise number of elements required.
timeout(optional integer) is the requested timeout (in milliseconds) which also determines the polling interval of the underlying 'listener', if an asynchronous listener is employed. By the default this is 1000 msec. If a faster update of the local buffers is desired, then this value may be adjusted accordingly. Note: if the the desired property is being 'scheduled' by the server, then the underlying listener will ALWAYS be updated 'immediately'. If the call needs to complete synchronously (e.g. some stock properties) then this value indeed specified a timeout which, if exceeded, can lead to a status error.
mode(optional string) can be used to give specific calling instructions, such as 'SYNC' (use a synchronous call, i.e. no listener) or 'CONNECT' (use a TCP connection instead of the default UDP).
Returns
the acquired data as a python dictionary object with keywords
  • 'status' giving the error/status code (which can be intepreted with strerror),
  • 'timestring' giving the UTC timestamp of the returned data as a string
  • 'timestamp' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • 'sysstamp' giving the system stamp assigned to the data (obtained from the CYCLER for the context accessed).
  • 'usrstamp' giving the user stamp assigned to the data (if any).
  • 'data' giving the returned data for the targeted property.
>>>
>>> d=PyTine.get(address='/TEST/SineServer/SineGen0',property='Amplitude')
>>> d
{'usrstamp': 0, 'data': [323.0, 278.29998779296875, 356.0, 256.0, 555.0, 256.0, 256.0, 256.0, 256.0, 256.0],
'timestamp': 1432913086.788, 'status': 0, 'sysstamp': 7294048, 'timestring': '29.05.15 17:24:46.788 CDT'}
>>>
>>> d['data']
[323.0, 278.29998779296875, 356.0, 256.0, 555.0, 256.0, 256.0, 256.0, 256.0, 256.0]
>>>

Notice in the above example that the dictionary will not print the returned object in any systematic order according to the keywords. However this is not an issue, as one simply uses a keyword to focus in on the value(s) in question. For example the print dump of d['data'] in the above example.

As noted above, in the case of structures, one can specify the 'known' structure type in the call to tine_read as shown:

>>> s1=PyTine.get(address='/TEST/SineServer/SineGen0',property='SineInfo',size=1,format='struct.SineInfo')
>>>
>>> s1
{'usrstamp': 0, 'data': {'noise': 25.600000381469727, 'frequency': 1.0, 'description': 'Sine Generator 0 at your disposal', 'amplitude': 323.0, 'phase': 0.0, 'damping': 10.0}, 'timestamp': 1432914218.206, 'status': 0, 'sysstamp': 7296263, 'timestring': '29.05.15 17:43:38.206 CDT'}
>>>

Note also in the above example that the 'data' field of the returned object is also represented as a dictionary whose keywords are the stucture fields. Should the structure be 'nested' then the 'data' field will likewise contain nested dictionaries.

If the structure type is unknown, it may be safely omitted, in which case it will be discovered. In the above example if we omit all optional parameters the call returns the 'registered' data size and type, in this case an array of 10 such structures:

>>> s=PyTine.get(address='/TEST/SineServer/SineGen0',property='SineInfo')
>>>
>>> s
{'usrstamp': 0, 'data': [{'noise': 25.600000381469727, 'frequency': 1.0, 'description': 'Sine Generator 0 at your disposal', 'amplitude': 323.0, 'phase': 0.0, 'damping': 10.0}, {'noise': 52.974998474121094, 'frequency': 1.0, 'description':'Sine Generator 1 at your disposal', 'amplitude': 278.29998779296875, 'phase': 0.0, 'damping': 25.0}, {'noise': 33.5, 'frequency': 1.0, 'description': 'Sine Generator 2 at your disposal', 'amplitude': 356.0, 'phase': 0.0, 'damping': 10.0},{'noise': 31.0, 'frequency': 1.0, 'description': 'Sine Generator 3 at your disposal', 'amplitude': 256.0, 'phase': 0.0, 'damping': 0.0}, {'noise': 30.0, 'frequency': 1.0, 'description': 'Sine Generator 4 at your disposal', 'amplitude': 555.0, 'phase': 0.0, 'damping': 50.0}, {'noise': 30.0, 'frequency': 1.0, 'description': 'Sine Generator 5 at your disposal', 'amplitude': 256.0, 'phase': 0.0, 'damping': 50.0}, {'noise': 30.0, 'frequency': 1.0, 'description': 'Sine Generator 6 at your disposal', 'amplitude': 256.0, 'phase': 0.0, 'damping': 50.0}, {'noise': 30.0, 'frequency': 1.0, 'description': 'Sine Generator 7 at your disposal', 'amplitude': 256.0, 'phase': 0.0, 'damping': 70.0}, {'noise': 30.0, 'frequency': 1.0, 'description': 'Sine Generator 8 at your disposal', 'amplitude': 256.0, 'phase': 0.0, 'damping': 80.0}, {'noise': 30.0, 'frequency': 1.0, 'description': 'Sine Generator 9 at your disposal', 'amplitude': 256.0, 'phase': 0.0, 'damping': 90.0}], 'timestamp': 1432913965.211, 'status': 0, 'sysstamp': 7295768, 'timestring': '29.05.15 17:39:25.210 CDT'}
>>>

As a final note: the format string given in the format parameter is case 'insensitive' with respect to the TINE format type. That it, 'struct' is identical to 'STRUCT', 'float' is identical to 'FLOAT'. However (and this is important) if a structure tag is appended to the format string 'struct' it is case 'sensitive'! That is 'SineInfo' is NOT the same as 'SINEINFO', etc. as far as structure tags are concerned. Also note further that the property being accessed is called 'SineInfo' as is the structure tag name. This is an unfortunate coincidence.

PyTine.stop_get

As noted, a call to PyTine.get is liable to start an asynchronous listener in order to locally reflect the targeted values from some server. Additional synchronous calls to PyTine.get with the same address parameters will object data from the local buffer. An asynchronous listener will stop listening following a dead-time of roughly five minutes without any additional calls to PyTine.get with the associated address parameters.

Under some circumstances this can result in an unwanted burden on network traffic and CPU load if the client application knows that it is no longer interested in the targeted values. For instance an combo box swithes to another device accessing a large waveform. In order to avoid waiting out the 5-minute deadtime, an application can proactively call PyTine.stop_get, with the same calling parameters as used in the original PyTine.get call. This will close the link to the underlying listener and the unnecessary extra network traffic and CPU load.

Simply typing 'PyTine.stop_get' at the python command prompt will generate a syntax exception with the following helper text:

>>> import PyTine as pt
>>> pt.stop_get()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.stop_get(address='str',property='str'[,input=obj,format='str',size=val,inputformat='str',inputsize=val)
>>>

PyTine.set

With 'PyTine.set' you can set the current target value of any targeted endpoint which allows WRITE access. Simply typing 'PyTine.set' at the python command prompt will generate a syntax exception with the following helper text:

>>> import PyTine
>>>
>>> PyTine.set()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.set(address='str',property='str'[,input=obj,format='str',size=val,timeout=val,mode='str')
>>>

Or within a python GUI environment such as IDLE you will see helper text when you type the method:

One sees that there are once again two primary required arguments, namely the target address and target property.

The parameter description is given in more detail below:

Parameters
addressis the initial parameter and must be a string of the form /<context>/<server>/<device>. This essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (for the target property as established by the targeted server) will be acquired. See below.
propertyis a string giving the desired property to be obtained from the target address. If the property is not 'static' then an asynchronous listener will be established updating the value every 1000 msec. No 'callbacks' events will be issued. It is assumed that the application will continue to issue the same read requests for its life cycle. If this is not the case, then after an idle period of 5 minutes without any subsequent 'read' requests on the same parameter will cause the listener to be canceled, thereby notifying the corresonding server that this client is no longer interested in the parameter.
input(python object) is optional. If omitted the the 'set' call is a simple command which calls the target property with WRITE access. Some propertys such as 'INIT', 'RESET', etc. may be simple commands which do not take or require input data. Otherwise the python object passed can be a single text, number, or dictionary (structure) value or an array of such.
format(string) is optional. If used it can specify the desired data input format. If this is omitted, then the call will try to ascertain the default data input format. Make use of this parameter to override the default data type.
size(optional integer) is the input data size, namely the number of elements to send to the target. Use this to override the size of the input array passed as the input argument.
timeout(optional integer) is the requested timeout (in milliseconds) which, if exceeded, can lead to a status error. Default = 1000 msec.
mode(optional string) can be used to give specific calling instructions, such as 'CONNECT' (use a TCP connection instead of the default UDP).
callback(optional callable python function) if passed to the set call this will effectively instruct PyTine.set to send the command asynchronously and return immediately. The results of the set operation are then posted in the callback function given.
Returns
void. Throws an exception if not successful.

Consider the simple task of setting some attribute, for instance the amplitude of a sine curve. Below we do this and read it back:

>>> PyTine.set(address='/TEST/SineServer/SineGen4',property='Amplitude',input=278)
>>>
>>> a=PyTine.get(address='/TEST/SineServer/SineGen4',property='Amplitude',size=1)
>>>
>>> a
{'usrstamp': 0, 'data': 278.0, 'timestamp': 1432916038.612, 'status': 0, 'sysstamp': 7299825, 'timestring': '29.05.15 18:13:58.611 CDT'}
>>>

Note: If a structure is to be sent, then the structure fields (at least as far as the data types and sizes are concerned) MUST be known a priori. Theoretically a call to PyTine.get() can be made to discover the structure data type (as long as it is known that the designated property supports the delivered structure data type also as an 'input' data type!). Or the appropriate list query call can be made to likewise determine and register the structure in the local application.

When one knows the structure fields, one can construct the dictionary object to send as input.

In the example below, we use the 'SineInfo' structure as input to set several attributes of a sine curve atomically:

>>> import PyTine as pt
>>> inf = {'amplitude': 323.0,'frequency':1,'noise':25,'phase':0,'damping':10,'description':'python altered description'}
>>>
>>> pt.set(address='/TEST/SineServer/SineGen0',property='SineInfo',input=inf)
>>>
>>> s=pt.get(address='/TEST/SineServer/SineGen0',property='SineInfo',size=1)
>>>
>>> s
{'timestring': '29.05.15 18:23:13.890 CDT', 'status': 0, 'data': {'damping': 10.0, 'noise': 25.0, 'amplitude': 323.0, 'description': 'python altered description', 'phase': 0.0, 'frequency': 1.0}, 'usrstamp': 0, 'timestamp': 1432916593.89, 'sysstamp': 7300912}
>>>

PyTine.call

With 'PyTine.call' you can atomically set and readback the current target value of any targeted endpoint which allows WRITE access.
You can also issue any READ call which requires input data.

Simply typing 'PyTine.call' at the python command prompt will generate a syntax exception the following helper text:

>>> import PyTine as pt
>>>
>>> pt.call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.call(address='str',property='str'[,input=obj,format='str',size=val,inputformat='str',inputsize=val,timeout=val,mode='str')
>>>

Or within a python GUI environment such as IDLE you will see helper text when you type the method:

One sees that there are once again two primary required arguments, namely the target address and target property. If these are the only two arguments supplied then PyTine.call() effectively is equivalent to PyTine.get().

The parameter description is given in more detail below:

Parameters
addressis the initial parameter and must be a string of the form /<context>/<server>/<device>. This essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (for the target property as established by the targeted server) will be acquired. See below.
propertyis a string giving the desired property to be obtained from the target address. If the property is not 'static' then an asynchronous listener will be established updating the value every 1000 msec. No 'callbacks' events will be issued. It is assumed that the application will continue to issue the same read requests for its life cycle. If this is not the case, then after an idle period of 5 minutes without any subsequent 'read' requests on the same parameter will cause the listener to be canceled, thereby notifying the corresonding server that this client is no longer interested in the parameter.
input(python object) is optional. If omitted the the 'set' call is a simple command which calls the target property with WRITE access. Some propertys such as 'INIT', 'RESET', etc. may be simple commands which do not take or require input data. Otherwise the python object passed can be a single text, number, or dictionary (structure) value or an array of such.
format(string) is optional. If used it can specify the desired data output format. If this is omitted, then the call will try to ascertain the default data output format. Make use of this parameter to override the default data type.
size(optional integer) is the output data size, namely the number of elements to receive from the target.
inputformat(string) is optional. If used it can specify the desired data input format. If this is omitted and format has been supplied, then the input data type is taken from the output format. If neither has been supplied then the call will try to ascertain the default data input format.
inputsize(optional integer) is the intput data size, namely the number of elements to send to the target. Use this to override the size of the input array passed as the input argument. The default value is 1 if an input object has been provided.
timeout(optional integer) is the requested timeout (in milliseconds) which, if exceeded, can lead to a status error. Default = 1000 msec.
mode(optional string) can be used to give specific calling instructions, such as 'CONNECT' (use a TCP connection instead of the default UDP) and in particular the data access mode, i.e. 'WRITE' for WRITE access. Simply OR all desired mode instructions (e.g. 'WRITE|CONNECT').
Returns
the acquired data as a python dictionary object with keywords
  • 'status' giving the error/status code (which can be intepreted with strerror),
  • 'timestring' giving the UTC timestamp of the returned data as a string
  • 'timestamp' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • 'sysstamp' giving the system stamp assigned to the data (obtained from the CYCLER for the context accessed).
  • 'usrstamp' giving the user stamp assigned to the data (if any).
  • 'data' giving the returned data for the targeted property.

And an example, here we issue an atomic 'WRITE/READ' where we set the 'Noise' of '/TEST/SineServer/SineGen3' to 31.
We specify the size as '1' so that the returned data only delivers the single value (as we know in advance that property 'Noise' is a multi-channel array property and by default will deliver all values):

>>> import PyTine as pt
>>> c=pt.call(address='/TEST/SineServer/SineGen3',property='Noise',input=31,size=1,mode='read|write')
>>>
>>> c
{'usrstamp': 0, 'timestring': '30.05.15 11:09:44.012 CDT', 'data': 31.0, 'timestamp': 1432976984.01279, 'sysstamp': 7419150, 'status': 0}
>>>

PyTine.attach

Besides making use of the underlying 'listeners' to monitor and reflect the data of targeted properties, you an also explicitly issue asynchronous data acquision by making use of PyTine.attach and providing a callback function. This has the advantage of responding immediately to a data update as opposed to synchronously polling within a python application. The monitor so established can also be instructed to notify on 'datachange' or even on 'event' (where the targeted server is explicity scheduling property data in order to avoid readback latency).

Simply typing 'PyTine.call' at the python command prompt will generate a syntax exception the following helper text:

>>> import PyTine as pt
>>>
>>> pt.attach()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.attach(address='str',property='str',callback=obj[,input=obj,format='str',size=val,inputformat='str',inputsize=val,interval=val,mode='str',id=val)
>>>

Or within a python GUI environment such as IDLE you will see helper text when you type the method:

One sees that there are here three primary required arguments, namely the target address and target property and a 'callable' python function, which should take (int,int,object) as arguments.

The parameter description is given in more detail below:

Parameters
addressis the initial parameter and must be a string of the form /<context>/<server>/<device>. This essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (for the target property as established by the targeted server) will be acquired. See below.
propertyis a string giving the desired property to be obtained from the target address. If the property is not 'static' then an asynchronous listener will be established updating the value every 1000 msec. No 'callbacks' events will be issued. It is assumed that the application will continue to issue the same read requests for its life cycle. If this is not the case, then after an idle period of 5 minutes without any subsequent 'read' requests on the same parameter will cause the listener to be canceled, thereby notifying the corresonding server that this client is no longer interested in the parameter.
callbackis a python 'callable' function which takes arguments (int id, int cc, Object data).
input(python object) is optional. If omitted the the 'set' call is a simple command which calls the target property with WRITE access. Some propertys such as 'INIT', 'RESET', etc. may be simple commands which do not take or require input data. Otherwise the python object passed can be a single text, number, or dictionary (structure) value or an array of such.
format(string) is optional. If used it can specify the desired data output format. If this is omitted, then the call will try to ascertain the default data output format. Make use of this parameter to override the default data type.
size(optional integer) is the output data size, namely the number of elements to receive from the target.
inputformat(string) is optional. If used it can specify the desired data input format. If this is omitted and format has been supplied, then the input data type is taken from the output format. If neither has been supplied then the call will try to ascertain the default data input format.
inputsize(optional integer) is the intput data size, namely the number of elements to send to the target. Use this to override the size of the input array passed as the input argument. The default value is 1 if an input object has been provided.
interval(optional integer) is the requested update interval (in milliseconds). Even in a DATACHANGE mode, this interval plays a role, as it instructs the targeted server 'how often it should look'.
mode(optional string) can be used to give specific calling instructions, such as 'CONNECT' (use a TCP connection instead of the default UDP) or 'NETWORK' (send as UDP multicast).
id(optional int) can be used to specify a desired callback 'id' (the first int argument in the provided callback routine). If this is not given, then id will always contain '0'.
access(optional string) can be used to specify the access of the contract (i.e. READ and/or WRITE. The standard default access is READ. If you apply the WRITE access as well the call to PyTine.attach reverts to a SINGLE transfer (as opposed to TIMER or DATACHANGE). The results of the operation are then posted in the given callback function.
Returns
the link id which can later be used to 'detach()' (i.e. stop monitoring).

When the callback routine is fired, the 'data' (third) argument passed will be a Python object which parallels the object returned from a PyTine.get() call. That is, the object will be a python dictionary containing:

  • 'status' giving the error/status code (which can be intepreted with strerror),
  • 'timestring' giving the UTC timestamp of the returned data as a string
  • 'timestamp' giving the UTC timestamp of the returned data as double (representing the number of seconds since January 1, 1970 with fractional seconds).
  • 'sysstamp' giving the system stamp assigned to the data (obtained from the CYCLER for the context accessed).
  • 'usrstamp' giving the user stamp assigned to the data (if any).
  • 'data' giving the returned data for the targeted property.

Consider the following example, which establishes a data link to get the beam current in PETRA:

Example:

>>> import PyTine as pt
>>>
>>> def cb(id,cc,d):
... print(d['timestring'])
... print(d['data'])
...
>>>
>>> lid=pt.attach(address='/PETRA/Idc/Buffer-0',property='I',callback=cb)
>>> 30.05.15 11:50:13.413 CDT
100.5762939453125
30.05.15 11:50:14.297 CDT
100.57471466064453
30.05.15 11:50:15.401 CDT
100.57176208496094
30.05.15 11:50:16.503 CDT
100.56889343261719
30.05.15 11:50:17.387 CDT
100.56660461425781
30.05.15 11:50:18.271 CDT
100.56481170654297
30.05.15 11:50:18.271 CDT
100.56481170654297
30.05.15 11:50:19.374 CDT
100.56138610839844
30.05.15 11:50:19.374 CDT

First a callback routine is declared (defined), which in this simple example just prints out the data timestamp as a string and the data when the callback is fired.
The monitor link is started and the returned link ID is kept in a global variable called 'lid'. The callback is then called regularly at 1 second intervals (because the default interval 1000 and the default mode TIMER have been used).

The monitor can be stopped by calling PyTine.detach() (here: 'pt.detach(lid)').

PyTine.detach

As noted above, a monitor link can be halted at any time by noting the link id returned from the initial monitor call and using it as argument to PyTine.detach().

The parameter description is given in more detail below:

Parameters
linkidis the link id returned from the PyTine.attach() call used to start the monitor.

PyTine.list PyTine.hist PyTine.strerror PyTine.version PyTine.debug

Browsing Utilities

Browing the control system for elements can generally be achieved by making use of PyTine.list().

PyTine.list

PyTine.list() can be called without arguments. That is all arguments are optional. The parameter description for PyTine.list is given below:

Parameters
contextis a string which identifies the targeted context.
serveris a string which identifies the targeted server. If server is provided as an argument then context must also be provided, otherwise a query to get the contexts will ensue.
deviceis a string which identifies the targeted device name. It might be necessary to provide this parameter for 'device oriented' servers, where different devices might have different associated properties.
propertyis a string which identifies the targeted property. It might be necessary to provide this parameter for 'property oriented' servers, where different properties might have different associated device names.
structureis a string which identifies the targeted structure tag for which the field names are desired. In general the context and server must likely be provided for a call to get the structure fields.

The top tier of the TINE naming hierarchy is the 'context'. To ascertain the available contexts within the control system, simply call 'PyTine.list()' without arguments.

A call to 'PyTine.list()' without arguments will return a list of all available contexts as a dictionary with the single keyword 'contexts'.

>>> import PyTine as pt
>>>
>>> pt.list()
{'contexts': ['HERA', 'SERVICE', 'TTF', 'LINAC2', 'DESY3', 'DORIS', 'PETRA', 'DESY2', 'SITE', 'TEST', 'TTF2', 'MHF', 'PITZ', 'LINAC3', 'FLASH', 'LINAC2.SIM', 'Common', 'HERA.SEDAC', 'LINAC2.TEST', 'DESY2.TEST', 'MKK', 'DORIS.EXT', 'DESY.TEST', 'PETRA2', 'PEX', 'LAB.TEST', 'HASYLAB', 'FLASH.TEST', 'MTF', 'PETRA.TEST', 'HASYLAB.TEST', 'HASYLAB.SIM', 'PETRA.EXT', 'PETRA.SIM', 'DESY2.SIM', 'FLASH.SIM', 'REGAE', 'Common.Test', 'REGAE.TEST', 'AMTF.TEST', 'Common.SIM', 'LAB', 'AMTF', 'GKSS', 'CMTB.TEST', 'LAB30', 'CMTB', 'SALOME', 'MVS', 'SFLASH', 'INTLK4_SYSTEMS', 'HARDWARE', 'MPS', 'TEST.TEST', 'XFEL.TEST', 'MSKLAB4', 'XFEL', 'XFEL.SIM', 'RF', 'MSKLAB2', 'ANGUS', 'ILC', 'DEX', 'XFEL2', 'MSKLAB3', 'HZG', 'CFEL.CMI','SERVICE.TEST', 'TEST.LABUDDA']}
>>>

The next tier of the TINE naming hierarchy is the device server (or device group). Note: a device 'group' can appear as a logical server in a list of device servers, when in fact it refers to a 'group' of physically distinct servers of a the same variety.

A call to 'PyTine.list()' with the context parameter only will return a list of available servers in the given context as a dictionary with the single keyword 'servers'.

>>> import PyTine as pt
>>>
>>> pt.list(context='REGAE')
{'servers': ['EVENTAPC', 'EVENTSTORE', 'EVENTS', 'Mag.Group.Corr', 'Mag.Corr', 'RegCanCorr', 'ARCHIVER', 'HISTORY', 'RGVAC.CDI', 'VAC.TPG', 'Mag.Group', 'VAC.TSP', 'VAC.SV', 'GLOBALS', 'VAC.ION_PUMP', 'ACCLXRGS03B.WATCH', 'RFRgModulator', 'RF.RgModulator.CDI', 'STATE', 'FECSTATS', 'CAS', 'CSSPY', 'ALARMSTATE', 'CAS.ARCHIVE', 'PiPrivCtrls_RegaeP', 'PiPrivCond_RegaeP', 'PiConditions', 'PiControls',
'OTR.SGP', 'OTR.JPEG', 'OTR.USC', 'WATER', 'ACCLXRGS03C.WATCH', 'MOTOR1', 'IOBOX.1', 'CameraIntensifier', 'RFRgModulatorMeta', 'LLRF_TIMER', 'MOTORBOX.2', 'CameraShutter', 'VAC.FRM', 'FaradayCup', 'LLRF.CTRL_UTCA', 'MOTORBOX.3', 'MOTORBOX.4', 'Laser.SGP', 'MOTORMBOX.1', 'Laser.USC', 'DaMon', 'CameraShutter1', 'CameraShutter2', 'CameraShutter3', 'DarkCurrent', 'ModulatorState', 'REGZYKHIST', 'REGAEZYKHIST', 'RgPiloProxy', 'RgWdwProxy', 'TempRe.CDI', 'CYCLER', 'Pilotherme_Rg','RgS02e1.CDI', 'TempRg', 'LLRF.SINCAV', 'Laser.JPEG', 'LUX.SGP.1', 'LUX.USC', 'LUX.R2J', 'LUX.SGP.2', 'Pulse.Data', 'LaserPulse', 'Spectrum', 'SEQUENCER', 'TIMER.3', 'TIMER']}
>>>

The next tier of the TINE naming hierarchy is the device name. Most servers are device servers with a flat hierarchy at this stage. By this we mean that they will provide a set of registered devices and a set of registered properties, and each property is supported by each device as well as each device supports all registered properties.

Thus a call to 'PyTine.list()' with both the context and a target server specified will return a list of the registered properties and devices of targeted server. Here the returned dictionary has a list of names for keyword 'devices' and a list of name for keyword 'properties':

>>> import PyTine as pt
>>>
>>> pt.list(context='PETRA',server='BLM')
{'devices': ['PU01I', 'PU01O', 'PU02I', 'PU02I_I', 'PU03O', 'PU03O_I', 'PU04I','PU04O', 'PU05I', 'PU06O', 'PU07I', 'PU07O', 'PU08I', 'PU09O', 'PU10I', 'PU10O', 'PU11I', 'PU12O', 'PU13I', 'PU14O', 'ColSWL015_O', 'ColSWL015_U', 'ColSWR015_O', 'ColSWR015_U', 'ScrSWR020_O', 'ScrSWR020_U', 'ScrSWR020_L', 'ScrSWR020_R', 'ColNOL015_O', 'ColNOL015_U', 'ColNOR04_O', 'ColNOR04_U'], 'properties': ['Mode', 'PreScaler', 'LossRates', 'Enabled', 'Status.Bits', 'Status', 'Timing', 'Reset']}
>>>

It is possible to register a server as a 'device-oriented' server, whereby it cannot be a-priori assumed that each device managed by the server supports the same list of properties. Likewise it is also possible to register a server as a 'property-oriented' server whereby each individual registered property might support its own independent set of 'keywords' (which then assume the role of 'device names'). This is typical of 'service-oriented' servers (e.g. Central Archive Server, or Central Alarm Server) and is definitely true of CDI servers.

If a call to 'PyTine.list()' with context and specified lands on such a server, then the returned dictionary will only contain the single keyword 'devices' if the server is device oriented or it will contain the single keyword 'properties'if the server is property oriented. To obtain the properties for a device, the 'PyTine.list()' call needs to be issued with a specific device entered. For instance, below a video server ('device oriented') is queried:

>>> import PyTine as pt
>>>
>>> pt.list(context='PETRA',server='MDI2_JPEG1')
{'devices': ['Server', 'Source', 'Output']}
>>>
>>> pt.list(context='PETRA',server='MDI2_JPEG1',device='Output')
{'properties': ['Header', 'Frame.Sched', 'Header.Sched', 'Format', 'Frame', 'FormatQuality', 'FormatParameter', 'SizeInOutPercent']}
>>>

To obtain the device list for a property from a property-oriented server, then 'PyTine.list()' call needs to be issued with a specific property. For instance, below a CDI server is queried:

>>> import PyTine as pt
>>>
>>> pt.list(context='PETRA',server='MOMO.CDI')
{'properties': ['RECV', 'ADC_Pointer-Hi', 'SEND.RECV.SEND.CLBR', 'BUSSCAN.NAM','INSTANCES', 'RANGE', 'SEND.SEND.ATOM', 'BUSTYPE', 'SEND', 'SEND.RECV.CLBR', 'ADC_Ram', 'UNITS', 'Mix8', 'ADC_FW', 'SEND.RECV.RECV.ATOM', 'PRECISION', 'BUSTYPES', 'RECV.RECV.CLBR', 'TEMPLATE.NAM', 'BUSDEVICES.NAM', 'ADC_Adder', 'RECV.SEND.ATOM', 'CDIVERSION', 'SEND.RECV.RECV.CLBR', 'NUMBER', 'CDIMF.DB', 'TEMPLATE', 'DISPLAYFORMAT', 'SEND.RECV.ATOM', 'LINESTATUS', 'DISPLAYSIZE', 'SEND.CLBR', 'ADC_Pointer-Lo', 'ADC_PointerWr', 'RECV.RECV.ATOM', 'BUSADDR', 'DESCRIPTION', 'NINSTANCES', 'CDISERV.DB', 'IDLE', 'BUSERRORS', 'RECV.SEND.CLBR', 'ADC_Adder-Lo', 'CDIADDR.DB', 'RECV.CLBR', 'BUSDEVICES', 'ADC_Adder-Hi', 'CDISCHED.DB', 'NINSTANCES.NAM', 'ADC_PointerRd', 'SEND.SEND.CLBR', 'SEND.RECV.SEND.ATOM', 'INSTANCES.NAM', 'BUSNAMES', 'BUSNAME', 'BUSSCAN']}
>>>
>>> pt.list(context='PETRA',server='MOMO.CDI',property='ADC_adder')
{'devices': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6']}
>>>

Archive Utilities

Many of the control system parameters will be archived and ready for retrievel and examination when called for.

Archived data can be stored 'centrally', where a range of filtering parameters might be in play (so as to reduce the amount of unnecessary data commited to disk). 'centrally' stored data are always availible and never expired.

Archive data can also be stored 'locally', where simpler filtering based on tolerances might be in play. 'locally' stored data are available only for a (configurable) duration, typically 1 to 3 months.

Archive data might be stored 'centrally' based on an 'event trigger'. This usually refers to 'post-mortem' events, such as an RF trip or unexpected beam loss, etc. Such data are managed differently than the regular trend archives descibed above. Event data generally have an associated event 'comment' (the reason why the event was triggered), which can be edited by 'experts' at any time. Event data are associated with a specific point in time and a specific trigger. Consequently retrieving archived event data is a bit more 'involved' than simple history trends of stored machine variables (see Event Archive Utilities below).

The primary python method for retrieving and analysizing archive data over time is PyTine.history().

PyTine.history

Simply typing 'PyTine.history()' at the command prompt will generate the 'usage' message shown below:

>>> import PyTine
>>>
>>> PyTine.history()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.hist(address='str',property='str'[,stop='str',depth='str',flags='str',timeout=val)
>>>

Or within a python GUI environment such as IDLE you will see helper text when you type the method:

One sees that there are once again two primary required arguments, namely the target address and target property.

The parameter description is given in more detail below:

Parameters
addressis the initial parameter and must be a string of the form /<context>/<server>/<device>. This essentially follows the TINE naming hierarchy. If NO other input parameters are given, the default 'read' data type and data size (for the target property as established by the targeted server) will be acquired. If data from the central archiver are to be obtained, then the 'server' in the address string should be 'HISTORY'.
propertyis a string giving the desired property to be obtained from the target address.
stop(optional string) gives the stop time to use in the data range of the archive call (default = 'Now'). The 'stop time' should be given in a string data format ('dd.mm.yyyy hh:mm:ss') or the string 'now' to refer to the current time.
depth(optional string) should begin with a number and be followed by a representative unit of time ('days','hours','minutes', etc.). (default = '1day'). The 'depth' can also be used to specify the acquisition of a data 'snapshot' (e.g. of a waveform or multi-channel array) at a particular time. Then the 'stop time' gives the desired time and 'depth' should contain the string 'snapshot'.
flags(optional string) is a string which can be used to supply archive acquisition options. For instance to retrieve the archived data system stamps along with the data and timestamps, then 'flags' = 'SYSTEMSTAMP' should be specified.
timeout(optional integer) is the requested timeout (in milliseconds) which, if exceeded, can lead to a status error. Default = 1000 msec.
sample(optinal integer) is the requested sampling raster. If '0' (default) then the target server will determine the best sampling raster to use in order to return representative data over the time range (stop time and depth) for the number of points requested (default = 1000). Every effort will be made to ensure that points of interest (e.g. spikes and dips) will be returned in the data. However, to be on the safe side you may want to specify the sampling raster (e.g. '1'), if all stored archive data are required. Note that the returned data will likely not cover the requested range, in which case the call should be repeated using the same stop time and a depth given by the \stop time minus the time of the last returned data point.
numberPoints(optional integer) is the requested number of returned data points (default = 1000). The returned number of archived data points will not exceed this number. You should decide what the goal of the archive history call is in deciding on the optimal number of points. If a simply plot of stored data over a range is desired, then the default settings for sample and numberPoints are most likely fine. If all stored data are required for a more extensive analysis, then perhaps a large numberPoints and a sample raster of '1' are optimal.

The example below shows a simple call to get the local history from a targeted server, specifying a depth of 8 hours.

>>> import PyTine as pt
>>>
>>> h=pt.history(address='/PETRA/Idc/Buffer-0',property='I',depth='8hours')
>>>
>>> h
[(100.16088104248047, 1433071642.3126984), (100.1563720703125, 1433071644.2986984), (100.15116119384766, 1433071646.2836983), (100.14693450927734, 1433071648.2726984), (100.14277648925781, 1433071650.2576983)]
>>>

As there is no long term storage, the call only returns a few points over this interval. The returned data are given in 'value-timestamp' pairs, where the timestamp is UTC seconds since 1970 (including fractional seconds). Making the same call again, but passing flags='SYSTEMSTAMP' will return an array of data 'triplets' containing 'value-timestamp-systemstamp' tuples.

>>> import PyTine as pt
>>>
>>> h=pt.history(address='/PETRA/Idc/Buffer-0',property='I',depth='8hours',flags='SYSTEMSTAMP')
>>>
>>> h
[(100.55929565429688, 1433071923.1276984, 433121708.0), (100.55653381347656, 1433071924.2326984, 433121714.0), (100.55467987060547, 1433071925.3356984, 433121721.0), (100.54900360107422, 1433071927.3236983, 433121734.0), (100.54425048828125, 1433071929.3116984, 433121746.0), (100.54147338867188, 1433071930.4146984, 433121753.0), (100.53712463378906, 1433071932.1816983, 433121765.0)]
>>>

A call to the central archiver might look like:

>>> import PyTine as pt
>>>
>>> h=pt.history(address='/PETRA/HISTORY/keyword',property='CurDC',depth='10minutes',flags='SYSTEMSTAMP')
>>>
>>>
>>> h
[(100.26112365722656, 1433071599.054698, 433119681.0), (100.24056243896484, 1433071608.106698, 433119737.0), (100.22010040283203, 1433071617.157698, 433119794.0), (100.19963836669922, 1433071625.981698, 433119849.0), (100.17849731445312, 1433071635.030698, 433119906.0), (100.15709686279297, 1433071644.078698, 433119962.0), (100.13603973388672, 1433071653.125698, 433120019.0), (100.11412048339844,1433071662.173698, 433120075.0), (100.09407806396484, 1433071670.999698, 433120131.0), (100.07147979736328, 1433071681.151698, 433120194.0), (100.05000305175781, 1433071690.200698, 433120250.0), (100.02851867675781, 1433071699.025698, 433120306.0), (100.00794982910156, 1433071708.073698, 433120362.0), (100.06372833251953, 1433071719.998698, 433120438.0), (100.14871978759766, 1433071721.986698, 433120450.0), (100.23856353759766, 1433071723.971698, 433120463.0), (100.33224487304688, 1433071726.178698, 433120476.0), (100.46665954589844, 1433071729.049698, 433120494.0), (100.56047821044922, 1433071731.037698, 433120507.0), (100.66224670410156, 1433071733.022698, 433120519.0), (100.76863861083984, 1433071735.008698, 433120532.0), (100.88715362548828, 1433071737.218698, 433120545.0), (100.9892349243164, 1433071740.087698, 433120563.0), (100.96807098388672, 1433071749.140698, 433120620.0), (100.94657135009766, 1433071757.973698, 433120676.0), (100.92382049560547, 1433071768.130698, 433120739.0), (100.9025650024414, 1433071777.183698, 433120795.0), (100.88214111328125, 1433071786.016698, 433120851.0), (100.86176300048828, 1433071794.186698, 433120901.0), (100.8414306640625, 1433071803.020698, 433120957.0), (100.81731414794922, 1433071813.173698, 433121020.0), (100.79691314697266, 1433071822.004698, 433121076.0), (100.77603149414062, 1433071831.056698, 433121132.0), (100.75334167480469, 1433071840.109698, 433121189.0), (100.73240661621094, 1433071849.162698, 433121245.0), (100.71087646484375, 1433071857.995698, 433121301.0), (100.6904067993164, 1433071867.047698, 433121357.0), (100.67037200927734, 1433071875.215698, 433121408.0), (100.64784240722656, 1433071885.154698, 433121470.0), (100.62753295898438, 1433071893.986698, 433121526.0), (100.60551452636719, 1433071903.033698, 433121582.0), (100.58477783203125, 1433071912.087698, 433121638.0), (100.56295013427734, 1433071921.141698, 433121695.0), (100.54257202148438, 1433071929.973698, 433121751.0), (100.5220718383789, 1433071939.025698, 433121807.0), (100.50088500976562, 1433071948.079698, 433121863.0),(100.47802734375, 1433071958.016698, 433121926.0), (100.45743560791016, 1433071967.070698, 433121982.0), (100.4339828491211, 1433071976.122698, 433122039.0), (100.4118423461914, 1433071986.054698, 433122101.0), (100.3902359008789, 1433071995.107698, 433122157.0), (100.3697280883789, 1433072004.161698, 433122214.0), (100.3486328125, 1433072012.995698, 433122270.0), (100.3272476196289, 1433072022.047698, 433122326.0), (100.30717468261719, 1433072031.101698, 433122382.0), (100.28593444824219, 1433072040.155698, 433122439.0), (100.26518249511719, 1433072048.989698, 433122495.0), (100.24400329589844, 1433072058.043698, 433122551.0), (100.2217025756836, 1433072065.990698, 433122601.0), (100.20166015625, 1433072074.158698, 433122651.0), (100.18148040771484, 1433072083.206698, 433122708.0), (100.16059112548828, 1433072092.032698, 433122764.0), (100.14013671875, 1433072101.081698, 433122820.0), (100.11965942382812, 1433072109.025698, 433122870.0), (100.09722137451172, 1433072119.177698, 433122933.0), (100.07508850097656, 1433072129.109698, 433122995.0), (100.0526123046875, 1433072138.157698, 433123052.0), (100.02921295166016, 1433072148.088698, 433123114.0), (100.00878143310547, 1433072157.131698, 433123170.0), (99.98725128173828, 1433072166.187698, 433123227.0), (100.01158905029297, 1433072170.164698, 433123252.0), (100.07632446289062, 1433072173.030698, 433123270.0), (100.13461303710938, 1433072175.017698, 433123283.0), (100.19831085205078, 1433072177.003698, 433123295.0), (100.26598358154297, 1433072178.989698, 433123308.0), (100.35281372070312, 1433072181.198698, 433123321.0), (100.53555297851562, 1433072185.172698, 433123346.0), (100.6556396484375, 1433072188.043698, 433123364.0), (100.74319458007812, 1433072190.030698, 433123376.0),
(100.82766723632812, 1433072192.239698, 433123389.0), (100.92707824707031, 1433072195.109698, 433123408.0)]
>>>

As an example of a 'snapshot', below shows the acquistion of the entire multi-channel array of beam loss monitor rates at PETRA for a specific time:

>>> import PyTine as pt
>>>
>>> h=pt.history(address='/PETRA/HISTORY/PU01I',property='BeamLoss',stop='30.5.2015 13:00:00',depth='snapshot')
>>>
>>> h
{'timestamp': '30.05.15 13:00:01.000 CDT', 'data': [146.0, 90.0, 26.0, 23.0, 0.0, 215.0, 38.0, 1.0, 18.0, 2.0, 12.0, 0.0, 10.0, 17.0, 20.0, 1.0, 17.0, 5.0, 13.0, 36.0, 2211.0, 3401.0, 1210.0, 853.0, 564.0, 3401.0, 313.0, 642.0, 1739.0, 1102.0, 333.0, 666.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'utc': 1432983601.0}
>>>

Note that the returned data will be the closest time (equal to or greater than) the specified target time.

Event Archive Utilities

You can also use python to easily interface with the TINE Post Mortem/Event Archive System. The following utilities are available in PyTine :

PyTine.triggerEvent

Use this call if you need to trigger an event from python.

Simply typing 'PyTine.triggerEvent()' at the command prompt will generate the 'usage' exception message shown below:

SyntaxError: PyTine.triggerEvent(context='str',event='str',[comment='str',triggerLevel=val,triggerTime=val,rangeStart=val,rangeStop=val,rangeMax=val,options=val])

The parameter description is given in more detail below:

Parameters
contextis the TINE context to which the event server receiving the trigger belongs.
eventis the event trigger name. The event trigger name defines the event. A call to triggerEvent signals the the event server to run through the data acquistion instructions related to the event identified by this trigger name. Ergo, this must be a known event, or this call will result in an invalid_index return code.
commentis an optional comment to be assigned to the event at the time of the trigger. This comment will be designated as 'static' and under most circumstances will not disappear if a user further annotates the event comment for this particular event.
triggerLevelis an optional trigger level (default = 1), which indicates which step in the event data acquistion should be taken as the initial step. A value of '-1' indicates that the event server should obtain a global event number for this particular event from the SITE event server.
triggerTimecan be used to optionally specify the UTC event id to be assigned to this event. Generally this will be the UTC value for now at the time of trigger, or a global value from the SITE event server. Under some circumstances a server might wish to e.g. collect data from hardware and post-assign a UTC time id to the event after the data have been taken.
rangeStartgives the input as a system stamp specification. A negative value or '0' signals the system to apply treat the rangeStart value as an offset to the provided 'triggerTime' as to use the input as a time stamp specification.
rangeStopprovides the end of a system-stamp (or time-stamp) range to use when obtaining data froma a server's local history. If rangeStop is less that rangeStart, then the value given is used as an increment to apply to the given rangeStart (with a maximum cutoff at 1000). In other words, if rangeStop < rangeStart then rangeStop = rangeStart + rangeStop.
rangeMaxprovides a maximum number of sequence entries to obtain over the range provided. A negative value will negate the range specifcations entirely. A value of '0' will signal the system to use a default maximum (typically = 100).
optionsprovides additional 'flags' to define trigger criteria. Currently, the only available option is EVNT_TRIGGER_USE_USERSTAMP which signals the event server to focus on the 'user' data stamp (and not the system stamp) in the range specifications.

As an example:

>>> import PyTine as pt
>>>
>>> pt.triggerEvent("TEST","sine_trigger_copy", "test triggered from pytine")
>>>

PyTine.getEventList

Use this call to obtain a list of stored events for the trigger specified.

Simply typing 'PyTine.getEventList()' at the command prompt will generate the 'usage' exception message shown below:

SyntaxError: PyTine.getEventList(context='str',event='str',[startTime='str',stopTime='str',limit=val])

The parameter description is given in more detail below:

Parameters
contextis the TINE context to which the event server receiving the trigger belongs.
eventis the event trigger name for which the event list is desired.
startTimeoptionally provides the beginning of the time range for which the event list is desired. If omitted, now minus one month will be used.
stopTimeoptionally provides the end of the time range for which the event list is desired. If omitted, now will be used.
limitoptionally provides the maximum number of events to retrieve. The returned list will be in descending order. If omitted, the limit will be '1' (i.e. the most recent stored event).

As an example:

>>> import PyTine as pt
>>> pt.getEventList("TEST","sine_trigger_copy")
>>>
{'event': 'sine_trigger_copy', 'events': [{'id': 1592490377, 'time': '18.06.20 16:26:17.000 CDT'}], 'context': 'TEST'}
>>>
>>> pt.getEventList("TEST","sine_trigger_copy","10.12.2019 19:00:00", "NOW", limit=10)
>>>
{'event': 'sine_trigger_copy', 'events': [
{'time': '18.06.20 16:26:17.000 CDT', 'id': 1592490377}, {'time': '18.06.20 15:34:25.000 CDT', 'id': 1592487265},
{'time': '17.06.20 15:58:50.000 CDT', 'id': 1592402330}, {'time': '09.06.20 22:14:52.000 CDT', 'id': 1591733692},
{'time': '09.06.20 22:14:49.000 CDT', 'id': 1591733689}, {'time': '09.06.20 22:14:46.000 CDT', 'id': 1591733686},
{'time': '09.06.20 22:14:43.000 CDT', 'id': 1591733683}, {'time': '09.06.20 22:14:40.000 CDT', 'id': 1591733680},
{'time': '09.06.20 22:14:37.000 CDT', 'id': 1591733677}, {'time': '09.06.20 22:14:35.000 CDT', 'id': 1591733675}],
'context': 'TEST'}
>>>

PyTine.getArchivedEventData

Use this call to actually retrieve data stored with the event.

Simply typing 'PyTine.getArchivedEventData()' at the command prompt will generate the 'usage' exception message shown below:

SyntaxError: PyTine.getArchivedEventData(context='str',event='str',eventId=val[,channel='str',eventServer='str',eventDevice='str',eventProperty='str',eventContext='str',format='str',size=val])

The parameter description is given in more detail below:

Parameters
contextis the TINE context to which the event server receiving the trigger belongs.
eventis the event trigger name for which the event data is desired.
eventIdis the UTC event id specifying the particular event whose data are desired. This should provide the unique UTC event Id assigned to the event when it was triggered and can be passed as a UTC integer value or a human readable string representation which corresponds to the UTC event Id.
channeloptionally provides a full stored address entry string in the form /<context>/<server>/<device>[<property>]. if this parameter is not provided then the eventServer, eventDevice, and eventProperty parameters must be provided. The point being: the stored address of the item whose data are desired must be provided.
eventServeroptionally provides the stored server name whose data are desired (if channel is not used).
eventDeviceoptionally provides the stored device name whose data are desired (if channel is not used).
eventPropertyoptionally provides the stored property name whose data are desired (if channel is not used).
eventContextoptionally provides the stored context name whose data are desired (if channel is not used). If eventContext (and channel) are not provided then the value of context will be assumed.
formatoptionally provides the desired format specification for the returned data.
sizeoptionally provides the desired (maximum) array size for the returned data.

As an example:

>>> import PyTine as pt
>>>
>>> pt.getArchivedEventData(context='TEST',event='sine_trigger_copy',eventId=1591733692,channel='/TEST/SineServer1/SineGen0[Amplitude]')
{'timestamp': 1591733692.693753, 'usrstamp': 0, 'channel': '/TEST/SineServer1/SineGen0[Amplitude]', 'status': 0, 'event': 'sine_trigger_copy', 'sysstamp': 21134185, 'eventId': 1591733692, 'timestring': '09.06.20 22:14:52.693 CDT', 'context': 'TEST', 'data': [602.0, 233.0, 10.0, 399.0, 105.0, 322.0, 234.0, 222.0, 281.7380065917969, 1.0]}
>>>

In the above, the channel parameter was used to specify the desired stored address and the event ID was passed directely as a UTC integer ID.

PyTine.getEventArchiveComment

Each stored event can (and usually does) provide a comment (an annotation) describing the particular event. In most cases the initial comment is provided with the event trigger at the time of the trigger (the static comment). Experts who later examine the contents of the stored event can then further annotate the event in question (the user comment), as well as specifiy that the event should not expired (be removed from the system after some length of time), i.e. the status).

Simply typing 'PyTine.getEventArchiveComment()' at the command prompt will generate the 'usage' exception message shown below:

SyntaxError: PyTine.getEventArchiveComment(context='str',event='str',eventId=val)

The parameter description is given in more detail below:

Parameters
contextis the TINE context to which the event server receiving the trigger belongs.
eventis the event trigger name for which the event annotation is desired.
eventIdis the UTC event id specifying the particular event whose data are desired. This should provide the unique UTC event Id assigned to the event when it was triggered and can be passed as a UTC integer value or a human readable string representation which corresponds to the UTC event Id.

As an example:

>>> import PyTine as pt
>>>
>>> pt.getEventArchiveComment(context='PETRA',event='mhf_sl0cav_trc',eventId=1563281073)
{'eventId': 1563281073, 'comment': {'static': 'PE_SL_Kly1/Treiber/Vorlaufleistung_Max/ hat getriggert', 'user': '_Thales TH-2178, SN 178004, DESY-Nr 304, zeigt Instabilität bei etwa 50 W Treiberleistung', 'status': 'SAVE'}, 'context': 'PETRA', 'event': 'mhf_sl0cav_trc'}
>>>
>>> pt.getEventArchiveComment(context='PETRA',event='mhf_sl0cav_trc',eventId='16.07.2019 14:44:33')
{'eventId': 1563281073, 'comment': {'static': 'PE_SL_Kly1/Treiber/Vorlaufleistung_Max/ hat getriggert', 'user': '_Thales TH-2178, SN 178004, DESY-Nr 304, zeigt Instabilität bei etwa 50 W Treiberleistung', 'status': 'SAVE'}, 'context': 'PETRA', 'event': 'mhf_sl0cav_trc'}
>>>

We see that the returned comment is actually a dictionary with keys status (the current event status - primary either 'SAVE', 'NONE' or 'DELETE'), static (the static event trigger comment), and user (the expert analysis annotation).

PyTine.setEventArchiveComment

You can assume the role of an expert and supply specific event annotations with this method.

Simply typing 'PyTine.setEventArchiveComment()' at the command prompt will generate the 'usage' exception message shown below:

SyntaxError: PyTine.setEventArchiveComment(context='str',event='str',eventId=val,comment='str')

The parameter description is given in more detail below:

Parameters
contextis the TINE context to which the event server receiving the trigger belongs.
eventis the event trigger name for which the event annotation is desired.
eventIdis the UTC event id specifying the particular event whose data are desired. This should provide the unique UTC event Id assigned to the event when it was triggered and can be passed as a UTC integer value or a human readable string representation which corresponds to the UTC event Id.
commentgives the annotation string to apply to this specific event. This can either be a simple comment string with the associated STATUS, STATIC, and USER sections or not (in which case the comment string is treated as a USER annotation. Or the comment passed can be a dictionary object with the keys status, static, and user provided).

As an example:

>>> import PyTine as pt
>>>
>>> mycmt = { 'status': 'KEEP', 'static':'a static comment','user':'get them thar sine curves and show em...'}
>>> pt.setEventArchiveComment(context='TEST',event='sine_trigger_copy',eventId=1591733692,comment=mycmt)
>>>

Server API

Python is in many cases a very good language in which to write middle layer logic, where data is acquired from one or more front-end servers, manipulated, and then some resulting data should be made available to the control system 'at large' for purposes of display or archiving, etc.

You can write a TINE server completely in Python by making use of the following PyTine functions described below. Once again, these routines follow in the most part the paradigm of the Buffered Server.

A Python server can simply attach to an existing server configuration database (either a .csv file set or a single .xml file specifying the property and device information along with the server's name, etc. See Attaching a Server to a Database) or it can make use of registration calls such as register_server, register_property, register_device, etc. to do the same, essentially on the fly (See a Simple On-the-fly Server Registration).

List of API Calls (details below)

  • PyTine.attach_server attaches to an existing server configuration database (either .csv or .xml based).
  • PyTine.attach_handler attaches a python handler function to a specified property so as to handle WRITE events.
  • PyTine.pushdata pushes a python data set to a specified property.
  • PyTine.register_fec assigns a FEC name and other parameters to the Python server (in lieu of attach_server).
  • PyTine.register_server assigns a server name (and context) to the Python server (in lieu of attach_server).
  • PyTine.register_device registers a device with the Python server.
  • PyTine.register_property registers a property with the Python server.
  • PyTine.register_type registers a structure data type.
  • PyTine.register_error_code registers a user-defined error code (beyond the systematically known error codes).
  • PyTine.register_death_handler registers a Python function to handle any server termination event that might occur during initialization.
  • PyTine.setalarm sets an alarm for the given device.
  • PyTine.clearalarm clears an alarm for the given device or all devices (depending on input).
  • PyTine.allowed_users retrieves, adds, or removes user names to/from the list of users with WRITE permission
  • PyTine.allowed_addresses retrieves, adds, or removes network addresses to/from the list of addresses with WRITE permission
  • PyTine.errorlist retrieves the list of error code enumerations
  • PyTine.log appends log file entries to the desired log file

Attaching a Server to a Database

PyTine.attach_server

If the server's properties and devices are available via a TINE database (produced, for instance, by using the TINE server wizard), then a simple call to 'PyTine.attach_server()' will cause the configuration database to be read and make the configured properties and devices avialable. The server will automatically 'plug' itself into the control system and be visable to prospective clients. At this stage there will likely be NO intersting data to be read from any of the properties, as the underlying buffers will have been initialized to contain '0'. A call to 'PyTine.attach_server()' without any arguments at all will look only for a 'fec.xml' file, where it will expect to find all information necessary to register the fec process along with any servers and their properties, devices, and associated information.

Parameters
eqm(string) is the so-called 'local name' of the equipment module. This is a 6-character name used for administration purposes within the running process and is thus required only to be unique within the process. In Python, you will likely have only a single registered server per Python process, so this minimal restriction scarely presents a problem. Although a meaningless character string such as "1" will suffice, it is typical to provide a 3-letter acronym followed by "EQM" (for equipment module), for instance "MLBEQM".
server(string) is the equipment module's exported name. This is the server name which all control system clients will 'see'. This can be up to 32-characters in length. This name must be unique within the registered context (as given in the fecid.csv file or fec.xml file).
capacity(int) is the maximum number of device instances that this server will manage.
Returns
0 upon success, otherwise a TINE error code

Alternatively you can completely forgo any configuration database and register all necessary information via the registration API calls 'PyTine.register_fec', 'PyTine.register_server', 'PyTine.register_device', and 'PyTine.register_property' (see below).

PyTine.pushdata

In order to supply the registered properties with data, the Python 'server' should call 'PyTine.pushdata' when it has determined that new data are available for the property in question. Using just 'PyTine.attach_server' and 'PyTine.pushdata' in this manner are theoretically the only Python calls necessary to provide a 'READ-ONLY' server.

Parameters
property(string) is the property for which the supplied data are to be used.
device(string) is the specific device instance for which the supplied data are to be used. This must be a string corresponding to a registered device or a string of the form "#1", etc. which then indicates the device instance 'numerically'.
devicenumber(int) is the specific device instance according to its numerical form only. This is frequently a better option for a server, which may not know (or need to know) which device 'names' have been configured. If both device and devicenumber are provided, devicenumber will take precedence.
data(object) is the data (array) which is to be 'pushed' into the underlying property buffer.
size(int) is the length of the data array to push into the property buffer. If omitted, the entire contents of the data array will be used.
scheduled(int) is an integer flag which if non-zero instructs the subsystem to immediately notify all listening clients of a change in the property's data.
timestamp(double) is an explicit (utc) timestamp with which to 'tag' the data. Normally, the time of the call to 'PyTine.pushdata' is used as the data timestamp. The double value represents seconds since Jan. 1, 1970 and can contain fractions of a second.
systemstamp(int) is an explicit system cycle/event number stamp with which to 'tag' the data. If not provided, then the system-wide cycle/event number will be used (if known).
userstamp(int) is an option user-defined stamp with which to 'tag' the data.
Returns
0 upon success, otherwise a TINE error code

If the server is to respond to WRITE commands, it should provide a property dispatch handler by making use of 'PyTine.attach_handler'.

Note that if the data to be pushed is a structure, this must correspond to a registered structure AND the property in question must be registered to support this structure. See the discussion below concerning registering a structure and registering a property.

PyTine.attach_handler

If a property is to accept WRITE requests, that is requests which attempt to change a setting, then the Python server should provide a dispatch handler for the corresponding property. This is done by make a call to 'PyTine.attach_handler' and providing the appropriate Python function to act as the dispatcher.

Parameters
propertyis the property to which the handler is to be associated.
handleris a Python callable function to be called when a WRITE transaction for the property is being requested by some client.
The handler routine passed should accept a single Python Object will be be Python dictionary and return an integer (used as a TINE return code). The dictionary object passed to the handler will contain the fields property (indicating the property which is triggering the handler), device (indicating the device which is triggering the handler), devicenumber (indicating the device as the associated device number which is triggering the handler), caller (indicating the caller who is triggering the handler), and data (the input data being passed to the handler - Py_None if no data have been sent).
Returns
0 upon success, otherwise a TINE error code

It is up to the dispatch routine to either accept the call (return '0') or to reject the setting on some other grounds (return non-zero : see the section on TINE error codes).

An atomic 'write/read' call will expect to read back the value it just sent (if the return code indicates success), so a call to PyTine.pushdata should be included in the handler if all goes well. This detail however is entirely up to the developer.

An example of server attaching to a 'csv-style' server database with equipment module 'SINEQM' is shown below. A Python script makes calls to 'PyTine.attach_server', which attaches itself to a pre-configured data base. It then pushes a startup value for the (known) property 'Amplitude' and defines and attaches a property handler for property 'Amplitude' by calling 'PyTine.attach_handler'.

>>> import PyTine as pt
>>>
>>> status = pt.attach_server(eqm='SINEQM')
>>> status = pt.pushdata(property='Amplitude',devicenumber=0,data=33)
>>>
>>> def hndlr(inpt):
... pt.pushdata(property=inpt['property'],device=inpt['device'],data=inpt['data'])
...
>>> status = pt.attach_handler(property='Amplitude',handler=hndlr)
>>>

In the above case, the property handler always returns '0' (success). Under certain circumstances it might be desireable to rerurn an error code. In such cases, simply return a valid tine error code or a user-defined (see register_error_code) error code. For instance,

>>> import PyTine as pt
>>>
>>> status = pt.attach_server(eqm='SINEQM')
>>> status = pt.pushdata(property='Amplitude',devicenumber=0,data=33)
>>>
>>> running = True
>>> def hndlr(inpt):
... global running
... if (not running) : return pt.command_not_accepted;
... pt.pushdata(property=inpt['property'],device=inpt['device'],data=inpt['data'])
...
>>> status = pt.attach_handler(property='Amplitude',handler=hndlr)
>>>

The call to 'tine_attach_server' as noted above attaches itself to a configuration database.
In this case, it consists of a set of .csv files.

The file 'fecid.csv' is located in the FEC_HOME directory:

EXPORT_NAME,FEC_NAME,Context,SubSystem,Port_Offset,Description,Location,Hardware,Responsible
MLSineServer,MLSINEGEN.7,TEST,SER,7,Test,Bldg 30 Room 502,None,P.Duval

The file 'exports.csv' is located in a subdirectory of the FEC_HOME directory called 'SINEQM' (the subdirectory name MUST be the same as given the call to 'tine_attach_server').

CONTEXT,EXPORT_NAME,LOCAL_NAME,PROPERTY,PROPERTY_SIZE,PROPERTY_INSIZE,PROPERTY_ID,ACCESS,FORMAT,NUM_DEVICES,DESCRIPTION
TEST,MLSineServer,SINEQM,Sine,8192,0,1,READ|XREAD,float.SPECTRUM,10,[-1000:1000 V][0:1000 ms]Sine Curve
TEST,MLSineServer,SINEQM,Amplitude,10,1,2,READ|WRITE,float.CHANNEL,10,[1:1000 V !LOG]Sine Curve Amplitude
TEST,MLSineServer,SINEQM,Frequency,10,1,3,READ|WRITE|SAVERESTORE,float.CHANNEL,10,[1:60]Sine Curve Frequency
TEST,MLSineServer,SINEQM,Phase,10,1,4,READ|STATIC,float.CHANNEL,10,[0:512]Sine Curve Phase
TEST,MLSineServer,SINEQM,Noise,10,1,5,XREAD|WRITE,float.CHANNEL,10,[0:100 V]Sine Curve Noise Level

This file essentially gives the names of the exported properties as well as all relevant information about the exported properties. This information is in fact used to determine the sizes and behaviors of the underlying property buffers. The file 'exports.csv' also provides the exported server name, in this case "MLSineServer". This exported server name is used as a cross-reference within the fecid.csv file to latch onto the appropriate FEC, in case of any ambiguity (note: a fecid.csv can contain multiple entries).

The file 'devices.csv' is also located in the 'SINEQM' subdirectory and provides the device names for the individual devices.

DEVICE_NUMBER,DEVICE_NAME,DEVICE_DESCRIPTION
0,SineGen0,sine generator 1
1,SineGen1,sine generator 2
2,SineGen2,sine generator 3
3,SineGen3,sine generator 4
4,SineGen4,sine generator 5
5,SineGen5,sine generator 6
6,SineGen6,sine generator 7
7,SineGen7,sine generator 8
8,SineGen8,sine generator 9
9,SineGen9,sine generator 10

Note that the number of devices in total is given in the 'exports.csv' file as '10' (the NUM_DEVICES column). Thus, at most 10 entries will be read from the 'devices.csv' file.

An alternative server configuration database involves the single file 'fec.xml' which contains all of the configuration details. Going this route would have the 'all-eggs-in-one-basket' advantage (a set of .csv Files can be large and confusing), but have the disadvange of not being able to easily focus on targeted configuration changes. If the call to PyTine.attach_server is made without options then the server initialization only looks for a single fec.xml file.

The advantage of 'attaching' to a server database is that all of the configuration details are kept in a separate configuration file or set of files and not hard-coded.

The disadvantage is that the Python server must know a-priori what the contents of the configuration database are. E.g. 'know' that there is a property 'Amplitude' in the above example, 'know' how many devices are supprted, etc. etc.

It is then often more advantageous to register all configuration information directly in Python. As the python server uses a 'one-FEC, one-server' policy, the information necessary to launch a fully functioning server on-the-fly is minimal (e.g. an 'acceptible' - in most cases - FEC Name can be generated from the input server name and context, the local equipment module name is simply taken to be 'PYEQM').

The set of available server configuration routines consist of the following:

PyTine.register_fec

You can assign a FEC name to your Python server via the API call 'PyTine.register_fec'.
If you want to register a specific FEC name or provide other specific FEC information you can do so with this call.

Simply typing 'PyTine.register_fec()' at the Python prompt will produce the following output:

>>> import PyTine
>>>
>>> PyTine.register_fec()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.register_fec(name='str'[,subsystem='str',context='str',descripton='str',location='str',hardware='str',responsible='str',port=val])
>>>

The one required argument is the 'name', which provices the system-wide unique FEC Name (see the Overview documentation: 'What's in a Name?'). However if all other arguments are omitted, then the default port offset will be determined by scanning the local FEC manifest in order to avoid a conflict with other servers which are possibly running on the same host. Likewise it is often useful to provide information as the location, responsibility, 'context' (default = "TEST") and 'subsystem' (default = "TEST"). So making use of all parameters is encouraged.

Parameters
name(string) is the system wide unique name of the FEC process (up to 16 characters in length)
subsystem(optional string) is the control subsystem to which the servers should be associated. (e.g. "VAC", "DIAG", "MAG", etc.). This is not a part of the name hierarchy but can be used in browsing.
context(optional string) is the control system context in which the servers should be registered.
description(optional string) is a description (up to 64 characters) of the functionality of the FEC.
locationi(optional string) s a string (32 characters) containing the phyisical location of the FEC host computer.
hardware(optional string) is a string description of attached hardware. For most Python middle layers, this will simply be "none".
responsible(optional string) is the person (or persons) to contact in case of problems. It should also contain the 'user name' if possible of such persons, as administrative actions (such as 'removing' the FEC from the ENS database) will require a 'match' on the user name of the person attempting such actions versus those 'responsible' for the FEC in question.
port(optional int) is the port 'offset' to be applied to all of the server's listening service ports. This should be a simple integer between 0 and 55500, but preferably small. The default is '0'.
If multiple FECs run on a single computer, then each must have its own unique port offset. Hence the default value of '0' will work only once per host. Once again, this is not the listening 'port address' but is an 'offset' to be applied to a set of listening ports (UDP, TCP, STREAM, Debug, and even possibly IPX).
Returns
'0' upon success or a TINE error code.

PyTine.register_server

You can assign the server's exported name and local equipment module name to your Python server via the API call 'PyTine.register_server'.

Simply typing 'PyTine.register_server()' at the Python prompt will produce the following output:

>>> import PyTine
>>>
>>> PyTine.register_server()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.register_server(name='str'[,context='str',eqm='str',capacity=val,fec='str'])
>>>
Parameters
name(string) is the desired exported server name. This is the server name which all control system clients will 'see'. This can be up to 32-characters in length. This name must be unique within the registered context.
context(optional string) is the desired context for the server (default = 'TEST'). Note that the combination of server name and context must be system-wide unique (or the server will not register itself in the system and an 'address in use' message will be returned from the equipment name server).
eqm(optional string) is the so-called 'local name' of the equipment module. This is a 6-character name used for administration purposes within the running process and is thus required only to be unique within the process. (default = 'PYEQM').
capacity(optional int) is the maximum number of device instances that this server will manage. (default = 1000).
fec(optional string) is the desired FEC name. You can completely forgo the call to PyTine.register_fec if the value of the additional FEC information is not relevant and provide a FEC name here via this parameter. If the FEC name has already been determined then the value of this parameter is irrelevant.
Returns
'0' upon success or a TINE error code.
Note
If no call to PyTine.register_fec has been made and no 'fec' parameter has been supplied in the call to PyTine.register_server then a viable FEC name will be determined, based on the context and server names known at the time of registration. As the FEC name must also be system-wide unique but only consists of 16 characters, there could possibly be a name collision if this is left to 'chance'.
Thus a look in the fec.log if things should go wrong is advisable.
if no port offset is specified an attempt to find a viable port is made be scaning the local fec manifest.

PyTine.register_device

You can assign the server's device instance names within your Python server via the API call 'PyTine.register_device'

Simply typing 'PyTine.register_device()' at the Python prompt will produce the following output:

>>> import PyTine
>>>
>>> PyTine.register_device()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.register_device(name='str',number=val[,description='str',location='str',zposition=val,redirection='str'])
>>>
Parameters
name(string) is the name of the device instance to be registered.
number(int) is the associated device number. This must be greater than or equal to 0 and smaller than the device 'capacity' entered in 'PyTine.register_server' in order to succeed.
description(optional string) can be used to supply a device description.
location(optional string) can be used to supply a device location information.
zpostion(optional float) can be used to supply a device z-position information.
redirection(optional string) must be a string of the form '/<context>/<server>/<device>[<property>]' if the device instance in question does reside on the local server but should be redirected to a remote server.
propertylist(optional string list) can be used to associate a list of properties to the given device. This will effectively establish a device-oriented server.
Returns
'0' upon success or a TINE error code.

PyTine.register_property

You can assign the server's property names and information within your Python server via the API call 'PyTine.register_property'.

Simply typing 'PyTine.register_property()' at the Python prompt will produce the following output:

>>> import PyTine
>>> PyTine.register_property()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.register_property(name='str',size=val,format='str'[,size_input=val,format_input='str',mode='str,min=val,max=val,units='str',description='str',devicelist=Dict])
>>>

Here a detailed description of the parameters:

Parameters
name(string) is the property name to be registered.
size(int) gives the array size of the property's output.
format(string) gives the data type of the property. This should by a string such as 'float', 'int32' (synonym: 'int'), etc. Strings entries are best dealt with by using a 'fixed-capacity' string type such as 'NAME16' or 'NAME64', etc. Additional array 'type' information is supplied by attaching e.g. '.CHANNEL' (for channel array) or '.SPECTRUM' for (a spectrum array).
size_input(optional int) gives the array size of the property's input, if the property is to accept input data of a different array length than the registered output size.
format_input(optional string) gives the data type of the property's input data, if different from the registered output data format.
mode(optional string) gives the access mode of the property.
('READ', 'WRITE', 'READ|WRITE', etc.) If 'WRITE' is among the mode instructions, then the input size will be taken as '1' and input format as the same as the output format (i.e. attribute like conditions). If the output data size is 0 then the input data size is also 0 and the access mode must be specified as 'WRITE'. Such a case would signal a 'command-style' property.
min(optional float) gives the minimum range of the property values.
max(optional float) gives the maximum range of the property values.
units(optional string) gives the engineering units of the property (a string not to exceed 16 characters).
description(optional string) gives a description of the data supplied by, or the action initiated by calling the property.
deviceList(optional Dictionary) specifies a list of device names (or keywords) to associate with the registered property. For normal multi-channel properties, the registered device list is taken to be the channel names associated with the array elements. This association can be over-ridden with this parameter.
Returns
A positive 'id' for the registered property upon success or the negative of a TINE error code if there is an error.

Simple On-the-fly Server Registration

It is actually quite easy to make use of the above registration calls to produce a Python server on-the-fly at the command line. Consider the following example:

>>> import PyTine as pt
>>>
>>> status=pt.register_server(name='PYSineServer')
>>> status=pt.register_device(name='device0',number=0)
>>> status=pt.register_device(name='device1',number=1)
>>> status=pt.register_device(name='device2',number=2)
>>> status=pt.register_property(name='value',size=1,format='float',mode='read|write')
>>>
>>> status=pt.pushdata(property='value',data=23)
>>> status=pt.pushdata(property='value',devicenumber=1,data=33)
>>>
>>> def hndlr(inpt):
... print(inpt)
... pt.pushdata(property=inpt['property'],device=inpt['device'],data=inpt['data'])
...
>>> status=pt.attach_handler(property='value',handler=hndlr)
>>>
>>>

Here the server name is the only argument passed to PyTine.register_server. Thus the context is by default 'TEST'. A Fec Name is generated based on this information, a port is deduced from the local manifest and the server is registered and available to the control system:

This particular server does not do very much other than accept commands to change the values stored for the three devices registered.

One can make use of Python threads and timers to otherwise update the data represented by the property 'Value'.

Similarly, an update thread or timer might also set and clear alarms.

PyTine.setalarm

Alarms are in general associated with a particular device and defined by a specific alarm code (see the section on the Alarm System). The static information associated with an alarm code is found in the alarms definition file alarms.csv. If conditions warrant you can set an alarm within an update routine via this API call. Simply typing PyTine.setalarm() at the command prompt will produce the following usage text:

>>> import PyTine
>>> PyTine.setalarm()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.setalarm(code=val[,device='str',devicenumber=val,data=Object,options='str'])
>>>
Parameters
code(integer) is the alarm code which designates which alarm is being applied to the device given.
device(string) is the device name (optional) indicating which device is setting the alarm.
devicenumber(integer) is the device number (optional) indicating which device is setting the alarm. Either the device or the devicenumber parameter should be supplied (whichever is the more convenient coding paradigm). If both are omitted, then the alarm is applied to device 0.
data(type given in the alarms.csv definition) is the optional data associated with the alarm.
options(string) is an optional alarm descriptor which can specify the type of alarm. Here only "TRANSIENT" is supported (signalling the that alarm has no duration and is both new and terminated at the same time).

PyTine.clearalarm

An alarm once set will remain in the local alarm tables until its clear counter has passed the removal threshold (typically 8).

Simply typing PyTine.clearalarm() is a valid call as it stands. To see the usage text, one can type e.g. PyTine.clearalarm(help) at the command prompt and see the following usage text:

>>> import PyTine
>>> PyTine.clearalarm(help)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.clearalarm(code=val[,device='str',devicenumber=val,options='str'])
>>>
Parameters
code(integer) is the alarm code specifying which alarm should be cleared. If omitted, then the clear counter of all active alarms for the given device is increased by 1.
Otherwise, the designated alarm is marked for immediate termination.
device(string) is the device name (optional) indicating which device is to be cleared. If omitted, then all alarms will be cleared. Note: if code is specified then either device or devicenumber must be specified as well. Otherwise, the call will return an error (invalid_parameter).
devicenumber(integer) is the device number (optional) indicating which device is setting the alarm (if device has not been passed.

PyTine.register_type

A Python server can handle structures as input or output like any other TINE server. You will need to register the structure(s) you wish to use during initialization. This is best accomplished by making use of a call to 'PyTine.register_type'. Simply typing PyTine.register_type() at the command prompt will produce the following usage text:

>>> PyTine.register_type()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
SyntaxError: PyTine.registerType(tag='str',struct=obj)
>>>
Parameters
tag(string) is a string identifier to associate with the structure being registered. This should not be longer than 16 characters, as the underlying tine kernel will truncate the structure tag to 16 characters if need be.
struct(obj) is a python dictionary of key-value pairs giving the overall makeup of the structure.
The initial values in the key-value pair list are irrelevant other than their values do in fact determine the format of the associated structure field. Thus integer values will be taken as 32-bit integers (unless otherwise decorated) and float values will be taken as 32-bit float values (unless otherwises decorated). String values will be assumed to be fix-length string fields with the length of the field being given by the length of the string used in initialization. Hint: make use of e.g. .ljust(64) or .rjust(64) to specify a 64-character string field.

As an example consider the C structure:

typedef struct MyHeader
{
char name[64];
int size;
int type;
char units[16];
} MyHeader;

To realize this in Python so as to pass it along to PyTine.register_type() you would do something like :

import PyTine as pt
myhdr = {'name': 'something'.ljust(64), 'size': 1, 'type': 517, 'units': 'units'.ljust(16)}
pt.register_type(tag='MyHeader', struct=myhdr)

A server making use of this new data type for property Header might register itself along these lines:

import PyTine as pt
myhdr = {'name': 'something'.ljust(64), 'size': 1, 'type': 517, 'units': 'units'.ljust(16)}
pt.register_type(tag='MyHeader', struct=myhdr)
# the 'type' is now known. Register a server:
pt.register_server(name='PyStructServer')
# give the server a couple of devices
pt.register_device(name='device0',number=0)
pt.register_device(name='device1',number=1)
# and a property 'Header' which will deliver data as in the structure registered
pt.register_property(name='Header',size=1,format='STRUCT.MyHeader',mode='read')
# now push something into this new property, for device 0 :
hdr1 = {'name': 'channel1', 'size': 10, 'type': 517, 'units': 'mA'}
pt.pushdata(property='Header',device='device0',data=hdr1)
# and some data for device 1 :
hdr2 = {'name': 'channel2', 'size': 20, 'type': 512, 'units': 'V'}
pt.pushdata(property='Header',device='device1',data=hdr2)

Then a client-side call for this property Header will yield the desired structure:

PyTine.register_error_code

Use this call to register a error code which can be used as a return code from a property handler (in addition to the system error codes).

Parameters
code(integer) is the user defined error code to be inserted into the error registry. Must be >= 512.
textis a short (up to 32 characters) text description to be associated with the error code.
longtextis a longer (up to 128 characters) text description to be associated with the error code.

PyTine.register_death_handler

A tine server will under some circumstances make a hard exit if it cannot be successfully initialized. For instance, the server socket cannot be opened, or the desired server or FEC name cannot be assigned because it is already being used, etc. In such cases, it is usually better to halt execution (with appropriate log file entries and console messages) and force the problem to be dealt with rather than give the impression that the server is somehow running.

When this happens, the process can optionally be informed that such a signal has occurred and revoke the automatic process termination and take steps to gracerfully return resources to the system, etc. If this is desired, the Python server should register a death handler via this API call.

Parameters
handleris a callable python function which will be called in the event of a termination signal from the tine kernel.

PyTine.allowed_users

In general, those users to be allowed WRITE permission to those settable properties which may have been registered can most easily be supplied via a users.csv file (see the section on Security). One can also supply a list of users directly from Python via this API call.

Parameters
add(string or list of strings) will add those user names in the list to the current users access control list.
remove(string or list of strings) will remove those user names in the list from the current users access control list.
Returns
the current users access control list.

If no parameters are supplied, the call simply returns the current list.

PyTine.allowed_addresses

In general, those network addresses to be allowed WRITE permission to those settable properties which may have been registered can most easily be supplied via a ipnets.csv file (see the section on Security). One can also supply a list of addresses directly from Python via this API call.

Parameters
add(string or list of strings) will add those network addresses in the list to the current users access control list.
remove(string or list of strings) will remove those network addresses in the list from the current users access control list.
Returns
the current network address access control list.

If no parameters are supplied, the call simply returns the current list.

PyTine.errorlist

The tine system error codes are available in Python as enumerated constants. One can obtain the entire list by simply calling this method without arguments. Otherwise the desired text or code can be obtained by passing one or the other parameter.

Parameters
codeis the error code for which the text message is desired.
textis the text message for which the error code is desired.

PyTine.log

You can append server log file entries to the log file of choice via this method.

Parameters
messageis the log file entry to be appended to the log file
file(optional) is the log file name. If ommitted, then 'fec.log' is assumed. The extenstion '.log' will be applied to any file name given.
severity(optional) is a log severity from 0 (INFO) to 3(FATAL) which will be inserted into the log message. If omitted, INFO (informational) is assumed.
tag(optional) is a tag string which will be inserted into the log message (files other than fec.log). If omitted then the severity will be used.

Impressum   |   Imprint   |   Datenschutzerklaerung   |   Data Privacy Policy   |   Declaration of Accessibility   |   Erklaerung zur Barrierefreiheit
Generated for TINE API by  doxygen 1.5.8