def return_energy_usage(energy_usage, device_measurements_all, conversion_all): """ Calculate energy usage from Inputs/Maths measuring amps """ energy_usage_stats = {} graph_info = {} for each_energy in energy_usage: graph_info[each_energy.unique_id] = {} energy_usage_stats[each_energy.unique_id] = {} energy_usage_stats[each_energy.unique_id]['hour'] = 0 energy_usage_stats[each_energy.unique_id]['day'] = 0 energy_usage_stats[each_energy.unique_id]['week'] = 0 energy_usage_stats[each_energy.unique_id]['month'] = 0 device_measurement = device_measurements_all.filter( DeviceMeasurements.unique_id == each_energy.measurement_id).first() if device_measurement: conversion = conversion_all.filter( Conversion.unique_id == device_measurement.conversion_id).first() else: conversion = None channel, unit, measurement = return_measurement_info( device_measurement, conversion) graph_info[each_energy.unique_id]['main'] = {} graph_info[each_energy.unique_id]['main']['device_id'] = each_energy.device_id graph_info[each_energy.unique_id]['main']['measurement_id'] = each_energy.measurement_id graph_info[each_energy.unique_id]['main']['channel'] = channel graph_info[each_energy.unique_id]['main']['unit'] = unit graph_info[each_energy.unique_id]['main']['measurement'] = measurement graph_info[each_energy.unique_id]['main']['start_time_epoch'] = ( datetime.datetime.now() - datetime.timedelta(seconds=2629800)).strftime('%s') if unit == 'A': # If unit is amps, proceed hour = average_past_seconds( each_energy.device_id, unit, channel, 3600, measure=measurement) if hour: energy_usage_stats[each_energy.unique_id]['hour'] = hour day = average_past_seconds( each_energy.device_id, unit, channel, 86400, measure=measurement) if day: energy_usage_stats[each_energy.unique_id]['day'] = day week = average_past_seconds( each_energy.device_id, unit, channel, 604800, measure=measurement) if week: energy_usage_stats[each_energy.unique_id]['week'] = week month = average_past_seconds( each_energy.device_id, unit, channel, 2629800, measure=measurement) if month: energy_usage_stats[each_energy.unique_id]['month'] = month return energy_usage_stats, graph_info
def math_average_single(self, measurement_dict): (device_id, math_dev_measurement, math_unit, measure_channel, measure_unit, measure_measurement) = self.return_single_measure_info() try: return_value = average_past_seconds(device_id, measure_unit, measure_channel, self.max_measure_age, measure=measure_measurement) if math_dev_measurement.conversion_id: return_value = convert_units( math_dev_measurement.conversion_id, return_value) if return_value: measurement_dict = { math_dev_measurement.channel: { 'measurement': measure_measurement, 'unit': math_unit, 'value': return_value } } else: self.error_not_within_max_age() except Exception as msg: self.logger.exception( "average_single Error: {err}".format(err=msg)) return measurement_dict
def loop(self): if self.timer_loop > time.time(): return while self.timer_loop < time.time(): self.timer_loop += self.period device_measurement = get_measurement( self.select_measurement_measurement_id) if not device_measurement: self.logger.error("Could not find Device Measurement") return conversion = db_retrieve_table_daemon( Conversion, unique_id=device_measurement.conversion_id) channel, unit, measurement = return_measurement_info( device_measurement, conversion) average = average_past_seconds(self.select_measurement_device_id, unit, channel, self.max_measure_age, measure=measurement) if not average: self.logger.error( "Could not find measurement within the set Max Age") return False measurement_dict = { 0: { 'measurement': self.channels_measurement[0].measurement, 'unit': self.channels_measurement[0].unit, 'value': average } } if measurement_dict: self.logger.debug( "Adding measurements to InfluxDB with ID {}: {}".format( self.unique_id, measurement_dict)) add_measurements_influxdb(self.unique_id, measurement_dict) else: self.logger.debug( "No measurements to add to InfluxDB with ID {}".format( self.unique_id))
def calculate_math(self): measurement_dict = {} # # Average (multiple channels) # if self.math_type == 'average': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() channel, unit, measurement = return_measurement_info( math_dev_measurement, None) success, measure = self.get_measurements_from_str(self.inputs) if success: average = float(sum(measure) / float(len(measure))) measurement_dict = { channel: { 'measurement': measurement, 'unit': unit, 'value': average } } elif measure: self.logger.error(measure) else: self.error_not_within_max_age() # # Average (single channel) # elif self.math_type == 'average_single': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() math_conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) (math_channel, math_unit, math_measurement) = return_measurement_info( math_dev_measurement, math_conversion) device_id = self.inputs.split(',')[0] measurement_id = self.inputs.split(',')[1] if measurement_id == 'output': output = db_retrieve_table_daemon(Output, unique_id=device_id) measure_channel = output.channel measure_unit = output.unit measure_measurement = output.measurement else: device_measurement = db_retrieve_table_daemon( DeviceMeasurements, unique_id=measurement_id) if device_measurement: measure_conversion = db_retrieve_table_daemon( Conversion, unique_id=device_measurement.conversion_id) else: measure_conversion = None (measure_channel, measure_unit, measure_measurement) = return_measurement_info( device_measurement, measure_conversion) try: return_value = average_past_seconds( device_id, measure_unit, measure_channel, self.max_measure_age, measure=measure_measurement) if math_dev_measurement.conversion_id: return_value = convert_units( math_dev_measurement.conversion_id, return_value) if return_value: measurement_dict = { math_dev_measurement.channel: { 'measurement': measure_measurement, 'unit': math_unit, 'value': return_value } } else: self.error_not_within_max_age() except Exception as msg: self.logger.exception( "average_single Error: {err}".format(err=msg)) # # Sum (multiple channels) # elif self.math_type == 'sum': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() if math_dev_measurement: conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) else: conversion = None channel, unit, measurement = return_measurement_info( math_dev_measurement, conversion) success, measure = self.get_measurements_from_str(self.inputs) if success: sum_value = float(sum(measure)) measurement_dict = { channel: { 'measurement': measurement, 'unit': unit, 'value': sum_value } } elif measure: self.logger.error(measure) else: self.error_not_within_max_age() # # Sum (single channel) # elif self.math_type == 'sum_single': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() math_conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) (math_channel, math_unit, math_measurement) = return_measurement_info( math_dev_measurement, math_conversion) device_id = self.inputs.split(',')[0] measurement_id = self.inputs.split(',')[1] if measurement_id == 'output': output = db_retrieve_table_daemon(Output, unique_id=device_id) measure_channel = output.channel measure_unit = output.unit measure_measurement = output.measurement else: device_measurement = db_retrieve_table_daemon( DeviceMeasurements, unique_id=measurement_id) if device_measurement: measure_conversion = db_retrieve_table_daemon( Conversion, unique_id=device_measurement.conversion_id) else: measure_conversion = None (measure_channel, measure_unit, measure_measurement) = return_measurement_info( device_measurement, measure_conversion) try: return_value = sum_past_seconds( device_id, measure_unit, measure_channel, self.max_measure_age, measure=measure_measurement) if math_dev_measurement.conversion_id: return_value = convert_units( math_dev_measurement.conversion_id, return_value) if return_value: measurement_dict = { math_dev_measurement.channel: { 'measurement': measure_measurement, 'unit': math_unit, 'value': return_value } } else: self.error_not_within_max_age() except Exception as msg: self.logger.exception( "sum_single Error: {err}".format(err=msg)) # # Difference between two channels # elif self.math_type == 'difference': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() if math_dev_measurement: conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) else: conversion = None channel, unit, measurement = return_measurement_info( math_dev_measurement, conversion) success, measure = self.get_measurements_from_str(self.inputs) if success: if self.difference_reverse_order: difference = measure[1] - measure[0] else: difference = measure[0] - measure[1] if self.difference_absolute: difference = abs(difference) measurement_dict = { channel: { 'measurement': measurement, 'unit': unit, 'value': difference } } elif measure: self.logger.error(measure) else: self.error_not_within_max_age() # # Equation (math performed on measurement) # elif self.math_type == 'equation': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() if math_dev_measurement: conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) else: conversion = None channel, unit, measurement = return_measurement_info( math_dev_measurement, conversion) success, measure = self.get_measurements_from_str( self.equation_input) if success: if 'x' in self.equation: replaced_str = self.equation.replace('x', str(measure[0])) else: replaced_str = self.equation equation_output = eval(replaced_str) measurement_dict = { channel: { 'measurement': measurement, 'unit': unit, 'value': float(equation_output) } } elif measure: self.logger.error(measure) else: self.error_not_within_max_age() # # Redundancy (Use next measurement if one isn't currently available) # elif self.math_type == 'redundancy': list_order = self.order_of_use.split(';') measurement_success = False for each_id_measurement_id in list_order: device_id = each_id_measurement_id.split(',')[0] measurement_id = each_id_measurement_id.split(',')[1] math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() if math_dev_measurement: conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) else: conversion = None channel, unit, measurement = return_measurement_info( math_dev_measurement, conversion) try: success_measure, measure = self.get_measurements_from_id( device_id, measurement_id) if success_measure: measurement_dict = { channel: { 'measurement': measurement, 'unit': unit, 'value': float(measure[1]), 'timestamp_utc': measure[0], } } measurement_success = True break except Exception as msg: self.logger.exception( "redundancy Error: {err}".format(err=msg)) if not measurement_success: self.error_not_within_max_age() # # Statistical analysis on all measurements from a period of time # elif self.math_type == 'statistics': success, measure = self.get_measurements_from_str(self.inputs) if success: # Perform some math stat_mean = float(sum(measure) / float(len(measure))) stat_median = median(measure) stat_minimum = min(measure) stat_maximum = max(measure) stdev_ = stdev(measure) stdev_mean_upper = stat_mean + stdev_ stdev_mean_lower = stat_mean - stdev_ list_measurement = [ stat_mean, stat_median, stat_minimum, stat_maximum, stdev_, stdev_mean_upper, stdev_mean_lower ] for each_measurement in self.device_measurements.all(): conversion = db_retrieve_table_daemon( Conversion, unique_id=each_measurement.conversion_id) channel, unit, measurement = return_measurement_info( each_measurement, conversion) measurement_dict[channel] = { 'measurement': measurement, 'unit': unit, 'value': list_measurement[channel] } elif measure: self.logger.error(measure) else: self.error_not_within_max_age() # # Verification (only use measurement if it's close to another measurement) # elif self.math_type == 'verification': math_dev_measurement = self.device_measurements.filter( DeviceMeasurements.channel == 0).first() if math_dev_measurement: conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) else: conversion = None channel, unit, measurement = return_measurement_info( math_dev_measurement, conversion) success, measure = self.get_measurements_from_str(self.inputs) if (success and max(measure) - min(measure) < self.max_difference): difference = max(measure) - min(measure) measurement_dict = { channel: { 'measurement': measurement, 'unit': unit, 'value': difference } } elif measure: self.logger.error(measure) else: self.error_not_within_max_age() # # Calculate humidity from wet- and dry-bulb temperatures # elif self.math_type == 'humidity': pressure_pa = 101325 critical_error = False if self.pressure_pa_id and self.pressure_pa_measure_id: success_pa, pressure = self.get_measurements_from_id( self.pressure_pa_id, self.pressure_pa_measure_id) if success_pa: pressure_pa = int(pressure[1]) # Pressure must be in Pa, convert if not measurement_press = db_retrieve_table_daemon( DeviceMeasurements, unique_id=self.pressure_pa_measure_id) if not measurement_press: self.logger.error( "Could not find pressure measurement") measurement_press = None critical_error = True if measurement_press and measurement_press.unit != 'Pa': pressure_pa, status = self.is_measurement_unit( measurement_press.unit, 'Pa', pressure_pa) if status == 'error': critical_error = True success_dbt, dry_bulb_t = self.get_measurements_from_id( self.dry_bulb_t_id, self.dry_bulb_t_measure_id) success_wbt, wet_bulb_t = self.get_measurements_from_id( self.wet_bulb_t_id, self.wet_bulb_t_measure_id) if success_dbt and success_wbt: dbt_kelvin = float(dry_bulb_t[1]) wbt_kelvin = float(wet_bulb_t[1]) measurement_db_temp = db_retrieve_table_daemon( DeviceMeasurements, unique_id=self.dry_bulb_t_measure_id) if not measurement_db_temp: self.logger.error( "Could not find dry bulb temperature measurement") measurement_db_temp = None critical_error = True if measurement_db_temp and measurement_db_temp.unit != 'K': dbt_kelvin, status = self.is_measurement_unit( measurement_db_temp.unit, 'K', dbt_kelvin) if status == 'error': critical_error = True measurement_wb_temp = db_retrieve_table_daemon( DeviceMeasurements, unique_id=self.wet_bulb_t_measure_id) if not measurement_wb_temp: self.logger.error( "Could not find wet bulb temperature measurement") measurement_wb_temp = None critical_error = True if measurement_wb_temp and measurement_wb_temp.unit != 'K': wbt_kelvin, status = self.is_measurement_unit( measurement_wb_temp.unit, 'K', wbt_kelvin) if status == 'error': critical_error = True # Convert temperatures to Kelvin (already done above) # dbt_kelvin = celsius_to_kelvin(dry_bulb_t_c) # wbt_kelvin = celsius_to_kelvin(wet_bulb_t_c) psypi = None try: if not critical_error: psypi = SI.state( "DBT", dbt_kelvin, "WBT", wbt_kelvin, pressure_pa) else: self.logger.error( "One or more critical errors prevented the " "humidity from being calculated") except TypeError as err: self.logger.error("TypeError: {msg}".format(msg=err)) if psypi: percent_relative_humidity = psypi[2] * 100 # Ensure percent humidity stays within 0 - 100 % range if percent_relative_humidity > 100: percent_relative_humidity = 100 elif percent_relative_humidity < 0: percent_relative_humidity = 0 # Dry bulb temperature: psypi[0]) # Wet bulb temperature: psypi[5]) specific_enthalpy = float(psypi[1]) humidity = float(percent_relative_humidity) specific_volume = float(psypi[3]) humidity_ratio = float(psypi[4]) list_measurement = [ specific_enthalpy, humidity, specific_volume, humidity_ratio ] for each_measurement in self.device_measurements.all(): conversion = db_retrieve_table_daemon( Conversion, unique_id=each_measurement.conversion_id) channel, unit, measurement = return_measurement_info( each_measurement, conversion) measurement_dict[channel] = { 'measurement': measurement, 'unit': unit, 'value': list_measurement[channel] } else: self.error_not_within_max_age() # # Calculate vapor pressure deficit from temperature and humidity # elif self.math_type == 'vapor_pressure_deficit': vpd_pa = None critical_error = False success_temp, temperature = self.get_measurements_from_id( self.unique_id_1, self.unique_measurement_id_1) success_hum, humidity = self.get_measurements_from_id( self.unique_id_2, self.unique_measurement_id_2) if success_temp and success_hum: vpd_temperature_celsius = float(temperature[1]) vpd_humidity_percent = float(humidity[1]) measurement_temp = db_retrieve_table_daemon( DeviceMeasurements, unique_id=self.unique_measurement_id_1) if not measurement_temp: self.logger.error("Could not find temperature measurement") measurement_temp = None critical_error = True if measurement_temp and measurement_temp.unit != 'C': vpd_temperature_celsius, status = self.is_measurement_unit( measurement_temp.unit, 'C', vpd_temperature_celsius) if status == 'error': critical_error = True measurement_hum = db_retrieve_table_daemon( DeviceMeasurements, unique_id=self.unique_measurement_id_2) if not measurement_hum: self.logger.error("Could not find humidity measurement") measurement_hum = None critical_error = True if measurement_hum and measurement_hum.unit != 'percent': vpd_humidity_percent, status = self.is_measurement_unit( measurement_hum.unit, 'percent', vpd_humidity_percent) if status == 'error': critical_error = True try: if not critical_error: vpd_pa = calculate_vapor_pressure_deficit( vpd_temperature_celsius, vpd_humidity_percent) else: self.logger.error( "One or more critical errors prevented the " "vapor pressure deficit from being calculated") except TypeError as err: self.logger.error("TypeError: {msg}".format(msg=err)) if vpd_pa: math_dev_measurement = self.device_measurements.first() conversion = db_retrieve_table_daemon( Conversion, unique_id=math_dev_measurement.conversion_id) channel, unit, measurement = return_measurement_info( math_dev_measurement, conversion) measurement_dict[channel] = { 'measurement': measurement, 'unit': unit, 'value': vpd_pa } else: self.error_not_within_max_age() else: self.logger.error("Unknown math type: {type}".format(type=self.math_type)) # Finally, add measurements to influxdb if measurement_dict: self.logger.debug( "Adding measurements to InfluxDB with ID {}: {}".format( self.unique_id, measurement_dict)) add_measurements_influxdb(self.unique_id, measurement_dict) else: self.logger.debug( "No measurements to add to InfluxDB with ID {}".format( self.unique_id))