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)