Manage dynamically changed attributes and database.

Good day,

Is there a way for a PyTango device server to "catch" and handle any API_AttrNotFound exceptions at startup due to dynamic attributes that might not exist but have previously been stored in the database?

My application is for a generic device protocol translator allowing existing KATCP (http://pythonhosted.org/katcp/, https://casper.berkeley.edu/wiki/KATCP) devices to expose a TANGO interface. We are developing this at SKA SA potentially as a solution for allowing the MeerKAT telescope (which is based on KATCP) to interoperate with the forthcoming SKA telescope (which will be TANGO based).

When the translator starts up, it connectes to the KATCP device, and interrogates it for sensors and requests (equivalent to attributes and commands in Tango). Once it knows what the KATCP device has, it populates the Tango Device class using dynamic attributes / commands.

The problem occurs if attribute settings (polling, event, archiving event, etc) is written to the database, and the tango device is restarted. When it starts up it initially has no attributes (until it has communicated with the KATCP device), and the standard tango behavior of trying to re-apply settings from the data base fails with API_AttrNotFound.

How I would like to handle this is for the Tango Device to catch and cache all these errors. Once the KATCP is synced up, it can apply the settings from the database. Is there a way to do this with PyTango?

Thanks
Neilen
Hi
Until today, as I know, there is no way to catch this exception at startup.
The problem occurs with dynamic attributes, if polling has not been removed at server shutdown.
Or during development phase if you rename a pooled attribute.

I can just give a How To to remove polling to be able to start the server.
    - On Astor do a right click on specified server.
    - Select Polling Manager
    - On polling window unselect non existing attribute(s)
    - Click on Apply

I hope it helps
Pascal
Hi Neilen,
just to comment, the problem you report should only show up when you have dynamic attributes which no more exist, that is are no more created, but still have the polling configured. Moreover, consider the case to define you dynamic attributes before leaving the init_device() method. If you foresee you need to change your set of dynamic attributes at runtime then consider starting and stopping polling programmatically at device startup and shutdown.
Cheers,
Lorenzo
For now I fixed the problem by having the translator device wait for the KATCP client to be synced up before returning from init_device(). However, in the future I may want a more comprehensive solution. In init_device() there is still the opportunity to query the tango database and to set up placeholder attributes:


# inside init_device():
db = PyTango.Database()
name = self.get_name()

# I could not find out how to query the database for a list of properties with
# attributes. I ended up using a DeviceProxy to the database to get the list:
dbp = PyTango.DeviceProxy('sys/database/2')
attrs = dbp.DbGetDeviceAttributeList([name, '*'])
attr_props = db.get_device_attribute_property(name, attrs)
polled_attr_data = db.get_device_property(name, 'polled_attr')
# Do something here to intialise dynamic sensors to "receive" the settings.

It would be nice to maintain attribute properties (e.g. archive event settings) during a transient issue with the KATCP side of the equation.

Cheers
Neilen
Hi Neilen,

your proposal to catch the exception you mentioned (API_AttrNotFound) sounds reasonable. I suggest we add a feature request to catch as many exceptions as possible during the startup. It would allow to start servers in almost any condition which is what we recommend to all device server developers.

Andy
Hi,

was the feature request added? I could not find it in the GitHub issue tracker.

I have a Tango server in C++ where some attributes are created sometimes and sometimes not, so I also encountered the problem. I followed lorenzo's advice and am starting and stopping the polling programatically and it works well. Here it is in case somebody else needs it:

I use Pogo to set which attributes should be polled and then in add_dynamic_attributes(), after I created the dynamic attributes, I start the polling:

   for (Tango::Attribute *attr : get_device_attr()->get_attribute_list())
   {
      std::string attrName = attr->get_name();
      if (get_attribute_poll_period(attrName) <= 0)
         continue;
      int period = get_attribute_poll_period(attrName);
      DEBUG_STREAM << "Starting polling of " << attrName << " with period "
                   << period << ENDLOG;
      poll_attribute(attrName, period);
   }

In delete_device, I stop the polling:

   std::vector<std::string> polledAttrs;
   for (Tango::Attribute *attr : get_device_attr()->get_attribute_list())
   {
      std::string attrName = attr->get_name();
      if (is_attribute_polled(attrName))
         polledAttrs.push_back(attrName);
   }
   for (const string &attr : polledAttrs)
   {
      DEBUG_STREAM << "Stopping polling of " << attr << " with period "
                   << get_attribute_poll_period(attr) << ENDLOG;
      try
      {
         stop_poll_attribute(attr);
      }
      catch (const Tango::DevFailed &ex)
      {
         DEBUG_STREAM << "The attribute " << attr << " is not polled." << ENDLOG;
      }
   }
Cheers,
Josef
 
Register or login to create to post a reply.