Beispiel #1
0
    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))
Beispiel #2
0
    def math_humidity(self, measurement_dict):
        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()
        return measurement_dict
Beispiel #3
0
    def calculate_math(self):
        if self.math_type == 'average':
            success, measure = self.get_measurements_from_str(self.inputs)
            if success:
                measure_dict = {
                    self.measure:
                    float('{0:.4f}'.format(sum(measure) / float(len(measure))))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'average_single':
            device_id = self.inputs.split(',')[0]
            measurement = self.inputs.split(',')[1]
            try:
                last_measurements = read_past_influxdb(device_id, measurement,
                                                       self.max_measure_age)

                if last_measurements:
                    measure_list = []
                    for each_set in last_measurements:
                        if len(each_set) == 2:
                            measure_list.append(each_set[1])
                    average = sum(measure_list) / float(len(measure_list))

                    measure_dict = {
                        self.measure: float('{0:.4f}'.format(average))
                    }
                    self.measurements = Measurement(measure_dict)
                    add_measure_influxdb(self.unique_id, self.measurements)
                else:
                    self.error_not_within_max_age()
            except Exception as msg:
                self.logger.error(
                    "average_single Error: {err}".format(err=msg))

        elif self.math_type == 'difference':
            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)
                measure_dict = {
                    self.measure: float('{0:.4f}'.format(difference))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'equation':
            success, measure = self.get_measurements_from_str(
                self.equation_input)
            if success:
                replaced_str = self.equation.replace('x', str(measure[0]))
                equation_output = eval(replaced_str)
                measure_dict = {
                    self.measure: float('{0:.4f}'.format(equation_output))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'median':
            success, measure = self.get_measurements_from_str(self.inputs)
            if success:
                measure_dict = {
                    self.measure: float('{0:.4f}'.format(median(measure)))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'maximum':
            success, measure = self.get_measurements_from_str(self.inputs)
            if success:
                measure_dict = {
                    self.measure: float('{0:.4f}'.format(max(measure)))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'minimum':
            success, measure = self.get_measurements_from_str(self.inputs)
            if success:
                measure_dict = {
                    self.measure: float('{0:.4f}'.format(min(measure)))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'verification':
            success, measure = self.get_measurements_from_str(self.inputs)
            if (success and max(measure) - min(measure) < self.max_difference):
                measure_dict = {
                    self.measure:
                    float('{0:.4f}'.format(sum(measure) / float(len(measure))))
                }
                self.measurements = Measurement(measure_dict)
                add_measure_influxdb(self.unique_id, self.measurements)
            elif measure:
                self.logger.error(measure)
            else:
                self.error_not_within_max_age()

        elif self.math_type == 'humidity':
            measure_temps_good = False
            pressure_pa = 101325

            success_dbt, dry_bulb_t = self.get_measurements_from_id(
                self.dry_bulb_t_id, self.dry_bulb_t_measure)
            success_wbt, wet_bulb_t = self.get_measurements_from_id(
                self.wet_bulb_t_id, self.wet_bulb_t_measure)
            if success_dbt and success_wbt:
                measure_temps_good = True

            if self.pressure_pa_id and self.pressure_pa_measure:
                success_pa, pressure = self.get_measurements_from_id(
                    self.pressure_pa_id, self.pressure_pa_measure)
                if success_pa:
                    pressure_pa = int(pressure[1])

            if measure_temps_good:
                dbt_kelvin = celsius_to_kelvin(float(dry_bulb_t[1]))
                wbt_kelvin = celsius_to_kelvin(float(wet_bulb_t[1]))
                psypi = None

                try:
                    psypi = SI.state("DBT", dbt_kelvin, "WBT", wbt_kelvin,
                                     pressure_pa)
                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])

                    measure_dict = dict(
                        specific_enthalpy=float('{0:.5f}'.format(psypi[1])),
                        humidity=float(
                            '{0:.5f}'.format(percent_relative_humidity)),
                        specific_volume=float('{0:.5f}'.format(psypi[3])),
                        humidity_ratio=float('{0:.5f}'.format(psypi[4])))
                    self.measurements = Measurement(measure_dict)
                    add_measure_influxdb(self.unique_id, self.measurements)
            else:
                self.error_not_within_max_age()
Beispiel #4
0
    def calculate_math(self):
        measurement_dict = {}

        if self.math_type == 'average':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()

            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            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()

        elif self.math_type == 'average_single':

            device_id = self.inputs.split(',')[0]
            measurement_id = self.inputs.split(',')[1]

            device_measurement = db_retrieve_table_daemon(
                DeviceMeasurements, unique_id=measurement_id)
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            try:
                last_measurements = read_past_influxdb(device_id, unit,
                                                       measurement, channel,
                                                       self.max_measure_age)

                if last_measurements:
                    measure_list = []
                    for each_set in last_measurements:
                        if len(each_set) == 2:
                            measure_list.append(each_set[1])
                    average = sum(measure_list) / float(len(measure_list))

                    measurement_dict = {
                        channel: {
                            'measurement': measurement,
                            'unit': unit,
                            'value': average
                        }
                    }
                else:
                    self.error_not_within_max_age()
            except Exception as msg:
                self.logger.exception(
                    "average_single Error: {err}".format(err=msg))

        elif self.math_type == 'difference':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_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()

        elif self.math_type == 'equation':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            success, measure = self.get_measurements_from_str(self.inputs)
            if success:
                replaced_str = self.equation.replace('x', str(measure[0]))
                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()

        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]

                device_measurement = self.device_measurements.filter(
                    DeviceMeasurements.channel == 0).first()
                if device_measurement:
                    conversion = db_retrieve_table_daemon(
                        Conversion, unique_id=device_measurement.conversion_id)
                else:
                    conversion = None
                channel, unit, measurement = return_measurement_info(
                    device_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': 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()

        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()

        elif self.math_type == 'verification':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_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()

        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

                    if db_retrieve_table_daemon(
                            DeviceMeasurements,
                            unique_id=self.pressure_pa_measure_id):
                        measurement = db_retrieve_table_daemon(
                            DeviceMeasurements,
                            unique_id=self.pressure_pa_measure_id)
                    else:
                        self.logger.error(
                            "Could not find pressure measurement")
                        measurement = None
                        critical_error = True

                    if measurement and measurement.unit != 'Pa':
                        for each_conv in db_retrieve_table_daemon(Conversion,
                                                                  entry='all'):
                            if (each_conv.convert_unit_from == measurement.unit
                                    and each_conv.convert_unit_to == 'Pa'):
                                pressure_pa = convert_units(
                                    each_conv.unique_id, pressure_pa)
                            else:
                                self.logger.error(
                                    "Could not find conversion for unit "
                                    "{unit} to Pa (Pascals)".format(
                                        unit=measurement.unit))
                                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])

                if db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.dry_bulb_t_measure_id):
                    measurement = db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.dry_bulb_t_measure_id)
                else:
                    self.logger.error("Could not find pressure measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'K':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion,
                                                              entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit
                                and each_conv.convert_unit_to == 'K'):
                            dbt_kelvin = convert_units(each_conv.unique_id,
                                                       dbt_kelvin)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error("Could not find conversion for unit "
                                          "{unit} to K (Kelvin)".format(
                                              unit=measurement.unit))
                        critical_error = True

                if db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.dry_bulb_t_measure_id):
                    measurement = db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.dry_bulb_t_measure_id)
                else:
                    self.logger.error("Could not find pressure measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'K':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion,
                                                              entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit
                                and each_conv.convert_unit_to == 'K'):
                            wbt_kelvin = convert_units(each_conv.unique_id,
                                                       wbt_kelvin)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error("Could not find conversion for unit "
                                          "{unit} to K (Kelvin)".format(
                                              unit=measurement.unit))
                        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()

        elif self.math_type == 'vapor_pressure_deficit':

            vpd_pa = None
            critical_error = False

            success_dbt, temperature = self.get_measurements_from_id(
                self.unique_id_1, self.unique_measurement_id_1)
            success_wbt, humidity = self.get_measurements_from_id(
                self.unique_id_2, self.unique_measurement_id_2)

            if success_dbt and success_wbt:
                vpd_temperature_celsius = float(temperature[1])
                vpd_humidity_percent = float(humidity[1])

                if db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_1):
                    measurement = db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_1)
                else:
                    self.logger.error("Could not find temperature measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'C':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion,
                                                              entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit
                                and each_conv.convert_unit_to == 'C'):
                            vpd_temperature_celsius = convert_units(
                                each_conv.unique_id, vpd_temperature_celsius)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error("Could not find conversion for unit "
                                          "{unit} to C (Celsius)".format(
                                              unit=measurement.unit))
                        critical_error = True

                if db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_2):
                    measurement = db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_2)
                else:
                    self.logger.error("Could not find humidity measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'percent':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion,
                                                              entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit
                                and each_conv.convert_unit_to == 'percent'):
                            vpd_humidity_percent = convert_units(
                                each_conv.unique_id, vpd_humidity_percent)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error("Could not find conversion for unit "
                                          "{unit} to percent (%)".format(
                                              unit=measurement.unit))
                        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:
                    measure = self.device_measurements.first()
                    conversion = db_retrieve_table_daemon(
                        Conversion, unique_id=measure.conversion_id)
                    channel, unit, measurement = return_measurement_info(
                        measure, 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
        add_measurements_influxdb(self.unique_id, measurement_dict)
Beispiel #5
0
    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:
                # Pause loop to modify conditional statements.
                # Prevents execution of conditional while variables are
                # being modified.
                if self.pause_loop:
                    self.verify_pause_loop = True
                    while self.pause_loop:
                        time.sleep(0.1)

                if self.is_activated and time.time() > self.timer:

                    # If PID is active, retrieve input measurement and update PID output
                    if self.math_type == 'average':
                        success, measure = self.get_measurements_from_str(
                            self.inputs)
                        if success:
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(
                                    sum(measure) / float(len(measure))))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'difference':
                        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)
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(difference))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'equation':
                        success, measure = self.get_measurements_from_str(
                            self.equation_input)
                        if success:
                            replaced_str = self.equation.replace(
                                'x', str(measure[0]))
                            equation_output = eval(replaced_str)
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(equation_output))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'median':
                        success, measure = self.get_measurements_from_str(
                            self.inputs)
                        if success:
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(median(measure)))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'maximum':
                        success, measure = self.get_measurements_from_str(
                            self.inputs)
                        if success:
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(max(measure)))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'minimum':
                        success, measure = self.get_measurements_from_str(
                            self.inputs)
                        if success:
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(min(measure)))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'verification':
                        success, measure = self.get_measurements_from_str(
                            self.inputs)
                        if (success and max(measure) - min(measure) <
                                self.max_difference):
                            measure_dict = {
                                self.measure:
                                float('{0:.4f}'.format(
                                    sum(measure) / float(len(measure))))
                            }
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        elif measure:
                            self.logger.error(measure)
                        else:
                            self.error_not_within_max_age()

                    elif self.math_type == 'humidity':
                        measure_temps_good = False
                        measure_press_good = False
                        pressure_pa = 101325

                        success_dbt, dry_bulb_t = self.get_measurements_from_id(
                            self.dry_bulb_t_id, self.dry_bulb_t_measure)
                        success_wbt, wet_bulb_t = self.get_measurements_from_id(
                            self.wet_bulb_t_id, self.wet_bulb_t_measure)
                        if success_dbt and success_wbt:
                            measure_temps_good = True

                        if self.pressure_pa_id and self.pressure_pa_measure:
                            success_pa, pressure = self.get_measurements_from_id(
                                self.pressure_pa_id, self.pressure_pa_measure)
                            if success_pa:
                                pressure_pa = int(pressure[1])
                                measure_press_good = True

                        if (measure_temps_good and
                            ((self.pressure_pa_id and self.pressure_pa_measure
                              and measure_press_good) or
                             (not self.pressure_pa_id
                              or not self.pressure_pa_measure))):

                            dbt_kelvin = celsius_to_kelvin(float(
                                dry_bulb_t[1]))
                            wbt_kelvin = celsius_to_kelvin(float(
                                wet_bulb_t[1]))

                            psypi = SI.state("DBT", dbt_kelvin, "WBT",
                                             wbt_kelvin, pressure_pa)

                            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])

                            measure_dict = dict(
                                specific_enthalpy=float('{0:.5f}'.format(
                                    psypi[1])),
                                humidity=float('{0:.5f}'.format(
                                    percent_relative_humidity)),
                                specific_volume=float('{0:.5f}'.format(
                                    psypi[3])),
                                humidity_ratio=float('{0:.5f}'.format(
                                    psypi[4])))
                            self.measurements = Measurement(measure_dict)
                            add_measure_influxdb(self.unique_id,
                                                 self.measurements)
                        else:
                            self.error_not_within_max_age()

                    # Ensure the next timer ends in the future
                    while time.time() > self.timer:
                        self.timer += self.period

                time.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))
Beispiel #6
0
    def run_function(self):
        temp_wet_k = None
        temp_dry_k = None
        pressure_pa = 101325

        if (self.select_measurement_pressure_pa_device_id
                and self.select_measurement_pressure_pa_measurement_id
                and self.max_measure_age_pressure_pa):

            device_measurement = get_measurement(
                self.select_measurement_pressure_pa_measurement_id)
            conversion = db_retrieve_table_daemon(
                Conversion, unique_id=device_measurement.conversion_id)
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            last_measurement_pa = self.get_last_measurement(
                self.select_measurement_pressure_pa_device_id,
                self.select_measurement_pressure_pa_measurement_id,
                max_age=self.max_measure_age_pressure_pa)

            if last_measurement_pa:
                pressure_pa = convert_from_x_to_y_unit(unit, 'Pa',
                                                       last_measurement_pa[1])

        last_measurement_wet = self.get_last_measurement(
            self.select_measurement_temp_wet_c_device_id,
            self.select_measurement_temp_wet_c_measurement_id,
            max_age=self.max_measure_age_temp_wet_c)

        if last_measurement_wet:
            device_measurement = get_measurement(
                self.select_measurement_temp_wet_c_measurement_id)
            conversion = db_retrieve_table_daemon(
                Conversion, unique_id=device_measurement.conversion_id)
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)
            temp_wet_k = convert_from_x_to_y_unit(unit, 'K',
                                                  last_measurement_wet[1])

        last_measurement_dry = self.get_last_measurement(
            self.select_measurement_temp_dry_c_device_id,
            self.select_measurement_temp_dry_c_measurement_id,
            max_age=self.max_measure_age_temp_dry_c)

        if last_measurement_dry:
            device_measurement = get_measurement(
                self.select_measurement_temp_dry_c_measurement_id)
            conversion = db_retrieve_table_daemon(
                Conversion, unique_id=device_measurement.conversion_id)
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)
            temp_dry_k = convert_from_x_to_y_unit(unit, 'K',
                                                  last_measurement_dry[1])

        if temp_wet_k and temp_dry_k:
            measurements = copy.deepcopy(measurements_dict)
            psypi = None

            try:
                psypi = SI.state("DBT", temp_dry_k, "WBT", temp_wet_k,
                                 pressure_pa)
            except TypeError as err:
                self.logger.error("TypeError: {msg}".format(msg=err))

            if not psypi:
                self.logger.error(
                    "Could not calculate humidity from wet/dry bulbs")
                return

            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])

            self.logger.debug("Dry Temp: {dtk}, "
                              "Wet Temp: {wtk}, "
                              "Pressure: {pres},"
                              "Humidity: {rh}".format(dtk=temp_dry_k,
                                                      wtk=temp_wet_k,
                                                      pres=pressure_pa,
                                                      rh=humidity))

            list_measurement = [
                humidity, humidity_ratio, specific_enthalpy, specific_volume
            ]

            for each_measurement in self.device_measurements.all():
                if each_measurement.is_enabled:
                    conversion = db_retrieve_table_daemon(
                        Conversion, unique_id=each_measurement.conversion_id)
                    channel, unit, measurement = return_measurement_info(
                        each_measurement, conversion)

                    measurements[channel] = {
                        'measurement': measurement,
                        'unit': unit,
                        'value': list_measurement[channel]
                    }

            # Add measurement(s) to influxdb
            if measurements:
                self.logger.debug(
                    "Adding measurements to InfluxDB with ID {}: {}".format(
                        self.unique_id, measurements))
                add_measurements_influxdb(self.unique_id, measurements)
            else:
                self.logger.debug(
                    "No measurements to add to InfluxDB with ID {}".format(
                        self.unique_id))
Beispiel #7
0
    def calculate_math(self):
        measurement_dict = {}

        if self.math_type == 'average':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()

            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            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()

        elif self.math_type == 'average_single':

            device_id = self.inputs.split(',')[0]
            measurement_id = self.inputs.split(',')[1]

            device_measurement = db_retrieve_table_daemon(
                DeviceMeasurements, unique_id=measurement_id)
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            try:
                last_measurements = read_past_influxdb(
                    device_id,
                    unit,
                    measurement,
                    channel,
                    self.max_measure_age)

                if last_measurements:
                    measure_list = []
                    for each_set in last_measurements:
                        if len(each_set) == 2:
                            measure_list.append(each_set[1])
                    average = sum(measure_list) / float(len(measure_list))

                    measurement_dict = {
                        channel: {
                            'measurement': measurement,
                            'unit': unit,
                            'value': average
                        }
                    }
                else:
                    self.error_not_within_max_age()
            except Exception as msg:
                self.logger.exception("average_single Error: {err}".format(err=msg))

        elif self.math_type == 'difference':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_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()

        elif self.math_type == 'equation':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)

            success, measure = self.get_measurements_from_str(self.inputs)
            if success:
                replaced_str = self.equation.replace('x', str(measure[0]))
                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()

        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]

                device_measurement = self.device_measurements.filter(
                    DeviceMeasurements.channel == 0).first()
                if device_measurement:
                    conversion = db_retrieve_table_daemon(
                        Conversion, unique_id=device_measurement.conversion_id)
                else:
                    conversion = None
                channel, unit, measurement = return_measurement_info(
                    device_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': 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()

        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()

        elif self.math_type == 'verification':

            device_measurement = self.device_measurements.filter(
                DeviceMeasurements.channel == 0).first()
            if device_measurement:
                conversion = db_retrieve_table_daemon(
                    Conversion, unique_id=device_measurement.conversion_id)
            else:
                conversion = None
            channel, unit, measurement = return_measurement_info(
                device_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()

        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

                    if db_retrieve_table_daemon(DeviceMeasurements, unique_id=self.pressure_pa_measure_id):
                        measurement = db_retrieve_table_daemon(DeviceMeasurements, unique_id=self.pressure_pa_measure_id)
                    else:
                        self.logger.error("Could not find pressure measurement")
                        measurement = None
                        critical_error = True

                    if measurement and measurement.unit != 'Pa':
                        for each_conv in db_retrieve_table_daemon(Conversion, entry='all'):
                            if (each_conv.convert_unit_from == measurement.unit and
                                    each_conv.convert_unit_to == 'Pa'):
                                pressure_pa = convert_units(
                                    each_conv.unique_id, pressure_pa)
                            else:
                                self.logger.error(
                                    "Could not find conversion for unit "
                                    "{unit} to Pa (Pascals)".format(
                                        unit=measurement.unit))
                                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])

                if db_retrieve_table_daemon(DeviceMeasurements, unique_id=self.dry_bulb_t_measure_id):
                    measurement = db_retrieve_table_daemon(DeviceMeasurements, unique_id=self.dry_bulb_t_measure_id)
                else:
                    self.logger.error("Could not find pressure measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'K':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion, entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit and
                                each_conv.convert_unit_to == 'K'):
                            dbt_kelvin = convert_units(
                                each_conv.unique_id, dbt_kelvin)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error(
                            "Could not find conversion for unit "
                            "{unit} to K (Kelvin)".format(
                                unit=measurement.unit))
                        critical_error = True

                if db_retrieve_table_daemon(DeviceMeasurements, unique_id=self.dry_bulb_t_measure_id):
                    measurement = db_retrieve_table_daemon(DeviceMeasurements, unique_id=self.dry_bulb_t_measure_id)
                else:
                    self.logger.error("Could not find pressure measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'K':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion, entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit and
                                each_conv.convert_unit_to == 'K'):
                            wbt_kelvin = convert_units(
                                each_conv.unique_id, wbt_kelvin)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error(
                            "Could not find conversion for unit "
                            "{unit} to K (Kelvin)".format(
                                unit=measurement.unit))
                        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()

        elif self.math_type == 'vapor_pressure_deficit':

            vpd_pa = None
            critical_error = False

            success_dbt, temperature = self.get_measurements_from_id(
                self.unique_id_1, self.unique_measurement_id_1)
            success_wbt, humidity = self.get_measurements_from_id(
                self.unique_id_2, self.unique_measurement_id_2)

            if success_dbt and success_wbt:
                vpd_temperature_celsius = float(temperature[1])
                vpd_humidity_percent = float(humidity[1])

                if db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_1):
                    measurement = db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_1)
                else:
                    self.logger.error("Could not find temperature measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'C':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion, entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit and
                                each_conv.convert_unit_to == 'C'):
                            vpd_temperature_celsius = convert_units(
                                each_conv.unique_id, vpd_temperature_celsius)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error(
                            "Could not find conversion for unit "
                            "{unit} to C (Celsius)".format(
                                unit=measurement.unit))
                        critical_error = True

                if db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_2):
                    measurement = db_retrieve_table_daemon(
                        DeviceMeasurements,
                        unique_id=self.unique_measurement_id_2)
                else:
                    self.logger.error("Could not find humidity measurement")
                    measurement = None
                    critical_error = True

                if measurement and measurement.unit != 'percent':
                    conversion_found = False
                    for each_conv in db_retrieve_table_daemon(Conversion, entry='all'):
                        if (each_conv.convert_unit_from == measurement.unit and
                                each_conv.convert_unit_to == 'percent'):
                            vpd_humidity_percent = convert_units(
                                each_conv.unique_id, vpd_humidity_percent)
                            conversion_found = True
                    if not conversion_found:
                        self.logger.error(
                            "Could not find conversion for unit "
                            "{unit} to percent (%)".format(
                                unit=measurement.unit))
                        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:
                    measure = self.device_measurements.first()
                    conversion = db_retrieve_table_daemon(
                        Conversion, unique_id=measure.conversion_id)
                    channel, unit, measurement = return_measurement_info(
                        measure, 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
        add_measurements_influxdb(self.unique_id, measurement_dict)