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 step(self, value, data={}, listeners=[]): """ This function will compare the value with the previous value and if they are different send the data to the next listener else don't send the data along. :param value: The number to add to the list of numbers. :type value: boolean, int or float :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: value, data, listeners :rtype: float, dict, listeners :Raises: ValueError, KeyError """ device, port = Common.getDeviceAndPort(data) new_entry = Common.generateDevicePortTree(value, device, port, self.current_value) if ((value == self.current_value[device][port]) and not new_entry): listeners = [] self.logger.debug( 'No change detected: steps discontinued: device = {} port = {} volue = {} previous value = {}' .format(device, port, value, self.current_value[device][port])) else: self.logger.debug( 'Change detected: continue stepping device = {} port = {} volue = {} previous value = {}' .format(device, port, value, self.current_value[device][port])) self.current_value[device][port] = value return value, data, listeners
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 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 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 step( self, value, data={}, listeners=[] ): """ This function will compare the value with the previous value and if they are different send the data to the next listener else don't send the data along. :param value: The number to add to the list of numbers. :type value: boolean, int or float :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: value, data, listeners :rtype: float, dict, listeners :Raises: ValueError, KeyError """ device, port = Common.getDeviceAndPort( data ) new_entry = Common.generateDevicePortTree( value, device, port, self.current_value ) if ( ( value == self.current_value[device][port] ) and not new_entry ): listeners = [] self.logger.debug( 'No change detected: steps discontinued: device = {} port = {} volue = {} previous value = {}'.format( device, port, value, self.current_value[device][port] ) ) else: self.logger.debug( 'Change detected: continue stepping device = {} port = {} volue = {} previous value = {}'.format( device, port, value, self.current_value[device][port] ) ) self.current_value[device][port] = value return value, data, listeners
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 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 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 step( self, value, data={}, listeners=[] ): """ This function will take one sample out of limit samples. :param value: The input value to be processesed :type value: int, float, string, etc :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: new_value, new_data, new_listeners :rtype: int, dict, listeners :raises: KeyError >>> from steps.oneInN import oneInN >>> oneInN = oneInN() >>> c2f.step(0, {'device': 'test', 'port': 'test'}, ['a', 'b']) (32.0, {'device': 'test', 'units': 'F', 'port': 'test'}, []) >>> c2f.step(100, {'device': 'test', 'port': 'test'}, ['a', 'b']) (212.0, {'device': 'test', 'units': 'F', 'port': 'test'}, ['a', 'b']) """ device, port = Common.getDeviceAndPort( data ) limit = int( self.config[device][port] ) Common.generateDevicePortTree( 0, device, port, self.count ) if ( self.count[device][port] % limit ) != 0: listeners = [] self.logger.debug( "count is {}: don't send data".format( self.count[device][port] ) ) else: self.logger.debug( "count is {}: send data".format( self.count[device][port] ) ) self.count[device][port] += 1 return value, data, listeners
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 step(self, value, data={}, listeners=[]): """ This function will compute the average for each device and port. :param value: The input value to be processesed :type value: int, float, string, etc :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: new_value, new_data, new_listeners :rtype: int, dict, listeners :raises: None >>> from steps.average import Average >>> avg = Average() >>> avg.step(0.0, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (0, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) >>> avg.step(1.0, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (0.5, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) """ device, port = Common.getDeviceAndPort(data) number_of_samples = self.get_number_of_samples(device, port) samples = self.get_samples(device, port, number_of_samples) samples.append(value) average = sum(samples) / len(samples) self.save_samples(device, port, samples) self.logger.debug("average = {}".format(average)) return average, data, listeners
def output( self, data={}, http=None ): """ Output the results to COSMSend.com If the data dictionary contain 'action' and it is set to 'send' this routine will send data to COSM. if the key is not set to send the this routine will store the data as a data point and transmit with an other packet going to COSM. :param value: the current value :type value: :param data: additional data about the value :type dict: :returns: None :raises: None """ try: device, port = Common.getDeviceAndPort( data ) self.createDataStream( device, port, data ) if Constants.DataPacket.action in data and data[Constants.DataPacket.action] == Constants.DataPacket.send: self.json = self.createJSONReport( device, port, data ) self.report_data( self.json, data, http=http ) self.empty_datastream_list() except Exception as ex: self.logger.exception( "exception in send.output {}".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 step( self, value, data={}, listeners=[] ): """ This function will compute the average for each device and port. :param value: The input value to be processesed :type value: int, float, string, etc :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: new_value, new_data, new_listeners :rtype: int, dict, listeners :raises: None >>> from steps.average import Average >>> avg = Average() >>> avg.step(0.0, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (0, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) >>> avg.step(1.0, {'device': 'xyz', 'port': 'abc'}, ['a', 'b']) (0.5, {'device': 'xyz', 'units': 'V', 'port': 'abc'}, ['a', 'b']) """ device, port = Common.getDeviceAndPort( data ) number_of_samples = self.get_number_of_samples( device, port ) samples = self.get_samples( device, port, number_of_samples ) samples.append( value ) average = sum( samples ) / len( samples ) self.save_samples( device, port, samples ) self.logger.debug( "average = {}".format( average ) ) return average, data, listeners
def output(self, data={}, http=None): """ Output the results to COSMSend.com If the data dictionary contain 'action' and it is set to 'send' this routine will send data to COSM. if the key is not set to send the this routine will store the data as a data point and transmit with an other packet going to COSM. :param value: the current value :type value: :param data: additional data about the value :type dict: :returns: None :raises: None """ try: device, port = Common.getDeviceAndPort(data) self.createDataStream(device, port, data) if Constants.DataPacket.action in data and data[Constants.DataPacket.action] == Constants.DataPacket.send: self.json = self.createJSONReport(device, port, data) self.report_data(self.json, data, http=http) self.empty_datastream_list() except Exception as ex: self.logger.exception("exception in send.output {}".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 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 step(self, value, data={}, listeners=[]): """ This function will record the max value. :param value: The number to add to the list of numbers. :type value: boolean, int or float :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: value, data, listeners :rtype: float, dict, listeners :raises: ValueError, KeyError """ device, port = Common.getDeviceAndPort(data) Common.generateDevicePortTree(value, device, port, self.max_value) if value > self.max_value[device][port]: self.max_value[device][port] = value return value, data, listeners
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 step( self, value, data={}, listeners=[] ): """ This function will record the max value. :param value: The number to add to the list of numbers. :type value: boolean, int or float :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: value, data, listeners :rtype: float, dict, listeners :raises: ValueError, KeyError """ device, port = Common.getDeviceAndPort( data ) Common.generateDevicePortTree( value, device, port, self.max_value ) if value > self.max_value[device][port]: self.max_value[device][port] = value return value, data, listeners
def test_generateDevicePortTree( self ): values = {} value = ( 'a', 'b' ) devices = ( 'device1', 'device2' ) ports = ( 'port1', 'port2' ) expected_values = {devices[0]: {ports[0]: value[0]}} added = Common.generateDevicePortTree( value[0], devices[0], ports[0], values ) self.assertDictEqual( expected_values, values ) self.assertTrue( added ) # Check if no new entry was added added = Common.generateDevicePortTree( value[0], devices[0], ports[0], values ) self.assertDictEqual( expected_values, values ) self.assertFalse( added ) # Check port expected_values = {devices[0]: {ports[0]: value[0], ports[1]: value[1]}} added = Common.generateDevicePortTree( value[1], devices[0], ports[1], values ) self.assertDictEqual( expected_values, values ) self.assertTrue( added )
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 report_data(self, json, data, http=None): """ reportData - Sends the json object to the COSMSend web site if the options.in_test_mode is NOT set then don't send data to COSM web site. The options.in_test_mode is set with the command line argument --test the httplib2 debuglevel is set with the command line argument --http N where N is a positive integer. :param json: the current value :type json: :param data: the data that is pasted between steps :type dict: :returns: None :raises: None """ device, port = Common.getDeviceAndPort(data) headers = { "Content-Type": "application/x-www-form-urlencoded", "X-PachubeApiKey": self.config[device][port][Constants.Cosm.apikey], } try: url = self.config[device][port][Constants.Cosm.url].format(self.config[device][port][Constants.Cosm.id]) if http == None: http = httplib2.Http() httplib2.debuglevel = self.options.http2lib_debug_level self.logger.debug("send packet {}".format(json)) # if the test flag --test or -t is set at startup if not self.options.in_test_mode: response, content = http.request(url, method="PUT", body=json, headers=headers) if response.status == 200: self.logger.info("Successfully sent data to COSM") else: self.logger.error( "Error sending data to {} status = {} response = {} content = ".format( url, response.status, response, content ) ) except HttpLib2Error as error: self.logger.error("exception from httplib2 {}".format(error)) except AttributeError as error: self.logger.exception("exception from httplib2 {}".format(error))
def report_data( self, json, data, http=None ): """ reportData - Sends the json object to the COSMSend web site if the options.in_test_mode is NOT set then don't send data to COSM web site. The options.in_test_mode is set with the command line argument --test the httplib2 debuglevel is set with the command line argument --http N where N is a positive integer. :param json: the current value :type json: :param data: the data that is pasted between steps :type dict: :returns: None :raises: None """ device, port = Common.getDeviceAndPort( data ) headers = {'Content-Type': 'application/x-www-form-urlencoded', 'X-PachubeApiKey': self.config[device][port][Constants.Cosm.apikey]} try: url = self.config[device][port][Constants.Cosm.url].\ format( self.config[device][port][Constants.Cosm.id] ) if ( http == None ): http = httplib2.Http() httplib2.debuglevel = self.options.http2lib_debug_level self.logger.debug( "send packet {}".format( json ) ) # if the test flag --test or -t is set at startup if ( not self.options.in_test_mode ): response, content = http.request( url, method="PUT", body=json, headers=headers ) if ( response.status == 200 ): self.logger.info( 'Successfully sent data to COSM' ) else: self.logger.error( 'Error sending data to {} status = {} response = {} content = '.format( url, response.status, response, content ) ) except HttpLib2Error as error: self.logger.error( "exception from httplib2 {}".format( error ) ) except AttributeError as error: self.logger.exception( "exception from httplib2 {}".format( error ) )
def step( self, value, data={}, listeners=[] ): """ This function will format value as specified in the format stored in formatvalue.xml. :param value: The input value to be processesed :type value: int, float, string, etc :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: new_value, new_data, new_listeners :rtype: int, dict, listeners :raises: ValueError, KeyError """ device, port = Common.getDeviceAndPort( data ) format_specification = self.config[device][port] try: new_value = format_specification.format( value ) self.logger.debug( "FormatValue received {} sent out {}".format( value, new_value ) ) except ValueError as ve: error = "The format is incompatable with the input data type {}: device {} port {} file {}: error message {}".\ format( format_specification, device, port, self.configuration_file_name, ve ) raise ValueError( error ) return new_value, data, listeners
def step(self, value, data={}, listeners=[]): """ This function will format value as specified in the format stored in formatvalue.xml. :param value: The input value to be processesed :type value: int, float, string, etc :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: new_value, new_data, new_listeners :rtype: int, dict, listeners :raises: ValueError, KeyError """ device, port = Common.getDeviceAndPort(data) format_specification = self.config[device][port] try: new_value = format_specification.format(value) self.logger.debug("FormatValue received {} sent out {}".format( value, new_value)) except ValueError as ve: error = "The format is incompatable with the input data type {}: device {} port {} file {}: error message {}".\ format( format_specification, device, port, self.configuration_file_name, ve ) raise ValueError(error) return new_value, data, listeners
def step(self, value, data={}, listeners=[]): """ Store the current value. :param value: The number to add to the list of numbers. :type value: boolean, int or float :param data: a dictionary containing more information about the value. :param value: The input value to be processesed :type value: int, float, string, etc :param data: a dictionary containing more information about the value. :param listeners: a list of the subscribed routines to send the data to :returns: new_value, new_data, new_listeners :rtype: int, dict, listeners :raises: None """ device, port = Common.getDeviceAndPort(data) current_data = self.current_values.buildDataBlock(value, data) self.current_values.store(value, device, port, current_data) self.logger.debug("currentvalue table {} {} {}".format( device, port, value)) # pprint.pprint(self.current_values.get()) return value, data, listeners
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'] )
def test_getDeviceAndPort_with_good_data( self ): data = {'device': 'abc', 'port': 'def'} device, port = Common.getDeviceAndPort( data ) self.assertEqual( device, 'abc' ) self.assertEqual( port, 'def' )
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_getDeviceAndPort_with_missing_device( self ): data = {'port': 'def'} with self.assertRaisesRegexp( KeyError, 'The device is missing from the data block:' ): device, port = Common.getDeviceAndPort( data )