def getLastMeasurement(self, measurement_type): """ Retrieve the latest sensor measurement :return: The latest sensor value or None if no data available :rtype: float or None :param measurement_type: Environmental condition of a sensor (e.g. temperature, humidity, pressure, etc.) :type measurement_type: str """ last_measurement = read_last_influxdb(INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.sensor_id, measurement_type, int(self.period*1.5)).raw if last_measurement: number = len(last_measurement['series'][0]['values']) last_value = last_measurement['series'][0]['values'][number-1][1] return last_value else: return None
def get_measurement(self, display_id, i): try: if self.lcd_line[display_id][i]['measurement'] == 'relay_state': self.lcd_line[display_id][i][ 'measurement_value'] = self.output_state( self.lcd_line[display_id][i]['id']) return True else: if self.lcd_line[display_id][i]['measurement'] == 'time': last_measurement = read_last_influxdb( self.lcd_line[display_id][i]['id'], '/.*/', duration_sec=self.lcd_max_age[display_id][i]) else: last_measurement = read_last_influxdb( self.lcd_line[display_id][i]['id'], self.lcd_line[display_id][i]['measurement'], duration_sec=self.lcd_max_age[display_id][i]) if last_measurement: self.lcd_line[display_id][i]['time'] = last_measurement[0] self.lcd_line[display_id][i][ 'measurement_value'] = last_measurement[1] utc_dt = datetime.datetime.strptime( self.lcd_line[display_id][i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str( datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("Latest {}: {} @ {}".format( self.lcd_line[display_id][i]['measurement'], self.lcd_line[display_id][i]['measurement_value'], local_timestamp)) return True else: self.lcd_line[display_id][i]['time'] = None self.lcd_line[display_id][i]['measurement_value'] = None self.logger.debug("No data returned from influxdb") return False except Exception as except_msg: self.logger.debug( "Failed to read measurement from the influxdb database: " "{err}".format(err=except_msg)) return False
def run(self): try: self.running = True self.logger.info("Activated in {:.1f} ms".format( (timeit.default_timer() - self.thread_startup_timer) * 1000)) self.ready.set() while self.running: if self.is_activated and t.time() > self.timer: # Ensure the timer ends in the future while t.time() > self.timer: self.timer = self.timer + self.period # If PID is active, retrieve input measurement and update PID output if self.math_type == 'average' and self.inputs: missing_measure = False measurements = [] inputs_list = self.inputs.split(';') for each_input_set in inputs_list: input_id = each_input_set.split(',')[0] input_measure = each_input_set.split(',')[1] last_measurement = read_last_influxdb( input_id, input_measure, self.max_measure_age) if not last_measurement: missing_measure = True else: measurements.append(last_measurement[1]) if not missing_measure: average = sum(measurements) / float( len(measurements)) write_math_db = threading.Thread( target=write_influxdb_value, args=( self.math_unique_id, self.measure, average, )) write_math_db.start() else: self.logger.error( "One or more inputs were not within the " "Max Age that has been set. Ensure all " "Inputs are operating properly.") t.sleep(0.1) self.running = False self.logger.info("Deactivated in {:.1f} ms".format( (timeit.default_timer() - self.thread_shutdown_timer) * 1000)) except Exception as except_msg: self.logger.exception("Run Error: {err}".format(err=except_msg))
def write_log(self): """ Append log file with latest measurement if the latest measurement timestamp is more recent than the last retrieved timestamp. """ self.logger.debug("Log Controller: {} ({}) {} {} {}".format( self.log_id, self.name, self.sensor_id, self.measure_type, self.period)) try: self.last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.sensor_id, self.measure_type) if self.last_measurement: measurement_list = list(self.last_measurement.get_points( measurement=self.measure_type)) self.last_time = measurement_list[0]['time'] self.last_measurement = measurement_list[0]['value'] else: self.logger.warning("[Log {}] No data returned " "from influxdb".format(self.log_id)) return 1 self.dt = date_parse(self.last_time) self.timestamp = calendar.timegm(self.dt.timetuple()) if self.last_timestamp != self.timestamp: self.last_timestamp = self.timestamp self.logger.debug("[Log {}] Time: {}, {} Value: " "{}".format(self.log_id, self.last_time, self.timestamp, self.last_measurement)) SENSOR_LOG_FILE = os.path.join( LOG_PATH, "{}-{}.log".format(self.sensor_id, self.measure_type)) assure_path_exists(LOG_PATH) with open(SENSOR_LOG_FILE, "a") as log_file: log_file.write("{},{}\n".format(self.timestamp, self.last_measurement)) # Ensure log is owned by user 'mycodo' if find_owner(SENSOR_LOG_FILE) != 'mycodo': set_user_grp(SENSOR_LOG_FILE, 'mycodo', 'mycodo') else: self.logger.debug("[Log {}] No new data from " "influxdb could be " "retrieved.".format(self.log_id)) except Exception as except_msg: self.logger.exception("[Log {}] Could not retrieve influxdb" " data: {}".format(self.log_id, except_msg))
def get_last_measurement(self): """ Retrieve the latest input measurement from InfluxDB :rtype: None """ self.last_measurement_success = False # Get latest measurement (from within the past minute) from influxdb try: if self.input_duration < 60: duration = 60 else: duration = int(self.input_duration * 1.5) self.last_measurement = read_last_influxdb(self.input_unique_id, self.measurement, duration) if self.last_measurement: self.last_time = self.last_measurement[0] self.last_measurement = self.last_measurement[1] utc_dt = datetime.datetime.strptime( self.last_time.split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str( datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("Latest {meas}: {last} @ {ts}".format( meas=self.measurement, last=self.last_measurement, ts=local_timestamp)) if calendar.timegm( t.gmtime()) - utc_timestamp > self.max_measure_age: self.logger.error( "Last measurement was {last_sec} seconds ago, however" " the maximum measurement age is set to {max_sec}" " seconds.".format( last_sec=calendar.timegm(t.gmtime()) - utc_timestamp, max_sec=self.max_measure_age)) self.last_measurement_success = True else: self.logger.warning("No data returned from influxdb") except requests.ConnectionError: self.logger.error("Failed to read measurement from the " "influxdb database: Could not connect.") except Exception as except_msg: self.logger.exception( "Exception while reading measurement from the influxdb " "database: {err}".format(err=except_msg))
def get_last_measurement(self, measurement_type): """ Retrieve the latest sensor measurement :return: The latest sensor value or None if no data available :rtype: float or None :param measurement_type: Environmental condition of a sensor (e.g. temperature, humidity, pressure, etc.) :type measurement_type: str """ last_measurement = read_last_influxdb(self.sensor_id, measurement_type, int(self.period * 1.5)).raw if last_measurement: number = len(last_measurement['series'][0]['values']) last_value = last_measurement['series'][0]['values'][number - 1][1] return last_value else: return None
def get_last_measurement(self, measurement_type): """ Retrieve the latest input measurement :return: The latest input value or None if no data available :rtype: float or None :param measurement_type: Environmental condition of a input (e.g. temperature, humidity, pressure, etc.) :type measurement_type: str """ last_measurement = read_last_influxdb(self.unique_id, measurement_type, int(self.period * 1.5)) if last_measurement: last_value = last_measurement[1] return last_value else: return None
def get_last_measurement(self): """ Retrieve the latest sensor measurement from InfluxDB :rtype: None """ self.last_measurement_success = False # Get latest measurement (from within the past minute) from influxdb try: if self.sensor_duration < 60: duration = 60 else: duration = int(self.sensor_duration*1.5) self.last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.sensor_id, self.measure_type, duration) if self.last_measurement: measurement_list = list(self.last_measurement.get_points( measurement=self.measure_type)) self.last_time = measurement_list[0]['time'] self.last_measurement = measurement_list[0]['value'] utc_dt = datetime.datetime.strptime(self.last_time.split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str(datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("[PID {}] Latest {}: {} @ {}".format( self.pid_id, self.measure_type, self.last_measurement, local_timestamp)) self.last_measurement_success = True else: self.logger.warning("[PID {}] No data returned " "from influxdb".format(self.pid_id)) except Exception as except_msg: self.logger.exception("[PID {}] Failed to read " "measurement from the influxdb " "database: {}".format(self.pid_id, except_msg))
def get_last_measurement(self): """ Retrieve the latest sensor measurement from InfluxDB :rtype: None """ self.last_measurement_success = False # Get latest measurement (from within the past minute) from influxdb try: if self.sensor_duration/60 < 1: duration = 1 else: duration = self.sensor_duration/60*1.5 self.last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.sensor_id, self.measure_type, duration) if self.last_measurement: measurement_list = list(self.last_measurement.get_points( measurement=self.measure_type)) self.last_time = measurement_list[0]['time'] self.last_measurement = measurement_list[0]['value'] utc_dt = datetime.datetime.strptime(self.last_time.split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str(datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("[PID {}] Latest {}: {} @ {}".format( self.pid_id, self.measure_type, self.last_measurement, local_timestamp)) self.last_measurement_success = True else: self.logger.warning("[PID {}] No data returned " "from influxdb".format(self.pid_id)) except Exception as except_msg: self.logger.exception("[PID {}] Failed to read " "measurement from the influxdb " "database: {}".format(self.pid_id, except_msg))
def get_last_measurement(self): """ Retrieve the latest sensor measurement from InfluxDB :rtype: None """ self.last_measurement_success = False # Get latest measurement (from within the past minute) from influxdb try: if self.sensor_duration < 60: duration = 60 else: duration = int(self.sensor_duration * 1.5) self.last_measurement = read_last_influxdb(self.sensor_id, self.measure_type, duration) if self.last_measurement: measurement_list = list( self.last_measurement.get_points( measurement=self.measure_type)) self.last_time = measurement_list[0]['time'] self.last_measurement = measurement_list[0]['value'] utc_dt = datetime.datetime.strptime( self.last_time.split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str( datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("Latest {}: {} @ {}".format( self.measure_type, self.last_measurement, local_timestamp)) self.last_measurement_success = True else: self.logger.warning("No data returned from influxdb") except Exception as except_msg: self.logger.exception( "Failed to read measurement from the influxdb database: " "{err}".format(err=except_msg))
def get_lcd_strings(self): """ Retrieve measurements and/or timestamps and create strings for LCDs If no data is retrieveable, create string "NO DATA RETURNED". """ # loop to acquire all measurements required to be displayed on the LCD for i in range(1, self.lcd_y_lines + 1): if self.lcd_line[i]['id']: # Get latest measurement (within past minute) from influxdb # FROM '/.*/' returns any measurement (for grabbing time of last measurement) last_measurement_success = False try: if self.lcd_line[i]['measurement'] == 'relay_state': self.lcd_line[i][ 'measurement_value'] = self.relay_state( self.lcd_line[i]['id']) last_measurement_success = True else: if self.lcd_line[i]['measurement'] == 'time': last_measurement = read_last_influxdb( self.lcd_line[i]['id'], '/.*/') else: last_measurement = read_last_influxdb( self.lcd_line[i]['id'], self.lcd_line[i]['measurement']) if last_measurement: self.lcd_line[i]['time'] = last_measurement[0] self.lcd_line[i][ 'measurement_value'] = last_measurement[1] utc_dt = datetime.datetime.strptime( self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str( datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("Latest {}: {} @ {}".format( self.lcd_line[i]['measurement'], self.lcd_line[i]['measurement_value'], local_timestamp)) last_measurement_success = True else: self.lcd_line[i]['time'] = None self.lcd_line[i]['measurement_value'] = None self.logger.debug("No data returned from " "influxdb") except Exception as except_msg: self.logger.debug( "Failed to read measurement from the " "influxdb database: {err}".format(err=except_msg)) try: if last_measurement_success: # Determine if the LCD output will have a value unit measurement = '' if self.lcd_line[i]['measurement'] == 'setpoint': pid = db_retrieve_table_daemon( PID, unique_id=self.lcd_line[i]['id']) measurement = pid.measurement elif self.lcd_line[i]['measurement'] == 'duration_sec': measurement = 'duration_sec' self.lcd_line[i][ 'measurement_value'] = '{:.2f}'.format( self.lcd_line[i]['measurement_value']) elif self.lcd_line[i][ 'measurement'] in MEASUREMENT_UNITS: measurement = self.lcd_line[i]['measurement'] # Produce the line that will be displayed on the LCD number_characters = self.lcd_x_characters if self.lcd_line[i]['measurement'] == 'time': # Convert UTC timestamp to local timezone utc_dt = datetime.datetime.strptime( self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) self.lcd_string_line[i] = str( datetime.datetime.fromtimestamp(utc_timestamp)) elif measurement: value_length = len( str(self.lcd_line[i]['measurement_value'])) unit_length = len( MEASUREMENT_UNITS[measurement]['unit']) name_length = number_characters - value_length - unit_length - 2 name_cropped = self.lcd_line[i]['name'].ljust( name_length)[:name_length] self.lcd_string_line[ i] = u'{name} {value} {unit}'.format( name=name_cropped, value=self.lcd_line[i] ['measurement_value'], unit=MEASUREMENT_UNITS[measurement] ['unit']) else: value_length = len( str(self.lcd_line[i]['measurement_value'])) name_length = number_characters - value_length - 1 name_cropped = self.lcd_line[i][ 'name'][:name_length] self.lcd_string_line[i] = u'{name} {value}'.format( name=name_cropped, value=self.lcd_line[i]['measurement_value']) else: self.lcd_string_line[i] = 'ERROR: NO DATA' except Exception as except_msg: self.logger.exception( "Error: {err}".format(err=except_msg)) else: self.lcd_string_line[i] = ''
def get_lcd_strings(self): """ Retrieve measurements and/or timestamps and create strings for LCDs If no data is retrieveable, create string "NO DATA RETURNED". """ # loop to acquire all measurements required to be displayed on the LCD for i in range(1, self.lcd_y_lines + 1): if self.lcd_line[i]['id']: # Get latest measurement (from within the past minute) from influxdb # FROM '/.*/' returns any measurement (for grabbing time of last measurement) last_measurement_success = False try: if self.lcd_line[i]['measurement'] == 'relay_state': self.lcd_line[i][ 'measurement_value'] = self.relay_state( self.lcd_line[i]['id']) last_measurement_success = True else: if self.lcd_line[i]['measurement'] == 'time': last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.lcd_line[i]['id'], '/.*/').raw else: last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.lcd_line[i]['id'], self.lcd_line[i]['measurement']).raw if last_measurement: number = len( last_measurement['series'][0]['values']) self.lcd_line[i]['time'] = last_measurement[ 'series'][0]['values'][number - 1][0] self.lcd_line[i][ 'measurement_value'] = last_measurement[ 'series'][0]['values'][number - 1][1] utc_dt = datetime.datetime.strptime( self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str( datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug( "[LCD {}] Latest {}: {} @ {}".format( self.lcd_id, self.lcd_line[i]['measurement'], self.lcd_line[i]['measurement_value'], local_timestamp)) last_measurement_success = True else: self.lcd_line[i]['time'] = None self.lcd_line[i]['measurement_value'] = None self.logger.debug("[LCD {}] No data returned " "from influxdb".format( self.lcd_id)) except Exception as except_msg: self.logger.debug( "[LCD {}] Failed to read " "measurement from the influxdb database: " "{}".format(self.lcd_id, except_msg)) try: if last_measurement_success: # Determine if the LCD output will have a value unit measurement = '' if self.lcd_line[i]['measurement'] == 'setpoint': with session_scope(MYCODO_DB_PATH) as new_session: pid = new_session.query(PID).filter( PID.id == self.lcd_line[i]['id']).first() new_session.expunge_all() new_session.close() measurement = pid.measure_type elif self.lcd_line[i]['measurement'] in [ 'temperature', 'temperature_die', 'temperature_object', 'humidity', 'co2', 'lux', 'pressure', 'altitude' ]: measurement = self.lcd_line[i]['measurement'] elif self.lcd_line[i]['measurement'] == 'duration_sec': measurement = 'duration_sec' # Produce the line that will be displayed on the LCD number_characters = self.lcd_x_characters if self.lcd_line[i]['measurement'] == 'time': # Convert UTC timestamp to local timezone utc_dt = datetime.datetime.strptime( self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) self.lcd_string_line[i] = str( datetime.datetime.fromtimestamp(utc_timestamp)) elif measurement: value_length = len( str(self.lcd_line[i]['measurement_value'])) unit_length = len( self.measurement_unit['metric'][measurement]) name_length = number_characters - value_length - unit_length - 2 name_cropped = self.lcd_line[i]['name'].ljust( name_length)[:name_length] self.lcd_string_line[i] = '{} {} {}'.format( name_cropped, self.lcd_line[i]['measurement_value'], self.measurement_unit['metric'][measurement]) else: value_length = len( str(self.lcd_line[i]['measurement_value'])) name_length = number_characters - value_length - 1 name_cropped = self.lcd_line[i][ 'name'][:name_length] self.lcd_string_line[i] = '{} {}'.format( name_cropped, self.lcd_line[i]['measurement_value']) else: self.lcd_string_line[i] = 'NO DATA < 5 MIN' except Exception as except_msg: self.logger.exception("[LCD {}] Error ({}): {}".format( self.lcd_id, except_msg)) else: self.lcd_string_line[i] = ''
def get_lcd_strings(self): """ Retrieve measurements and/or timestamps and create strings for LCDs If no data is retrieveable, create string "NO DATA RETURNED". """ # loop to acquire all measurements required to be displayed on the LCD for i in range(1, self.lcd_y_lines+1): if self.lcd_line[i]['id']: # Get latest measurement (from within the past minute) from influxdb # FROM '/.*/' returns any measurement (for grabbing time of last measurement) last_measurement_success = False try: if self.lcd_line[i]['measurement'] == 'relay_state': self.lcd_line[i]['measurement_value'] = self.relay_state(self.lcd_line[i]['id']) last_measurement_success = True else: if self.lcd_line[i]['measurement'] == 'time': last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.lcd_line[i]['id'], '/.*/').raw else: last_measurement = read_last_influxdb( INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_USER, INFLUXDB_PASSWORD, INFLUXDB_DATABASE, self.lcd_line[i]['id'], self.lcd_line[i]['measurement']).raw if last_measurement: number = len(last_measurement['series'][0]['values']) self.lcd_line[i]['time'] = last_measurement['series'][0]['values'][number-1][0] self.lcd_line[i]['measurement_value'] = last_measurement['series'][0]['values'][number-1][1] utc_dt = datetime.datetime.strptime(self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str(datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("[LCD {}] Latest {}: {} @ {}".format( self.lcd_id, self.lcd_line[i]['measurement'], self.lcd_line[i]['measurement_value'], local_timestamp)) last_measurement_success = True else: self.lcd_line[i]['time'] = None self.lcd_line[i]['measurement_value'] = None self.logger.debug("[LCD {}] No data returned " "from influxdb".format(self.lcd_id)) except Exception as except_msg: self.logger.debug("[LCD {}] Failed to read " "measurement from the influxdb database: " "{}".format(self.lcd_id, except_msg)) try: if last_measurement_success: # Determine if the LCD output will have a value unit measurement = '' if self.lcd_line[i]['measurement'] == 'setpoint': with session_scope(MYCODO_DB_PATH) as new_session: pid = new_session.query(PID).filter( PID.id == self.lcd_line[i]['id']).first() new_session.expunge_all() new_session.close() measurement = pid.measure_type elif self.lcd_line[i]['measurement'] in ['temperature', 'temperature_die', 'temperature_object', 'humidity', 'co2', 'lux', 'pressure', 'altitude']: measurement = self.lcd_line[i]['measurement'] elif self.lcd_line[i]['measurement'] == 'duration_sec': measurement = 'duration_sec' # Produce the line that will be displayed on the LCD number_characters = self.lcd_x_characters if self.lcd_line[i]['measurement'] == 'time': # Convert UTC timestamp to local timezone utc_dt = datetime.datetime.strptime(self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) self.lcd_string_line[i] = str(datetime.datetime.fromtimestamp(utc_timestamp)) elif measurement: value_length = len(str(self.lcd_line[i]['measurement_value'])) unit_length = len(self.measurement_unit['metric'][measurement]) name_length = number_characters - value_length - unit_length - 2 name_cropped = self.lcd_line[i]['name'].ljust(name_length)[:name_length] self.lcd_string_line[i] = '{} {} {}'.format( name_cropped, self.lcd_line[i]['measurement_value'], self.measurement_unit['metric'][measurement]) else: value_length = len(str(self.lcd_line[i]['measurement_value'])) name_length = number_characters - value_length - 1 name_cropped = self.lcd_line[i]['name'][:name_length] self.lcd_string_line[i] = '{} {}'.format( name_cropped, self.lcd_line[i]['measurement_value']) else: self.lcd_string_line[i] = 'NO DATA < 5 MIN' except Exception as except_msg: self.logger.exception("[LCD {}] Error ({}): {}".format( self.lcd_id, except_msg)) else: self.lcd_string_line[i] = ''
def get_lcd_strings(self): """ Retrieve measurements and/or timestamps and create strings for LCDs If no data is retrieveable, create string "NO DATA RETURNED". """ # loop to acquire all measurements required to be displayed on the LCD for i in range(1, self.lcd_y_lines + 1): if self.lcd_line[i]['id']: # Get latest measurement (within past minute) from influxdb # FROM '/.*/' returns any measurement (for grabbing time of last measurement) last_measurement_success = False try: if self.lcd_line[i]['measurement'] == 'relay_state': self.lcd_line[i]['measurement_value'] = self.relay_state(self.lcd_line[i]['id']) last_measurement_success = True else: if self.lcd_line[i]['measurement'] == 'time': last_measurement = read_last_influxdb( self.lcd_line[i]['id'], '/.*/').raw else: last_measurement = read_last_influxdb( self.lcd_line[i]['id'], self.lcd_line[i]['measurement']).raw if last_measurement: number = len(last_measurement['series'][0]['values']) self.lcd_line[i]['time'] = last_measurement['series'][0]['values'][number - 1][0] self.lcd_line[i]['measurement_value'] = last_measurement['series'][0]['values'][number - 1][1] utc_dt = datetime.datetime.strptime( self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) local_timestamp = str(datetime.datetime.fromtimestamp(utc_timestamp)) self.logger.debug("Latest {}: {} @ {}".format( self.lcd_line[i]['measurement'], self.lcd_line[i]['measurement_value'], local_timestamp)) last_measurement_success = True else: self.lcd_line[i]['time'] = None self.lcd_line[i]['measurement_value'] = None self.logger.debug("No data returned from " "influxdb") except Exception as except_msg: self.logger.debug("Failed to read measurement from the " "influxdb database: {err}".format( err=except_msg)) try: if last_measurement_success: # Determine if the LCD output will have a value unit measurement = '' if self.lcd_line[i]['measurement'] == 'setpoint': pid = db_retrieve_table( MYCODO_DB_PATH, PID, device_id=self.lcd_line[i]['id']) measurement = pid.measure_type elif self.lcd_line[i]['measurement'] in [ 'temperature', 'temperature_die', 'temperature_object', 'humidity', 'co2', 'lux', 'pressure', 'altitude']: measurement = self.lcd_line[i]['measurement'] elif self.lcd_line[i]['measurement'] == 'duration_sec': measurement = 'duration_sec' # Produce the line that will be displayed on the LCD number_characters = self.lcd_x_characters if self.lcd_line[i]['measurement'] == 'time': # Convert UTC timestamp to local timezone utc_dt = datetime.datetime.strptime( self.lcd_line[i]['time'].split(".")[0], '%Y-%m-%dT%H:%M:%S') utc_timestamp = calendar.timegm(utc_dt.timetuple()) self.lcd_string_line[i] = str( datetime.datetime.fromtimestamp(utc_timestamp)) elif measurement: value_length = len(str( self.lcd_line[i]['measurement_value'])) unit_length = len(MEASUREMENT_UNITS[measurement]) name_length = number_characters - value_length - unit_length - 2 name_cropped = self.lcd_line[i]['name'].ljust(name_length)[:name_length] self.lcd_string_line[i] = '{} {} {}'.format( name_cropped, self.lcd_line[i]['measurement_value'], MEASUREMENT_UNITS[measurement]) else: value_length = len(str( self.lcd_line[i]['measurement_value'])) name_length = number_characters - value_length - 1 name_cropped = self.lcd_line[i]['name'][:name_length] self.lcd_string_line[i] = '{} {}'.format( name_cropped, self.lcd_line[i]['measurement_value']) else: self.lcd_string_line[i] = 'NO DATA < 5 MIN' except Exception as except_msg: self.logger.exception("Error: {err}".format( err=except_msg)) else: self.lcd_string_line[i] = ''