Exemple #1
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)