def substep( self, value, data, listeners ): ''' This function is wraps step function. It counts usage, errors then sends the data to next function. :param value: The number to convert to volts. :type value: int, float, string, etc :param data: a dictionary containing more information about the value. Data can be added to this as needed. Here is a list of values that will be in the data dictionary: | 1 **date:** time received: time when value was received. | 2. **units:** units of the number | 3. **name:** name assigned to the value | 4. **device** name of the device the data is from. | 5. **port** name of the port the data is from. :param listeners: a list of the pubsub routines to send the data to :returns: value, data, listeners :rtype: value, dict, listeners :Raises: None ''' # Trap any exceptions from getting to pubsub try: value, data, listeners = self.step( value, data, listeners ) self.counter += 1 self.last_count_time = datetime.utcnow() self.logger.debug( 'value {} listeners {}'.format( value, listeners ) ) Common.send( value, data, listeners ) except Exception as ex: self.logger.exception( "{}: {}".format( __name__, ex ) ) self.errors += 1 self.last_error_time = datetime.utcnow()
def process( self, env ): ''' Process a envelope received from the XBee. This involves the following: 1. get the addresses from the header 2. get the data out of the packet 3. get information about the source of the data 4. send each packet using the pub/sub system Args: :param envelope: a packet received from the XBee radio and decomposed by the ZigBee module :type DataEnvelope: Return: None :Raises: None ''' self.logger.debug( 'processing command {}'.format( env ) ) try: value = env[Constants.EnvelopeContents.VALUE] steps = copy.copy( env[Constants.EnvelopeContents.STEPS] ) Common.send( value, env.args, steps ) self.logger.debug( "Successfully sent command to XBee" ) except KeyError as ex: self.logger.exception( 'value or steps missing from env {}'. format( env ) ) except ListenerSpecIncomplete as lsi: self.logger.error( 'Invalid topic: {}'.format( lsi ) )
def getUseCount(self, value, data, listeners): ''' Report the number of times that step has been called. :param value: Not used. :type value: int :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the to. :returns: int, dict, listeners >>> from steps.zigbee2volts import ZigbeeCountToVolts >>> zig = ZigbeeCountToVolts() >>> zig.getUseCount(100, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (0, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) >>> zig.step(1, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) >>> zig.getUseCount(100, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (1, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) ''' if (self.counter != 0): self.logger.debug('getUseCount = {}'.format(self.counter)) data[Constants.DataPacket.device] = 'HouseMonitor.' + self.whoami data[Constants.DataPacket.port] = data[ Constants.DataPacket.name] = 'Count' data[Constants.DataPacket.arrival_time] = self.last_count_time try: Common.send(self.counter, data, copy.copy(listeners)) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def getErrorCount(self, value, data, listeners): ''' Report the number of errors that has occurred in this step. :param value: Not used. :type value: int :param data: a dictionary containing more information about the value. Data can be added to this as needed. Here is a list of values that will be in the data dictionary: | 1. **date:** time received: time when value was received. | 2. **units:** units of the number | 3. **name:** name assigned to the value :param listeners: a list of the subscribed routines to send the data to :returns: count, data, listeners :rtype: float, dict, listeners :Raises: None >>> from steps.zigbee2volts import ZigbeeCountToVolts >>> zig = ZigbeeCountToVolts() >>> zig.getErrorCount(100, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) ''' if (self.errors != 0): self.logger.debug('getErrorCount = {}'.format(self.errors)) data[Constants.DataPacket.device] = 'HouseMonitor.' + self.whoami data[Constants.DataPacket.port] = data[ Constants.DataPacket.name] = 'Error Count' data[Constants.DataPacket.arrival_time] = self.last_error_time try: Common.send(self.errors, data, copy.copy(listeners)) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def getUseCount( self, value, data, listeners ): ''' Report the number of times that step has been called. :param value: Not used. :type value: int :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the to. :returns: int, dict, listeners >>> from steps.zigbee2volts import ZigbeeCountToVolts >>> zig = ZigbeeCountToVolts() >>> zig.getUseCount(100, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (0, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) >>> zig.step(1, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) >>> zig.getUseCount(100, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (1, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) ''' if ( self.counter != 0 ): self.logger.debug( 'getUseCount = {}'.format( self.counter ) ) data[Constants.DataPacket.device] = 'HouseMonitor.' + self.whoami data[Constants.DataPacket.port] = data[Constants.DataPacket.name] = 'Count' data[Constants.DataPacket.arrival_time] = self.last_count_time try: Common.send( self.counter, data, copy.copy( listeners ) ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def substep(self, value, data, listeners): ''' This function is wraps step function. It counts usage, errors then sends the data to next function. :param value: The number to convert to volts. :type value: int, float, string, etc :param data: a dictionary containing more information about the value. Data can be added to this as needed. Here is a list of values that will be in the data dictionary: | 1 **date:** time received: time when value was received. | 2. **units:** units of the number | 3. **name:** name assigned to the value | 4. **device** name of the device the data is from. | 5. **port** name of the port the data is from. :param listeners: a list of the pubsub routines to send the data to :returns: value, data, listeners :rtype: value, dict, listeners :Raises: None ''' # Trap any exceptions from getting to pubsub try: value, data, listeners = self.step(value, data, listeners) self.counter += 1 self.last_count_time = datetime.utcnow() self.logger.debug('value {} listeners {}'.format(value, listeners)) Common.send(value, data, listeners) except Exception as ex: self.logger.exception("{}: {}".format(__name__, ex)) self.errors += 1 self.last_error_time = datetime.utcnow()
def process(self, env): ''' Process a envelope received from the XBee. This involves the following: 1. get the addresses from the header 2. get the data out of the packet 3. get information about the source of the data 4. send each packet using the pub/sub system Args: :param envelope: a packet received from the XBee radio and decomposed by the ZigBee module :type DataEnvelope: Return: None :Raises: None ''' self.logger.debug('processing command {}'.format(env)) try: value = env[Constants.EnvelopeContents.VALUE] steps = copy.copy(env[Constants.EnvelopeContents.STEPS]) Common.send(value, env.args, steps) self.logger.debug("Successfully sent command to XBee") except KeyError as ex: self.logger.exception( 'value or steps missing from env {}'.format(env)) except ListenerSpecIncomplete as lsi: self.logger.error('Invalid topic: {}'.format(lsi))
def getErrorCount( self, value, data, listeners ): ''' Report the number of errors that has occurred in this step. :param value: Not used. :type value: int :param data: a dictionary containing more information about the value. Data can be added to this as needed. Here is a list of values that will be in the data dictionary: | 1. **date:** time received: time when value was received. | 2. **units:** units of the number | 3. **name:** name assigned to the value :param listeners: a list of the subscribed routines to send the data to :returns: count, data, listeners :rtype: float, dict, listeners :Raises: None >>> from steps.zigbee2volts import ZigbeeCountToVolts >>> zig = ZigbeeCountToVolts() >>> zig.getErrorCount(100, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) ''' if ( self.errors != 0 ): self.logger.debug( 'getErrorCount = {}'.format( self.errors ) ) data[Constants.DataPacket.device] = 'HouseMonitor.' + self.whoami data[Constants.DataPacket.port] = data[Constants.DataPacket.name] = 'Error Count' data[Constants.DataPacket.arrival_time] = self.last_error_time try: Common.send( self.errors, data, copy.copy( listeners ) ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def output( self, value, data, listeners ): ''' This routine will output a log of data that it receives Args: value: the value for the data data: more information about the value listeners: the various listeners for this object Return: the string that is printed Execptions: None ''' name = data['Name'] date = data['date time received'] line = "{:25.25s} {} {}{}".format( name, date, value, os.linesep ) self.os.write( line ) try: Common.send( value=value, data=data, listeners=listeners ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) ) return line
def output(self, value, data, listeners): ''' This routine will output a log of data that it receives Args: value: the value for the data data: more information about the value listeners: the various listeners for this object Return: the string that is printed Execptions: None ''' name = data['Name'] date = data['date time received'] line = "{:25.25s} {} {}{}".format(name, date, value, os.linesep) self.os.write(line) try: Common.send(value=value, data=data, listeners=listeners) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex)) return line
def test_send_with_split( self, sendMessage ): value = 1 data = {'device': {'port': {'a': 'b'}}} listeners = [['x', 'y', 'z'], 'a', 'b', 'c'] Common.send( value, data, listeners ) expected_call_list = [call( 'x', listeners=['y', 'z'], data={'device': {'port': {'a': 'b'}}}, value=1 ), call( 'a', listeners=['b', 'c'], data={'device': {'port': {'a': 'b'}}}, value=1 )] self.assertEqual( sendMessage.mock_calls, expected_call_list )
def process( self, packet ): ''' Process a envelope received from the XBee. This involves the following: 1. get the addresses from the header 2. get the data out of the packet 3. get information about the source of the data 4. send each packet using the pub/sub system Args: :param envelope: a packet received from the XBee radio and decomposed by the ZigBee module :type DataEnvelope: Return: None :Raises: None ''' self.logger.debug( 'processing data from zigbee {}'.format( packet ) ) try: if packet[Constants.XBee.id] == Constants.XBee.api_responses.rx_io_data_long_addr: source_addr_long = "{:#x}".format( unpack( '!Q', packet[Constants.XBee.source_addr_long] )[0] ) source_addr = "{:#x}".format( unpack( '!H', packet[Constants.XBee.source_addr] )[0] ) if Constants.XBee.samples in packet: samples = packet[Constants.XBee.samples] for port in samples[0]: package = {} try: if ( self.devices.valid_device( source_addr_long ) ): package[Constants.DataPacket.device] = source_addr_long package[Constants.DataPacket.name] = self.devices.get_port_name( source_addr_long, port ) package[Constants.DataPacket.port] = port package[Constants.DataPacket.arrival_time] = datetime.utcnow() package[Constants.DataPacket.units] = self.devices.get_port_units( source_addr_long, port ) package[Constants.DataPacket.steps] = copy.copy( self.devices.get_steps( source_addr_long, port ) ) data = samples[0][port] Common.send( data, package, package[Constants.DataPacket.steps] ) except InvalidDeviceError as ie: self.logger.exception( str( ie ) ) except InvalidPortError as ie: self.logger.exception( str( ie ) ) except InvalidConfigurationOptionError as ie: self.logger.exception( str( ie ) ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) ) else: self.logger.info( 'None processed ZigBee response {}'.format( pprint.pformat( packet ) ) ) except KeyError: self.logger.exception( "error extracting data from {}".format( pprint.pformat( packet ) ) ) except ListenerSpecIncomplete as lsi: self.logger.error( 'Invalid topic: {}'.format( lsi ) )
def changeDisableButtonWarningLight(self, value): ''' Turn on or off the LED that indicates that the garage door is open. :param value: determines if the light will be on or off. :type value: Boolean :returns: none ''' steps = [Constants.TopicNames.ZigBeeOutput] data = {} data[Constants.DataPacket.device] = self.panel_address data[Constants.DataPacket.port] = self.panel_disable_button_led try: Common.send(value, data, steps) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def changeDisableButtonWarningLight( self, value ): ''' Turn on or off the LED that indicates that the garage door is open. :param value: determines if the light will be on or off. :type value: Boolean :returns: none ''' steps = [Constants.TopicNames.ZigBeeOutput] data = {} data[Constants.DataPacket.device] = self.panel_address data[Constants.DataPacket.port] = self.panel_disable_button_led try: Common.send( value, data, steps ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def changeGarageDoorWarningLight( self, value ): ''' Turn on or off the LED that indicates that the disable alarm has been pressed. :param value: determines if the light will be on or off. :type value: Boolean :returns: none ''' steps = [Constants.TopicNames.ZigBeeOutput] data = {} data[Constants.DataPacket.device] = self.panel_address data[Constants.DataPacket.port] = self.panel_garage_door_led light = not value try: Common.send( light, data, steps ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def changeGarageDoorWarningLight(self, value): ''' Turn on or off the LED that indicates that the disable alarm has been pressed. :param value: determines if the light will be on or off. :type value: Boolean :returns: none ''' steps = [Constants.TopicNames.ZigBeeOutput] data = {} data[Constants.DataPacket.device] = self.panel_address data[Constants.DataPacket.port] = self.panel_garage_door_led light = not value try: Common.send(light, data, steps) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def changeAlarm( self, value ): ''' Turn on or off the alarm that indicates that the garage door is open. :param value: determines if the alarm will be on or off. :type value: Boolean :returns: none ''' self.alarm = value steps = [Constants.TopicNames.ZigBeeOutput] data = {} data[Constants.DataPacket.device] = self.panel_address data[Constants.DataPacket.port] = self.panel_alarm self.logger.debug( "changeAlarm with {} {} {}".format( value, data, steps ) ) try: Common.send( value, data, steps ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def process( self, envelope ): ''' Process a packet received from the XBee. This involves the following: #. get the addresses from the header #. get the data out of the packet #. get information about the source of the data #. send each packet using the pub/sub system :param packet: a packet recived from the XBee radio and decomposed by the ZigBee module :return: None :Raises: None ''' try: value = envelope[Constants.EnvelopeContents.VALUE] if Constants.EnvelopeContents.VALUE in envelope else 1 listeners = envelope[Constants.EnvelopeContents.STEPS] Common.send( value, envelope.args, listeners ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def changeAlarm(self, value): ''' Turn on or off the alarm that indicates that the garage door is open. :param value: determines if the alarm will be on or off. :type value: Boolean :returns: none ''' self.alarm = value steps = [Constants.TopicNames.ZigBeeOutput] data = {} data[Constants.DataPacket.device] = self.panel_address data[Constants.DataPacket.port] = self.panel_alarm self.logger.debug("changeAlarm with {} {} {}".format( value, data, steps)) try: Common.send(value, data, steps) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def process(self, envelope): ''' Process a packet received from the XBee. This involves the following: #. get the addresses from the header #. get the data out of the packet #. get information about the source of the data #. send each packet using the pub/sub system :param packet: a packet recived from the XBee radio and decomposed by the ZigBee module :return: None :Raises: None ''' try: value = envelope[ Constants.EnvelopeContents. VALUE] if Constants.EnvelopeContents.VALUE in envelope else 1 listeners = envelope[Constants.EnvelopeContents.STEPS] Common.send(value, envelope.args, listeners) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def send_old_values( self, value, data, listeners ): new_data = copy( data ) new_listeners = copy( listeners ) if ( value == False ): new_data[Constants.DataPacket.units] = "closed" new_data[Constants.DataPacket.arrival_time] = new_data[Constants.DataPacket.arrival_time] - self.smuggen_before new_value = "1" elif( value == True ): new_data[Constants.DataPacket.units] = "open" new_data[Constants.DataPacket.arrival_time] = new_data[Constants.DataPacket.arrival_time] - self.smuggen_before new_value = "0" else: new_value = -1 new_data[Constants.DataPacket.units] = 'invalid' self.logger.warn( "invalid state %d", value ) self.logger.info( "prior door state was {} {} {}".format( new_value, new_data[Constants.DataPacket.units], listeners ) ) try: Common.send( new_value, new_data, new_listeners ) except Exception as ex: self.logger.exception( 'Common.send error {}'.format( ex ) )
def send_old_values(self, value, data, listeners): new_data = copy(data) new_listeners = copy(listeners) if (value == False): new_data[Constants.DataPacket.units] = "closed" new_data[Constants.DataPacket.arrival_time] = new_data[ Constants.DataPacket.arrival_time] - self.smuggen_before new_value = "1" elif (value == True): new_data[Constants.DataPacket.units] = "open" new_data[Constants.DataPacket.arrival_time] = new_data[ Constants.DataPacket.arrival_time] - self.smuggen_before new_value = "0" else: new_value = -1 new_data[Constants.DataPacket.units] = 'invalid' self.logger.warn("invalid state %d", value) self.logger.info("prior door state was {} {} {}".format( new_value, new_data[Constants.DataPacket.units], listeners)) try: Common.send(new_value, new_data, new_listeners) except Exception as ex: self.logger.exception('Common.send error {}'.format(ex))
def process(self, packet): ''' Process a envelope received from the XBee. This involves the following: 1. get the addresses from the header 2. get the data out of the packet 3. get information about the source of the data 4. send each packet using the pub/sub system Args: :param envelope: a packet received from the XBee radio and decomposed by the ZigBee module :type DataEnvelope: Return: None :Raises: None ''' self.logger.debug('processing data from zigbee {}'.format(packet)) try: if packet[Constants.XBee. id] == Constants.XBee.api_responses.rx_io_data_long_addr: source_addr_long = "{:#x}".format( unpack('!Q', packet[Constants.XBee.source_addr_long])[0]) source_addr = "{:#x}".format( unpack('!H', packet[Constants.XBee.source_addr])[0]) if Constants.XBee.samples in packet: samples = packet[Constants.XBee.samples] for port in samples[0]: package = {} try: if (self.devices.valid_device(source_addr_long)): package[Constants.DataPacket. device] = source_addr_long package[Constants.DataPacket. name] = self.devices.get_port_name( source_addr_long, port) package[Constants.DataPacket.port] = port package[Constants.DataPacket. arrival_time] = datetime.utcnow() package[Constants.DataPacket. units] = self.devices.get_port_units( source_addr_long, port) package[ Constants.DataPacket.steps] = copy.copy( self.devices.get_steps( source_addr_long, port)) data = samples[0][port] Common.send( data, package, package[Constants.DataPacket.steps]) except InvalidDeviceError as ie: self.logger.exception(str(ie)) except InvalidPortError as ie: self.logger.exception(str(ie)) except InvalidConfigurationOptionError as ie: self.logger.exception(str(ie)) except Exception as ex: self.logger.exception( 'Common.send error {}'.format(ex)) else: self.logger.info('None processed ZigBee response {}'.format( pprint.pformat(packet))) except KeyError: self.logger.exception("error extracting data from {}".format( pprint.pformat(packet))) except ListenerSpecIncomplete as lsi: self.logger.error('Invalid topic: {}'.format(lsi))
def test_send( self, sendMessage ): value = 1 data = {'device': {'port': {'a': 'b'}}} listeners = ['a', 'b', 'c'] Common.send( value, data, listeners ) sendMessage.assert_called_once_with( 'a', value=value, data=data, listeners=['b', 'c'] )