Ejemplo n.º 1
0
    def get_aggregate(self, obs_type, timespan, aggregate_type, db_manager,
                      **option_dict):
        """Calculate historical statistical aggregation for a date in the year"""

        dbtype = db_manager.connection.dbtype

        # Do we know how to calculate this kind of aggregation?
        if aggregate_type not in Historical.sql_stmts[dbtype]:
            raise weewx.UnknownAggregation(aggregate_type)

        # The time span must lie on midnight-to-midnight boundaries
        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("%s of %s" %
                                           (aggregate_type, timespan))

        start_day = datetime.date.fromtimestamp(timespan.start)
        stop_day = datetime.date.fromtimestamp(timespan.stop)

        # The timespan must cover just one day
        delta = stop_day - start_day
        if delta.days != 1:
            raise weewx.UnknownAggregation("%s of %s" %
                                           (aggregate_type, timespan))

        interp_dict = {
            'table': db_manager.table_name,
            'obs_type': obs_type,
            'month': start_day.month,
            'day': start_day.day
        }

        # Get the correct sql statement, and format it with the interpolation dictionary.
        sql_stmt = Historical.sql_stmts[dbtype][aggregate_type].format(
            **interp_dict)

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

        # Given the result set, calculate the desired value
        if not row or None in row:
            value = None
        elif aggregate_type == 'historical_avg':
            value = row[0] / row[1] if row[1] else None
        else:
            value = row[0]

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

        # Form the ValueTuple and return it:
        return weewx.units.ValueTuple(value, u, g)
Ejemplo n.º 2
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)
Ejemplo n.º 3
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)
Ejemplo n.º 4
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)