Server helper classes for writing Tango device servers.
This module provides a high level device server API. It implements TEP1. It exposes an easier API for developing a Tango device server.
Here is a simple example on how to write a Clock device server using the high level API:
import time
from PyTango.server import run
from PyTango.server import Device, DeviceMeta
from PyTango.server import attribute, command
class Clock(Device):
__metaclass__ = DeviceMeta
time = attribute()
def read_time(self):
return time.time()
@command(din_type=str, dout_type=str)
def strftime(self, format):
return time.strftime(format)
if __name__ == "__main__":
run((Clock,))
Here is a more complete example on how to write a PowerSupply device server using the high level API. The example contains:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | from time import time
from numpy.random import random_sample
from PyTango import AttrQuality, AttrWriteType, DispLevel, server_run
from PyTango.server import Device, DeviceMeta, attribute, command
from PyTango.server import class_property, device_property
class PowerSupply(Device):
__metaclass__ = DeviceMeta
voltage = attribute()
current = attribute(label="Current", dtype=float,
display_level=DispLevel.EXPERT,
access=AttrWriteType.READ_WRITE,
unit="A", format="8.4f",
min_value=0.0, max_value=8.5,
min_alarm=0.1, max_alarm=8.4,
min_warning=0.5, max_warning=8.0,
fget="get_current", fset="set_current",
doc="the power supply current")
noise = attribute(label="Noise", dtype=((float,),),
max_dim_x=1024, max_dim_y=1024,
fget="get_noise")
host = device_property(dtype=str)
port = class_property(dtype=int, default_value=9788)
def read_voltage(self):
self.info_stream("get voltage(%s, %d)" % (self.host, self.port))
return 10.0
def get_current(self):
return 2.3456, time(), AttrQuality.ATTR_WARNING
def set_current(self, current):
print("Current set to %f" % current)
def get_noise(self):
return random_sample((1024, 1024))
@command(dtype_in=float)
def ramp(self, value):
print("Ramping up...")
if __name__ == "__main__":
server_run((PowerSupply,))
|
Pretty cool, uh?
Note
the __metaclass__ statement is mandatory due to a limitation in the boost-python library used by PyTango.
If you are using python 3 you can write instead:
class PowerSupply(Device, metaclass=DeviceMeta)
pass
Data types
When declaring attributes, properties or commands, one of the most important information is the data type. It is given by the keyword argument dtype. In order to provide a more pythonic interface, this argument is not restricted to the CmdArgType options.
For example, to define a SCALAR DevLong attribute you have several possibilities:
To define a SPECTRUM attribute simply wrap the scalar data type in any python sequence:
To define an IMAGE attribute simply wrap the scalar data type in any python sequence of sequences:
Below is the complete table of equivalences.
dtype argument | converts to tango type |
---|---|
None | DevVoid |
'None' | DevVoid |
DevVoid | DevVoid |
'DevVoid' | DevVoid |
DevState | DevState |
'DevState' | DevState |
bool | DevBoolean |
'bool' | DevBoolean |
'boolean' | DevBoolean |
DevBoolean | DevBoolean |
'DevBoolean' | DevBoolean |
numpy.bool_ | DevBoolean |
'char' | DevUChar |
'chr' | DevUChar |
'byte' | DevUChar |
chr | DevUChar |
DevUChar | DevUChar |
'DevUChar' | DevUChar |
numpy.uint8 | DevUChar |
'int16' | DevShort |
DevShort | DevShort |
'DevShort' | DevShort |
numpy.int16 | DevShort |
'uint16' | DevUShort |
DevUShort | DevUShort |
'DevUShort' | DevUShort |
numpy.uint16 | DevUShort |
int | DevLong |
'int' | DevLong |
'int32' | DevLong |
DevLong | DevLong |
'DevLong' | DevLong |
numpy.int32 | DevLong |
'uint' | DevULong |
'uint32' | DevULong |
DevULong | DevULong |
'DevULong' | DevULong |
numpy.uint32 | DevULong |
'int64' | DevLong64 |
DevLong64 | DevLong64 |
'DevLong64' | DevLong64 |
numpy.int64 | DevLong64 |
'uint64' | DevULong64 |
DevULong64 | DevULong64 |
'DevULong64' | DevULong64 |
numpy.uint64 | DevULong64 |
DevInt | DevInt |
'DevInt' | DevInt |
'float32' | DevFloat |
DevFloat | DevFloat |
'DevFloat' | DevFloat |
numpy.float32 | DevFloat |
float | DevDouble |
'double' | DevDouble |
'float' | DevDouble |
'float64' | DevDouble |
DevDouble | DevDouble |
'DevDouble' | DevDouble |
numpy.float64 | DevDouble |
str | DevString |
'str' | DevString |
'string' | DevString |
'text' | DevString |
DevString | DevString |
'DevString' | DevString |
bytearray | DevEncoded |
'bytearray' | DevEncoded |
'bytes' | DevEncoded |
DevEncoded | DevEncoded |
'DevEncoded' | DevEncoded |
DevVarBooleanArray | DevVarBooleanArray |
'DevVarBooleanArray' | DevVarBooleanArray |
DevVarCharArray | DevVarCharArray |
'DevVarCharArray' | DevVarCharArray |
DevVarShortArray | DevVarShortArray |
'DevVarShortArray' | DevVarShortArray |
DevVarLongArray | DevVarLongArray |
'DevVarLongArray' | DevVarLongArray |
DevVarLong64Array | DevVarLong64Array |
'DevVarLong64Array' | DevVarLong64Array |
DevVarULong64Array | DevVarULong64Array |
'DevVarULong64Array' | DevVarULong64Array |
DevVarFloatArray | DevVarFloatArray |
'DevVarFloatArray' | DevVarFloatArray |
DevVarDoubleArray | DevVarDoubleArray |
'DevVarDoubleArray' | DevVarDoubleArray |
DevVarUShortArray | DevVarUShortArray |
'DevVarUShortArray' | DevVarUShortArray |
DevVarULongArray | DevVarULongArray |
'DevVarULongArray' | DevVarULongArray |
DevVarStringArray | DevVarStringArray |
'DevVarStringArray' | DevVarStringArray |
DevVarLongStringArray | DevVarLongStringArray |
'DevVarLongStringArray' | DevVarLongStringArray |
DevVarDoubleStringArray | DevVarDoubleStringArray |
'DevVarDoubleStringArray' | DevVarDoubleStringArray |
Bases: PyTango._PyTango.Device_4Impl
High level DeviceImpl API. All Device specific classes should inherit from this class.
Add a new attribute to the device attribute list. Please, note that if you add an attribute to a device at device creation time, this attribute will be added to the device class attribute list. Therefore, all devices belonging to the same class created after this attribute addition will also have this attribute.
Parameters : |
|
||||||||
---|---|---|---|---|---|---|---|---|---|
Return : | (Attr) the newly created attribute. |
||||||||
Throws : | DevFailed |
Tango always_executed_hook. Default implementation does nothing
Appends a string to the device status.
Parameters: status : (str) the string to be appened to the device status new_line : (bool) If true, appends a new line character before the string. Default is False Return: None
This method check that a command is supported by the device and does not need input value. The method throws an exception if the command is not defined or needs an input value
Parameters:
cmd_name: (str) the command name Return: None
Throws: DevFailed API_IncompatibleCmdArgumentType, API_CommandNotFound
New in PyTango 7.1.2
Sends the given message to the tango debug stream.
Since PyTango 7.1.3, the same can be achieved with:
print(msg, file=self.log_debug)
Parameters : |
|
||
---|---|---|---|
Return : | None |
Get device state. Default method to get device state. The behaviour of this method depends on the device state. If the device state is ON or ALARM, it reads the attribute(s) with an alarm level defined, check if the read value is above/below the alarm and eventually change the state to ALARM, return the device state. For all th other device state, this method simply returns the state This method can be redefined in sub-classes in case of the default behaviour does not fullfill the needs.
Parameters: None Return: (DevState) the device state Throws: DevFailed - If it is necessary to read attribute(s) and a problem occurs during the reading
Get device status. Default method to get device status. It returns the contents of the device dev_status field. If the device state is ALARM, alarm messages are added to the device status. This method can be redefined in sub-classes in case of the default behaviour does not fullfill the needs.
Parameters: None Return: (str) the device status Throws: DevFailed - If it is necessary to read attribute(s) and a problem occurs during the reading
Sends the given message to the tango error stream.
Since PyTango 7.1.3, the same can be achieved with:
print(msg, file=self.log_error)
Parameters : |
|
||
---|---|---|---|
Return : | None |
Sends the given message to the tango fatal stream.
Since PyTango 7.1.3, the same can be achieved with:
print(msg, file=self.log_fatal)
Parameters : |
|
||
---|---|---|---|
Return : | None |
Returns the min attribute poll period
Parameters: None Return: (seq) the min attribute poll period New in PyTango 7.2.0
Returns the min command poll period
Parameters: None Return: (seq) the min command poll period New in PyTango 7.2.0
Get device multi attribute object.
Parameters: None Return: (MultiAttribute) the device’s MultiAttribute object
Utility method that fetches all the device properties from the database and converts them into members of this DeviceImpl.
Parameters : |
|
||
---|---|---|---|
Return : | None |
||
Throws : | DevFailed |
Returns the state of the exported flag
Parameters: None Return: (bool) the state of the exported flag New in PyTango 7.1.2
Returns the Logger object for this device
Parameters: None Return: (Logger) the Logger object for this device
Get a COPY of the device name.
Parameters: None Return: (str) the device name
Returns a COPY of the list of non automatic polled attributes
Parameters: None Return: (sequence<str>) a COPY of the list of non automatic polled attributes New in PyTango 7.1.2
Returns a COPY of the list of non automatic polled commands
Parameters: None Return: (sequence<str>) a COPY of the list of non automatic polled commands New in PyTango 7.1.2
Returns a COPY of the list of polled attributes
Parameters: None Return: (sequence<str>) a COPY of the list of polled attributes New in PyTango 7.1.2
Returns a COPY of the list of polled commands
Parameters: None Return: (sequence<str>) a COPY of the list of polled commands New in PyTango 7.1.2
Get a COPY of the device’s previous state.
Parameters: None Return: (DevState) the device’s previous state
Get a COPY of the device state.
Parameters: None Return: (DevState) Current device state
Get a COPY of the device status.
Parameters: None Return: (str) the device status
Sends the given message to the tango info stream.
Since PyTango 7.1.3, the same can be achieved with:
print(msg, file=self.log_info)
Parameters : |
|
||
---|---|---|---|
Return : | None |
Tango init_device method. Default implementation calls get_device_properties()
Method executed at initializion phase to create dynamic attributes. Default implementation does nothing. Overwrite when necessary.
Returns if this device is locked by a client
Parameters: None Return: (bool) True if it is locked or False otherwise New in PyTango 7.1.2
Returns if it is polled
Parameters: None Return: (bool) True if it is polled or False otherwise New in PyTango 7.1.2
push_archive_event (self, attr_name, except) -> None
push_archive_event (self, attr_name, data, dim_x = 1, dim_y = 0) -> None
push_archive_event (self, attr_name, str_data, data) -> None
push_archive_event (self, attr_name, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None
push_archive_event (self, attr_name, str_data, data, time_stamp, quality) -> None
Push an archive event for the given attribute name. The event is pushed to the notification daemon.
Parameters:
attr_name: (str) attribute name data: the data to be sent as attribute event data. Data must be compatible with the attribute type and format. for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements compatible with the attribute type str_data: (str) special variation for DevEncoded data type. In this case ‘data’ must be a str or an object with the buffer interface. except: (DevFailed) Instead of data, you may want to send an exception. dim_x: (int) the attribute x length. Default value is 1 dim_y: (int) the attribute y length. Default value is 0 time_stamp: (double) the time stamp quality: (AttrQuality) the attribute quality factor Throws: DevFailed If the attribute data type is not coherent.
Push an attribute configuration event.
Parameters: (Attribute) the attribute for which the configuration event will be sent. Return: None New in PyTango 7.2.1
push_change_event (self, attr_name, except) -> None
push_change_event (self, attr_name, data, dim_x = 1, dim_y = 0) -> None
push_change_event (self, attr_name, str_data, data) -> None
push_change_event (self, attr_name, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None
push_change_event (self, attr_name, str_data, data, time_stamp, quality) -> None
Push a change event for the given attribute name. The event is pushed to the notification daemon.
Parameters:
attr_name: (str) attribute name data: the data to be sent as attribute event data. Data must be compatible with the attribute type and format. for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements compatible with the attribute type str_data: (str) special variation for DevEncoded data type. In this case ‘data’ must be a str or an object with the buffer interface. except: (DevFailed) Instead of data, you may want to send an exception. dim_x: (int) the attribute x length. Default value is 1 dim_y: (int) the attribute y length. Default value is 0 time_stamp: (double) the time stamp quality: (AttrQuality) the attribute quality factor Throws: DevFailed If the attribute data type is not coherent.
Push a data ready event for the given attribute name. The event is pushed to the notification daemon.
The method needs only the attribue name and an optional “counter” which will be passed unchanged within the event
Parameters:
attr_name: (str) attribute name counter: (int) the user counter Return: None
Throws: DevFailed If the attribute name is unknown.
push_event (self, attr_name, filt_names, filt_vals, data, dim_x = 1, dim_y = 0) -> None
push_event (self, attr_name, filt_names, filt_vals, str_data, data) -> None
push_event (self, attr_name, filt_names, filt_vals, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None
push_event (self, attr_name, filt_names, filt_vals, str_data, data, time_stamp, quality) -> None
Push a user event for the given attribute name. The event is pushed to the notification daemon.
Parameters:
attr_name: (str) attribute name filt_names: (sequence<str>) the filterable fields name filt_vals: (sequence<double>) the filterable fields value data: the data to be sent as attribute event data. Data must be compatible with the attribute type and format. for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements compatible with the attribute type str_data: (str) special variation for DevEncoded data type. In this case ‘data’ must be a str or an object with the buffer interface. dim_x: (int) the attribute x length. Default value is 1 dim_y: (int) the attribute y length. Default value is 0 time_stamp: (double) the time stamp quality: (AttrQuality) the attribute quality factor Throws: DevFailed If the attribute data type is not coherent.
Read the hardware to return attribute value(s). Default method to implement an action necessary on a device to read the hardware involved in a a read attribute CORBA call. This method must be redefined in sub-classes in order to support attribute reading
Parameters:
- attr_list : (sequence<int>) list of indices in the device object attribute vector
of an attribute to be read.
Return: None
Throws: DevFailed This method does not throw exception but a redefined method can.
Register a signal. Register this device as device to be informed when signal signo is sent to to the device server process
Parameters:
signo: (int) signal identifier Return: None
Remove one attribute from the device attribute list.
Parameters : |
|
||
---|---|---|---|
Return : | None |
||
Throws : | DevFailed |
Set an implemented flag for the attribute to indicate that the server fires archive events manually, without the polling to be started. If the detect parameter is set to true, the criteria specified for the archive event are verified and the event is only pushed if they are fullfilled. If detect is set to false the event is fired without any value checking!
Parameters:
attr_name: (str) attribute name implemented: (bool) True when the server fires change events manually. detect: (bool) Triggers the verification of the change event properties when set to true. Default value is true. Return: None
Set an implemented flag for the attribute to indicate that the server fires change events manually, without the polling to be started. If the detect parameter is set to true, the criteria specified for the change event are verified and the event is only pushed if they are fullfilled. If detect is set to false the event is fired without any value checking!
Parameters:
attr_name: (str) attribute name implemented: (bool) True when the server fires change events manually. detect: (bool) Triggers the verification of the change event properties when set to true. Default value is true. Return: None
Set device state.
Parameters:
new_state: (DevState) the new device state Return: None
Set device status.
Parameters:
new_status: (str) the new device status Return: None
Signal handler. The method executed when the signal arrived in the device server process. This method is defined as virtual and then, can be redefined following device needs.
Parameters:
signo: (int) the signal number Return: None
Throws: DevFailed This method does not throw exception but a redefined method can.
stop_polling (self, with_db_upd) -> None
Stop all polling for a device. if the device is polled, call this method before deleting it.
Parameters:
with_db_upd: (bool) Is it necessary to update db ? Return: None
New in PyTango 7.1.2
Unregister a signal. Unregister this device as device to be informed when signal signo is sent to to the device server process
Parameters:
signo: (int) signal identifier Return: None
Sends the given message to the tango warn stream.
Since PyTango 7.1.3, the same can be achieved with:
print(msg, file=self.log_warn)
Parameters : |
|
||
---|---|---|---|
Return : | None |
Write the hardware for attributes. Default method to implement an action necessary on a device to write the hardware involved in a a write attribute. This method must be redefined in sub-classes in order to support writable attribute
Parameters:
- attr_list : (sequence<int>) list of indices in the device object attribute vector
of an attribute to be written.
Return: None
Throws: DevFailed This method does not throw exception but a redefined method can.
Declares a new tango attribute in a Device. To be used like the python native property function. For example, to declare a scalar, PyTango.DevDouble, read-only attribute called voltage in a PowerSupply Device do:
class PowerSupply(Device):
__metaclass__ = DeviceMeta
voltage = attribute()
def read_voltage(self):
return 999.999
The same can be achieved with:
class PowerSupply(Device):
__metaclass__ = DeviceMeta
@attribute
def voltage(self):
return 999.999
It receives multiple keyword arguments.
parameter | type | default value | description |
---|---|---|---|
name | str | class member name | alternative attribute name |
dtype | object | DevDouble | data type (see Data type equivalence) |
dformat | AttrDataFormat | SCALAR | data format |
max_dim_x | int | 1 | maximum size for x dimension (ignored for SCALAR format) |
max_dim_y | int | 0 | maximum size for y dimension (ignored for SCALAR and SPECTRUM formats) |
display_level | DispLevel | OPERATOR | display level |
polling_period | int | -1 | polling period |
memorized | bool | False | attribute should or not be memorized |
hw_memorized | bool | False | write method should be called at startup when restoring memorize value (dangerous!) |
access | AttrWriteType | READ | read only/ read write / write only access |
fget (or fread) | str or callable | ‘read_<attr_name>’ | read method name or method object |
fset (or fwrite) | str or callable | ‘write_<attr_name>’ | write method name or method object |
is_allowed | str or callable | ‘is_<attr_name>_allowed’ | is allowed method name or method object |
label | str | ‘<attr_name>’ | attribute label |
doc (or description) | str | ‘’ | attribute description |
unit | str | ‘’ | physical units the attribute value is in |
standard_unit | str | ‘’ | physical standard unit |
display_unit | str | ‘’ | physical display unit (hint for clients) |
format | str | ‘6.2f’ | attribute representation format |
min_value | str | None | minimum allowed value |
max_value | str | None | maximum allowed value |
min_alarm | str | None | minimum value to trigger attribute alarm |
max_alarm | str | None | maximum value to trigger attribute alarm |
min_warning | str | None | minimum value to trigger attribute warning |
max_warning | str | None | maximum value to trigger attribute warning |
delta_val | str | None | |
delta_t | str | None | |
abs_change | str | None | minimum value change between events that causes event filter to send the event |
rel_change | str | None | minimum relative change between events that causes event filter to send the event (%) |
period | str | None | |
archive_abs_change | str | None | |
archive_rel_change | str | None | |
archive_period | str | None |
Note
avoid using dformat parameter. If you need a SPECTRUM attribute of say, boolean type, use instead dtype=(bool,).
Example of a integer writable attribute with a customized label, unit and description:
class PowerSupply(Device):
__metaclass__ = DeviceMeta
current = attribute(label="Current", unit="mA", dtype=int,
access=AttrWriteType.READ_WRITE,
doc="the power supply current")
def init_device(self):
Device.init_device(self)
self._current = -1
def read_current(self):
return self._current
def write_current(self, current):
self._current = current
The same, but using attribute as a decorator:
class PowerSupply(Device):
__metaclass__ = DeviceMeta
def init_device(self):
Device.init_device(self)
self._current = -1
@attribute(label="Current", unit="mA", dtype=int)
def current(self):
"""the power supply current"""
return 999.999
@current.write
def current(self, current):
self._current = current
In this second format, defining the write implies setting the attribute access to READ_WRITE.
Declares a new tango command in a Device. To be used like a decorator in the methods you want to declare as tango commands. The following example declares commands:
- void TurnOn(void)
- void Ramp(DevDouble current)
- DevBool Pressurize(DevDouble pressure)
class PowerSupply(Device):
__metaclass__ = DeviceMeta
@command
def TurnOn(self):
self.info_stream('Turning on the power supply')
@command(dtype_in=float)
def Ramp(self, current):
self.info_stream('Ramping on %f...' % current)
@command(dtype_in=float, doc_in='the pressure to be set',
dtype_out=bool, doc_out='True if it worked, False otherwise')
def Pressurize(self, pressure):
self.info_stream('Pressurizing to %f...' % pressure)
Note
avoid using dformat parameter. If you need a SPECTRUM attribute of say, boolean type, use instead dtype=(bool,).
Parameters: |
|
---|
Declares a new tango device property in a Device. To be used like the python native property function. For example, to declare a scalar, PyTango.DevString, device property called host in a PowerSupply Device do:
from PyTango.server import Device, DeviceMeta
from PyTango.server import device_property
class PowerSupply(Device):
__metaclass__ = DeviceMeta
host = device_property(dtype=str)
Parameters: |
|
---|
Declares a new tango class property in a Device. To be used like the python native property function. For example, to declare a scalar, PyTango.DevString, class property called port in a PowerSupply Device do:
from PyTango.server import Device, DeviceMeta
from PyTango.server import class_property
class PowerSupply(Device):
__metaclass__ = DeviceMeta
port = class_property(dtype=int, default_value=9788)
Parameters: |
|
---|
Provides a simple way to run a tango server. It handles exceptions by writting a message to the msg_stream.
The classes parameter can be either a sequence of:
or a dictionary where:
key is the tango class name
The optional post_init_callback can be a callable (without arguments) or a tuple where the first element is the callable, the second is a list of arguments (optional) and the third is a dictionary of keyword arguments (also optional).
Note
the order of registration of tango classes defines the order tango uses to initialize the corresponding devices. if using a dictionary as argument for classes be aware that the order of registration becomes arbitrary. If you need a predefined order use a sequence or an OrderedDict.
Example 1: registering and running a PowerSupply inheriting from Device:
from PyTango.server import Device, DeviceMeta, run
class PowerSupply(Device):
__metaclass__ = DeviceMeta
run((PowerSupply,))
Example 2: registering and running a MyServer defined by tango classes MyServerClass and MyServer:
from PyTango import Device_4Impl, DeviceClass
from PyTango.server import run
class MyServer(Device_4Impl):
pass
class MyServerClass(DeviceClass):
pass
run({'MyServer': (MyServerClass, MyServer)})
Example 3: registering and running a MyServer defined by tango classes MyServerClass and MyServer:
from PyTango import Device_4Impl, DeviceClass
from PyTango.server import Device, DeviceMeta, run
class PowerSupply(Device):
__metaclass__ = DeviceMeta
class MyServer(Device_4Impl):
pass
class MyServerClass(DeviceClass):
pass
run([PowerSupply, [MyServerClass, MyServer]])
# or: run({'MyServer': (MyServerClass, MyServer)})
Parameters: |
|
---|---|
Returns: | The Util singleton object |
Return type: |
New in version 8.1.2.
Changed in version 8.1.4: when classes argument is a sequence, the items can also be a sequence <TangoClass, TangoClassClass>[, tango class name]
Since PyTango 8.1.2 it is just an alias to run(). Use run() instead.
New in version 8.0.0.
Changed in version 8.0.3: Added util keyword parameter. Returns util object
Changed in version 8.1.1: Changed default msg_stream from stderr to stdout Added event_loop keyword parameter. Returns util object
Changed in version 8.1.2: Added post_init_callback keyword parameter
Deprecated since version 8.1.2: Use run() instead.