Polling attributes

Hi all,

I have two commands Start and Stop. When I execute Start, the state is set to ON, and I want to read some data, then to wait some time (variable TimePause), and I want to do that continuously until I execute command Stop.

I have done this like below:

def Start(self):

self.set_state(PyTango.DevState.ON)


def Stop(self):

self.set_state(PyTango.DevState.OFF)


def read_Data(self, attr):

if (self.get_state() in [PyTango.DevState.RUNNING.ON]):
DO SOMETHING
self.attr_Data_read= data i have read;
time.sleep(TimePause)
attr.set_value(self.attr_Data_read)


But, in this way, I have to wait TimePause seconds for all atributes to update their values.
How can I do this so that one atribute is updated every TimePause seconds, and other attributes update their values by polling?

I hope I was clear and that someone can help me with this.

Cheers,
O
Edited 6 years ago
Hi O,

Let me clarify my understanding to the problem and later suggest you a solution.

While you execute the function read_Data, you want to update a particular attribute at every TimePause seconds while other attributes get updated by their polling.

Issue:
Now, the problem you are facing is because you have used sleep in the read_Data function, the main thread for your device is paused too. Hence, other attributes are taking the sleep time to update the values.

Solution:
You can create start a new read_Data thread when the Start command is fired. In the read_Data thread, you can include the logic of TimePause. You also need to add the logic to stop the read_Data thread when the Stop command is executed. In this way, your custom thread will run in parallel to the main thread and other attributes will get updated based on their polling.

I hope, I was able to understand the problem and clarify myself.

Kind regards,
Jyotin
I have wrote code below, is this OK? I have some errors, just want to check if I am on a good way.
t_read_Data is a thread, variable t_start is set to 1 when I execute command Start, and it is set to 0 when I execute command Stop.

import thread

def t_read_Data():
while(self.t_start==1)
DO_SOMETHING
self.attr_Data_read= data i have read;
time.sleep(TimePause)
attr.set_value(self.attr_Data_read())

def Start(self):

self.set_state(PyTango.DevState.ON)
self.t_start=1
thread.start_new_thread(t_read_Data)


def Stop(self):

self.set_state(PyTango.DevState.OFF)
self.t_start=0


Should I somehow specify in POGO that I created thread?
P.S. I would escape solvng this by creating new Thread subclass if it is possible.

Best regards,
O

Edited 6 years ago
Hi O,

Yes, you are on the correct path. There is no need to specify in POGO that you created a new thread.
Creating a new Thread subclass is worth exploring.

Feel free to let us know if you find any issues in between.

Kind regards,
Jyotin

Hi DanOb,

You are close the solution. I have three comments:
  1. You might want to use threading instead of thread (thread is low level python API)
  2. You should not do set_value in the thread. This causes a memory leak in C++.
  3. Maybe your device should be in state STANDBY when the server starts and RUNNING when someone executes the command Start.

Here is a proposal:


import threading

class MyDevice:

    def init_device(self):
        self.__stop = True
        self.__loop = None
        self.__data = None
        self.set_state(STANDBY)
   
    def delete_device(self):
        self.Stop()

    def read_loop(self):
        self.set_state(RUNNING)
        try:
            while not self.__stop:
                self.__data = do_something_and_return_data();
                time.sleep(TimePause)
        finally:
            self.set_state(STANDBY)
            self.__data = None
   
    def Start(self):
        if self.__loop:
            raise RuntimeError("device is already started")
        self.__stop = False
        self.__loop = threading.Thread(target=self.read_loop)
        self.__loop.start()

    def Stop(self):
        if self.__loop:
            self.__stop = True
            self.__loop.join()
            self.__loop = None

    # assuming attribute is called "MyAttribute"
    def read_MyAttribute(self, attr):
        if self.__loop is None:
            raise RuntimeError("No value: device is not started")
        if self.__data is None:
            raise RuntimeError("No value available yet")
        attr.set_value(self.__data)


Edited 6 years ago
Po,

I have solved problem, and now everything works just fine.
I will try to do this with Thread subclass also.
Thank you very much for your help, I really appreciate it!

Cheers,
O
TCoutInho, I have not seen your post till now. Thank you for your help.
I have tried what you proposed, and I like the idea, but I have next problem:

Let's say that polling is executed every 3 seconds and that I change my data values every 500ms.
In your way, read_MyAttribute will be called every 3 seconds, which means that attribute will be updated by every 6th data value.
I've used set_value in the thread because I wanted every time I get new data value to update my attribute.
How can I solve this problem without calling set_value in the thread?

I hope I was clear, please tell me if I should be more specific or clearer.

Many thanks,
O
Edited 6 years ago
Hi,

in C++, I think you don't get any memory leak if you fire a change or archive event after having invoked set_value from a thread. You will need to declare in Pogo that you will push events by user code for this attribute and add a call to the PyTango equivalent of C++ Tango::Attribute::fire_change_event() method (I'm no PyTango expert so I don't know the exact syntax in PyTango).
You might also consider using the externally triggered polling advanced feature from Tango (See 7.3.5 section from the Tango book), using trigger_attr_polling() method. Again, I don't know how you do that in PyTango.

Kind regards,
Reynald
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
First let me say that I assume when you said polling you were not talking about tango polling since you asked to start your own thread. Therefore, the solution I proposed does not involve tango polling.


DanOb
Let's say that polling is executed every 3 seconds and that I change my data values every 500ms.
In your way, read_MyAttribute will be called every 3 seconds, which means that attribute will be updated by every 6th data value.
I've used set_value in the thread because I wanted every time I get new data value to update my attribute.
How can I solve this problem without calling set_value in the thread?
In practice, my proposal only solves the problems I mentioned before (*)
When a client asks to read the value of the attribute MyAttribute, on the server side, the method read_MyAttribute is invoked. What it is doing is fetching the last value updated by the thread and send it back to the client. In other words, the client always gets the last value which was updated by the thread.
If the client reads more often than the value is updated by the loop thread then of course it will read several times the same value. The only solution I know is to increase the polling frequency.


(*) actually it solves also a problem that occurs if a client reads more often than the server updates the value.

Edited 6 years ago
Thank you for answers guys, I will definitely try trigger_attr_polling() Reynald, it looks interesting. :)

I have one more question, though. In Tango manual, page 84, is said:

But if the object (attribute) is not marked as event driven, the REFRESH () method of the A TTRIBUTE L IST , asks the object to refresh itself by calling the “ REFRESH ()” method of that object (attribute or device). The REFRESH () method of an attribute will in turn call the “readAttribute” on the Tango device.
Does this mean that only difference between polling and refreshing period (which is set from AtkPanel) is that refreshing period only calls readAttribute, while polling also calls always_executed_hook and read_attr_hardware?
And If I am right, attribute's value is displayed in AtkPanel whenever metod readAttribute is called?

Many thanks,
O
Edited 6 years ago
 
Register or login to create to post a reply.