Hi,
Let’s say you have a hardware device that sends you updates at more or less random intervals and that a client wants to receive events every time this happens. I tried to write a PyTango Device that simulates this using a thread that pushes new attribute values. Actually, I also want to have a simulator, so having the simulator work is useful too ![]()
I’m completely new to Tango, so I’m not sure what is the right way to go about it. Some questions:
-
What Device() methods are thread safe? I’m pretty sure I’m doing something wrong since if I uncomment the time.sleep() between set_value() and fire_change_event() I get segfaults. What is the correct way to do this? Is there a lock somewhere I must grab, or is there some thread-safe way to push the attribute value?
-
It seems set_value() stores the new value somewhere in the Attribute instance, but how to get hold of it? I would like the attribute read function to return that same value rather than having to cache it in a private variable.
-
Is it possible to control the attribute date when using the attribute read method? If a client does reading = dev.read_attribute(‘randomnumber’) (where dev is a DeviceProxy) I would like reading.time to refer to the time when the value was received from the device (i.e. the same time as used for self.randomnumber.set_date()), not the time that the attribute read method was called.
Below is my device server
Thanks
Neilen
import time
import threading
import random
import logging
import PyTango
from PyTango.server import server_run
from PyTango.server import Device, DeviceMeta
from PyTango.server import attribute, command
from PyTango import AttrQuality, AttrWriteType, DispLevel
logger = logging.getLogger('ThingumDS')
class Thingum(Device):
__metaclass__ = DeviceMeta
def __init__(self, *args, **kwargs):
logging.info('In __init__')
self._randomnumber = 0
super(Thingum, self).__init__(*args, **kwargs)
@attribute(label="Random Number", dtype=float,
access=AttrWriteType.READ)
def randomnumber(self):
print 'Reading randomnumber at {}'.format(time.time())
return self._randomnumber
@attribute
def time(self):
return time.time()
def init_device(self):
super(Thingum, self).init_device()
self.t = threading.Thread(target=self.update_loop)
self.t.setDaemon(True)
self.t.start()
def update_loop(self):
while True:
try:
new_number = random.randint(0, 10000)
ts = time.time()
sleeptime = random.random()*10
logger.info(
'Timestamp: {} New count: {} sleeptime: {}'
.format(ts, new_number, sleeptime))
self.randomnumber.set_value(new_number)
self.randomnumber.set_date(
PyTango.TimeVal.fromtimestamp(ts))
self._randomnumber = new_number
# Uncomment this sleep to get segfaults if a
#client reads an attribute
# time.sleep(10)
try:
self.randomnumber.fire_change_event()
except Exception:
logger.exception(
'Exception while firing change event')
time.sleep(sleeptime)
except Exception:
logger.exception('Exception in update loop')
time.sleep(1)
if __name__ == "__main__":
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s - '
'%(pathname)s : %(lineno)d - %(message)s',
level=logging.INFO)
server_run([Thingum])