def start(self): if not self._monitor.is_running(): self._monitor.start_monitor() self._running = True self._synchronous_transaction = Transaction(self, None, self._bump_cv) self._synchronous_transaction.set_timeout(self.timeout) ImmortalThread.start(self) return
def start(self): if not self._monitor.is_running(): self._monitor.start_monitor() self._running = True self._synchronous_transaction = Transaction( self, None, self._bump_cv) self._synchronous_transaction.set_timeout(self.timeout) ImmortalThread.start(self) return
class Gateway(CompositeNode): def __init__(self): self.lightpoints = {} self.running = False self.endpoint = None self.lh = None self._seq_num = 1 self._sched_lock = Lock() super(Gateway, self).__init__() def configure(self, cd): super(Gateway, self).configure(cd) set_attribute(self, 'address', REQUIRED, cd) set_attribute(self, 'debug', 1, cd, int) set_attribute(self, 'net_grp_id', 125, cd, int) # network net_grp_id set_attribute(self, 'rpc_port', 9003, cd, int) set_attribute(self, 'serial_forwarder_port', 9001, cd, int) if self.running is True: # force endpoint reconfiguration if self.endpoint and self.endpoint.connection_ok(): self.endpoint.close_connection() self.running = False self.start() def configuration(self): cd = super(Gateway, self).configuration() get_attribute(self, 'address', cd) get_attribute(self, 'debug', cd) get_attribute(self, 'net_grp_id', cd) get_attribute(self, 'rpc_port', cd) get_attribute(self, 'serial_forwarder_port', cd) return cd def start(self): if self.running is False: self.endpoint = XCommandIface( self.rpc_port, self.address, self.debug ) self.lh = SerialFramerIface( self.serial_forwarder_port, self.address, self.debug ) self._thread = ImmortalThread(target=self._run, args=()) self.running = True self._thread.start() super(Gateway, self).start() def stop(self): self.running = False def _run(self): while self.running: # initialize the communications interface try: msglog.log('Adura', INFO, 'Initializing XServer SerialFramer connection.') self.lh.open_connection() msglog.log('Adura', INFO, 'XServer connection succeeded.') except EResourceError: self.stop() msglog.log('Adura', ERR, 'Failed to connect to XServer.') raise except (EConnectionError, ETimeout): msglog.log('Adura', WARN, 'Failed to connect to XServer - attempting to reconnect.') pass except: # unaccounted for exception - send it to the msglog msglog.log('Adura', ERR, 'Failed to connect to XServer.') msglog.exception() while self.lh.connection_ok(): msg = None try: msg = self.lh.get_next_msg() except: # connection will now be closed, re-init comm. msglog.exception(prefix='Ignored') if msg: frame = AduraFrame(msg) if self.debug: msglog.log('Adura', INFO, frame.get_value_string()) if frame.frame_type == 'lightpoint_data_config': lp = self.lightpoints.get(frame.get('firmware_id')) if lp is not None: lp.update(frame) time.sleep(30) #pause before attempting to reconnect else: if self.lh.connection_ok(): self.lh.close_connection() self._thread.should_die() return def register(self, lightpoint): self.lightpoints[lightpoint.lightpoint_id] = lightpoint def _check_cov_timeout(self): for lp in self.lightpoints: if (uptime.secs() - lp._last_update) > lp.group.ttl: # generate an ETimeout for the benefit of event consumers lp.update({'relayState1':ETimeout()}) def _get_next_seq(self): seq = self._seq_num self._seq_num += 1 if self._seq_num >= 0xffff: self._seq_num = 1 return seq # LightLogic XML-RPC methods follow. Note, HTTP is *not* used # for transport. It's just a raw socket that begins with a 4-byte # length field followed by xml-rpc based payload. ## # The control command for an individual LightPoint # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network (125) # @param actDevice The id of the relay (5) # @actState The action (0 = OFF, 1 = ON) # def actuate(self, dest, act_device, act_state): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':act_device, 'actState':act_state} if act_device == 12: # broadcast to all lightpoints - requires additional param # that is a 16 bit incrementing seq number. params['seqNumber'] = self._get_next_seq() return self.endpoint.write('xmesh.actuate', params) ## # Clears previous schedule events # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actState 1536 # @param seqNumber Unique sequence number for the specific command # def adura_clear_schedule(self, dest=ADURA_ALL_LIGHT_POINTS_ADDR): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actState':ADURA_CLR_SCHED, 'seqNumber':self._get_next_seq()} return self.endpoint.write('xmesh.adura_clear_schedule', params) # The following 5 messages are repeated n times, depending on how many # schedule events are required. ## # Sets the day of the schedule event (currently 10 - all days) # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actDevice Day ID (10) # @param actState 1792 # @param seqNumber Unique sequence number for the specific command # def adura_setschedule_day(self, dest, act_device): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':act_device, 'actState':ADURA_SET_SCHED_DAY, 'seqNumber':self._get_next_seq()} return self.endpoint.write('adura_setschedule_day', params) ## # Sets the number of hours relative to sunrise # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actDevice The hours 0 - 23 or # Sunrise == hour + 128 = number of hours after sunrise # hour + 160 = number of hours before sunrise # Sunset == hour + 64 = number of hourse after sunset # hour + 96 = number of hours before sunset # @param actState 2304 # @param seqNumber Unique sequence number for the specific command def adura_setschedule_hour(self, dest, act_device): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':act_device, 'actState':ADURA_SET_SCHED_HOUR, 'seqNumber':self._get_next_seq()} return self.endpoint.write('adura_setschedule_hour', params) ## # Sets the number of minutes relative to adura_setschedule_hour # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actDevice Minutes (0-60). Added to hour above # @param actState 2560 # @param seqNumber Unique sequence number for the specific command # def adura_setschedule_minute(self, dest, act_device): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':act_device, 'actState':ADURA_SET_SCHED_MIN, 'seqNumber':self._get_next_seq()} return self.endpoint.write('adura_setschedule_minute', params) ## # Sets the lighting group that the schedule controls. Currently that is limited to the # "All LightPoints group (12). # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actDevice The lighting group to actuate # @param actState 2816 # @param seqNumber Unique sequence number for the specific command # def adura_setschedule_group(self, dest): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':ADURA_ALL_LIGHT_POINTS_GRP, 'actState':ADURA_SET_SCHED_GROUP, 'seqNumber':self._get_next_seq()} return self.endpoint.write('adura_setschedule_group', params) ## # Sets the action for the schedule event and initiates the schedule event # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actDevice 0 = Off, 1 = On # @param actState 2048 # @param seqNumber Unique sequence number for the specific command # def adura_setschedule_action(self, dest, act_device): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':act_device, 'actState':ADURA_SET_SCHED_ACTION, 'seqNumber':self._get_next_seq()} return self.endpoint.write('adura_setschedule_group', params) ## # Sets the current date and time. Date and time are stored in a 32-bit format. # Two messages must be sent, the first to set the high word, the latter the low word. # # @param destAddress The LightPoint ID to which the command is sent or 0xffff (all) # @param groupId The network group id of the lighting network # @param actDevice DateTime value (16bit value) # @param actState Which word to set, 0x0502 == high, 0x0501 == low # @param seqNumber Unique sequence number for the specific command # def adura_setdatetime(self, dest, act_device, act_state): params = {'destAddress':dest, 'groupId':self.net_grp_id, 'actDevice':act_device, 'actState':act_state, 'seqNumber':self._get_next_seq()} return self.endpoint.write('adura_setdatetime', params)
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:
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: