Moved get_aggregate() to aggregate.py. Added heat/cool to aggregate

This commit is contained in:
Tom Keffer
2019-10-12 12:00:12 -07:00
parent 575c131d48
commit 96d4e681d8
4 changed files with 121 additions and 25 deletions

23
TODO.md
View File

@@ -1,10 +1,13 @@
### Extensible types
Need some way of initializing the daily summaries for wind.
### Logging
Refactor wee_import to use the new logging facility.
Refactor `wee_import` to use the new logging facility.
Update *Upgrading Guide*.
### Issue 435 (Update WU uploader)
### Issue [#435](https://github.com/weewx/weewx/issues/435) (Update WU uploader)
Need to test some of the new types, in particular `windSpeed2`, `windGust10`,
`windGustDir10`.
@@ -15,22 +18,6 @@ from `weeutil.weeutil`.
Document the suffixes `.exists` and `.has_data`.
Explore introducing extendable observation types. They would be registered
with `Manager`.
The following drivers have been checked under Python 3:
```
vantage.py
wmr100.py
```
In general, we should expect the user to run the command `python`, whatever that might
point to. On some systems, it will be Python 2, others Python 3.
Nevertheless, we should probably include a section on how to run explicitly under
Python 2 vs 3.
Update macos.htm for how to install using Python 3.
Update redhat.htm for how to install using Python 3.

View File

@@ -39,8 +39,9 @@ simple_sql = "SELECT %(aggregate_type)s(%(obs_type)s) FROM %(table_name)s " \
"WHERE dateTime > %(start)s AND dateTime <= %(stop)s AND %(obs_type)s IS NOT NULL"
def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
"""Returns an aggregation of an observation type over a given time period.
def get_aggregate_archive(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', ...)
@@ -195,7 +196,7 @@ def get_aggregate_daily(obs_type, timespan, aggregate_type, db_manager, **option
# 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.ViolatedPrecondition("Invalid timespan for using daily summaries: %s" % timespan)
raise weewx.UnknownAggregation(aggregate_type)
if 'val' in option_dict:
val = option_dict['val']
@@ -392,3 +393,93 @@ def get_aggregate_wind(obs_type, timespan, aggregate_type, db_manager, **option_
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)
def get_aggregate_heatcool(obs_type, timespan, aggregate_type, db_manager, **option_dict):
"""Returns an aggregation of a wind type over a timespan by 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. Note that the value contained in the ValueTuple
will be a complex number for aggregation_types of 'avg', 'sum', 'first', 'last', 'min', and 'max'.
"""
# Default base temperature and unit type for heating and cooling degree days,
# as a value tuple
default_heatbase = (65.0, "degree_F", "group_temperature")
default_coolbase = (65.0, "degree_F", "group_temperature")
default_growbase = (50.0, "degree_F", "group_temperature")
# 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', default_heatbase)
coolbase = dd_dict.get('cooling_base', default_coolbase)
growbase = dd_dict.get('growing_base', default_growbase)
heatbase_t = (float(heatbase[0]), heatbase[1], "group_temperature")
coolbase_t = (float(coolbase[0]), coolbase[1], "group_temperature")
growbase_t = (float(growbase[0]), growbase[1], "group_temperature")
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 = get_aggregate_daily('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':
# Convert average temperature to the same units as heatbase:
Tavg_target_t = weewx.units.convert(Tavg_t, heatbase_t[1])
total += weewx.wxformulas.heating_degrees(Tavg_target_t[0], heatbase_t[0])
elif obs_type == 'cooldeg':
# Convert average temperature to the same units as coolbase:
Tavg_target_t = weewx.units.convert(Tavg_t, coolbase_t[1])
total += weewx.wxformulas.cooling_degrees(Tavg_target_t[0], coolbase_t[0])
else:
# Must be 'growdeg'. Convert average temperature to the same units as growbase:
Tavg_target_t = weewx.units.convert(Tavg_t, growbase_t[1])
total += weewx.wxformulas.cooling_degrees(Tavg_target_t[0], growbase_t[0])
count += 1
if aggregate_type == 'sum':
result = total
else:
result = 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(result, t, g)
aggregate_fns = [get_aggregate_heatcool,
get_aggregate_wind,
get_aggregate_daily,
get_aggregate_archive]
def get_aggregate(obs_type, timespan, aggregate_type, db_manager, **option_dict):
for agg_fn in aggregate_fns:
try:
return agg_fn(obs_type, timespan, aggregate_type, db_manager, **option_dict)
except (weewx.UnknownAggregation, weewx.UnknownType):
pass
raise weewx.UnknownAggregation(aggregate_type)

View File

@@ -19,6 +19,7 @@ import gen_fake_data
import weeutil.logger
import weewx
import weewx.aggregate
import weewx.manager
from weeutil.weeutil import TimeSpan
from weewx.units import ValueTuple
@@ -56,7 +57,7 @@ class TestAggregate(unittest.TestCase):
def test_get_aggregate(self):
# Use the same function to test calculating aggregations from the main archive file, as well
# as from the daily summaries:
self.get_aggregate_fn(weewx.aggregate.get_aggregate)
self.get_aggregate_fn(weewx.aggregate.get_aggregate_archive)
self.get_aggregate_fn(weewx.aggregate.get_aggregate_daily)
def get_aggregate_fn(self, aggregate_fn):
@@ -88,7 +89,7 @@ class TestAggregate(unittest.TestCase):
self.assertAlmostEqual(sum_vt[0], 7.68, 2)
# get_aggregate() has a few extra aggregate types:
if aggregate_fn == weewx.aggregate.get_aggregate:
if aggregate_fn == weewx.aggregate.get_aggregate_archive:
first_vt = aggregate_fn('outTemp', TimeSpan(start_ts, stop_ts), 'first', db_manager)
# Get the timestamp of the first record inside the month
ts = start_ts + gen_fake_data.interval
@@ -134,7 +135,7 @@ class TestAggregate(unittest.TestCase):
avg_wind_vt = weewx.aggregate.get_aggregate_daily('wind', TimeSpan(start_ts, stop_ts), 'avg', db_manager)
self.assertAlmostEqual(avg_wind_vt[0], 10.21, 2)
# Double check this last one against the average calculated from the archive
avg_wind_vt = weewx.aggregate.get_aggregate('windSpeed', TimeSpan(start_ts, stop_ts), 'avg', db_manager)
avg_wind_vt = weewx.aggregate.get_aggregate_archive('windSpeed', TimeSpan(start_ts, stop_ts), 'avg', db_manager)
self.assertAlmostEqual(avg_wind_vt[0], 10.21, 2)
vecavg_wind_vt = weewx.aggregate.get_aggregate_daily('wind', TimeSpan(start_ts, stop_ts), 'vecavg',
@@ -145,6 +146,24 @@ class TestAggregate(unittest.TestCase):
db_manager)
self.assertAlmostEqual(vecdir_wind_vt[0], 88.74, 2)
def test_get_aggregate_heatcool(self):
with weewx.manager.open_manager_with_config(self.config_dict, 'wx_binding') as db_manager:
month_start_tt = (2010, 3, 1, 0, 0, 0, 0, 0, -1)
month_stop_tt = (2010, 4, 1, 0, 0, 0, 0, 0, -1)
start_ts = time.mktime(month_start_tt)
stop_ts = time.mktime(month_stop_tt)
# First, with the default heating base:
heatdeg = weewx.aggregate.get_aggregate_heatcool('heatdeg', TimeSpan(start_ts, stop_ts), 'sum', db_manager)
self.assertAlmostEqual(heatdeg[0], 1123.99, 2)
# Now with an explicit heating base:
heatdeg = weewx.aggregate.get_aggregate_heatcool('heatdeg', TimeSpan(start_ts, stop_ts), 'sum',
db_manager,
skin_dict={'Units': {'DegreeDays': {
'heating_base': (60.0, "degree_F", "group_temperature")
}}})
self.assertAlmostEqual(heatdeg[0], 968.99, 2)
if __name__ == '__main__':
unittest.main()

View File

@@ -9,7 +9,6 @@ from __future__ import print_function
import weewx
scalar_types = []
series_types = []
def get_scalar(key, record, db_manager=None):