def _process_rx(self, cargo): """Process a frame of data f (string): 'NodeID val1 val2 ...' This function splits the string into numbers and check its validity. 'NodeID val1 val2 ...' is the generic data format. If the source uses a different format, override this method. Return data as a list: [NodeID, val1, val2] """ # Log data self._log.debug(str(cargo.uri) + " NEW FRAME : " + str(cargo.rawdata)) rxc = cargo decoded = [] node = str(rxc.nodeid) datacode = True # Discard if data is non-existent if len(rxc.realdata) < 1: self._log.warning( str(cargo.uri) + " Discarded RX frame 'string too short' : " + str(rxc.realdata)) return False # Discard if anything non-numerical found try: [float(val) for val in rxc.realdata] except Exception: self._log.warning( str(cargo.uri) + " Discarded RX frame 'non-numerical content' : " + str(rxc.realdata)) return False # Discard if first value is not a valid node id # n = float(rxc.realdata[0]) # if n % 1 != 0 or n < 0 or n > 31: # self._log.warning(str(cargo.uri) + " Discarded RX frame 'node id outside scope' : " + str(rxc.realdata)) # return False # check if node is listed and has individual datacodes for each value if node in ehc.nodelist and 'rx' in ehc.nodelist[ node] and 'datacodes' in ehc.nodelist[node]['rx']: # fetch the string of datacodes datacodes = ehc.nodelist[node]['rx']['datacodes'] # fetch a string of data sizes based on the string of datacodes datasizes = [] for code in datacodes: datasizes.append(ehc.check_datacode(str(code))) # Discard the frame & return 'False' if it doesn't match the summed datasizes if len(rxc.realdata) != sum(datasizes): self._log.warning( str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + " is not valid for datacodes " + str(datacodes)) return False else: # Determine the expected number of values to be decoded count = len(datacodes) # Set decoder to "Per value" decoding using datacode 'False' as flag datacode = False else: # if node is listed, but has only a single default datacode for all values if node in ehc.nodelist and 'rx' in ehc.nodelist[ node] and 'datacode' in ehc.nodelist[node]['rx']: datacode = ehc.nodelist[node]['rx']['datacode'] else: # when node not listed or has no datacode(s) use the interfacers default if specified datacode = self._settings['datacode'] # Ensure only int 0 is passed not str 0 if datacode == '0': datacode = 0 # when no (default)datacode(s) specified, pass string values back as numerical values if not datacode: for val in rxc.realdata: if float(val) % 1 != 0: val = float(val) else: val = int(float(val)) decoded.append(val) # Discard frame if total size is not an exact multiple of the specified datacode size. elif len(rxc.realdata) % ehc.check_datacode(datacode) != 0: self._log.warning( str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + " is not valid for datacode " + str(datacode)) return False else: # Determine the number of values in the frame of the specified code & size count = len(rxc.realdata) / ehc.check_datacode(datacode) # Decode the string of data one value at a time into "decoded" if not decoded: bytepos = int(0) for i in range(0, count, 1): # Use single datacode unless datacode = False then use datacodes dc = str(datacode) if not datacode: dc = str(datacodes[i]) # Determine the number of bytes to use for each value by it's datacode size = int(ehc.check_datacode(dc)) try: value = ehc.decode( dc, [int(v) for v in rxc.realdata[bytepos:bytepos + size]]) except: self._log.warning( str(rxc.uri) + " Unable to decode as values incorrect for datacode(s)" ) return False bytepos += size decoded.append(value) # check if node is listed and has individual scales for each value if node in ehc.nodelist and 'rx' in ehc.nodelist[ node] and 'scales' in ehc.nodelist[node]['rx']: scales = ehc.nodelist[node]['rx']['scales'] # === Removed check for scales length so that failure mode is more gracious === # Discard the frame & return 'False' if it doesn't match the number of scales # if len(decoded) != len(scales): # self._log.warning(str(rxc.uri) + " Scales " + str(scales) + " for RX data : " + str(rxc.realdata) + " not suitable " ) # return False # else: # Determine the expected number of values to be decoded # Set decoder to "Per value" scaling using scale 'False' as flag # scale = False if len(scales) > 1: scale = False else: scale = "1" else: # if node is listed, but has only a single default scale for all values if node in ehc.nodelist and 'rx' in ehc.nodelist[ node] and 'scale' in ehc.nodelist[node]['rx']: scale = ehc.nodelist[node]['rx']['scale'] else: # when node not listed or has no scale(s) use the interfacers default if specified scale = self._settings['scale'] if not scale == "1": for i in range(0, len(decoded), 1): x = scale if not scale: if i < len(scales): x = scales[i] else: x = 1 if x != "1": val = decoded[i] * float(x) if val % 1 == 0: decoded[i] = int(val) else: decoded[i] = float(val) rxc.realdata = decoded names = [] if node in ehc.nodelist and 'rx' in ehc.nodelist[ node] and 'names' in ehc.nodelist[node]['rx']: names = ehc.nodelist[node]['rx']['names'] rxc.names = names nodename = False if node in ehc.nodelist and 'nodename' in ehc.nodelist[node]: nodename = ehc.nodelist[node]['nodename'] rxc.nodename = nodename if not rxc: return False self._log.debug(str(rxc.uri) + " Timestamp : " + str(rxc.timestamp)) self._log.debug(str(rxc.uri) + " From Node : " + str(rxc.nodeid)) if rxc.target: self._log.debug(str(rxc.uri) + " To Target : " + str(rxc.target)) self._log.debug(str(rxc.uri) + " Values : " + str(rxc.realdata)) if rxc.rssi: self._log.debug(str(rxc.uri) + " RSSI : " + str(rxc.rssi)) return rxc
def _process_rx(self, cargo): """Process a frame of data f (string): 'NodeID val1 val2 ...' This function splits the string into numbers and check its validity. 'NodeID val1 val2 ...' is the generic data format. If the source uses a different format, override this method. Return data as a list: [NodeID, val1, val2] """ # Log data self._log.debug(str(cargo.uri) + " NEW FRAME : " + str(cargo.rawdata)) rxc = cargo decoded = [] node = str(rxc.nodeid) datacode = True # Discard if data is non-existent if len(rxc.realdata) < 1: self._log.warning(str(cargo.uri) + " Discarded RX frame 'string too short' : " + str(rxc.realdata)) return False # Discard if anything non-numerical found try: [float(val) for val in rxc.realdata] except Exception: self._log.warning(str(cargo.uri) + " Discarded RX frame 'non-numerical content' : " + str(rxc.realdata)) return False # Discard if first value is not a valid node id # n = float(rxc.realdata[0]) # if n % 1 != 0 or n < 0 or n > 31: # self._log.warning(str(cargo.uri) + " Discarded RX frame 'node id outside scope' : " + str(rxc.realdata)) # return False # check if node is listed and has individual datacodes for each value if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'datacodes' in ehc.nodelist[node]['rx']: # fetch the string of datacodes datacodes = ehc.nodelist[node]['rx']['datacodes'] # fetch a string of data sizes based on the string of datacodes datasizes = [] for code in datacodes: datasizes.append(ehc.check_datacode(str(code))) # Discard the frame & return 'False' if it doesn't match the summed datasizes if len(rxc.realdata) != sum(datasizes): self._log.warning(str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + " is not valid for datacodes " + str(datacodes)) return False else: # Determine the expected number of values to be decoded count = len(datacodes) # Set decoder to "Per value" decoding using datacode 'False' as flag datacode = False else: # if node is listed, but has only a single default datacode for all values if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'datacode' in ehc.nodelist[node]['rx']: datacode = ehc.nodelist[node]['rx']['datacode'] else: # when node not listed or has no datacode(s) use the interfacers default if specified datacode = self._settings['datacode'] # Ensure only int 0 is passed not str 0 if datacode == '0': datacode = 0 # when no (default)datacode(s) specified, pass string values back as numerical values if not datacode: for val in rxc.realdata: if float(val) % 1 != 0: val = float(val) else: val = int(float(val)) decoded.append(val) # Discard frame if total size is not an exact multiple of the specified datacode size. elif len(rxc.realdata) % ehc.check_datacode(datacode) != 0: self._log.warning(str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + " is not valid for datacode " + str(datacode)) return False else: # Determine the number of values in the frame of the specified code & size count = len(rxc.realdata) / ehc.check_datacode(datacode) # Decode the string of data one value at a time into "decoded" if not decoded: bytepos = int(0) for i in range(0, count, 1): # Use single datacode unless datacode = False then use datacodes dc = str(datacode) if not datacode: dc = str(datacodes[i]) # Determine the number of bytes to use for each value by it's datacode size = int(ehc.check_datacode(dc)) try: value = ehc.decode(dc, [int(v) for v in rxc.realdata[bytepos:bytepos+size]]) except: self._log.warning(str(rxc.uri) + " Unable to decode as values incorrect for datacode(s)") return False bytepos += size decoded.append(value) # check if node is listed and has individual scales for each value if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'scales' in ehc.nodelist[node]['rx']: scales = ehc.nodelist[node]['rx']['scales'] # === Removed check for scales length so that failure mode is more gracious === # Discard the frame & return 'False' if it doesn't match the number of scales # if len(decoded) != len(scales): # self._log.warning(str(rxc.uri) + " Scales " + str(scales) + " for RX data : " + str(rxc.realdata) + " not suitable " ) # return False # else: # Determine the expected number of values to be decoded # Set decoder to "Per value" scaling using scale 'False' as flag # scale = False if len(scales)>1: scale = False else: scale = "1" else: # if node is listed, but has only a single default scale for all values if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'scale' in ehc.nodelist[node]['rx']: scale = ehc.nodelist[node]['rx']['scale'] else: # when node not listed or has no scale(s) use the interfacers default if specified scale = self._settings['scale'] if not scale == "1": for i in range(0, len(decoded), 1): x = scale if not scale: if i<len(scales): x = scales[i] else: x = 1 if x != "1": val = decoded[i] * float(x) if val % 1 == 0: decoded[i] = int(val) else: decoded[i] = float(val) rxc.realdata = decoded names = [] if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'names' in ehc.nodelist[node]['rx']: names = ehc.nodelist[node]['rx']['names'] rxc.names = names nodename = False if node in ehc.nodelist and 'nodename' in ehc.nodelist[node]: nodename = ehc.nodelist[node]['nodename'] rxc.nodename = nodename if not rxc: return False self._log.debug(str(rxc.uri) + " Timestamp : " + str(rxc.timestamp)) self._log.debug(str(rxc.uri) + " From Node : " + str(rxc.nodeid)) if rxc.target: self._log.debug(str(rxc.uri) + " To Target : " + str(rxc.target)) self._log.debug(str(rxc.uri) + " Values : " + str(rxc.realdata)) if rxc.rssi: self._log.debug(str(rxc.uri) + " RSSI : " + str(rxc.rssi)) return rxc
def _decode_frame(self, ref, data): """Decodes a frame of data Performs decoding of data types Returns decoded string of data. """ node = data[0] data = data[1:] decoded = [] # check if node is listed and has individual datacodes for each value if node in ehc.nodelist and 'datacodes' in ehc.nodelist[node]: # fetch the string of datacodes datacodes = ehc.nodelist[node]['datacodes'] # fetch a string of data sizes based on the string of datacodes datasizes = [] for code in datacodes: datasizes.append(ehc.check_datacode(code)) # Discard the frame & return 'False' if it doesn't match the summed datasizes if len(data) != sum(datasizes): self._log.warning(str(ref) + " RX data length: " + str(len(data)) + " is not valid for datacodes " + str(datacodes)) return False else: # Determine the expected number of values to be decoded count = len(datacodes) # Set decoder to "Per value" decoding using datacode 'False' as flag datacode = False else: # if node is listed, but has only a single default datacode for all values if node in ehc.nodelist and 'datacode' in ehc.nodelist[node]: datacode = ehc.nodelist[node]['datacode'] else: # when node not listed or has no datacode(s) use the interfacers default if specified datacode = self._settings['datacode'] # Ensure only int 0 is passed not str 0 if datacode == '0': datacode = 0 # when no (default)datacode(s) specified, pass string values back as numerical values if not datacode: for val in data: if float(val) % 1 != 0: val = float(val) else: val = int(float(val)) decoded.append(val) # Discard frame if total size is not an exact multiple of the specified datacode size. elif len(data) % ehc.check_datacode(datacode) != 0: self._log.warning(str(ref) + " RX data length: " + str(len(data)) + " is not valid for datacode " + str(datacode)) return False else: # Determine the number of values in the frame of the specified code & size count = len(data) / ehc.check_datacode(datacode) # Decode the string of data one value at a time into "decoded" if not decoded: bytepos = int(0) for i in range(0, count, 1): # Use single datacode unless datacode = False then use datacodes dc = datacode if not datacode: dc = datacodes[i] # Determine the number of bytes to use for each value by it's datacode size = int(ehc.check_datacode(dc)) try: value = ehc.decode(dc, [int(v) for v in data[bytepos:bytepos+size]]) except: self._log.warning(str(ref) + " Unable to decode as values incorrect for datacode(s)") return False bytepos += size decoded.append(value) # Insert node ID before data decoded.insert(0, int(node)) return decoded
class EmonHubInterfacer(threading.Thread): def __init__(self, name): # Initialize logger self._log = logging.getLogger("EmonHub") # Initialise thread threading.Thread.__init__(self) self.setName(name) # Initialise settings self.init_settings = {} self._defaults = {'pause': 'off', 'interval': 0, 'datacode': '0', 'scale':'1', 'timestamped': False, 'targeted': False, 'nodeoffset' : '0','pubchannels':["ch1"],'subchannels':["ch2"]} self._settings = {} # This line will stop the default values printing to logfile at start-up # unless they have been overwritten by emonhub.conf entries # comment out if diagnosing a startup value issue self._settings.update(self._defaults) # Initialize interval timer's "started at" timestamp self._interval_timestamp = 0 # create a stop self.stop = False def run(self): """ Run the interfacer. Any regularly performed tasks actioned here along with passing received values """ while not self.stop: # Read the input and process data if available rxc = self.read() # if 'pause' in self._settings and \ # str.lower(self._settings['pause']) in ['all', 'in']: # pass # else: if rxc: rxc = self._process_rx(rxc) if rxc: for channel in self._settings["pubchannels"]: dispatcher.send(channel, cargo=rxc) self._log.debug(str(rxc.uri) + " Sent to channel' : " + str(channel)) # Don't loop to fast time.sleep(0.1) # Action reporter tasks self.action() # Subscribed channels entry def receiver(self, cargo): txc = self._process_tx(cargo) self.send(txc) def read(self): """Read raw data from interface and pass for processing. Specific version to be created for each interfacer Returns an EmonHubCargo object """ pass def send(self, cargo): """Send data from interface. Specific version to be created for each interfacer Accepts an EmonHubCargo object """ pass def action(self): """Action any interfacer tasks, Specific version to be created for each interfacer """ pass def _process_rx(self, cargo): """Process a frame of data f (string): 'NodeID val1 val2 ...' This function splits the string into numbers and check its validity. 'NodeID val1 val2 ...' is the generic data format. If the source uses a different format, override this method. Return data as a list: [NodeID, val1, val2] """ # Log data self._log.debug(str(cargo.uri) + " NEW FRAME : " + str(cargo.rawdata)) rxc = cargo decoded = [] node = str(rxc.nodeid) datacode = True # Discard if data is non-existent if len(rxc.realdata) < 1: self._log.warning(str(cargo.uri) + " Discarded RX frame 'string too short' : " + str(rxc.realdata)) return False # Discard if anything non-numerical found try: tempval = 0 for val in rxc.realdata: tempval = float(val) #[float(val) for val in rxc.realdata] except Exception,e: self._log.warning(str(cargo.uri) + " Discarded RX frame 'non-numerical content' : " + str(rxc.realdata) + " value: " + str(tempval)) print e return False # Discard if first value is not a valid node id # n = float(rxc.realdata[0]) # if n % 1 != 0 or n < 0 or n > 31: # self._log.warning(str(cargo.uri) + " Discarded RX frame 'node id outside scope' : " + str(rxc.realdata)) # return False # check if node is listed and has individual datacodes for each value if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'datacodes' in ehc.nodelist[node]['rx']: # fetch the string of datacodes datacodes = ehc.nodelist[node]['rx']['datacodes'] rxc.names = ehc.nodelist[node]['rx']['names'] rxc.units = ehc.nodelist[node]['rx']['units'] #self._log.debug("Debuging====="+str(rxc.names)) # fetch a string of data sizes based on the string of datacodes datasizes = [] for code in datacodes: datasizes.append(ehc.check_datacode(str(code))) # Discard the frame & return 'False' if it doesn't match the summed datasizes if len(rxc.realdata) != sum(datasizes): self._log.warning(str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + " is not valid for datacodes " + str(datacodes)) return False else: # Determine the expected number of values to be decoded count = len(datacodes) # Set decoder to "Per value" decoding using datacode 'False' as flag datacode = False else: # if node is listed, but has only a single default datacode for all values if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'datacode' in ehc.nodelist[node]['rx']: datacode = ehc.nodelist[node]['rx']['datacode'] rxc.names = ehc.nodelist[node]['rx']['names'] rxc.units = ehc.nodelist[node]['rx']['units'] else: # when node not listed or has no datacode(s) use the interfacers default if specified datacode = self._settings['datacode'] # Ensure only int 0 is passed not str 0 if datacode == '0': datacode = 0 # when no (default)datacode(s) specified, pass string values back as numerical values if not datacode: for val in rxc.realdata: if float(val) % 1 != 0: val = float(val) else: val = int(float(val)) decoded.append(val) # Discard frame if total size is not an exact multiple of the specified datacode size. elif len(rxc.realdata) % ehc.check_datacode(datacode) != 0: self._log.warning(str(rxc.uri) + " RX data length: " + str(len(rxc.realdata)) + " is not valid for datacode " + str(datacode)) return False else: # Determine the number of values in the frame of the specified code & size count = len(rxc.realdata) / ehc.check_datacode(datacode) # Decode the string of data one value at a time into "decoded" if not decoded: bytepos = int(0) for i in range(0, count, 1): # Use single datacode unless datacode = False then use datacodes dc = str(datacode) if not datacode: dc = str(datacodes[i]) # Determine the number of bytes to use for each value by it's datacode size = int(ehc.check_datacode(dc)) try: value = ehc.decode(dc, [int(v) for v in rxc.realdata[bytepos:bytepos+size]]) except: self._log.warning(str(rxc.uri) + " Unable to decode as values incorrect for datacode(s)") return False bytepos += size decoded.append(value) # check if node is listed and has individual scales for each value if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'scales' in ehc.nodelist[node]['rx']: scales = ehc.nodelist[node]['rx']['scales'] # Discard the frame & return 'False' if it doesn't match the number of scales if len(decoded) != len(scales): self._log.warning(str(rxc.uri) + " Scales " + str(scales) + " length:" +str(len(scales)) +" for RX data : " + str(rxc.realdata) + " not suitable length:" + str(len(rxc.realdata))) #self._log.warning(str(rxc.uri) + " Scales " + str(scales) + " for RX data : " + str(rxc.realdata) + # " not suitable " ) return False else: # Determine the expected number of values to be decoded # Set decoder to "Per value" scaling using scale 'False' as flag scale = False else: # if node is listed, but has only a single default scale for all values if node in ehc.nodelist and 'rx' in ehc.nodelist[node] and 'scale' in ehc.nodelist[node]['rx']: scale = ehc.nodelist[node]['rx']['scale'] else: # when node not listed or has no scale(s) use the interfacers default if specified scale = self._settings['scale'] if not scale == "1": for i in range(0, len(decoded), 1): x = scale if not scale: x = scales[i] if x != "1": val = decoded[i] * float(x) if val % 1 == 0: decoded[i] = int(val) else: decoded[i] = float(val) rxc.realdata = decoded if not rxc: return False self._log.debug(str(rxc.uri) + " Timestamp : " + str(rxc.timestamp)) self._log.debug(str(rxc.uri) + " From Node : " + str(rxc.nodeid)) if rxc.target: self._log.debug(str(rxc.uri) + " To Target : " + str(rxc.target)) self._log.debug(str(rxc.uri) + " Values : " + str(rxc.realdata)) if rxc.rssi: self._log.debug(str(rxc.uri) + " RSSI : " + str(rxc.rssi)) return rxc