Example #1
0
 def __init__(self):
     self.__alarm_queue = Queue()
     self.__current_thread = None
     self.__lock = Lock()
     self._init_default_attribute_values()
     Client.__init__(self)
     return
Example #2
0
 def setUp(self):
     DefaultTestFixture.setUp(self)
     self.lock = Lock()
     self.pool = ThreadPool(3)
     self.queue = Queue()
     self.simple_action_counter = 0
     return
Example #3
0
 def __init__(self):
     ServiceNode.__init__(self)
     EventConsumerMixin.__init__(self, self.handle_alarm, \
                                 self.handle_exception)
     self.__running = 0
     self.__queue = Queue()
     self._id_manager = None
     self._dynamic_alarms = {}
     return
Example #4
0
 def __init__(self):
     self.__server = None
     self.__sched_lock = Lock()
     self.__sched_thread = None
     self.__schedules = Queue()
     self.__pv = None
     super(LightingGroup, self).__init__()
     EventConsumerMixin.__init__(self, self._sched_update,
                                 self._sched_exception)
     return
Example #5
0
 def __init__(self):
     AVRNode.__init__(self)
     AutoDiscoveredNode.__init__(self)
     self._lock = Lock()
     self.conversion_list = {}
     self._queue = Queue()
     self.debug = 0
     self.running = 0
     self._start_called = 0
     self.devices = ''
     self.device_addresses = []
     self._been_discovered = 0
 def setUp(self):
     DefaultTestFixture.setUp(self)
     self.lock = Lock()
     self.pool = ThreadPool(3)
     self.queue = Queue()
     self.simple_action_counter = 0
     return
Example #7
0
 def _startmanager(self):
     self._queue = queue = Queue()
     self._stopflag = stopflag = Flag()
     self._thread = thread = ImmortalThread(name=self.url,
                                            target=self._runmanager,
                                            args=(stopflag, queue))
     thread.start()
Example #8
0
 def __init__(self):
     self.__alarm_queue = Queue()
     self.__current_thread = None
     self.__lock = Lock()
     self._init_default_attribute_values()
     Client.__init__(self)
     return
Example #9
0
 def _proxy_start_active_mode(self):
     if self.link:
         try:
             if self._proxy_sid is None:  #have not started subscription service yet
                 if self.proxy_direction == GET_ONLY:
                     self._proxy_active_source = self._proxy_linked_node()
                     if self._proxy_active_source is None:
                         raise ENotStarted()
                     self._proxy_active_destination = self
                 else:  #SET_ONLY
                     self._proxy_active_source = self
                     self._proxy_active_destination = self._proxy_linked_node(
                     )
                     if self._proxy_active_destination is None:
                         raise ENotStarted()
                 self._proxy_active_queue = Queue()
                 self._proxy_sid = SM.create_delivered(
                     self, {1: self._proxy_active_source})
                 if self.debug:
                     print 'Active proxy %s started successfully' % (
                         self.name)
         except:
             #it didn't work.  Setup schedule to try again in x seconds.
             if self._retry_win_high < 90:
                 self._retry_win_high += 1
             retry_in = randint(int(self._retry_win_high * .66),
                                self._retry_win_high)
             scheduler.seconds_from_now_do(retry_in,
                                           self._proxy_start_active_mode)
             #raise  #took this out since it mostly just served to force the scheduler tread to restart
             if self.debug: msglog.exception()
Example #10
0
 def __init__(self):
     ServiceNode.__init__(self)
     EventConsumerMixin.__init__(self, self.handle_alarm, \
                                 self.handle_exception)
     self.__running = 0
     self.__queue = Queue()
     self._id_manager = None
     self._dynamic_alarms = {}
     return
Example #11
0
 def __init__(self):
     AVRNode.__init__(self)
     AutoDiscoveredNode.__init__(self)
     self._lock = Lock()
     self.conversion_list = {}
     self._queue = Queue()
     self.debug = 0
     self.running = 0
     self._start_called = 0
     self.devices = ''
     self.device_addresses = []
     self._been_discovered = 0
Example #12
0
class EWebConnectAlarmClient(Client):
    _batch_mode_default = 0
    _host_default = REQUIRED
    _port_default = 4546
    _timeout_default = 60

    def _init_default_attribute_values(self):
        self.batch_mode = self._batch_mode_default
        self.host = self._host_default
        self.port = self._port_default
        self.timeout = self._timeout_default
        return

    def __init__(self):
        self.__alarm_queue = Queue()
        self.__current_thread = None
        self.__lock = Lock()
        self._init_default_attribute_values()
        Client.__init__(self)
        return

    def configure(self, config):
        Client.configure(self, config)
        set_attribute(self, 'batch_mode', self._batch_mode_default, config,
                      int)
        set_attribute(self, 'host', self._host_default, config, str)
        set_attribute(self, 'port', self._port_default, config, int)
        set_attribute(self, 'timeout', self._timeout_default, config, int)
        return

    def configuration(self):
        config = Client.configuration(self)
        get_attribute(self, 'batch_mode', config, int)
        get_attribute(self, 'host', config, str)
        get_attribute(self, 'port', config, int)
        get_attribute(self, 'timeout', config, int)
        return config

    def start(self):
        self.__lock.acquire()
        try:
            self.__running = 1
            self.register_event(NewAlarmsEvent, self._new_alarms)
        finally:
            self.__lock.release()
        Client.start(self)
        self.debug = 1

    def stop(self):
        self.__lock.acquire()
        try:
            self.unregister_event(NewAlarmsEvent)
            self.__running = 0
        finally:
            self.__lock.release()
        Client.stop(self)

    def is_running(self):
        return self.__running

    def message_log(self, message, message_type=msglog.types.DB):
        if message_type != msglog.types.DB or self.debug:
            msglog.log('EWebConnect Alarm Client', message_type, message)

    ##
    # Event handler for the NewAlarmsEvent
    #
    # Queues each new alarm for processing and then schedules
    # _prime_process_alarm_queue() on a thread pool to ensure that alarms
    # are processed.
    def _new_alarms(self, event):
        self.__lock.acquire()
        try:
            if not self.is_running():
                raise ENotStarted('%s' % self.as_node_url())
        finally:
            self.__lock.release()
        for alarm in event:
            self.__alarm_queue.put(alarm.as_dictionary())
        self.message_log('New Alarms Event, queuing action')
        LOW.queue_noresult(self._prime_process_alarm_queue)
        return

    ##
    # If no thread is actively processing the alarm queue, then set this thread
    # as the current alarm queue processor and invoke _process_alarm_queue().
    #
    # @note This method is in invoked as an action queued on a thread pool and
    #       should never be called directly when processing an event.
    def _prime_process_alarm_queue(self):
        # @todo Save queue in a PDO?
        thread = currentThread()
        self.__current_thread = thread
        self._process_alarm_queue(thread)

    ##
    # Process all alarms on the alarm queue.
    #
    # @note This method is in invoked indirectly as an action queued on a
    #       thread pool and should never be called directly when processing an
    #       event.
    def _process_alarm_queue(self, my_thread):
        self.message_log('Processing Alarm Queue...')
        while my_thread == self.__current_thread:
            alarm_dict = self.__alarm_queue.get(0)
            if alarm_dict is NOTHING:
                break
            try:
                self._send_alarm_dict(alarm_dict)
            except:
                self.message_log('Failed to send alarm:\n  %r' % alarm_dict,
                                 msglog.types.ERR)
                msglog.exception()
        else:
            self.message_log(
                'New alarm process coincided with running process')
        self.message_log('Finished Processing Alarm Queue')

    ##
    # Format the Alarm described by alarm_dict as an eWebConnect Alarm
    # message and send it to the eWebConnect server.
    # @note This method always succeeds to format a message, any field that
    #       is not valid for any reason is set to "N/A".   Furthermore,
    #       this method does not intercept any networking failures as it
    #       is the caller's responsibility to handle retries, etc...
    def _send_alarm_dict(self, alarm_dict):
        if self.host is None:
            self.message_log(
                'Failed to send alarm; host address is None:\n  %r' %
                alarm_dict, msglog.types.INFO)
            return  # nowhere to send it!
        ewebconnect_text = (
            "%(timestamp)s, %(TZ)s, %(host)s, %(what)s, %(code)s:"
            " %(type)s %(text)s") % {
                "timestamp": self._alarm_timestamp(alarm_dict),
                "TZ": self._alarm_tz(alarm_dict),
                "host": self._alarm_host(alarm_dict),
                "what": self._alarm_what(alarm_dict),
                "code": self._alarm_code(alarm_dict),
                "type": self._alarm_type(alarm_dict),
                "text": self._alarm_text(alarm_dict),
            }
        self.message_log('Sending Alarm: %s' % ewebconnect_text)
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            # @fixme Try block only exists because the normal desctructor
            #        invokation does not appear to work on mpx.lib.socket
            #        sockets which is a big deal if there is an exception.
            #        - mevans
            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server_socket.connect((self.host, self.port), self.timeout)
            server_socket.sendall(ewebconnect_text, self.timeout)
        finally:
            # A finally block is used because the normal desctructor invokation
            # does not appear to work on mpx.lib.socket socket's. - mevans
            # @fixme Figure out why!
            server_socket.close()  # Could this hang?  Should I use shutdown?
        self.message_log('Alarm Sent')
        return

    ##
    # Convert an Alarm's time-stamp to a string in eWebConnect's format.
    #
    # @param alarm_dict The dictionary representation of an Alarm, presumably
    #                   returned by the Alarm's as_dictionary() method.
    # @return A string representing the the time-stamp in eWebConnect's format.
    # @note Any failure during the conversion results in the string "N/A" and
    #       the exception is logged to the msglog.  This is to help ensure that
    #       the alarm is still delivered with as much useful information as
    #       possible.
    def _alarm_timestamp(self, alarm_dict):
        result = "N/A"
        try:
            localtime = time.localtime(alarm_dict['timestamp'])
            result = time.strftime("%m/%d/%Y %H:%M:%S", localtime)
        except:
            msglog.exception()
        return result

    ##
    # @see _alarm_timestamp().
    def _alarm_tz(self, alarm_dict):
        result = "N/A"
        try:
            is_dst = time.localtime(alarm_dict['timestamp']).tm_isdst
            result = time.tzname[is_dst]
        except:
            msglog.exception()
        return result

    ##
    # @see _alarm_timestamp().
    def _alarm_host(self, alarm_dict):
        result = "N/A"
        try:
            # @fixme F/W should have this as a 'system attribute' (aka
            #        property) and should support COV on properties.
            result = socket.gethostbyaddr(socket.gethostname())[0]
        except:
            msglog.exception()
        return result

    ##
    # @see _alarm_timestamp().
    def _alarm_code(self, alarm_dict):
        result = "N/A"
        try:
            result = alarm_dict['state']
        except:
            msglog.exception()
        return result

    ##
    # @see _alarm_timestamp().
    def _alarm_what(self, alarm_dict):
        result = "ALARM"
        return result

    ##
    # @see _alarm_timestamp().
    def _alarm_type(self, alarm_dict):
        result = "N/A"
        try:
            result = alarm_dict['type']
        except:
            msglog.exception()
        return result

    ##
    # @see _alarm_timestamp().
    def _alarm_text(self, alarm_dict):
        result = "N/A"
        try:
            result = alarm_dict['data']
        except:
            msglog.exception()
        return result
Example #13
0
class EWebConnectAlarmClient(Client):
    _batch_mode_default = 0
    _host_default = REQUIRED
    _port_default = 4546
    _timeout_default = 60
    def _init_default_attribute_values(self):
        self.batch_mode = self._batch_mode_default
        self.host = self._host_default
        self.port = self._port_default
        self.timeout = self._timeout_default
        return
    def __init__(self):
        self.__alarm_queue = Queue()
        self.__current_thread = None
        self.__lock = Lock()
        self._init_default_attribute_values()
        Client.__init__(self)
        return
    def configure(self,config):
        Client.configure(self,config)
        set_attribute(self,'batch_mode', self._batch_mode_default, config, int)
        set_attribute(self,'host', self._host_default, config, str)
        set_attribute(self,'port', self._port_default, config, int)
        set_attribute(self,'timeout', self._timeout_default, config, int)
        return
    def configuration(self):
        config = Client.configuration(self)
        get_attribute(self, 'batch_mode', config, int)
        get_attribute(self, 'host', config, str)
        get_attribute(self, 'port', config, int)
        get_attribute(self, 'timeout', config, int)
        return config
    def start(self):
        self.__lock.acquire()
        try:
            self.__running = 1
            self.register_event(NewAlarmsEvent,self._new_alarms)
        finally:
            self.__lock.release()
        Client.start(self)
        self.debug = 1
    def stop(self):
        self.__lock.acquire()
        try:
            self.unregister_event(NewAlarmsEvent)
            self.__running = 0
        finally:
            self.__lock.release()
        Client.stop(self)
    def is_running(self):
        return self.__running
    def message_log(self,message,message_type=msglog.types.DB):
        if message_type != msglog.types.DB or self.debug:
            msglog.log('EWebConnect Alarm Client',message_type,message)
    ##
    # Event handler for the NewAlarmsEvent
    #
    # Queues each new alarm for processing and then schedules
    # _prime_process_alarm_queue() on a thread pool to ensure that alarms
    # are processed.
    def _new_alarms(self, event):
        self.__lock.acquire()
        try:
            if not self.is_running():
                raise ENotStarted('%s' % self.as_node_url())
        finally:
            self.__lock.release()
        for alarm in event:
            self.__alarm_queue.put(alarm.as_dictionary())
        self.message_log('New Alarms Event, queuing action')
        LOW.queue_noresult(self._prime_process_alarm_queue)
        return
    ##
    # If no thread is actively processing the alarm queue, then set this thread
    # as the current alarm queue processor and invoke _process_alarm_queue().
    #
    # @note This method is in invoked as an action queued on a thread pool and
    #       should never be called directly when processing an event.
    def _prime_process_alarm_queue(self):
        # @todo Save queue in a PDO?
        thread = currentThread()
        self.__current_thread = thread
        self._process_alarm_queue(thread)
    ##
    # Process all alarms on the alarm queue.
    #
    # @note This method is in invoked indirectly as an action queued on a
    #       thread pool and should never be called directly when processing an
    #       event.
    def _process_alarm_queue(self,my_thread):
        self.message_log('Processing Alarm Queue...')
        while my_thread == self.__current_thread:
            alarm_dict = self.__alarm_queue.get(0)
            if alarm_dict is NOTHING:
                break
            try:
                self._send_alarm_dict(alarm_dict)
            except:
                self.message_log('Failed to send alarm:\n  %r' % alarm_dict,
                                 msglog.types.ERR)
                msglog.exception()
        else:
            self.message_log('New alarm process coincided with running process')
        self.message_log('Finished Processing Alarm Queue')
    ##
    # Format the Alarm described by alarm_dict as an eWebConnect Alarm
    # message and send it to the eWebConnect server.
    # @note This method always succeeds to format a message, any field that
    #       is not valid for any reason is set to "N/A".   Furthermore,
    #       this method does not intercept any networking failures as it
    #       is the caller's responsibility to handle retries, etc...
    def _send_alarm_dict(self, alarm_dict):
        if self.host is None:
            self.message_log('Failed to send alarm; host address is None:\n  %r' % alarm_dict,
                                 msglog.types.INFO)
            return # nowhere to send it!
        ewebconnect_text = (
            "%(timestamp)s, %(TZ)s, %(host)s, %(what)s, %(code)s:"
            " %(type)s %(text)s"
            ) % {
            "timestamp":self._alarm_timestamp(alarm_dict),
            "TZ":self._alarm_tz(alarm_dict),
            "host":self._alarm_host(alarm_dict),
            "what":self._alarm_what(alarm_dict),
            "code":self._alarm_code(alarm_dict),
            "type":self._alarm_type(alarm_dict),
            "text":self._alarm_text(alarm_dict),
            }
        self.message_log('Sending Alarm: %s' % ewebconnect_text)
        server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        try:
            # @fixme Try block only exists because the normal desctructor
            #        invokation does not appear to work on mpx.lib.socket
            #        sockets which is a big deal if there is an exception.
            #        - mevans
            server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
            server_socket.connect((self.host, self.port), self.timeout)
            server_socket.sendall(ewebconnect_text, self.timeout)
        finally:
            # A finally block is used because the normal desctructor invokation
            # does not appear to work on mpx.lib.socket socket's. - mevans
            # @fixme Figure out why!
            server_socket.close() # Could this hang?  Should I use shutdown?
        self.message_log('Alarm Sent')
        return
    ##
    # Convert an Alarm's time-stamp to a string in eWebConnect's format.
    #
    # @param alarm_dict The dictionary representation of an Alarm, presumably
    #                   returned by the Alarm's as_dictionary() method.
    # @return A string representing the the time-stamp in eWebConnect's format.
    # @note Any failure during the conversion results in the string "N/A" and
    #       the exception is logged to the msglog.  This is to help ensure that
    #       the alarm is still delivered with as much useful information as
    #       possible.
    def _alarm_timestamp(self, alarm_dict):
        result = "N/A"
        try:
            localtime = time.localtime(alarm_dict['timestamp'])
            result = time.strftime("%m/%d/%Y %H:%M:%S", localtime)
        except:
            msglog.exception()
        return result
    ##
    # @see _alarm_timestamp().
    def _alarm_tz(self, alarm_dict):
        result = "N/A"
        try:
            is_dst = time.localtime(alarm_dict['timestamp']).tm_isdst
            result = time.tzname[is_dst]
        except:
            msglog.exception()
        return result
    ##
    # @see _alarm_timestamp().
    def _alarm_host(self, alarm_dict):
        result = "N/A"
        try:
            # @fixme F/W should have this as a 'system attribute' (aka
            #        property) and should support COV on properties.
            result = socket.gethostbyaddr(socket.gethostname())[0]
        except:
            msglog.exception()
        return result
    ##
    # @see _alarm_timestamp().
    def _alarm_code(self, alarm_dict):
        result = "N/A"
        try:
            result = alarm_dict['state']
        except:
            msglog.exception()
        return result
    ##
    # @see _alarm_timestamp().
    def _alarm_what(self, alarm_dict):
        result = "ALARM"
        return result
    ##
    # @see _alarm_timestamp().
    def _alarm_type(self, alarm_dict):
        result = "N/A"
        try:
            result = alarm_dict['type']
        except:
            msglog.exception()
        return result
    ##
    # @see _alarm_timestamp().
    def _alarm_text(self, alarm_dict):
        result = "N/A"
        try:
            result = alarm_dict['data']
        except:
            msglog.exception()
        return result
Example #14
0
class AlarmManager(ServiceNode,EventConsumerMixin):
    def __init__(self):
        ServiceNode.__init__(self)
        EventConsumerMixin.__init__(self, self.handle_alarm, \
                                    self.handle_exception)
        self.__running = 0
        self.__queue = Queue()
        self._id_manager = None
        self._dynamic_alarms = {}
        return
    def configure(self, config):
        ServiceNode.configure(self, config)
        if self._id_manager is None:
            self._id_manager = UniqueID(self)
        return
    def unique_id(self):
        return self._id_manager.allocate_id()
    def active(self):
        children = []
        for child in self.chidlren_nodes():
            if child.active():
                children.append(child)
        return children
    def acknowledged(self):
        children = []
        for child in self.children_nodes():
            if child.active() and child.acknowledged():
                children.append(child)
        return children
    def unacknowledged(self):
        children = []
        for child in self.children_nodes():
            if child.active() and not child.acknowledged():
                children.append(child)
        return children
    def add_dynamic_alarm(self, dynamic_alarm):
        dynamic_alarm_id = id(dynamic_alarm)
        if not self._dynamic_alarms.has_key(dynamic_alarm_id):
            self._dynamic_alarms[dynamic_alarm_id] = dynamic_alarm
            dynamic_alarm.event_subscribe(self, AlarmTriggerEvent)
            dynamic_alarm.event_subscribe(self, AlarmClearEvent)
        return
    def start(self):
        if not self.__running:
            known_alarms = self.get_child('alarms')
            for child in known_alarms.children_nodes():
                child.event_subscribe(self, AlarmTriggerEvent)
                child.event_subscribe(self, AlarmClearEvent)
            self.__running = 1
            self.__thread = ImmortalThread(name=self.name,target=self.__run)
            self.__thread.start()
            ServiceNode.start(self)
        return
    def stop(self):
        self.__running = 0
        self.__thread = None
        self.__queue.put(None)
        try:
            # @fixme try/except/else is a hack to survive testcases use
            #        of prune.  Really should revisit...
            alarms = self.get_child('alarms')
        except:
            pass
        else:
            for child in alarms.children_nodes():
                child.cancel(self, AlarmTriggerEvent)
                child.cancel(self, AlarmClearEvent)
        return ServiceNode.stop(self)
    def queue_alarm_check(self,alarm):
        self.__queue.put(alarm)
    def __run(self):
        while self.__running:
            alarm = self.__queue.get()
            if alarm:
                alarm.check_condition()
        else:
            self.__thread.should_die()
        return
    ##
    # Both AlarmClear and AlarmTrigger events come here,
    # separate the two and send to the appropriate handler.
    def handle_alarm(self, alarm):
        alarm.source.caught(alarm)
        if self.debug:
            msglog.log('broadway',msglog.types.ALARM,str(alarm))
        if alarm.__class__ == AlarmTriggerEvent:
            return self._handle_trigger(alarm)
        elif alarm.__class__ == AlarmClearEvent:
            return self._handle_clear(alarm)
        msglog.log('broadway', msglog.types.WARN,'Alarm manager %s got ' +
                   'an event that it does not recoginize, ignoring.' % 
                   self.name)
    def _handle_trigger(self, alarm):
        export_thread = Thread(name=alarm.source.name,
                               target=self._run_exports,
                               args=(alarm,))
        export_thread.start()
    def _run_exports(self,alarm):
        if self.has_child('exporters'):
            exporters = self.get_child('exporters').children_nodes()
            exceptions = []
            for exporter in exporters:
                try:
                    exporter.export(alarm)
                except Exception, e:
                    msglog.exception()
                    exceptions.append(e)
            if exceptions:
                alarm.source.fail(alarm)
            else:
                alarm.source.success(alarm)
        else:
Example #15
0
class TestCase(DefaultTestFixture):
    def setUp(self):
        DefaultTestFixture.setUp(self)
        self.lock = Lock()
        self.pool = ThreadPool(3)
        self.queue = Queue()
        self.simple_action_counter = 0
        return

    def tearDown(self):
        self.pool._unload()
        DefaultTestFixture.tearDown(self)
        return

    def simple_action(self, object):
        # @note It appears that even the '+= 1' operation is not
        #       guaranteed to be atomic.
        self.lock.acquire()
        self.simple_action_counter += 1
        self.lock.release()
        return 'simple_action_result'

    def slow_action(self, object):
        time.sleep(1.0)
        return 'slow_action_result'

    def simple_queue_action(self, object):
        self.queue.put(object)
        return

    def test_simple_queue(self):
        self.pool.queue(self.simple_queue_action, self)
        result = self.queue.get(1.0)
        if result is not self:
            raise "Queue returned %r instead of self, %r." % (result, self)
        return

    def test_result(self):
        t1 = time.time()
        pending_result = self.pool.queue(self.simple_action, self)
        result = pending_result.result(10.0)
        t2 = time.time()
        if result != 'simple_action_result':
            raise ("pending_result.result() returned the wrong value (%s)." %
                   result)
        if (t2 - t1) >= 10.0:
            raise "pending_result.result() blocked for no reason."
        return

    def test_pending_reasult(self):
        t1 = time.time()
        pending_result = PendingResult(None, None, self.simple_action, self)
        pending_result_two = self.pool.queue_pending_result(pending_result)
        if pending_result_two is not pending_result:
            raise "pending_result_two is NOT pending_result"
        result = pending_result.result(10.0)
        t2 = time.time()
        if result != 'simple_action_result':
            raise ("pending_result.result() returned the wrong value (%s)." %
                   result)
        if (t2 - t1) >= 10.0:
            raise "pending_result.result() blocked for no reason."
        return

    def test_pending_action(self):
        pending_action = PendingAction(self.simple_queue_action, self)
        self.pool.queue_pending_action(pending_action)
        result = self.queue.get(1.0)
        if result is not self:
            raise "Queue returned %r instead of self, %r." % (result, self)
        return
        return

    def test_result_timeout(self):
        t1 = time.time()
        pending_result = self.pool.queue(self.slow_action, self)
        result = pending_result.result(0.25)
        t2 = time.time()
        if (t2 - t2) >= 1.0:
            raise "Blocked 1 second when a 1/4 second timeout."
        if result != NORESULT:
            raise "Got a result (%s) when none was expected."
        return

    def test_1000_actions(self):
        for i in xrange(0, 1000):
            self.pool.queue(self.simple_action, self)
        time.sleep(0.1)
        t1 = time.time()
        while self.simple_action_counter < 1000:
            tn = time.time()
            if (tn - t1) > 3.0:
                raise (
                    "Taking ridiculously long to process 1000 queued actions.")
            time.sleep(0.1)
        return

    def test_HIGH_pool_1(self):
        t1 = time.time()
        pending_result = HIGH.queue(self.simple_action, self)
        result = pending_result.result(10.0)
        t2 = time.time()
        if result != 'simple_action_result':
            raise ("pending_result.result() returned the wrong value (%s)." %
                   result)
        if (t2 - t1) >= 10.0:
            raise "pending_result.result() blocked for no reason."
        return

    def test_HIGH_pool_2(self):
        self.test_HIGH_pool_1()
        return

    def test_HIGH_pool_resize_1(self):
        HIGH.resize(1)
        if HIGH.size() != 1:
            raise "Resize to 1 thread failed."
        for i in xrange(0, 100):
            HIGH.queue(self.simple_action, self)
        t1 = time.time()
        while self.simple_action_counter < 100:
            tn = time.time()
            if (tn - t1) > 3.0:
                raise (
                    "Taking ridiculously long to process 100 queued actions.")
            time.sleep(0.1)
        return

    def test_HIGH_pool_resize_20(self):
        HIGH.resize(20)
        if HIGH.size() != 20:
            raise "Resize to 20 threads failed."
        for i in xrange(0, 100):
            HIGH.queue(self.simple_action, self)
        t1 = time.time()
        while self.simple_action_counter < 100:
            tn = time.time()
            if (tn - t1) > 3.0:
                raise (
                    "Taking ridiculously long to process 100 queued actions.")
            time.sleep(0.1)
        return
Example #16
0
class DallasBus(AVRNode, AutoDiscoveredNode):

    # Cached commands that are independant of the bus.
    getkey_cmd = '\x15\x00\x01\xb0'

    def __init__(self):
        AVRNode.__init__(self)
        AutoDiscoveredNode.__init__(self)
        self._lock = Lock()
        self.conversion_list = {}
        self._queue = Queue()
        self.debug = 0
        self.running = 0
        self._start_called = 0
        self.devices = ''
        self.device_addresses = []
        self._been_discovered = 0

    def lock(self):
        self._lock.acquire()
    def unlock(self):
        self._lock.release()

    ##
    # @see node.AVRNode#configure
    #
    def configure(self,config):
        AVRNode.configure(self,config)
        id_chr = chr(self.id)

        # Commands cached in their entirety
        self.reset_cmd = '\x15\x00\x02\x10' + id_chr
        self.scan_cmd = '\x15\x00\x02\xc0' + id_chr
        self.unscan_cmd = '\x15\x00\x02\xd0' + id_chr
        self.convert_cmd = '\x15\x01\x04\x70' + id_chr + '\x01\x44'
        self.readscratch_cmd = '\x15\x00\x04\x70' + id_chr + '\x01\xbe'
        self.readrom_cmd = '\x15\x00\x04\x70' + id_chr + '\x01\x33'
        self.findfirst_cmd = '\x15\x00\x02\x80' + id_chr
        self.findfamily_cmd = '\x15\x00\x02\x81' + id_chr
        self.findnext_cmd = '\x15\x00\x03\x82' + id_chr + '\x00'
        # The beginning of commands of known length.
        self.matchrom_base = '\x15\x00\x0c\x70' + id_chr + '\x09\x55'
        self.skiprom_cmd = '\x15\x00\x04\x70' + id_chr + '\x01\xcc'
        self.readbits_base = '\x15\x00\x03\x40' + id_chr
        self.readbytes_base = '\x15\x00\x03\x50' + id_chr
        # Cached command codes + bus id.
        self.writebits_id = '\x60' + id_chr
        self.writebytes_id = '\x70' + id_chr
        return
    
    def configuration(self):
        self.devices, self.device_addresses = self.findall()
        self._been_discovered = 0
        config = AVRNode.configuration(self)
        get_attribute(self, 'devices', config)
        return config
        

    def _add_child(self, node):
        AVRNode._add_child(self, node)
        if not self.running and self._start_called:
            self.start()

    ##
    # start temperature conversions
    #
    def start(self):
        AVRNode.start(self)
        self._start_called = 1
        self.devices, self.device_addresses = self.findall()
        if self.running:
            raise EAlreadyRunning()

        # Inform in msglog the number of devices on the dallas bus and their addresses (CSCtl81599)
        if(self.devices == None ):
            no_of_devices=0
        else:
            no_of_devices=len(self.device_addresses)
        msglog.log('broadway',msglog.types.INFO,'There are %d devices found on "%s" bus' %(no_of_devices, self.name))
        if no_of_devices:
            addr_str=''
            for addr in self.device_addresses:
                dallas_bus_addr=address_to_asciihex(addr)
                addr_str=addr_str+' '+dallas_bus_addr
            msglog.log('broadway',msglog.types.INFO,'The device addresses on "%s" bus : %s\n' %(self.name,addr_str))
        
        # Start the thread to read the dallas bus irrespective for whether the devices are
        # present or not (CSCtl81599)
        self.running = 1
        thread = Thread(name=self.name,target=self._queue_thread,args=())
        self.request(self._convert_temperature_sensor_list)
        thread.start()            

    def stop(self):
        self.running = 0

    ##
    # discover and create object instances
    #
    def _discover_children(self, force=0):
        if force:
            self._been_discovered = 0
        if self.running == 1 and not self._been_discovered:
            # do a find_all irrespective of whether there are ny devices found previously (CSCtl81599)
            self.devices, self.device_addresses = self.findall()
            # get a list of addresses in existing children
            existing = self.children_nodes(auto_discover=0)
            existing = filter(lambda dev : hasattr(dev,'address'), existing)
            existing = [dev.address for dev in existing]
            for addr in self.device_addresses:
                if addr not in existing and not self._nascent_children.get(address_to_asciihex(addr), None):
                    if ord(addr[0]) in (0x28,0x10): # need to add new types
                        # add a new instance to the _nascent children
                        
                        t = Temperature()
                        t.address = addr
                        t.model = _models[family_name[ord(addr[0])]]
                        self._nascent_children[address_to_asciihex(addr)] = t
            # self._been_discovered = 1 #disabled to allow new objects to be discovered
        return self._nascent_children
    ##
    # Create a dallas message for a cmd and flags.
    #
    # @param cmd  The command turn into a message.
    # @param flags  Flags to send with message.
    # @return Dallas_message representing <code>cmd</code>
    #         with <code>flags</code>.
    #
    def dallas_message(self, cmd, flags):
        if flags:
            hdr = '\x15' + chr(flags)
        else:
            hdr = '\x15\x00'
        return hdr + chr(len(cmd)) + cmd

    ##
    # Send a command on dallas_bus.
    #
    # @param cmd  The dallas_command to send.
    # @param flags  Flags to send with command.
    # @default 0
    # @return Dallas bus response.
    #
    def invoke_command(self, cmd, flags=0):
        return self.avr.invoke_message(self.dallas_message(cmd, flags))

    ##
    # Read specified number of bits from dallas_bus.
    #
    # @param n  The number of bits to read.
    # @return <code>n</code> bits from dallas bus.
    #
    def readbits(self, n):
        msg = self.readbits_base + chr(n)
        return self.avr.invoke_message(msg)

    ##
    # Read specified number of bytes from dallas bus.
    #
    # @param n  Number of bytes to read.
    # @return <code>n</code> bytes from dallas bus.
    #
    def readbytes(self, n):
        msg = self.readbytes_base + chr(n)
        return self.avr.invoke_message(msg)

    ##
    # Write specified bits to dallas bus.
    #
    # @param n  Number of bits to write.
    # @param bits  Bits to write to dallas bus.
    # @return Dallas bus response.
    #
    def writebits(self, n, bits):
        msg = self.writebits_id + chr(n) + bits
        msg = self.dallas_message(msg, 0)
        return self.avr.invoke_message(msg)

    ##
    # Write specified bytes to dallas bus.
    #
    # @param n  Number of bytes to write.
    # @param bytes  Bytes to write.
    # @param flags  Flags to include with the message.
    # @return Dallas bus response.
    #
    def writebytes(self, n, bytes, flags):
        msg = self.writebytes_id + chr(n) + bytes
        msg = self.dallas_message(msg, flags)
        return self.avr.invoke_message(msg)

    ##
    # Send Get key command to dallas bus.
    #
    # @return Dallas bus response.
    #
    def getkey(self):
        return self.avr.invoke_message(self.getkey_cmd)

    ##
    # Wait for dallas key to be connected then
    # call <code>getkey</code>
    # @see #getkey
    #
    def waitforkey(self):
        self.avr.wait_for_oob()
        return self.getkey()

    ##
    # Tell avr to scan dallas bus for devices that get
    # connected.
    #
    # @return Dallas bus response.
    #
    def scan(self):
        return self.avr.invoke_message(self.scan_cmd)[0]

    ##
    # Tell avr to stop scanning dallas bus.
    #
    # @return Dallas bus response.
    #
    def unscan(self):
        return self.avr.invoke_message(self.unscan_cmd)[0]

    ##
    # Reset dallas bus.
    #
    # @return Dallas bus response.
    #
    def reset(self):
        return self.avr.invoke_message(self.reset_cmd)[0]

    ##
    # Issue matchrom command to dallas bus.
    #
    # @param address  The address of a specific
    #                 device.
    # @return Dallas bus response.
    # @throws EInvalidValue  If the <code>address</code>
    #                        sent in was invalid.
    #
    def matchrom(self, address):
        if len(address) != 8:
            raise EInvalidValue, ('address', address)
        return self.avr.invoke_message(self.matchrom_base + address)[0]

    ##
    # Issue skiprom command to dallas bus.
    #
    # @param None.
    # @return Dallas bus response.
    #
    def skiprom(self):
        return self.avr.invoke_message(self.skiprom_cmd)[0]

    ##
    # Tell device to do conversion.
    #
    # @return Dallas bus response.
    # @note Convertion is done by device whose
    #       address was previously matched.
    #
    def convert(self):
        return self.avr.invoke_message(self.convert_cmd)[0]

    ##
    # Tell device to read scratch onto dallas bus.
    #
    # @return dallas bus response.
    #
    def readscratch(self):
        return self.avr.invoke_message(self.readscratch_cmd)

    ##
    # Tell device to read ROM onto dallas bus.
    #
    # @return ROM of device.
    #
    def readrom(self):
        self.lock()
        try:
            self.reset()
            self.avr.invoke_message(self.readrom_cmd)
            result = self.readbytes(8)
        finally:
            self.unlock()
        return result
    ##
    # Do a search on the bus to find what devices are attached
    #
    # @return array of addresses and an array of formatted entries for the nodebrowser
    #
    def findall(self):
        devices = '<ol>'
        device_addresses = []
        self.lock()
        if not ord(self.reset()):
            self.unlock()
            return None, 'No devices attached'
        self.avr.invoke_message(self.findfirst_cmd)
        while 1:
            d = self.avr.invoke_message(self.findnext_cmd)
            if not ord(d[8]):
                break
            device_addresses.append(d[:8])
            device = '%s ' % (family_name[ord(d[0])])
            for i in range(8):
                device += '%2.2x' % ord(d[i])
            device += ' '
            devices += '<li>' + device + '</li>'
            self.reset()
        devices += '</ol>'
        self.unlock()
        return devices, device_addresses
    ##
    # Use a queue to control access to the channel
    #
    # Send a request in the form of a callback object with params
    #
    def request(self, target, *args):
        if self.debug:
            print "DALLASBUS:  Add Request to queue", target
        self._queue.put((target,args,))
    def _queue_thread(self):
       while self.running:
           try:
               while 1:
                   request = self._queue.get()
                   if self.debug:
                       print "DALLASBUS: just received request: ", request
                   if type(request) is tuple:
                       if len(request) == 2:
                           apply(request[0], request[1])
           except EInvalidResponse, e:
               msglog.log('Dallas Bus', 'information', str(e))
               if self.debug: msglog.exception()
           except:
Example #17
0
class AlarmManager(ServiceNode, EventConsumerMixin):
    def __init__(self):
        ServiceNode.__init__(self)
        EventConsumerMixin.__init__(self, self.handle_alarm, \
                                    self.handle_exception)
        self.__running = 0
        self.__queue = Queue()
        self._id_manager = None
        self._dynamic_alarms = {}
        return

    def configure(self, config):
        ServiceNode.configure(self, config)
        if self._id_manager is None:
            self._id_manager = UniqueID(self)
        return

    def unique_id(self):
        return self._id_manager.allocate_id()

    def active(self):
        children = []
        for child in self.chidlren_nodes():
            if child.active():
                children.append(child)
        return children

    def acknowledged(self):
        children = []
        for child in self.children_nodes():
            if child.active() and child.acknowledged():
                children.append(child)
        return children

    def unacknowledged(self):
        children = []
        for child in self.children_nodes():
            if child.active() and not child.acknowledged():
                children.append(child)
        return children

    def add_dynamic_alarm(self, dynamic_alarm):
        dynamic_alarm_id = id(dynamic_alarm)
        if not self._dynamic_alarms.has_key(dynamic_alarm_id):
            self._dynamic_alarms[dynamic_alarm_id] = dynamic_alarm
            dynamic_alarm.event_subscribe(self, AlarmTriggerEvent)
            dynamic_alarm.event_subscribe(self, AlarmClearEvent)
        return

    def start(self):
        if not self.__running:
            known_alarms = self.get_child('alarms')
            for child in known_alarms.children_nodes():
                child.event_subscribe(self, AlarmTriggerEvent)
                child.event_subscribe(self, AlarmClearEvent)
            self.__running = 1
            self.__thread = ImmortalThread(name=self.name, target=self.__run)
            self.__thread.start()
            ServiceNode.start(self)
        return

    def stop(self):
        self.__running = 0
        self.__thread = None
        self.__queue.put(None)
        try:
            # @fixme try/except/else is a hack to survive testcases use
            #        of prune.  Really should revisit...
            alarms = self.get_child('alarms')
        except:
            pass
        else:
            for child in alarms.children_nodes():
                child.cancel(self, AlarmTriggerEvent)
                child.cancel(self, AlarmClearEvent)
        return ServiceNode.stop(self)

    def queue_alarm_check(self, alarm):
        self.__queue.put(alarm)

    def __run(self):
        while self.__running:
            alarm = self.__queue.get()
            if alarm:
                alarm.check_condition()
        else:
            self.__thread.should_die()
        return

    ##
    # Both AlarmClear and AlarmTrigger events come here,
    # separate the two and send to the appropriate handler.
    def handle_alarm(self, alarm):
        alarm.source.caught(alarm)
        if self.debug:
            msglog.log('broadway', msglog.types.ALARM, str(alarm))
        if alarm.__class__ == AlarmTriggerEvent:
            return self._handle_trigger(alarm)
        elif alarm.__class__ == AlarmClearEvent:
            return self._handle_clear(alarm)
        msglog.log(
            'broadway', msglog.types.WARN, 'Alarm manager %s got ' +
            'an event that it does not recoginize, ignoring.' % self.name)

    def _handle_trigger(self, alarm):
        export_thread = Thread(name=alarm.source.name,
                               target=self._run_exports,
                               args=(alarm, ))
        export_thread.start()

    def _run_exports(self, alarm):
        if self.has_child('exporters'):
            exporters = self.get_child('exporters').children_nodes()
            exceptions = []
            for exporter in exporters:
                try:
                    exporter.export(alarm)
                except Exception, e:
                    msglog.exception()
                    exceptions.append(e)
            if exceptions:
                alarm.source.fail(alarm)
            else:
                alarm.source.success(alarm)
        else:
Example #18
0
class LightingGroup(CompositeNode, EventConsumerMixin):
    def __init__(self):
        self.__server = None
        self.__sched_lock = Lock()
        self.__sched_thread = None
        self.__schedules = Queue()
        self.__pv = None
        super(LightingGroup, self).__init__()
        EventConsumerMixin.__init__(self, self._sched_update,
                                    self._sched_exception)
        return
    
    def configure(self, cd):
        super(LightingGroup, self).configure(cd)
        set_attribute(self, 'group_id', 10, cd, int)
        set_attribute(self, 'ttl', 120, cd, int)
        #@fixme - the ability to store schedules locally in the LightPoint is 
        #currently not being utilized.
        set_attribute(self, 'schedule_link', '', cd)
        # config attr to deal with current Adura scheduling limitations
        # a future version of their API will address XML-RPC scheduling
        # deficiencies.
        set_attribute(self, 'one_schedule_only', 0, cd, as_boolean)
        
    def configuration(self):
        cd = super(LightingGroup, self).configuration()
        get_attribute(self, 'group_id', cd)
        get_attribute(self, 'ttl', cd)
        get_attribute(self, 'schedule_link', cd)
        return cd
        
    def start(self):
        if self.schedule_link:
            try:
                l = as_node(self.schedule_link)
                l.event_subscribe(self, ScheduleChangedEvent)
                self.__sched_thread = Thread(target=self._update_schedules)
                self.__sched_thread.start()
            except:
                msg = '%s: error subscribing to schedule changes' % \
                       self.as_node_url()
                msglog.log('Adura', ERR, msg)
        super(LightingGroup, self).start()
        for x in self.children_nodes():
            #force initial update
            try:
                x.get()
            except:
                pass
        
    def stop(self):
        if self.schedule_link:
            try:
                l = as_node(self.schedule_link)
                l.event_unsubscribe(self, ScheduleChangedEvent)
            except:
                msg = '%s: error unsubscribing from schedule changes' % \
                       self.as_node_url()
                msglog.log('Adura', ERR, msg)
        super(CompositeNode, self).stop()
    
    def get(self, skipCache=0):
        if self.__pv is None:
            count = 0
            in_err = 0
            for x in self.children_nodes():
                try:
                    count += int(x.get())
                except:
                    in_err += 1
            if count >= ((len(self.children_names()) - in_err)/2):
                #set the initial state of the lighting group
                #based on the average present state of the lightpoints
                self.__pv = 1
            else:
                self.__pv = 0
        return self.__pv
    
    #sets all LightPoints that are part of this group
    def set(self, value):
        value = int(value)
        if value < 0 or value > 1:
            raise EInvalidValue()
        self.__pv = value
        for lp in self.children_nodes():
            try:
                lp.set(value)
            except:
                msglog.exception()
        
    def _sched_exception(self, exc):
        msglog.exception()
        
    def _sched_update(self, evt):
        if isinstance(evt, ScheduleChangedEvent):
            daily = evt.new_schedule[0]
            schedule = AduraSched(daily)
            self.__schedules.put(schedule)
                
    def _update_schedules(self):
        days = ['sunday', 'monday', 'tuesday', 'wednesday',
                'thursday', 'friday', 'saturday']
        day_int_map = {'sunday':0,
                       'monday':1,
                       'tuesday':2,
                       'wednesday':3,
                       'thursday':4,
                       'friday':5,
                       'saturday':6,
                       'all':10}
        while 1:
            sched = self.__schedules.get()
            self._send_sched_msg('adura_clear_schedule')
            if self.one_schedule_only:
                days = ['all']
            for day in days:
                self._send_sched_msg(
                    'adura_setschedule_day', 
                    ADURA_ALL_LIGHT_POINTS_ADDR, 
                    day_int_map[day]
                    )
                for entry in sched.get_entries(day):
                    self._send_sched_msg(
                        'adura_setschedule_hour',
                        ADURA_ALL_LIGHT_POINTS_ADDR,
                        entry.h
                        )
                    self._send_sched_msg(
                        'adura_setschedule_minute', 
                        ADURA_ALL_LIGHT_POINTS_ADDR,
                        entry.m
                        )
                    self._send_sched_msg(
                        'adura_setschedule_group', 
                        ADURA_ALL_LIGHT_POINTS_ADDR
                    )
                    self._send_sched_msg(
                        'adura_setschedule_action', 
                        ADURA_ALL_LIGHT_POINTS_ADDR,
                        entry.value
                    )
        return
        
    def _send_sched_msg(self, method_name, *args):
        getattr(self.server, method_name)(args)
        _sched_pause()
        
    # Adura currently requires a 2 second pause between individual
    # schedule update messages
    def _sched_pause():
        time.sleep(ADURA_SCHED_MSG_DELAY)
            
    def _get_next_sched_entry(self):
        self.__sched_lock.acquire()
        try:
            self.__schedules.reverse()
            s = self.__schedules.pop()
            self.__schedules.reverse()
            return s
        finally:
            self.__sched_lock.release()
        
    def __get_server(self):
        if self.__server is None:
            self.__server = self.parent
        return self.__server
        
    server = property(__get_server)
Example #19
0
class TestCase(DefaultTestFixture):
    def setUp(self):
        DefaultTestFixture.setUp(self)
        self.lock = Lock()
        self.pool = ThreadPool(3)
        self.queue = Queue()
        self.simple_action_counter = 0
        return
    def tearDown(self):
        self.pool._unload()
        DefaultTestFixture.tearDown(self)
        return
    def simple_action(self, object):
        # @note It appears that even the '+= 1' operation is not
        #       guaranteed to be atomic.
        self.lock.acquire()
        self.simple_action_counter += 1
        self.lock.release()
        return 'simple_action_result'
    def slow_action(self, object):
        time.sleep(1.0)
        return 'slow_action_result'
    def simple_queue_action(self, object):
        self.queue.put(object)
        return
    def test_simple_queue(self):
        self.pool.queue(self.simple_queue_action, self)
        result = self.queue.get(1.0)
        if result is not self:
            raise "Queue returned %r instead of self, %r." % (result, self)
        return
    def test_result(self):
        t1 = time.time()
        pending_result = self.pool.queue(self.simple_action, self)
        result = pending_result.result(10.0)
        t2 = time.time()
        if result != 'simple_action_result':
            raise (
                "pending_result.result() returned the wrong value (%s)." %
                result
                )
        if (t2-t1) >= 10.0:
            raise "pending_result.result() blocked for no reason."
        return
    def test_pending_reasult(self):
        t1 = time.time()
        pending_result = PendingResult(None, None, self.simple_action, self)
        pending_result_two = self.pool.queue_pending_result(pending_result)
        if pending_result_two is not pending_result:
            raise "pending_result_two is NOT pending_result"
        result = pending_result.result(10.0)
        t2 = time.time()
        if result != 'simple_action_result':
            raise (
                "pending_result.result() returned the wrong value (%s)." %
                result
                )
        if (t2-t1) >= 10.0:
            raise "pending_result.result() blocked for no reason."
        return
    def test_pending_action(self):
        pending_action = PendingAction(self.simple_queue_action, self)
        self.pool.queue_pending_action(pending_action)
        result = self.queue.get(1.0)
        if result is not self:
            raise "Queue returned %r instead of self, %r." % (result, self)
        return
        return
    def test_result_timeout(self):
        t1 = time.time()
        pending_result = self.pool.queue(self.slow_action, self)
        result = pending_result.result(0.25)
        t2 = time.time()
        if (t2-t2) >= 1.0:
            raise "Blocked 1 second when a 1/4 second timeout."
        if result != NORESULT:
            raise "Got a result (%s) when none was expected."
        return
    def test_1000_actions(self):
        for i in xrange(0,1000):
            self.pool.queue(self.simple_action, self)
        time.sleep(0.1)
        t1 = time.time()
        while self.simple_action_counter < 1000:
            tn = time.time()
            if (tn-t1) > 3.0:
                raise (
                    "Taking ridiculously long to process 1000 queued actions."
                    )
            time.sleep(0.1)
        return
    def test_HIGH_pool_1(self):
        t1 = time.time()
        pending_result = HIGH.queue(self.simple_action, self)
        result = pending_result.result(10.0)
        t2 = time.time()
        if result != 'simple_action_result':
            raise (
                "pending_result.result() returned the wrong value (%s)." %
                result
                )
        if (t2-t1) >= 10.0:
            raise "pending_result.result() blocked for no reason."
        return
    def test_HIGH_pool_2(self):
        self.test_HIGH_pool_1()
        return
    def test_HIGH_pool_resize_1(self):
        HIGH.resize(1)
        if HIGH.size() != 1:
            raise "Resize to 1 thread failed."
        for i in xrange(0,100):
            HIGH.queue(self.simple_action, self)
        t1 = time.time()
        while self.simple_action_counter < 100:
            tn = time.time()
            if (tn-t1) > 3.0:
                raise (
                    "Taking ridiculously long to process 100 queued actions."
                    )
            time.sleep(0.1)
        return
    def test_HIGH_pool_resize_20(self):
        HIGH.resize(20)
        if HIGH.size() != 20:
            raise "Resize to 20 threads failed."
        for i in xrange(0,100):
            HIGH.queue(self.simple_action, self)
        t1 = time.time()
        while self.simple_action_counter < 100:
            tn = time.time()
            if (tn-t1) > 3.0:
                raise (
                    "Taking ridiculously long to process 100 queued actions."
                    )
            time.sleep(0.1)
        return
Example #20
0
class DallasBus(AVRNode, AutoDiscoveredNode):

    # Cached commands that are independant of the bus.
    getkey_cmd = '\x15\x00\x01\xb0'

    def __init__(self):
        AVRNode.__init__(self)
        AutoDiscoveredNode.__init__(self)
        self._lock = Lock()
        self.conversion_list = {}
        self._queue = Queue()
        self.debug = 0
        self.running = 0
        self._start_called = 0
        self.devices = ''
        self.device_addresses = []
        self._been_discovered = 0

    def lock(self):
        self._lock.acquire()

    def unlock(self):
        self._lock.release()

    ##
    # @see node.AVRNode#configure
    #
    def configure(self, config):
        AVRNode.configure(self, config)
        id_chr = chr(self.id)

        # Commands cached in their entirety
        self.reset_cmd = '\x15\x00\x02\x10' + id_chr
        self.scan_cmd = '\x15\x00\x02\xc0' + id_chr
        self.unscan_cmd = '\x15\x00\x02\xd0' + id_chr
        self.convert_cmd = '\x15\x01\x04\x70' + id_chr + '\x01\x44'
        self.readscratch_cmd = '\x15\x00\x04\x70' + id_chr + '\x01\xbe'
        self.readrom_cmd = '\x15\x00\x04\x70' + id_chr + '\x01\x33'
        self.findfirst_cmd = '\x15\x00\x02\x80' + id_chr
        self.findfamily_cmd = '\x15\x00\x02\x81' + id_chr
        self.findnext_cmd = '\x15\x00\x03\x82' + id_chr + '\x00'
        # The beginning of commands of known length.
        self.matchrom_base = '\x15\x00\x0c\x70' + id_chr + '\x09\x55'
        self.skiprom_cmd = '\x15\x00\x04\x70' + id_chr + '\x01\xcc'
        self.readbits_base = '\x15\x00\x03\x40' + id_chr
        self.readbytes_base = '\x15\x00\x03\x50' + id_chr
        # Cached command codes + bus id.
        self.writebits_id = '\x60' + id_chr
        self.writebytes_id = '\x70' + id_chr
        return

    def configuration(self):
        self.devices, self.device_addresses = self.findall()
        self._been_discovered = 0
        config = AVRNode.configuration(self)
        get_attribute(self, 'devices', config)
        return config

    def _add_child(self, node):
        AVRNode._add_child(self, node)
        if not self.running and self._start_called:
            self.start()

    ##
    # start temperature conversions
    #
    def start(self):
        AVRNode.start(self)
        self._start_called = 1
        self.devices, self.device_addresses = self.findall()
        if self.running:
            raise EAlreadyRunning()

        # Inform in msglog the number of devices on the dallas bus and their addresses (CSCtl81599)
        if (self.devices == None):
            no_of_devices = 0
        else:
            no_of_devices = len(self.device_addresses)
        msglog.log(
            'broadway', msglog.types.INFO,
            'There are %d devices found on "%s" bus' %
            (no_of_devices, self.name))
        if no_of_devices:
            addr_str = ''
            for addr in self.device_addresses:
                dallas_bus_addr = address_to_asciihex(addr)
                addr_str = addr_str + ' ' + dallas_bus_addr
            msglog.log(
                'broadway', msglog.types.INFO,
                'The device addresses on "%s" bus : %s\n' %
                (self.name, addr_str))

        # Start the thread to read the dallas bus irrespective for whether the devices are
        # present or not (CSCtl81599)
        self.running = 1
        thread = Thread(name=self.name, target=self._queue_thread, args=())
        self.request(self._convert_temperature_sensor_list)
        thread.start()

    def stop(self):
        self.running = 0

    ##
    # discover and create object instances
    #
    def _discover_children(self, force=0):
        if force:
            self._been_discovered = 0
        if self.running == 1 and not self._been_discovered:
            # do a find_all irrespective of whether there are ny devices found previously (CSCtl81599)
            self.devices, self.device_addresses = self.findall()
            # get a list of addresses in existing children
            existing = self.children_nodes(auto_discover=0)
            existing = filter(lambda dev: hasattr(dev, 'address'), existing)
            existing = [dev.address for dev in existing]
            for addr in self.device_addresses:
                if addr not in existing and not self._nascent_children.get(
                        address_to_asciihex(addr), None):
                    if ord(addr[0]) in (0x28, 0x10):  # need to add new types
                        # add a new instance to the _nascent children

                        t = Temperature()
                        t.address = addr
                        t.model = _models[family_name[ord(addr[0])]]
                        self._nascent_children[address_to_asciihex(addr)] = t
            # self._been_discovered = 1 #disabled to allow new objects to be discovered
        return self._nascent_children

    ##
    # Create a dallas message for a cmd and flags.
    #
    # @param cmd  The command turn into a message.
    # @param flags  Flags to send with message.
    # @return Dallas_message representing <code>cmd</code>
    #         with <code>flags</code>.
    #
    def dallas_message(self, cmd, flags):
        if flags:
            hdr = '\x15' + chr(flags)
        else:
            hdr = '\x15\x00'
        return hdr + chr(len(cmd)) + cmd

    ##
    # Send a command on dallas_bus.
    #
    # @param cmd  The dallas_command to send.
    # @param flags  Flags to send with command.
    # @default 0
    # @return Dallas bus response.
    #
    def invoke_command(self, cmd, flags=0):
        return self.avr.invoke_message(self.dallas_message(cmd, flags))

    ##
    # Read specified number of bits from dallas_bus.
    #
    # @param n  The number of bits to read.
    # @return <code>n</code> bits from dallas bus.
    #
    def readbits(self, n):
        msg = self.readbits_base + chr(n)
        return self.avr.invoke_message(msg)

    ##
    # Read specified number of bytes from dallas bus.
    #
    # @param n  Number of bytes to read.
    # @return <code>n</code> bytes from dallas bus.
    #
    def readbytes(self, n):
        msg = self.readbytes_base + chr(n)
        return self.avr.invoke_message(msg)

    ##
    # Write specified bits to dallas bus.
    #
    # @param n  Number of bits to write.
    # @param bits  Bits to write to dallas bus.
    # @return Dallas bus response.
    #
    def writebits(self, n, bits):
        msg = self.writebits_id + chr(n) + bits
        msg = self.dallas_message(msg, 0)
        return self.avr.invoke_message(msg)

    ##
    # Write specified bytes to dallas bus.
    #
    # @param n  Number of bytes to write.
    # @param bytes  Bytes to write.
    # @param flags  Flags to include with the message.
    # @return Dallas bus response.
    #
    def writebytes(self, n, bytes, flags):
        msg = self.writebytes_id + chr(n) + bytes
        msg = self.dallas_message(msg, flags)
        return self.avr.invoke_message(msg)

    ##
    # Send Get key command to dallas bus.
    #
    # @return Dallas bus response.
    #
    def getkey(self):
        return self.avr.invoke_message(self.getkey_cmd)

    ##
    # Wait for dallas key to be connected then
    # call <code>getkey</code>
    # @see #getkey
    #
    def waitforkey(self):
        self.avr.wait_for_oob()
        return self.getkey()

    ##
    # Tell avr to scan dallas bus for devices that get
    # connected.
    #
    # @return Dallas bus response.
    #
    def scan(self):
        return self.avr.invoke_message(self.scan_cmd)[0]

    ##
    # Tell avr to stop scanning dallas bus.
    #
    # @return Dallas bus response.
    #
    def unscan(self):
        return self.avr.invoke_message(self.unscan_cmd)[0]

    ##
    # Reset dallas bus.
    #
    # @return Dallas bus response.
    #
    def reset(self):
        return self.avr.invoke_message(self.reset_cmd)[0]

    ##
    # Issue matchrom command to dallas bus.
    #
    # @param address  The address of a specific
    #                 device.
    # @return Dallas bus response.
    # @throws EInvalidValue  If the <code>address</code>
    #                        sent in was invalid.
    #
    def matchrom(self, address):
        if len(address) != 8:
            raise EInvalidValue, ('address', address)
        return self.avr.invoke_message(self.matchrom_base + address)[0]

    ##
    # Issue skiprom command to dallas bus.
    #
    # @param None.
    # @return Dallas bus response.
    #
    def skiprom(self):
        return self.avr.invoke_message(self.skiprom_cmd)[0]

    ##
    # Tell device to do conversion.
    #
    # @return Dallas bus response.
    # @note Convertion is done by device whose
    #       address was previously matched.
    #
    def convert(self):
        return self.avr.invoke_message(self.convert_cmd)[0]

    ##
    # Tell device to read scratch onto dallas bus.
    #
    # @return dallas bus response.
    #
    def readscratch(self):
        return self.avr.invoke_message(self.readscratch_cmd)

    ##
    # Tell device to read ROM onto dallas bus.
    #
    # @return ROM of device.
    #
    def readrom(self):
        self.lock()
        try:
            self.reset()
            self.avr.invoke_message(self.readrom_cmd)
            result = self.readbytes(8)
        finally:
            self.unlock()
        return result

    ##
    # Do a search on the bus to find what devices are attached
    #
    # @return array of addresses and an array of formatted entries for the nodebrowser
    #
    def findall(self):
        devices = '<ol>'
        device_addresses = []
        self.lock()
        if not ord(self.reset()):
            self.unlock()
            return None, 'No devices attached'
        self.avr.invoke_message(self.findfirst_cmd)
        while 1:
            d = self.avr.invoke_message(self.findnext_cmd)
            if not ord(d[8]):
                break
            device_addresses.append(d[:8])
            device = '%s ' % (family_name[ord(d[0])])
            for i in range(8):
                device += '%2.2x' % ord(d[i])
            device += ' '
            devices += '<li>' + device + '</li>'
            self.reset()
        devices += '</ol>'
        self.unlock()
        return devices, device_addresses

    ##
    # Use a queue to control access to the channel
    #
    # Send a request in the form of a callback object with params
    #
    def request(self, target, *args):
        if self.debug:
            print "DALLASBUS:  Add Request to queue", target
        self._queue.put((
            target,
            args,
        ))

    def _queue_thread(self):
        while self.running:
            try:
                while 1:
                    request = self._queue.get()
                    if self.debug:
                        print "DALLASBUS: just received request: ", request
                    if type(request) is tuple:
                        if len(request) == 2:
                            apply(request[0], request[1])
            except EInvalidResponse, e:
                msglog.log('Dallas Bus', 'information', str(e))
                if self.debug: msglog.exception()
            except: