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