PyTango dynamic attributes

Hi,

I am trying to create a device server that can create new attributes during run-time. I am following the guide which gives the following example:


from PyTango import Util, Attr
from PyTango.server import DeviceMeta, Device, command

class MyDevice(Device):
    __metaclass__ = DeviceMeta

    @command(dtype_in=str)
    def CreateFloatAttribute(self, attr_name):
        attr = Attr(attr_name, PyTango.DevDouble)
        self.add_attribute(attr, self.read_General, self.write_General)

    def read_General(self, attr):
        self.info_stream("Reading attribute %s", attr.get_name())
        attr.set_value(99.99)

    def write_General(self, attr):
        self.info_stream("Writting attribute %s", attr.get_name())

Since I am not using the high-level Python API, I have created a command via POGO that creates a scalar attribute like so:


    def createScalarAttribute(self, argin):
        """ A method that creates a new scalar attribute.
        
        :param argin: New attribute name.
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevVoid """
        self.debug_stream("In createScalarAttribute()")
        #—– PROTECTED REGION ID(TPM_DS.createScalarAttribute) ENABLED START —–#
        attr = Attr(argin, PyTango.DevULong)
        self.add_attribute(attr, self.read_GeneralScalar, self.write_GeneralScalar)
        #—– PROTECTED REGION END —–#	//	TPM_DS.createScalarAttribute

Following this, I need to create new methods that are used for reading and writing this attribute. I can create these new methods in my python code, but since they are not in a protected region, every time I re-run POGO to add some other commands etc. these read/write methods are removed. Where would be the best place to put my methods?

Thanks. smile
Dr Andrea DeMarco, BSc (Hons) (Melita), MSc (Melita), DPhil (UEA)
Lecturer | Researcher
Department of Physics
Institute of Space Sciences and Astronomy

Room 220, Maths and Physics Building
University of Malta, Msida MSD2080, MALTA
Some additional information:

Given a method like the following, which creates a scalar attribute for a particular name, I require two methods for reading and writing this attribute. The method pointers are self.read_GeneralScalar (reading) and self.write_GeneralScalar.

    def createScalarAttribute(self, argin):
        """ A method that creates a new scalar attribute.
        
        :param argin: New attribute name.
        :type: PyTango.DevString
        :return: 
        :rtype: PyTango.DevVoid """
        self.debug_stream("In createScalarAttribute()")
        #—– PROTECTED REGION ID(TPM_DS.createScalarAttribute) ENABLED START —–#
        attr = Attr(argin, PyTango.DevULong)
        self.add_attribute(attr, self.read_GeneralScalar, self.write_GeneralScalar)
        #—– PROTECTED REGION END —–#	//	TPM_DS.createScalarAttribute

My problem is how to write those methods. In my scenario, when reading, I require the code to access an external API (which accesses the board given some parameters, and reads off a register value. So in my case I have written something like:

def read_GeneralScalar(self, attr):
        """ A method that reads from a scalar attribute.

        :param attr: The attribute to read from.
        :type: PyTango.DevAttr
        :return: The read data.
        :rtype: PyTango.DevULong """
        self.info_stream("Reading attribute %s", attr.get_name())
        arguments = {}
        dev = self.getDevice(attr.get_name())
        arguments['device'] = dev.value
        arguments['register'] = attr.get_name()
        arguments['words'] = 1
        arguments['offset'] = 0
        args = str(arguments)
        values_array = self.readRegister(args)  #get actual value by reading from register
        return values_array[0]  # readRegister returns an array, so a scalar requires a read from 0'th location

Am I right in assuming this function has to return the value? I ask because in this
tutorial, there seems to be a "set_value" method for Attr, which is not in the PyTango API (v.8.1.1)


    def read_General(self, attr):
        self.info_stream("Reading attribute %s", attr.get_name())
        attr.set_value(99.99)

Furthermore, when writing values to the attribute, I need to pass some actual data to the write function. So I would like to have this kind of function, where I am calling another method "writeRegister" with particular arguments as a string.

    def write_GeneralScalar(self, attr, data):
        """ A method that writes to a scalar attribute.

        :param attr: The attribute to write to.
        :type: PyTango.DevAttr
        :param data: The data to be written
        :type: PyTango.DevULong
        :return: Success or failure.
        :rtype: PyTango.DevBoolean """
        self.info_stream("Writing attribute %s", attr.get_name())
        arguments = {}
        dev = self.getDevice(attr.get_name())
        arguments['device'] = dev.value
        arguments['register'] = attr.get_name()
        arguments['offset'] = 0
        arguments['values'] = data
        args = str(arguments)
        return self.writeRegister(args)

But I'm not sure how the Tango device server would be able to pass the "data" argument. The tutorial mentioned above gives this example:


def write_General(self, attr):
        self.info_stream("Writting attribute %s", attr.get_name())

But I can't get how this writes to the attribute. Past API's seem to have had a set_value method, but this is not available anymore. Any help/suggestions are much appreciated.
Dr Andrea DeMarco, BSc (Hons) (Melita), MSc (Melita), DPhil (UEA)
Lecturer | Researcher
Department of Physics
Institute of Space Sciences and Astronomy

Room 220, Maths and Physics Building
University of Malta, Msida MSD2080, MALTA
Edited 8 years ago
Hi drea,

drea
Following this, I need to create new methods that are used for reading and writing this attribute. I can create these new methods in my python code, but since they are not in a protected region, every time I re-run POGO to add some other commands etc. these read/write methods are removed. Where would be the best place to put my methods?

I don't use pogo generator very often but unless I am mistaken, in the beginning of the device declaration there is an empty protected region (defined as global variables) you can use for that. Something like:


class MyDevice(PyTango.Device_4Impl):

    #——— Add you global variables here ————————–
    #—– PROTECTED REGION ID(MyDevice.global_variables) ENABLED START —–#

    def read_GeneralScalar(self, attr):
        pass

    def write_GeneralScalar(self, attr):
        pass
    
    #—– PROTECTED REGION END —–#	//	MyDevice.global_variables

drea
Am I right in assuming this function has to return the value? I ask because in this
tutorial, there seems to be a "set_value" method for Attr, which is not in the PyTango API (v.8.1.1)

When you declare a new attribute you do it with object Attr. When read_[…](self, attr) or write_(self, attr) is called, attr is an instance of Attribute (not Attr). You can find the documentation here

drea
Furthermore, when writing values to the attribute, I need to pass some actual data to the write function. So I would like to have this kind of function, where I am calling another method "writeRegister" with particular arguments as a string.
I am not sure I understand what you mean. I will assume that data is actually the value the client is trying to write into a certain attribute. If that is the case, then you should do:


class MyDevice(Device_4_impl):

    def write_GeneralAttribute(self, attr):
        name = attr.get_name()
        data = attr.get_write_value()
        self.info_stream("Writing into attribute %s the value %s", name, data)
        # […]

Hope it helps
Edited 8 years ago
Thanks a lot, that explains it perfectly! :)
Dr Andrea DeMarco, BSc (Hons) (Melita), MSc (Melita), DPhil (UEA)
Lecturer | Researcher
Department of Physics
Institute of Space Sciences and Astronomy

Room 220, Maths and Physics Building
University of Malta, Msida MSD2080, MALTA
Hi all,

I have another question related to creation of dynamic attributes. For the dynamic attributes created with the add_attribute() API call, I would also like to add optional parameters, such as MIN/MAX alarm values. The attr_list dictionary does not appear to be modifiable in PyTango as far as I can tell. On the other hand, using the Jive tool, I can set these values dynamically.

So assuming I have created an attribute in one of my commands with this code:

attr = Attr(argin, PyTango.DevULong)
self.add_attribute(attr, self.read_general_scalar, self.write_general_scalar)

How can I also add min/max alarm values (or any other optional parameters) to the attribute (perhaps even update old values)?

Thanks!
Dr Andrea DeMarco, BSc (Hons) (Melita), MSc (Melita), DPhil (UEA)
Lecturer | Researcher
Department of Physics
Institute of Space Sciences and Astronomy

Room 220, Maths and Physics Building
University of Malta, Msida MSD2080, MALTA
Hi,

To setup attribute properties at attribute creation time do:


attr = Attr(argin, PyTango.DevULong)
prop = PyTango.UserDefaultAttrProp()
prop.set_label("attr label")
prop.set_min_alarm("-5.0")
attr.set_default_properties(prop)
self.add_attribute(attr, self.read_general_scalar, self.write_general_scalar)

In the server, to update properties of an existing attribute do:


attr_name = "voltage"
multi_prop = PyTango.MultiAttrProp()
multi_attr = self.get_device_attr()
attribute = multi_attr.get_attr_by_name(attr_name)
multi_prop = attribute.get_properties()
multi_prop.label = "attr label"
multi_prop.min_alarm = "-5.0"
attribute.set_properties(multi_prop)

Hope it helps
That works wonderfully, thanks. I am still getting used to the API - I didn't know about MultiAttrProp() - problem solved now!
Dr Andrea DeMarco, BSc (Hons) (Melita), MSc (Melita), DPhil (UEA)
Lecturer | Researcher
Department of Physics
Institute of Space Sciences and Astronomy

Room 220, Maths and Physics Building
University of Malta, Msida MSD2080, MALTA
 
Register or login to create to post a reply.