Пример #1
0
 def get_scalar(obs_type, record, db_manager=None):
     log.debug('get_scalar(%s)' % obs_type)
     if obs_type not in [ 'pm2_5_aqi', 'pm2_5_aqi_color' ]:
         raise weewx.UnknownType(obs_type)
     log.debug('get_scalar(%s)' % obs_type)
     if record is None:
         log.debug('get_scalar called where record is None.')
         raise weewx.CannotCalculate(obs_type)
     if 'pm2_5' not in record:
         # Should not see this as pm2_5 is part of the extended schema that is required for this plugin.
         # Returning CannotCalculate causes exception in ImageGenerator, return UnknownType instead.
         # ERROR weewx.reportengine: Caught unrecoverable exception in generator 'weewx.imagegenerator.ImageGenerator'
         log.info('get_scalar called where record does not contain pm2_5.  This is unexpected.')
         raise weewx.UnknownType(obs_type)
     if record['pm2_5'] is None:
         # Returning CannotCalculate causes exception in ImageGenerator, return UnknownType instead.
         # ERROR weewx.reportengine: Caught unrecoverable exception in generator 'weewx.imagegenerator.ImageGenerator'
         # Any archive catchup records will have None for pm2_5.
         log.debug('get_scalar called where record[pm2_5] is None: %s.  Probably a catchup record.' %
             timestamp_to_string(record['dateTime']))
         raise weewx.UnknownType(obs_type)
     try:
         pm2_5 = record['pm2_5']
         if obs_type == 'pm2_5_aqi':
             value = AQI.compute_pm2_5_aqi(pm2_5)
         if obs_type == 'pm2_5_aqi_color':
             value = AQI.compute_pm2_5_aqi_color(AQI.compute_pm2_5_aqi(pm2_5))
         t, g = weewx.units.getStandardUnitType(record['usUnits'], obs_type)
         # Form the ValueTuple and return it:
         return weewx.units.ValueTuple(value, t, g)
     except KeyError:
         # Don't have everything we need. Raise an exception.
         raise weewx.CannotCalculate(obs_type)
Пример #2
0
 def get_scalar(obs_type, record, db_manager=None):
     log.debug('get_scalar(%s)' % obs_type)
     if obs_type not in ['pm2_5_aqi', 'pm2_5_aqi_color']:
         raise weewx.UnknownType(obs_type)
     log.debug('get_scalar(%s)' % obs_type)
     if record is None:
         log.debug('get_scalar called where record is None.')
         raise weewx.CannotCalculate(obs_type)
     if 'pm2_5' not in record:
         # Returning CannotCalculate causes exception in ImageGenerator, return UnknownType instead.
         # ERROR weewx.reportengine: Caught unrecoverable exception in generator 'weewx.imagegenerator.ImageGenerator'
         log.debug('get_scalar called where record does not contain pm2_5.')
         raise weewx.UnknownType(obs_type)
     if record['pm2_5'] is None:
         # Returning CannotCalculate causes exception in ImageGenerator, return UnknownType instead.
         # ERROR weewx.reportengine: Caught unrecoverable exception in generator 'weewx.imagegenerator.ImageGenerator'
         # This will happen for any catchup records inserted at weewx startup.
         log.debug('get_scalar called where record[pm2_5] is None.')
         raise weewx.UnknownType(obs_type)
     try:
         pm2_5 = record['pm2_5']
         if obs_type == 'pm2_5_aqi':
             value = AQI.compute_pm2_5_aqi(pm2_5)
         if obs_type == 'pm2_5_aqi_color':
             value = AQI.compute_pm2_5_aqi_color(
                 AQI.compute_pm2_5_aqi(pm2_5))
         t, g = weewx.units.getStandardUnitType(record['usUnits'], obs_type)
         # Form the ValueTuple and return it:
         return weewx.units.ValueTuple(value, t, g)
     except KeyError:
         # Don't have everything we need. Raise an exception.
         raise weewx.CannotCalculate(obs_type)
Пример #3
0
    def get_gts(self, obs_type, sod_ts, soy_ts):
        """ read GTS value out of the array """

        if obs_type == 'GTS':
            # Gruenlandtemperatursumme GTS
            try:
                if soy_ts is None or soy_ts not in self.gts_values:
                    __x = None
                else:
                    __x = self.gts_values[soy_ts][dayOfGTSYear(sod_ts, soy_ts)]
                return weewx.units.ValueTuple(__x, 'degree_C_day',
                                              'group_degree_day')
            except (ValueError, TypeError, IndexError, KeyError):
                logerr("soy_ts=%s sod_ts=%s" % (soy_ts, sod_ts))
                raise weewx.CannotCalculate(obs_type)
        elif obs_type == 'GTSdate':
            # date of value 200
            if soy_ts is None or soy_ts not in self.gts_date:
                return weewx.units.ValueTuple(None, 'unix_epoch', 'group_time')
            else:
                return weewx.units.ValueTuple(self.gts_date[soy_ts],
                                              'unix_epoch', 'group_time')
        else:
            # unknown type (should not happen here)
            raise weewx.UnknownType(obs_type)
Пример #4
0
    def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
        """Returns an aggregation of an observation type over a given time period, using the
        main archive table.
    
        obs_type: The type over which aggregation is to be done (e.g., 'barometer',
        'outTemp', 'rain', ...)
    
        timespan: An instance of weeutil.Timespan with the time period over which
        aggregation is to be done.
    
        aggregate_type: The type of aggregation to be done.
    
        db_manager: An instance of weewx.manager.Manager or subclass.
    
        option_dict: Not used in this version.
    
        returns: A ValueTuple containing the result."""

        if aggregate_type not in ['sum', 'count', 'avg', 'max', 'min'] \
                + list(ArchiveTable.agg_sql_dict.keys()):
            raise weewx.UnknownAggregation(aggregate_type)

        interpolate_dict = {
            'aggregate_type': aggregate_type,
            'obs_type': obs_type,
            'table_name': db_manager.table_name,
            'start': timespan.start,
            'stop': timespan.stop
        }

        select_stmt = ArchiveTable.agg_sql_dict.get(aggregate_type,
                                                    ArchiveTable.simple_agg_sql) % interpolate_dict

        try:
            row = db_manager.getSql(select_stmt)
        except weedb.NoColumnError:
            raise weewx.UnknownType(aggregate_type)

        value = row[0] if row else None

        # Look up the unit type and group of this combination of observation type and aggregation:
        u, g = weewx.units.getStandardUnitType(db_manager.std_unit_system, obs_type,
                                               aggregate_type)

        # Time derivatives have special rules. For example, the time derivative of watt-hours is
        # watts, scaled by the number of seconds in an hour. The unit group also changes to
        # group_power.
        if aggregate_type == 'tderiv':
            if u == 'watt_second':
                u = 'watt'
            elif u == 'watt_hour':
                u = 'watt'
                value *= 3600
            elif u == 'kilowatt_hour':
                u = 'kilowatt'
                value *= 3600
            g = 'group_power'

        # Form the ValueTuple and return it:
        return weewx.units.ValueTuple(value, u, g)
Пример #5
0
    def get_scalar(self, obs_type, record, db_manager):
        # We only know how to calculate 'vapor_p'. For everything else, raise an exception
        if obs_type != 'vapor_p':
            raise weewx.UnknownType(obs_type)

        # We need outTemp in order to do the calculation.
        if 'outTemp' not in record or record['outTemp'] is None:
            raise weewx.CannotCalculate(obs_type)

        # We have everything we need. Start by forming a ValueTuple for the outside temperature.
        # To do this, figure out what unit and group the record is in ...
        unit_and_group = weewx.units.getStandardUnitType(record['usUnits'], 'outTemp')
        # ... then form the ValueTuple.
        outTemp_vt = weewx.units.ValueTuple(record['outTemp'], *unit_and_group)

        # We need the temperature in Kelvin
        outTemp_K_vt = weewx.units.convert(outTemp_vt, 'degree_K')

        # Now we can use the formula. Results will be in mmHg. Create a ValueTuple out of it:
        p_vt = weewx.units.ValueTuple(math.exp(20.386 - 5132.0 / outTemp_K_vt[0]),
                                      'mmHg',
                                      'group_pressure')

        # We have the vapor pressure as a ValueTuple. Convert it back to the units used by
        # the incoming record and return it
        return weewx.units.convertStd(p_vt, record['usUnits'])
Пример #6
0
def get_series(obs_type,
               timespan,
               db_manager,
               aggregate_type=None,
               aggregate_interval=None,
               **option_dict):
    """Return a series (aka vector) of, possibly aggregated, values."""

    # Search the list, looking for a get_series() method that does not raise an UnknownType or
    # UnknownAggregation exception
    for xtype in xtypes:
        try:
            # Try this function. Be prepared to catch the TypeError exception if it is a legacy
            # style XType that does not accept kwargs.
            try:
                return xtype.get_series(obs_type, timespan, db_manager,
                                        aggregate_type, aggregate_interval,
                                        **option_dict)
            except TypeError:
                # We likely have a legacy style XType, so try calling it again, but this time
                # without the kwargs.
                return xtype.get_series(obs_type, timespan, db_manager,
                                        aggregate_type, aggregate_interval)
        except (weewx.UnknownType, weewx.UnknownAggregation):
            # This function does not know about the type and/or aggregation.
            # Move on to the next one.
            pass
    # None of the functions worked. Raise an exception with a hopefully helpful error message.
    if aggregate_type:
        msg = "'%s' or '%s'" % (obs_type, aggregate_type)
    else:
        msg = obs_type
    raise weewx.UnknownType(msg)
Пример #7
0
    def get_series(obs_type,
                   timespan,
                   db_manager,
                   aggregate_type=None,
                   aggregate_interval=None,
                   **option_dict):
        """Get a series, possibly with aggregation, for special 'wind vector' types. These are
        typically used for the wind vector plots.
        """

        # Check to see if the requested type is not 'windvec' or 'windgustvec'
        if obs_type not in WindVec.windvec_types:
            # The type is not one of the extended wind types. We can't handle it.
            raise weewx.UnknownType(obs_type)

        # It is an extended wind type. Prepare the lists that will hold the
        # final results.
        start_vec = list()
        stop_vec = list()
        data_vec = list()

        # Is aggregation requested?
        if aggregate_type:
            # Yes. Just use the regular series function. When it comes time to do the aggregation,
            # the specialized function WindVec.get_aggregate() (defined below), will be used.
            return ArchiveTable.get_series(obs_type, timespan, db_manager,
                                           aggregate_type, aggregate_interval)

        else:
            # No aggregation desired. However, we have will have to assemble the wind vector from
            # its flattened types. This SQL select string will select the proper wind types
            sql_str = 'SELECT dateTime, %s, %s, usUnits, `interval` FROM %s ' \
                      'WHERE dateTime >= ? AND dateTime <= ?' \
                      % (WindVec.windvec_types[obs_type][0], WindVec.windvec_types[obs_type][1],
                         db_manager.table_name)
            std_unit_system = None

            for record in db_manager.genSql(sql_str, timespan):
                ts, magnitude, direction, unit_system, interval = record
                if std_unit_system:
                    if std_unit_system != unit_system:
                        raise weewx.UnsupportedFeature(
                            "Unit type cannot change within a time interval.")
                else:
                    std_unit_system = unit_system

                value = weeutil.weeutil.to_complex(magnitude, direction)

                start_vec.append(ts - interval * 60)
                stop_vec.append(ts)
                data_vec.append(value)

            unit, unit_group = weewx.units.getStandardUnitType(
                std_unit_system, obs_type, aggregate_type)

        return (ValueTuple(start_vec, 'unix_epoch', 'group_time'),
                ValueTuple(stop_vec, 'unix_epoch',
                           'group_time'), ValueTuple(data_vec, unit,
                                                     unit_group))
Пример #8
0
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None):
        """Get a series, possibly with aggregation, from the main archive database.

        The general strategy is that if aggregation is asked for, chop the series up into separate chunks,
        calculating the aggregate for each chunk. Then assemble the results.

        If no aggregation is called for, just return the data directly out of the database.
        """

        startstamp, stopstamp = timespan
        start_vec = list()
        stop_vec = list()
        data_vec = list()

        if aggregate_type:
            # With aggregation
            unit, unit_group = None, None
            if aggregate_type == 'cumulative':
                total = 0
            for stamp in weeutil.weeutil.intervalgen(startstamp, stopstamp, aggregate_interval):
                agg_vt = get_aggregate(obs_type, stamp, aggregate_type, db_manager)
                if unit:
                    # It's OK if the unit is unknown (=None).
                    if agg_vt[1] is not None and (unit != agg_vt[1] or unit_group != agg_vt[2]):
                        raise weewx.UnsupportedFeature("Cannot change unit groups within an aggregation.")
                else:
                    unit, unit_group = agg_vt[1:]
                start_vec.append(stamp.start)
                stop_vec.append(stamp.stop)
                if aggregate_type == 'cumulative':
                    total += agg_vt[0]
                    data_vec.append(total)
                else:
                    data_vec.append(agg_vt[0])

        else:
            # Without aggregation. We only know how to get series that are in the database schema:
            if obs_type not in db_manager.sqlkeys:
                raise weewx.UnknownType(obs_type)

            # No aggregation
            sql_str = "SELECT dateTime, %s, usUnits, `interval` FROM %s " \
                      "WHERE dateTime >= ? AND dateTime <= ?" % (obs_type, db_manager.table_name)
            std_unit_system = None
            for record in db_manager.genSql(sql_str, (startstamp, stopstamp)):
                if std_unit_system:
                    if std_unit_system != record[2]:
                        raise weewx.UnsupportedFeature("Unit type cannot change within an aggregation interval.")
                else:
                    std_unit_system = record[2]
                start_vec.append(record[0] - record[3] * 60)
                stop_vec.append(record[0])
                data_vec.append(record[1])
            unit, unit_group = weewx.units.getStandardUnitType(std_unit_system, obs_type, aggregate_type)

        return (ValueTuple(start_vec, 'unix_epoch', 'group_time'),
                ValueTuple(stop_vec, 'unix_epoch', 'group_time'),
                ValueTuple(data_vec, unit, unit_group))
Пример #9
0
    def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
        """Returns an aggregation of pm2_5_aqi over a timespan by using the main archive
        table.

        obs_type

        timespan: An instance of weeutil.Timespan with the time period over which aggregation is to
        be done.

        aggregate_type: The type of aggregation to be done. For this function, must be 'avg',
        'sum', 'count', 'first', 'last', 'min', or 'max'. Anything else will cause
        weewx.UnknownAggregation to be raised.

        db_manager: An instance of weewx.manager.Manager or subclass.

        option_dict: Not used in this version.

        returns: A ValueTuple containing the result.
        """
        if obs_type not in [ 'pm2_5_aqi', 'pm2_5_aqi_color' ]:
            raise weewx.UnknownType(obs_type)

        log.debug('get_aggregate(%s, %s, %s, aggregate:%s)' % (
            obs_type, timestamp_to_string(timespan.start),
            timestamp_to_string(timespan.stop), aggregate_type))

        aggregate_type = aggregate_type.lower()

        # Raise exception if we don't know about this type of aggregation
        if aggregate_type not in list(AQI.agg_sql_dict.keys()):
            raise weewx.UnknownAggregation(aggregate_type)

        # Form the interpolation dictionary
        interpolation_dict = {
            'start': timespan.start,
            'stop': timespan.stop,
            'table_name': db_manager.table_name
        }

        select_stmt = AQI.agg_sql_dict[aggregate_type] % interpolation_dict
        row = db_manager.getSql(select_stmt)
        if row:
            value, std_unit_system = row
        else:
            value = None
            std_unit_system = None

        if value is not None:
            if obs_type == 'pm2_5_aqi':
                value = AQI.compute_pm2_5_aqi(value)
            if obs_type == 'pm2_5_aqi_color':
                value = AQI.compute_pm2_5_aqi_color(AQI.compute_pm2_5_aqi(value))
        t, g = weewx.units.getStandardUnitType(std_unit_system, obs_type, aggregate_type)
        # Form the ValueTuple and return it:
        log.debug('get_aggregate(%s, %s, %s, aggregate:%s, select_stmt: %s, returning %s)' % (
            obs_type, timestamp_to_string(timespan.start), timestamp_to_string(timespan.stop),
            aggregate_type, select_stmt, value))
        return weewx.units.ValueTuple(value, t, g)
Пример #10
0
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None):
        """Get a series, possibly with aggregation.
        """

        if obs_type not in [ 'pm2_5_aqi', 'pm2_5_aqi_color' ]:
            raise weewx.UnknownType(obs_type)

        log.debug('get_series(%s, %s, %s, aggregate:%s, aggregate_interval:%s)' % (
            obs_type, timestamp_to_string(timespan.start), timestamp_to_string(
            timespan.stop), aggregate_type, aggregate_interval))

        #  Prepare the lists that will hold the final results.
        start_vec = list()
        stop_vec = list()
        data_vec = list()

        # Is aggregation requested?
        if aggregate_type:
            # Yes. Just use the regular series function.
            return weewx.xtypes.ArchiveTable.get_series(obs_type, timespan, db_manager, aggregate_type,
                                           aggregate_interval)
        else:
            # No aggregation.
            sql_str = 'SELECT dateTime, usUnits, `interval`, pm2_5 FROM %s ' \
                      'WHERE dateTime >= ? AND dateTime <= ? AND pm2_5 IS NOT NULL' \
                      % db_manager.table_name
            std_unit_system = None

            for record in db_manager.genSql(sql_str, timespan):
                ts, unit_system, interval, pm2_5 = record
                if std_unit_system:
                    if std_unit_system != unit_system:
                        raise weewx.UnsupportedFeature(
                            "Unit type cannot change within a time interval.")
                else:
                    std_unit_system = unit_system

                if obs_type == 'pm2_5_aqi':
                    value = AQI.compute_pm2_5_aqi(pm2_5)
                if obs_type == 'pm2_5_aqi_color':
                    value = AQI.compute_pm2_5_aqi_color(AQI.compute_pm2_5_aqi(pm2_5))
                log.debug('get_series(%s): %s - %s - %s' % (obs_type,
                    timestamp_to_string(ts - interval * 60),
                    timestamp_to_string(ts), value))
                start_vec.append(ts - interval * 60)
                stop_vec.append(ts)
                data_vec.append(value)

            unit, unit_group = weewx.units.getStandardUnitType(std_unit_system, obs_type,
                                                               aggregate_type)

        return (ValueTuple(start_vec, 'unix_epoch', 'group_time'),
                ValueTuple(stop_vec, 'unix_epoch', 'group_time'),
                ValueTuple(data_vec, unit, unit_group))
Пример #11
0
    def get_aggregate(self,
                      obs_type,
                      timespan,
                      aggregate_type=None,
                      aggregate_interval=None):

        if obs_type.starts_with('ch'):
            "something"

        else:
            raise weewx.UnknownType(obs_type)
Пример #12
0
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None):
        """Get a series, possibly with aggregation, for special 'wind' types."""

        # Check to see if the requested type is not 'windvec' or 'windgustvec'
        if obs_type not in Wind.windvec_types:
            # The type is not one of the extended wind types. We can't handle it.
            raise weewx.UnknownType(obs_type)

        # It is an extended wind type. Prepare the lists that will hold the
        # final results.
        start_vec = list()
        stop_vec = list()
        data_vec = list()

        # Is aggregation requested?
        if aggregate_type:
            # Yes. Just use the regular series function, but with the special wind aggregate type. It will
            # call the proper aggregation function.
            return SeriesArchive.get_series(obs_type, timespan, db_manager, aggregate_type, aggregate_interval)

        else:
            # No aggregation desired. However, we have will have to assemble the wind vector from its flattened types.
            # This SQL select string will select the proper wind types
            sql_str = 'SELECT dateTime, %s, %s, usUnits, `interval` FROM %s WHERE dateTime >= ? AND dateTime <= ?' \
                      % (Wind.windvec_types[obs_type][0], Wind.windvec_types[obs_type][1], db_manager.table_name)
            std_unit_system = None

            for record in db_manager.genSql(sql_str, timespan):
                start_vec.append(record[0] - record[4] * 60)
                stop_vec.append(record[0])
                if std_unit_system:
                    if std_unit_system != record[3]:
                        raise weewx.UnsupportedFeature("Unit type cannot change within a time interval.")
                else:
                    std_unit_system = record[3]
                # Break the mag and dir down into x- and y-components.
                (magnitude, direction) = record[1:3]
                if magnitude is None or direction is None:
                    data_vec.append(None)
                else:
                    x = magnitude * math.cos(math.radians(90.0 - direction))
                    y = magnitude * math.sin(math.radians(90.0 - direction))
                    if weewx.debug:
                        # There seem to be some little rounding errors that
                        # are driving my debugging crazy. Zero them out
                        if abs(x) < 1.0e-6: x = 0.0
                        if abs(y) < 1.0e-6: y = 0.0
                    data_vec.append(complex(x, y))
            unit, unit_group = weewx.units.getStandardUnitType(std_unit_system, obs_type, aggregate_type)

        return (ValueTuple(start_vec, 'unix_epoch', 'group_time'),
                ValueTuple(stop_vec, 'unix_epoch', 'group_time'),
                ValueTuple(data_vec, unit, unit_group))
Пример #13
0
def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None):
    """Return a series (aka vector) of, possibly aggregated, values."""
    # Search the list, looking for a get_series() method that does not raise an exception
    for xtype in xtypes:
        try:
            # Try this function. It will raise an exception if it does not know about the type.
            return xtype.get_series(obs_type, timespan, db_manager, aggregate_type, aggregate_interval)
        except weewx.UnknownType:
            # This function does not know about the type. Move on to the next one.
            pass
    # None of the functions worked.
    raise weewx.UnknownType(obs_type)
Пример #14
0
def get_scalar(obs_type, record, db_manager=None):
    """Return a scalar value"""
    # Search the list, looking for a get_scalar() method that does not raise an exception
    for xtype in xtypes:
        try:
            # Try this function. It will raise an exception if it does not know about the type.
            return xtype.get_scalar(obs_type, record, db_manager)
        except weewx.UnknownType:
            # This function does not know about the type. Move on to the next one.
            pass
    # None of the functions worked.
    raise weewx.UnknownType(obs_type)
Пример #15
0
    def _check_eligibility(obs_type, timespan, db_manager, aggregate_type):

        # It has to be a type we know about
        if not hasattr(db_manager, 'daykeys') or obs_type not in db_manager.daykeys:
            raise weewx.UnknownType(obs_type)

        # We cannot use the day summaries if the starting and ending times of the aggregation
        # interval are not on midnight boundaries, and are not the first or last records in the
        # database.
        if db_manager.first_timestamp is None or db_manager.last_timestamp is None:
            raise weewx.UnknownAggregation(aggregate_type)
        if not (isStartOfDay(timespan.start) or timespan.start == db_manager.first_timestamp) \
                or not (isStartOfDay(timespan.stop) or timespan.stop == db_manager.last_timestamp):
            raise weewx.UnknownAggregation(aggregate_type)
Пример #16
0
    def get_value(self, obs_type, record, db_manager):

        if obs_type == 'dewpoint':
            if record['usUnits'] == weewx.US:
                return weewx.wxformulas.dewpointF(record.get('outTemp'),
                                                  record.get('outHumidity'))
            elif record['usUnits'] == weewx.METRIC or record[
                    'usUnits'] == weewx.METRICWX:
                return weewx.wxformulas.dewpointC(record.get('outTemp'),
                                                  record.get('outHumidity'))
            else:
                raise ValueError("Unknown unit system %s" % record['usUnits'])
        else:
            raise weewx.UnknownType(obs_type)
Пример #17
0
 def get_scalar(obs_type, record, db_manager=None):
     log.debug('get_scalar(%s)' % obs_type)
     if obs_type not in [
             'pm2_5_aqi', 'pm2_5_aqi_color', 'pm2_5_lrapa',
             'pm2_5_lrapa_aqi', 'pm2_5_lrapa_aqi_color', 'pm2_5_unbc',
             'pm2_5_unbc_aqi', 'pm2_5_unbc_aqi_color'
     ]:
         raise weewx.UnknownType(obs_type)
     log.debug('get_scalar(%s)' % obs_type)
     if record is None:
         log.debug('get_scalar called where record is None.')
         raise weewx.CannotCalculate(obs_type)
     if 'pm2_5' not in record:
         log.info('get_scalar called where record does not contain pm2_5.')
         raise weewx.CannotCalculate(obs_type)
     if record['pm2_5'] is None:
         log.info('get_scalar called where record[pm2_5] is None.')
         raise weewx.CannotCalculate(obs_type)
     try:
         pm2_5 = record['pm2_5']
         if obs_type == 'pm2_5_aqi':
             value = AQI.compute_pm2_5_aqi(pm2_5)
         if obs_type == 'pm2_5_aqi_color':
             value = AQI.compute_pm2_5_aqi_color(
                 AQI.compute_pm2_5_aqi(pm2_5))
         elif obs_type == 'pm2_5_lrapa':
             value = AQI.compute_pm2_5_lrapa(pm2_5)
         elif obs_type == 'pm2_5_lrapa_aqi':
             pm2_5_lrapa = AQI.compute_pm2_5_lrapa(pm2_5)
             value = AQI.compute_pm2_5_aqi(pm2_5_lrapa)
         elif obs_type == 'pm2_5_lrapa_aqi_color':
             value = AQI.compute_pm2_5_aqi_color(
                 AQI.compute_pm2_5_aqi(AQI.compute_pm2_5_lrapa(pm2_5)))
         elif obs_type == 'pm2_5_unbc':
             value = AQI.compute_pm2_5_unbc(pm2_5)
         elif obs_type == 'pm2_5_unbc_aqi':
             pm2_5_unbc = AQI.compute_pm2_5_unbc(pm2_5)
             value = AQI.compute_pm2_5_aqi(pm2_5_unbc)
         elif obs_type == 'pm2_5_unbc_aqi_color':
             value = AQI.compute_pm2_5_aqi_color(
                 AQI.compute_pm2_5_aqi(AQI.compute_pm2_5_unbc(pm2_5)))
         t, g = weewx.units.getStandardUnitType(record['usUnits'], obs_type)
         # Form the ValueTuple and return it:
         return weewx.units.ValueTuple(value, t, g)
     except KeyError:
         # Don't have everything we need. Raise an exception.
         raise weewx.CannotCalculate(obs_type)
Пример #18
0
    def get_aggregate(obs_type, timespan, aggregate_type, db_manager,
                      **option_dict):
        """Optimization for calculating 'avg' aggregations for type 'windvec'. The
        timespan must be on a daily boundary."""

        # We can only do observation type 'windvec'
        if obs_type != 'windvec':
            # We can't handle it.
            raise weewx.UnknownType(obs_type)

        # We can only do 'avg' or 'not_null
        if aggregate_type not in ['avg', 'not_null']:
            raise weewx.UnknownAggregation(aggregate_type)

        # We cannot use the day summaries if the starting and ending times of the aggregation
        # interval are not on midnight boundaries, and are not the first or last records in the
        # database.
        if not (isStartOfDay(timespan.start) or timespan.start == db_manager.first_timestamp) \
                or not (isStartOfDay(timespan.stop) or timespan.stop == db_manager.last_timestamp):
            raise weewx.UnknownAggregation(aggregate_type)

        if aggregate_type == 'not_null':
            # Aggregate type 'not_null' is actually run against 'wind'.
            return DailySummaries.get_aggregate('wind', timespan, 'not_null',
                                                db_manager, **option_dict)

        sql = 'SELECT SUM(xsum), SUM(ysum), SUM(dirsumtime) ' \
              'FROM %s_day_wind WHERE dateTime>=? AND dateTime<?;' % db_manager.table_name

        row = db_manager.getSql(sql, timespan)

        if not row or None in row or not row[2]:
            # If no row was returned, or if it contains any nulls (meaning that not
            # all required data was available to calculate the requested aggregate),
            # then set the resulting value to None.
            value = None
        else:
            value = complex(row[0], row[1]) / row[2]

        # Look up the unit type and group of the result:
        t, g = weewx.units.getStandardUnitType(db_manager.std_unit_system,
                                               obs_type, aggregate_type)
        # Return as a value tuple
        return weewx.units.ValueTuple(value, t, g)
Пример #19
0
    def get_scalar(self, obs_type, record, db_manager):
        # We only know how to calculate 'vapor_p'. For everything else, raise an exception UnknownType
        if obs_type != 'vapor_p':
            raise weewx.UnknownType(obs_type)

        # We need outTemp in order to do the calculation.
        if 'outTemp' not in record or record['outTemp'] is None:
            raise weewx.CannotCalculate(obs_type)

        # We have everything we need. Start by forming a ValueTuple for the outside temperature.
        # To do this, figure out what unit and group the record is in ...
        unit_and_group = weewx.units.getStandardUnitType(
            record['usUnits'], 'outTemp')
        # ... then form the ValueTuple.
        outTemp_vt = ValueTuple(record['outTemp'], *unit_and_group)

        # Both algorithms need temperature in Celsius, so let's make sure our incoming temperature
        # is in that unit. Use function convert(). The results will be in the form of a ValueTuple
        outTemp_C_vt = weewx.units.convert(outTemp_vt, 'degree_C')
        # Get the first element of the ValueTuple. This will be in Celsius:
        outTemp_C = outTemp_C_vt[0]

        if self.algorithm == 'simple':
            # Use the "Simple" algorithm.
            # We need temperature in Kelvin.
            outTemp_K = weewx.units.CtoK(outTemp_C)
            # Now we can use the formula. Results will be in mmHg. Create a ValueTuple out of it:
            p_vt = ValueTuple(math.exp(20.386 - 5132.0 / outTemp_K), 'mmHg',
                              'group_pressure')
        elif self.algorithm == 'tetens':
            # Use Teten's algorithm.
            # Use the formula. Results will be in kPa:
            p_kPa = 0.61078 * math.exp(17.27 * outTemp_C_vt[0] /
                                       (outTemp_C_vt[0] + 237.3))
            # Form a ValueTuple
            p_vt = ValueTuple(p_kPa, 'kPa', 'group_pressure')
        else:
            # Don't recognize the exception. Fail hard:
            raise ValueError(self.algorithm)

        # We have the vapor pressure as a ValueTuple. Convert it back to the units used by
        # the incoming record and return it
        return weewx.units.convertStd(p_vt, record['usUnits'])
Пример #20
0
    def get_scalar(self, obs_type, record, db_manager):
        # We only know how to calculate some sun and moon related stuff. For everything else, raise an exception UnknownType
        if obs_type not in ('sun_altitude', 'sun_azimuth'):
            raise weewx.UnknownType(obs_type)

        # we only report sun values if the sun is above the horizon
        almanac = Almanac(record['dateTime'], self.lat, self.lng,
                          0)  # TODO convert alt  to meters
        sun_altitude = almanac.sun.alt
        if obs_type == 'sun_altitude':
            value = ValueTuple(sun_altitude if sun_altitude >= 0 else None,
                               'degree_compass', 'group_direction')
        elif obs_type == 'sun_azimuth':
            value = ValueTuple(almanac.sun.az if sun_altitude >= 0 else None,
                               'degree_compass', 'group_direction')

        # We have the calculated values as ValueTuples. Convert them back to the units used by
        # the incoming record and return it
        return weewx.units.convertStd(value, record['usUnits'])
Пример #21
0
def get_scalar(obs_type, record, db_manager=None, **option_dict):
    """Return a scalar value"""

    # Search the list, looking for a get_scalar() method that does not raise an UnknownType
    # exception
    for xtype in xtypes:
        try:
            # Try this function. Be prepared to catch the TypeError exception if it is a legacy
            # style XType that does not accept kwargs.
            try:
                return xtype.get_scalar(obs_type, record, db_manager, **option_dict)
            except TypeError:
                # We likely have a legacy style XType, so try calling it again, but this time
                # without the kwargs.
                return xtype.get_scalar(obs_type, record, db_manager)
        except weewx.UnknownType:
            # This function does not know about the type. Move on to the next one.
            pass
    # None of the functions worked.
    raise weewx.UnknownType(obs_type)
Пример #22
0
    def get_scalar(self, obs_type, record, db_manager):
        # We only know how to calculate 'makkink'. For everything else, raise an exception UnknownType
        if obs_type != 'makkink':
            raise weewx.UnknownType(obs_type)

        # We need outTemp and the radiation in order to do the calculation.
        if 'outTemp' not in record or record['outTemp'] is None:
            raise weewx.CannotCalculate(obs_type)
        if 'radiation' not in record or record['radiation'] is None:
            raise weewx.CannotCalculate(obs_type)

        # We have everything we need. Start by forming a ValueTuple for the outside temperature.
        # To do this, figure out what unit and group the record is in ...
        unit_and_group = weewx.units.getStandardUnitType(
            record['usUnits'], 'outTemp')
        # ... then form the ValueTuple.
        outTemp_vt = ValueTuple(record['outTemp'], *unit_and_group)

        # same for radiation
        unit_and_group = weewx.units.getStandardUnitType(
            record['usUnits'], 'radiation')
        # ... then form the ValueTuple.
        radiation_vt = ValueTuple(record['radiation'], *unit_and_group)

        outTemp_C_vt = weewx.units.convert(outTemp_vt, 'degree_C')
        # Get the first element of the ValueTuple. This will be in Celsius:
        T = outTemp_C_vt[0]

        # just to make sure nothing fancy happens we do this for radiation as well
        # even though this is W/m2 in us as well as metric
        radiation_Wm2_vt = weewx.units.convert(radiation_vt,
                                               'watt_per_meter_squared')
        Kin = radiation_Wm2_vt[0]

        makkink = ValueTuple(
            self.Eref(T, Kin) * 3600, 'mm_per_hour',
            'group_rainrate')  # convert from kg/m2*s --> mm/hour

        # Convert it back to the units used by
        # the incoming record and return it
        return weewx.units.convertStd(makkink, record['usUnits'])
Пример #23
0
    def get_scalar(self, obs_type, record, db_manager, **option_dict):
        """ mandatory function to be defined for XType extensions """

        if obs_type is None:
            raise weewx.UnknownType("obs_type is None")

        # time offset of local mean time (LMT)
        if obs_type == 'utcoffsetLMT':
            return weewx.units.ValueTuple(
                self.lmt_tz.utcoffset(None).total_seconds(), 'second',
                'group_deltatime')

        # dateTime as string in local mean time
        if obs_type == 'LMTtime':
            if record is None:
                raise weewx.UnknownType("%s: no record" % obs_type)
            return weewx.units.ValueTuple(
                datetime.datetime.fromtimestamp(
                    record['dateTime'], self.lmt_tz).strftime("%H:%M:%S"),
                'unix_epoch', 'group_time')

        # This functions handles 'GTS' and 'GTSdate'.
        if obs_type not in [
                'GTS', 'GTSdate', 'dayET', 'ET24', 'yearGDD', 'seasonGDD'
        ]:
            raise weewx.UnknownType(obs_type)

        #if record is None:
        #    if self.record_ok:
        #        logerr("%s: no record (logged only once)" % obs_type)
        #        self.record_ok=False
        #    raise weewx.CannotCalculate("%s: no record" % obs_type)
        if db_manager is None:
            if self.db_manager_ok:
                logerr("%s: db_manager is None" & obs_type)
                self.db_manager_ok = False
            raise weewx.CannotCalculate("%s: no database reference" % obs_type)

        #logdbg("obs_type=%s" % obs_type)

        # needed timestamps
        if record is not None and 'dateTime' in record:
            _time_ts = record['dateTime']
        else:
            # that should never happen but does due to a bug in
            # Belchertown skin
            if self.record_ok:
                logerr("%s: no record (logged only once)" % obs_type)
                self.record_ok = False
            # to do something we deliver the last available value
            _time_ts = time.time()

        if obs_type == 'dayET':
            # dayET should be comparable to dayRain, so use the same
            # time span: not local mean time but archive time
            try:
                # startOfArchiveDay() considers midnight belonging
                # to the previous day. So the time span would be
                # always greater than 0.
                __x = weeutil.weeutil.startOfArchiveDay(_time_ts)
                __x = weeutil.weeutil.TimeSpan(__x, _time_ts)
            except (ValueError, TypeError, IndexError):
                raise weewx.CannotCalculate("dayET: invalid time")
            return weewx.xtypes.get_aggregate('ET', __x, 'sum', db_manager)

        if obs_type == 'ET24':
            try:
                __x = weeutil.weeutil.TimeSpan(_time_ts - 86400, _time_ts)
            except:
                raise weewx.CannotCalculate("ET24: invalid time")
            return weewx.xtypes.get_aggregate('ET', __x, 'sum', db_manager)

        _soy_ts = startOfYearTZ(_time_ts, self.lmt_tz)
        _sod_ts = startOfDayTZ(_time_ts, _soy_ts)  # start of day

        # If the start of the year in question is before the first
        # record in the database, no value can be calculated. The
        # same applies if the given timestamp is in future.
        #if _soy_ts<db_manager.first_timestamp or _sod_ts>db_manager.last_timestamp:
        #    raise weewx.CannotCalculate(obs_type)

        # growing degree days == Wachstumsgradtage
        # https://de.wikipedia.org/wiki/Wachstumsgradtag
        # https://en.wikipedia.org/wiki/Growing_degree-day
        if obs_type in ['yearGDD']:
            try:
                # calculate from the beginning of the year up to the
                # end of the current day
                __timespan = TimeSpan(_soy_ts, _sod_ts + 86400)
                return self.get_aggregate('outTemp', __timespan, 'GDD',
                                          db_manager, **option_dict)
            except (ValueError, TypeError, IndexError, KeyError):
                raise weewx.CannotCalculate("%s" % obs_type)

        # calculate GTS values for the given year
        # (if record['dateTime'] is within the current year, the
        # value is calculated up to the current day (today))
        self.calc_gts(_soy_ts, db_manager)

        # growing degree days == Wachstumsgradtage
        # https://de.wikipedia.org/wiki/Wachstumsgradtag
        # https://en.wikipedia.org/wiki/Growing_degree-day
        if obs_type in ['seasonGDD']:
            try:
                # calculate from the beginning of the year up to the
                # end of the current day
                __start_ts = self.gts_date[_soy_ts]
                if __start_ts and _sod_ts >= __start_ts and _sod_ts < _soy_ts + 26179200:
                    __timespan = TimeSpan(__start_ts, _sod_ts + 86400)
                    return self.get_aggregate('outTemp', __timespan, 'GDD',
                                              db_manager, **option_dict)
            except (ValueError, TypeError, IndexError, KeyError):
                #raise weewx.CannotCalculate("%s" % obs_type)
                pass
            return weewx.units.ValueTuple(None, 'degree_C_day',
                                          'group_degree_day')

        # check if the requested timestamp record['dateTime'] is within
        # the current day (today)
        # Note: After self.calc_gts() is run, self.last_gts_date
        #       points to the beginning of the current day, if
        #       record['dateTime'] is within the current year.
        #       if record['dateTime'] is _not_ within the current
        #       year, self.last_gts_date _may_ be None.
        if record is None:
            # record is not provided, we assume the actual time
            # Note: That should not happen but does due to a bug in
            #       Belchertown skin
            if _sod_ts != self.last_gts_date:
                raise weewx.CannotCalculate("%s: no record" % obs_type)
            __today = True
        elif self.last_gts_date is None or self.gts_value is None:
            # The current year is not calculated so far, that means,
            # record['dateTime'] cannot be within the current day (today).
            __today = False
        elif _time_ts <= self.last_gts_date:
            # record['dateTime'] is before self.last_gts_date.
            # As self.last_gts_date points to the beginning of
            # the current day, that means, record['dateTime'] is not
            # the current day (today).
            __today = False
        else:
            # record['dateTime'] is after the beginning of the
            # current day. If it is additionally before
            # self.last_gts_date+86400 (1d after), it is within
            # the current day (today).
            __today = _time_ts <= self.last_gts_date + 86400

        # get the result
        if __today:
            # current value
            if obs_type == 'GTS':
                # current GTS value
                __x = weewx.units.ValueTuple(self.gts_value, 'degree_C_day',
                                             'group_degree_day')
            elif obs_type == 'GTSdate':
                # current GTSdate value or None, if GTS<200
                if _soy_ts in self.gts_date:
                    __x = self.gts_date[_soy_ts]
                else:
                    __x = None
                __x = weewx.units.ValueTuple(__x, 'unix_epoch', 'group_time')
            else:
                # should not occure
                raise weewx.CannotCalculate(obs_type)
        else:
            # value from memory
            __x = self.get_gts(obs_type, _sod_ts, _soy_ts)
        """
        try:
          a=str(__x[0])
        except:
          logerr("get_scalar 0")
          a=""
        try:
          b=str(__x[1])
        except:
          logerr("get_scalar 1")
          b=""
        try:
          c=str(__x[2])
        except:
          logerr("get_scalar 2")
          c=""
        loginf("get_scalar %s,%s,%s" % (a,b,c))
        """
        if record is None: return __x
        return weewx.units.convertStd(__x, record['usUnits'])
Пример #24
0
    def get_aggregate(self, obs_type, timespan, aggregate_type, db_manager,
                      **option_dict):

        if obs_type is None:
            raise weewx.UnknownType("obs_type is None")

        # time offset of local mean time (LMT)
        if obs_type == 'utcoffsetLMT':
            return weewx.units.ValueTuple(
                self.lmt_tz.utcoffset(None).total_seconds(), 'second',
                'group_deltatime')

        # energy_integral can be calculated for group_radiation observation
        # types like 'radiation' and 'maxSolarRad'
        if aggregate_type == 'energy_integral':
            if obs_type in weewx.units.obs_group_dict and weewx.units.obs_group_dict[
                    obs_type] == 'group_radiation':
                return self.calc_radiation_integral(obs_type, timespan,
                                                    db_manager)

        # growing degree days == Wachstumsgradtage
        # https://de.wikipedia.org/wiki/Wachstumsgradtag
        # https://en.wikipedia.org/wiki/Growing_degree-day
        if aggregate_type in ['growdeg', 'GDD']:
            # growing degree day can only be calculated for a temperature
            if weewx.units.obs_group_dict.get(obs_type,
                                              '') != 'group_temperature':
                raise weewx.CannotCalculate(
                    "%s is not temperature for aggregation %s" %
                    (obs_type, aggregate_type))
            # if the base value is defined in skin.conf or weewx.conf, get
            # it for default
            units_dict = option_dict.get('skin_dict', {}).get('Units', {})
            dd_dict = units_dict.get('DegreeDays', {})
            base_vt = dd_dict.get(
                'growing_base',
                weewx.xtypes.AggregateHeatCool.default_growbase)
            # if parameters are specified get them
            val = option_dict.get('val')
            #loginf("%s" % type(val))
            #loginf(val)
            if val:
                # GDD with parameters
                try:
                    # dict
                    method = val.get('method', 'integral')
                    base_vt = val.get('base', base_vt)
                    limit_vt = val.get('limit', self.GDD_LIMIT_VT)
                    stop_vt = val.get('stop')
                except TypeError:
                    # tuple used as base temperature
                    base_vt = weewx.units.ValueTuple(float(val[0]), val[1],
                                                     'group_temperature')
                    limit_vt = None
                    stop_vt = None
                    method = 'integral'
            else:
                # GDD alone: use defaults
                method = 'integral'
                limit_vt = self.GDD_LIMIT_VT
                stop_vt = None
            # Convert to a ValueTuple in the same unit system as the database
            __base = weewx.units.convertStd(
                (float(base_vt[0]), base_vt[1], 'group_temperature'),
                db_manager.std_unit_system)[0]
            if limit_vt:
                try:
                    __limit = weewx.units.convertStd(
                        (float(limit_vt[0]), limit_vt[1], 'group_temperature'),
                        db_manager.std_unit_system)[0]
                except IndexError:
                    if limit_vt.lower() == 'none': __limit = None
            else:
                __limit = None
            if stop_vt:
                try:
                    __stop = weewx.units.convertStd(
                        (float(stop_vt[0]), stop_vt[1], 'group_temperature'),
                        db_manager.std_unit_system)[0]
                except IndexError:
                    if stop_vt.lower() == 'none': __stop = None
            else:
                __stop = None
            #loginf("method %s" % method)
            #loginf(base_vt)
            #loginf(limit_vt)
            # calculate GDD sum
            if method == 'integral':
                # integral over timespan
                return self.calc_GDD_integral(obs_type, timespan, db_manager,
                                              __base, __limit, __stop)
            if method in ['hiloavgA', 'hiloavgB', 'dayavg']:
                # based on daily average or average of high and low.
                # Check if day border should be based on Local Mean Time
                # or local timezone time
                __lmt_tz = option_dict.get('LMT', {}).get('timezone')
                if __lmt_tz is None:
                    __lmt_tz = option_dict.get('dayboundary',
                                               {}).get('timezone')
                return self.calc_GDD_avg(obs_type, timespan, db_manager,
                                         method, __base, __limit, __stop,
                                         __lmt_tz)
            if method == 'weewx' and obs_type == 'outTemp':
                # call builtin method of WeeWX for outTemp
                return weewx.xtypes.get_aggregate('growdeg', timespan, 'sum',
                                                  db_manager, **option_dict)
            raise weewx.CannotCalculate("GDD %s: unknown method" % method)

        # accumulated growing degree days
        if obs_type == 'yearGDD' or obs_type == 'seasonGDD':
            #loginf("GDD %s" % option_dict)
            #loginf("GDD %s" % aggregate_type)
            if aggregate_type.lower() == 'avg':
                if timespan.start > time.time() or (
                        timespan.start +
                        timespan.stop) / 2 > time.time() + 90000:
                    return weewx.units.ValueTuple(None, 'degree_C_day',
                                                  'group_degree_days')
                return self.get_scalar(
                    obs_type,
                    {'dateTime': (timespan.start + timespan.stop) / 2},
                    db_manager, **option_dict)
            if aggregate_type.lower() == 'last':
                return self.get_scalar(obs_type, {'dateTime': timespan.stop},
                                       db_manager, **option_dict)
            raise weewx.UnknownAggregation("%s undefinded aggregation %s" %
                                           (obs_type, aggregation_type))

        # This function handles 'GTS' and 'GTSdate'.
        if obs_type != 'GTS' and obs_type != 'GTSdate':
            raise weewx.UnknownType(obs_type)

        # aggregation types that are defined for those values
        if aggregate_type not in [
                'avg', 'max', 'min', 'last', 'maxtime', 'mintime', 'lasttime'
        ]:
            raise weewx.UnknownAggregation("%s undefinded aggregation %s" %
                                           (obs_type, aggregation_type))

        if timespan is None:
            raise weewx.CannotCalculate("%s %s no timespan" %
                                        (obs_type, aggregate_type))
        if db_manager is None:
            if self.db_manager_ok:
                logerr("%s: no database reference" % obs_type)
                self.db_manager_ok = False
            raise weewx.CannotCalculate("%s: no database reference" % obs_type)

        # needed timestamps
        _soya_ts = startOfYearTZ(timespan.start + 1, self.lmt_tz)
        _soye_ts = startOfYearTZ(timespan.stop, self.lmt_tz)

        # calculate GTS values for the years included in timespan
        # (if time span is within the current year, the
        # value is calculated up to the current day (today))
        __max = 0
        __maxtime = None
        __min = 10000000
        __mintime = None
        __ts = _soya_ts
        # Even if the time span starts after May 31st, the end value
        # is needed for some aggregations. So we have to calculate
        # that year, too.
        while __ts <= _soye_ts:
            # calculate GTS values for the year
            self.calc_gts(__ts, db_manager)
            # update minimum and maximum
            if __ts in self.gts_values:
                for __i, __val in enumerate(self.gts_values[__ts]):
                    if __val is not None and __val > __max:
                        __max = __val
                        __maxtime = __ts + __i * 86400
                    if __val is not None and __val < __min:
                        __min = __val
                        __mintime = __ts + __i * 86400
            # next year
            __ts = startOfYearTZ(__ts + 31708800, self.lmt_tz)

        if obs_type == 'GTS':
            if aggregate_type == 'avg':
                # 1 day is 86400s, but once a year it is 90000s or 82800s
                # when the daylight savings time is switched on or off.
                if timespan.stop - timespan.start <= 90000:
                    __a = startOfDayTZ(timespan.start, _soya_ts)
                    __b = startOfDayTZ(timespan.stop, _soye_ts)
                    if __a != __b:
                        # begin and end of timespan are different days
                        # according to timezone self.lmt_tz
                        # timespan.start <= __b <= timespan.stop
                        if __b - timespan.start > timespan.stop - __b:
                            __b = __a
                            _soye_ts = _soya_ts
                    if __b >= _soye_ts + 13046400:
                        __x = weewx.units.ValueTuple(None, 'degree_C_day',
                                                     'group_degree_day')
                    else:
                        __x = self.get_gts(obs_type, __b, _soye_ts)
                elif _soya_ts == _soye_ts and _soya_ts in self.gts_values:
                    # timespan within the same year but more than one day
                    # (not much use, but calculated anyway)
                    __a = dayOfGTSYear(timespan.start, _soya_ts)
                    __b = dayOfGTSYear(timespan.stop, _soye_ts)
                    if __a == __b:
                        __x = self.gts_values[_soya_ts][__a]
                    else:
                        __x = 0
                        for __i in xrange(__a, __b):
                            if self.gts_values[_soya_ts][__i] is not None:
                                __x += self.gts_values[_soya_ts][__i]
                        __x /= __b - __a
                else:
                    raise weewx.CannotCalculate(
                        "%s %s invalid timespan %s %s" %
                        (obs_type, aggregate_type,
                         timespan.stop - timespan.start,
                         time.strftime("%Y-%m-%d %H:%M:%S",
                                       time.localtime(timespan.start))))
            elif aggregate_type == 'lasttime':
                if timespan.stop >= self.last_gts_date:
                    # today or in future
                    __ts = self.last_gts_date
                else:
                    # before today
                    if _soye_ts not in self.gts_values:
                        raise weewx.CannotCalculate("%s %s" %
                                                    (obs_type, aggregate_type))
                    __ts = dayOfGTSYear(timespan.stop, _soye_ts)
                    for __i, __v in reversed(
                            enumerate(self.gts_values[_soye_ts])):
                        if __v is not None and __i <= __ts:
                            __ts = _soye_ts + 86400 * __i
                            break
                    else:
                        __ts = _soye_ts
                __x = weewx.units.ValueTuple(__ts, 'unix_epoch', 'group_time')
            elif aggregate_type == 'last':
                if timespan.stop >= _soye_ts + 13046400:
                    # after May 31st
                    __ts = _soye_ts + 13046400 - 86400
                else:
                    # between Jan 1st and May 31st
                    __ts = startOfDayTZ(timespan.stop, _soye_ts)
                    # startOfDay() returns for 24:00 the start of the
                    # next day. So we need to look for the day before.
                    if __ts == timespan.stop:
                        __ts -= 86400
                    # for today there is no value so far
                    if __ts == startOfDayTZ(time.time(), _soye_ts):
                        __ts -= 86400
                __x = self.get_gts(obs_type, __ts, _soye_ts)
            elif aggregate_type == 'max':
                __x = weewx.units.ValueTuple(__max, 'degree_C_day',
                                             'group_degree_day')
            elif aggregate_type == 'maxtime':
                __x = weewx.units.ValueTuple(__maxtime, 'unix_epoch',
                                             'group_time')
            elif aggregate_type == 'min':
                __x = weewx.units.ValueTuple(__min, 'degree_C_day',
                                             'group_degree_day')
            elif aggregate_type == 'mintime':
                __x = weewx.units.ValueTuple(__mintime, 'unix_epoch',
                                             'group_time')
            else:
                raise weewx.CannotCalculate("%s %s" %
                                            (obs_type, aggregate_type))
            """
            try:
              a=str(__x[0])
            except:
              logerr("get_aggregate 0")
              a=""
            try:
              b=str(__x[1])
            except:
              logerr("get_aggregate 1")
              b=""
            try:
              c=str(__x[2])
            except:
              logerr("get_aggregate 2")
              c=""
            loginf("get_aggregate %s,%s,%s" % (a,b,c))
            """
            return __x

        if obs_type == 'GTSdate':
            if aggregate_type == 'last' or aggregate_type == 'max':
                if _soye_ts in self.gts_date and self.gts_date[
                        _soye_ts] is not None and timespan.stop >= self.gts_date[
                            _soye_ts]:
                    __x = self.gts_date[_soye_ts]
                else:
                    __x = None
                return weewx.units.ValueTuple(__x, 'unix_epoch', 'group_time')

        raise weewx.CannotCalculate("%s %s" % (obs_type, aggregate_type))
Пример #25
0
    def get_gdd_series(self, obs_type, timespan, db_manager):
        """Get Growing Degree Days series.

        This function returns a list of four ValueTuple vectors:
        start_time, stop_time, gdd, and gdd_cumulative.

        """

        try:
            model = self.metadata[obs_type]
        except KeyError:
            raise weewx.UnknownType(obs_type)
        converter = weewx.units.StdUnitConverters[db_manager.std_unit_system]
        self.convert_metadata_to_standard_units(converter, model)
        vector_time_stamp = []
        vector_temp_min = []
        vector_temp_max = []
        for day_time_span in weeutil.weeutil.genDaySpans(*timespan):
            vector_time_stamp.append(day_time_span)
            temp_min = weewx.xtypes.DailySummaries.get_aggregate(
                'outTemp', day_time_span, 'min', db_manager)
            temp_max = weewx.xtypes.DailySummaries.get_aggregate(
                'outTemp', day_time_span, 'max', db_manager)
            vector_temp_min.append(temp_min)
            vector_temp_max.append(temp_max)
        day_count = len(vector_time_stamp)
        vector_time_stamp_start = []
        vector_time_stamp_stop = []
        vector_gdd = []
        vector_gdd_cumulative = []
        total = ZERO
        (threshold_temp, threshold_temp_units) = model['threshold_t'][:2]
        (cutoff_temp, cutoff_units) = model['cutoff_t'][:2]
        if cutoff_units in ['degree_F']:
            scale = 'f'
        else:
            scale = 'c'
        method = user.growing_degrees.__dict__[model['method']]
        for (ndx, day_time_span) in enumerate(vector_time_stamp):
            try:
                (temp_max, temp_max_units) = vector_temp_max[ndx][:2]
                (temp_min, temp_min_units) = vector_temp_min[ndx][:2]
                if ndx + 1 < day_count:
                    (temp_min_2,
                     temp_min_2_units) = vector_temp_min[ndx + 1][:2]
                else:
                    (temp_min_2, temp_min_2_units) = (None, None)
                assert temp_max_units == temp_min_units == threshold_temp_units
                if None in [temp_max, temp_min]:
                    gdd = None
                else:
                    gdd = method(
                        day_max_temp=temp_max,
                        day_min_temp=temp_min,
                        threshold_temp=threshold_temp,
                        cutoff_temp=cutoff_temp,
                        day_2_min_temp=temp_min_2,
                        scale=scale,
                    )
                    if gdd is None:
                        pass
                    else:
                        (day_time_stamp_start,
                         day_time_stamp_stop) = day_time_span
                        vector_time_stamp_start.append(day_time_stamp_start)
                        vector_time_stamp_stop.append(day_time_stamp_stop)
                        vector_gdd.append(gdd)
                        total += gdd
                        vector_gdd_cumulative.append(total)
            except KeyError as e:
                LOG.error("Missing model parameters.  {}".format(e))
                raise weewx.CannotCalculate
            except ValueError:
                LOG.error("Bad calculation.")
                raise weewx.CannotCalculate
            except AssertionError:
                LOG.error("Mixed units.")
                raise weewx.CannotCalculate
        (unit, unit_group) = weewx.units.getStandardUnitType(
            db_manager.std_unit_system, 'cooldeg', agg_type=None)
        result = []
        result.append(
            weewx.units.ValueTuple(vector_time_stamp_start, 'unix_epoch',
                                   'group_time'))
        result.append(
            weewx.units.ValueTuple(vector_time_stamp_stop, 'unix_epoch',
                                   'group_time'))
        result.append(weewx.units.ValueTuple(vector_gdd, unit, unit_group))
        result.append(
            weewx.units.ValueTuple(vector_gdd_cumulative, unit, unit_group))
        return result
Пример #26
0
    def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
        """Returns an aggregation of a wind vector type over a timespan by using the main archive table.

        obs_type: The type over which aggregation is to be done. For this function,
        it must be 'windvec' or 'windgustvec'. Anything else will cause weewx.UnknownType
        to be raised.

        timespan: An instance of weeutil.Timespan with the time period over which
        aggregation is to be done.

        aggregate_type: The type of aggregation to be done. For this function, must be
        'avg', 'sum', 'count', 'first', 'last', 'min', or 'max'. Anything else will cause
        weewx.UnknownAggregation to be raised.

        db_manager: An instance of weewx.manager.Manager or subclass.

        option_dict: Not used in this version.

        returns: A ValueTuple containing the result. Note that the value contained in the ValueTuple
        will be a complex number.
        """
        if obs_type not in WindVec.windvec_types:
            raise weewx.UnknownType(obs_type)

        aggregate_type = aggregate_type.lower()

        # Raise exception if we don't know about this type of aggregation
        if aggregate_type not in ['avg', 'sum'] + list(WindVec.agg_sql_dict.keys()):
            raise weewx.UnknownAggregation(aggregate_type)

        # Form the interpolation dictionary
        interpolation_dict = {
            'dir': WindVec.windvec_types[obs_type][1],
            'mag': WindVec.windvec_types[obs_type][0],
            'start': weeutil.weeutil.startOfDay(timespan.start),
            'stop': timespan.stop,
            'table_name': db_manager.table_name
        }

        if aggregate_type in WindVec.agg_sql_dict:
            # For these types (e.g., first, last, etc.), we can do the aggregation in a SELECT statement.
            select_stmt = WindVec.agg_sql_dict[aggregate_type] % interpolation_dict
            row = db_manager.getSql(select_stmt)
            if row:
                if aggregate_type == 'count':
                    value, std_unit_system = row
                else:
                    magnitude, direction, std_unit_system = row
                    value = weeutil.weeutil.to_complex(magnitude, direction)
            else:
                std_unit_system = db_manager.std_unit_system
                value = None
        else:
            # The result is more complex, requiring vector arithmetic. We will have to do it
            # in Python
            std_unit_system = None
            xsum = ysum = 0.0
            count = 0
            select_stmt = WindVec.complex_sql_wind % interpolation_dict

            for rec in db_manager.genSql(select_stmt, timespan):

                # Unpack the record
                mag, direction, unit_system = rec

                # Ignore rows where magnitude is NULL
                if mag is None:
                    continue

                # A good direction is necessary unless the mag is zero:
                if mag == 0.0 or direction is not None:
                    if std_unit_system:
                        if std_unit_system != unit_system:
                            raise weewx.UnsupportedFeature("Unit type cannot change within a time interval.")
                    else:
                        std_unit_system = unit_system

                    # An undefined direction is OK (and expected) if the magnitude
                    # is zero. But, in that case, it doesn't contribute to the sums either.
                    if direction is None:
                        # Sanity check
                        if weewx.debug:
                            assert (mag == 0.0)
                    else:
                        xsum += mag * math.cos(math.radians(90.0 - direction))
                        ysum += mag * math.sin(math.radians(90.0 - direction))
                    count += 1

            # We've gone through the whole interval. Were there any good data?
            if count:
                # Form the requested aggregation:
                if aggregate_type == 'sum':
                    value = complex(xsum, ysum)
                else:
                    # Must be 'avg'
                    value = complex(xsum, ysum) / count
            else:
                value = None

        # Look up the unit type and group of this combination of observation type and aggregation:
        t, g = weewx.units.getStandardUnitType(std_unit_system, obs_type, aggregate_type)
        # Form the ValueTuple and return it:
        return weewx.units.ValueTuple(value, t, g)
Пример #27
0
    def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
        """Returns heating and cooling degree days over a time period.

        obs_type: The type over which aggregation is to be done.  Must be one of 'heatdeg', 'cooldeg', or 'growdeg'.

        timespan: An instance of weeutil.Timespan with the time period over which
        aggregation is to be done.

        aggregate_type: The type of aggregation to be done. Must be 'avg' or 'sum'.

        db_manager: An instance of weewx.manager.Manager or subclass.

        option_dict: Not used in this version.

        returns: A ValueTuple containing the result.
        """

        # Check to see whether heating or cooling degree days are being asked for:
        if obs_type not in ['heatdeg', 'cooldeg', 'growdeg']:
            raise weewx.UnknownType(obs_type)

        # Only summation (total) or average heating or cooling degree days is supported:
        if aggregate_type not in ['sum', 'avg']:
            raise weewx.UnknownAggregation(aggregate_type)

        # Get the base for heating and cooling degree-days
        units_dict = option_dict.get('skin_dict', {}).get('Units', {})
        dd_dict = units_dict.get('DegreeDays', {})
        heatbase = dd_dict.get('heating_base', AggregateHeatCool.default_heatbase)
        coolbase = dd_dict.get('cooling_base', AggregateHeatCool.default_coolbase)
        growbase = dd_dict.get('growing_base', AggregateHeatCool.default_growbase)
        # Convert to a ValueTuple in the same unit system as the database
        heatbase_t = weewx.units.convertStd((float(heatbase[0]), heatbase[1], "group_temperature"),
                                            db_manager.std_unit_system)
        coolbase_t = weewx.units.convertStd((float(coolbase[0]), coolbase[1], "group_temperature"),
                                            db_manager.std_unit_system)
        growbase_t = weewx.units.convertStd((float(growbase[0]), growbase[1], "group_temperature"),
                                            db_manager.std_unit_system)

        total = 0.0
        count = 0
        for daySpan in weeutil.weeutil.genDaySpans(timespan.start, timespan.stop):
            # Get the average temperature for the day as a value tuple:
            Tavg_t = DailySummaries.get_aggregate('outTemp', daySpan, 'avg', db_manager)
            # Make sure it's valid before including it in the aggregation:
            if Tavg_t is not None and Tavg_t[0] is not None:
                if obs_type == 'heatdeg':
                    total += weewx.wxformulas.heating_degrees(Tavg_t[0], heatbase_t[0])
                elif obs_type == 'cooldeg':
                    total += weewx.wxformulas.cooling_degrees(Tavg_t[0], coolbase_t[0])
                else:
                    total += weewx.wxformulas.cooling_degrees(Tavg_t[0], growbase_t[0])

                count += 1

        if aggregate_type == 'sum':
            value = total
        else:
            value = total / count if count else None

        # Look up the unit type and group of the result:
        t, g = weewx.units.getStandardUnitType(db_manager.std_unit_system, obs_type, aggregate_type)
        # Return as a value tuple
        return weewx.units.ValueTuple(value, t, g)
Пример #28
0
    def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
        """Returns an aggregation of a statistical type for a given time period,
        by using the daily summaries.
    
        obs_type: The type over which aggregation is to be done (e.g., 'barometer',
        'outTemp', 'rain', ...)
    
        timespan: An instance of weeutil.Timespan with the time period over which
        aggregation is to be done.
    
        aggregate_type: The type of aggregation to be done.
    
        db_manager: An instance of weewx.manager.Manager or subclass.
    
        option_dict: Not used in this version.
    
        returns: A ValueTuple containing the result."""

        # Check to see if this is a valid daily summary type:
        if not hasattr(db_manager, 'daykeys') or obs_type not in db_manager.daykeys:
            raise weewx.UnknownType(obs_type)

        aggregate_type = aggregate_type.lower()

        # Raise exception if we don't know about this type of aggregation
        if aggregate_type not in DailySummaries.daily_sql_dict:
            raise weewx.UnknownAggregation(aggregate_type)

        # We cannot use the day summaries if the starting and ending times of the aggregation interval are not on
        # midnight boundaries, and are not the first or last records in the database.
        if not (isStartOfDay(timespan.start) or timespan.start == db_manager.first_timestamp) \
                or not (isStartOfDay(timespan.stop) or timespan.stop == db_manager.last_timestamp):
            raise weewx.UnknownAggregation(aggregate_type)

        val = option_dict.get('val')
        if val is None:
            target_val = None
        else:
            # The following is for backwards compatibility when ValueTuples had
            # just two members. This hack avoids breaking old skins.
            if len(val) == 2:
                if val[1] in ['degree_F', 'degree_C']:
                    val += ("group_temperature",)
                elif val[1] in ['inch', 'mm', 'cm']:
                    val += ("group_rain",)
            target_val = weewx.units.convertStd(val, db_manager.std_unit_system)[0]

        # Form the interpolation dictionary
        interDict = {
            'start': weeutil.weeutil.startOfDay(timespan.start),
            'stop': timespan.stop,
            'obs_key': obs_type,
            'aggregate_type': aggregate_type,
            'val': target_val,
            'table_name': db_manager.table_name
        }

        # Run the query against the database:
        row = db_manager.getSql(DailySummaries.daily_sql_dict[aggregate_type] % interDict)

        # Each aggregation type requires a slightly different calculation.
        if not row or None in row:
            # If no row was returned, or if it contains any nulls (meaning that not
            # all required data was available to calculate the requested aggregate),
            # then set the resulting value to None.
            value = None

        elif aggregate_type in ['min', 'maxmin', 'max', 'minmax', 'meanmin', 'meanmax',
                                'maxsum', 'minsum', 'sum', 'gustdir']:
            # These aggregates are passed through 'as is'.
            value = row[0]

        elif aggregate_type in ['mintime', 'maxmintime', 'maxtime', 'minmaxtime', 'maxsumtime',
                                'minsumtime', 'count', 'max_ge', 'max_le', 'min_ge', 'min_le',
                                'sum_ge', 'sum_le']:
            # These aggregates are always integers:
            value = int(row[0])

        elif aggregate_type == 'avg':
            value = row[0] / row[1] if row[1] else None

        elif aggregate_type == 'rms':
            value = math.sqrt(row[0] / row[1]) if row[1] else None

        elif aggregate_type == 'vecavg':
            value = math.sqrt((row[0] ** 2 + row[1] ** 2) / row[2] ** 2) if row[2] else None

        elif aggregate_type == 'vecdir':
            if row == (0.0, 0.0):
                value = None
            deg = 90.0 - math.degrees(math.atan2(row[1], row[0]))
            value = deg if deg >= 0 else deg + 360.0
        else:
            # Unknown aggregation. Should not have gotten this far...
            raise ValueError("Unexpected error. Aggregate type '%s'" % aggregate_type)

        # Look up the unit type and group of this combination of observation type and aggregation:
        t, g = weewx.units.getStandardUnitType(db_manager.std_unit_system, obs_type, aggregate_type)
        # Form the ValueTuple and return it:
        return weewx.units.ValueTuple(value, t, g)
Пример #29
0
    def get_series(obs_type,
                   timespan,
                   db_manager,
                   aggregate_type=None,
                   aggregate_interval=None):
        """Get a series, possibly with aggregation, from the main archive database.

        The general strategy is that if aggregation is asked for, chop the series up into separate
        chunks, calculating the aggregate for each chunk. Then assemble the results.

        If no aggregation is called for, just return the data directly out of the database.
        """

        startstamp, stopstamp = timespan
        start_vec = list()
        stop_vec = list()
        data_vec = list()

        if aggregate_type:
            # With aggregation
            unit, unit_group = None, None
            if aggregate_type == 'cumulative':
                do_aggregate = 'sum'
                total = 0
            else:
                do_aggregate = aggregate_type
            for stamp in weeutil.weeutil.intervalgen(startstamp, stopstamp,
                                                     aggregate_interval):
                # Get the aggregate as a ValueTuple
                agg_vt = get_aggregate(obs_type, stamp, do_aggregate,
                                       db_manager)
                if unit:
                    # It's OK if the unit is unknown (=None).
                    if agg_vt[1] is not None and (unit != agg_vt[1]
                                                  or unit_group != agg_vt[2]):
                        raise weewx.UnsupportedFeature(
                            "Cannot change unit groups "
                            "within an aggregation.")
                else:
                    unit, unit_group = agg_vt[1], agg_vt[2]
                start_vec.append(stamp.start)
                stop_vec.append(stamp.stop)
                if aggregate_type == 'cumulative':
                    if agg_vt[0] is not None:
                        total += agg_vt[0]
                    data_vec.append(total)
                else:
                    data_vec.append(agg_vt[0])

        else:

            # No aggregation
            sql_str = "SELECT dateTime, %s, usUnits, `interval` FROM %s " \
                      "WHERE dateTime >= ? AND dateTime <= ?" % (obs_type, db_manager.table_name)

            std_unit_system = None

            # Hit the database. It's possible the type is not in the database, so be prepared
            # to catch a NoColumnError:
            try:
                for record in db_manager.genSql(sql_str,
                                                (startstamp, stopstamp)):

                    # Unpack the record
                    timestamp, value, unit_system, interval = record

                    if std_unit_system:
                        if std_unit_system != unit_system:
                            raise weewx.UnsupportedFeature(
                                "Unit type cannot change "
                                "within an aggregation interval.")
                    else:
                        std_unit_system = unit_system
                    start_vec.append(timestamp - interval * 60)
                    stop_vec.append(timestamp)
                    data_vec.append(value)
            except weedb.NoColumnError:
                # The sql type doesn't exist. Convert to an UnknownType error
                raise weewx.UnknownType(obs_type)

            unit, unit_group = weewx.units.getStandardUnitType(
                std_unit_system, obs_type, aggregate_type)

        return (ValueTuple(start_vec, 'unix_epoch', 'group_time'),
                ValueTuple(stop_vec, 'unix_epoch',
                           'group_time'), ValueTuple(data_vec, unit,
                                                     unit_group))