mirror of
https://github.com/weewx/weewx.git
synced 2026-06-09 17:45:24 -04:00
Added aggregation types .last and .lasttime. Documented them. Included in test suites.
Still have to support them in aggregation vectors. Added new appendix to Customizing Guide that documents the various aggregation types.
This commit is contained in:
3
TODO.txt
3
TODO.txt
@@ -24,6 +24,9 @@ May need to update the guide on packaging an extension.
|
||||
On startup, the log should indicate not only which binding is in use, but what
|
||||
it is bound to (sqlite or mysql).
|
||||
|
||||
Make .last and .lasttime work for aggregation vectors.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -836,35 +836,38 @@ meta_replace_str = """REPLACE INTO %s_day__metadata VALUES(?, ?)"""
|
||||
select_update_str = """SELECT value FROM %s_day__metadata WHERE name = 'lastUpdate';"""
|
||||
|
||||
# Set of SQL statements to be used for calculating aggregate statistics. Key is the aggregation type.
|
||||
sqlDict = {'min' : "SELECT MIN(min) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'minmax' : "SELECT MIN(max) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'max' : "SELECT MAX(max) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'maxmin' : "SELECT MAX(min) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'meanmin' : "SELECT AVG(min) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'meanmax' : "SELECT AVG(max) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'maxsum' : "SELECT MAX(sum) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'mintime' : "SELECT mintime FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"min = (SELECT MIN(min) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'maxmintime' : "SELECT mintime FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"min = (SELECT MAX(min) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'maxtime' : "SELECT maxtime FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"max = (SELECT MAX(max) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'minmaxtime' : "SELECT maxtime FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"max = (SELECT MIN(max) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'maxsumtime' : "SELECT maxtime FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"sum = (SELECT MAX(sum) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'gustdir' : "SELECT max_dir FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"max = (SELECT MAX(max) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s)",
|
||||
'sum' : "SELECT SUM(sum) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'count' : "SELECT SUM(count) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'avg' : "SELECT SUM(wsum),SUM(sumtime) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'rms' : "SELECT SUM(wsquaresum),SUM(sumtime) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'vecavg' : "SELECT SUM(xsum),SUM(ysum),SUM(dirsumtime) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'vecdir' : "SELECT SUM(xsum),SUM(ysum) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'max_ge' : "SELECT SUM(max >= %(val)s) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'max_le' : "SELECT SUM(max <= %(val)s) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'min_le' : "SELECT SUM(min <= %(val)s) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'sum_ge' : "SELECT SUM(sum >= %(val)s) FROM %(table_name)s_day_%(day_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s"}
|
||||
sqlDict = {'min' : "SELECT MIN(min) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'minmax' : "SELECT MIN(max) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'max' : "SELECT MAX(max) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'maxmin' : "SELECT MAX(min) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'meanmin' : "SELECT AVG(min) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'meanmax' : "SELECT AVG(max) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'maxsum' : "SELECT MAX(sum) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'mintime' : "SELECT mintime FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"min = (SELECT MIN(min) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'maxmintime' : "SELECT mintime FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"min = (SELECT MAX(min) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'maxtime' : "SELECT maxtime FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"max = (SELECT MAX(max) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'minmaxtime' : "SELECT maxtime FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"max = (SELECT MIN(max) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'maxsumtime' : "SELECT maxtime FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"sum = (SELECT MAX(sum) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime <%(stop)s)",
|
||||
'gustdir' : "SELECT max_dir FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s AND " \
|
||||
"max = (SELECT MAX(max) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s)",
|
||||
'sum' : "SELECT SUM(sum) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'count' : "SELECT SUM(count) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'last' : "SELECT %(obs_key)s FROM %(table_name)s WHERE dateTime > %(start)s AND dateTime <= %(stop)s AND %(obs_key)s IS NOT NULL " \
|
||||
"ORDER BY dateTime DESC LIMIT 1",
|
||||
'lasttime' : "SELECT MAX(dateTime) FROM %(table_name)s WHERE dateTime > %(start)s AND dateTime <= %(stop)s AND %(obs_key)s IS NOT NULL",
|
||||
'avg' : "SELECT SUM(wsum),SUM(sumtime) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'rms' : "SELECT SUM(wsquaresum),SUM(sumtime) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'vecavg' : "SELECT SUM(xsum),SUM(ysum),SUM(dirsumtime) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'vecdir' : "SELECT SUM(xsum),SUM(ysum) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'max_ge' : "SELECT SUM(max >= %(val)s) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'max_le' : "SELECT SUM(max <= %(val)s) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'min_le' : "SELECT SUM(min <= %(val)s) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s",
|
||||
'sum_ge' : "SELECT SUM(sum >= %(val)s) FROM %(table_name)s_day_%(obs_key)s WHERE dateTime >= %(start)s AND dateTime < %(stop)s"}
|
||||
|
||||
#===============================================================================
|
||||
# Class DaySummaryManager
|
||||
@@ -1012,14 +1015,23 @@ class DaySummaryManager(Manager):
|
||||
val += ("group_rain",)
|
||||
target_val = weewx.units.convertStd(val, self.std_unit_system)[0]
|
||||
|
||||
# This dictionary is used for interpolating the SQL statement.
|
||||
interDict = {'start' : weeutil.weeutil.startOfDay(timespan.start),
|
||||
'stop' : timespan.stop,
|
||||
'day_key' : obs_type,
|
||||
'aggregateType' : aggregateType,
|
||||
'val' : target_val,
|
||||
'table_name' : self.table_name}
|
||||
# convert to lower-case:
|
||||
aggregateType = aggregateType.lower()
|
||||
|
||||
# Get the dictionary to be used for interpolating the SQL statement.
|
||||
if aggregateType == 'last' or aggregateType == 'lasttime':
|
||||
interDict = {'start' : timespan.start,
|
||||
'stop' : timespan.stop,
|
||||
'obs_key' : obs_type,
|
||||
'table_name' : self.table_name}
|
||||
else:
|
||||
interDict = {'start' : weeutil.weeutil.startOfDay(timespan.start),
|
||||
'stop' : timespan.stop,
|
||||
'obs_key' : obs_type,
|
||||
'aggregateType' : aggregateType,
|
||||
'val' : target_val,
|
||||
'table_name' : self.table_name}
|
||||
|
||||
# Run the query against the database:
|
||||
_row = self.xeqSql(sqlDict[aggregateType], interDict)
|
||||
|
||||
@@ -1034,11 +1046,12 @@ class DaySummaryManager(Manager):
|
||||
_result = None
|
||||
|
||||
# Do the required calculation for this aggregat type
|
||||
elif aggregateType in ['min', 'maxmin', 'max', 'minmax', 'meanmin', 'meanmax', 'maxsum', 'sum', 'gustdir']:
|
||||
elif aggregateType in ['min', 'maxmin', 'max', 'minmax', 'meanmin', 'meanmax',
|
||||
'maxsum', 'sum', 'gustdir', 'last']:
|
||||
# These aggregates are passed through 'as is'.
|
||||
_result = _row[0]
|
||||
|
||||
elif aggregateType in ['mintime', 'maxmintime', 'maxtime', 'minmaxtime', 'maxsumtime',
|
||||
elif aggregateType in ['mintime', 'maxmintime', 'maxtime', 'minmaxtime', 'maxsumtime', 'lasttime',
|
||||
'count', 'max_ge', 'max_le', 'min_le', 'sum_ge']:
|
||||
# These aggregates are always integers:
|
||||
_result = int(_row[0])
|
||||
|
||||
@@ -209,6 +209,14 @@
|
||||
<td>Time of min temperature:</td>
|
||||
<td>07:00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last temperature of the day</td>
|
||||
<td>63.6°F</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Time of the last temperature of the day</td>
|
||||
<td>09/04/10 00:00:00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max Temperature in alt_binding</td>
|
||||
<td>59.3°F</td>
|
||||
|
||||
@@ -209,6 +209,14 @@
|
||||
<td>Time of min temperature:</td>
|
||||
<td>07:00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last temperature of the day</td>
|
||||
<td>17.6°C</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Time of the last temperature of the day</td>
|
||||
<td>09/04/10 00:00:00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max Temperature in alt_binding</td>
|
||||
<td>15.2°C</td>
|
||||
|
||||
@@ -237,6 +237,14 @@
|
||||
<td>Time of min temperature:</td>
|
||||
<td>$day.outTemp.mintime</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last temperature of the day</td>
|
||||
<td>$day.outTemp.last</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Time of the last temperature of the day</td>
|
||||
<td>$day.outTemp.lasttime.format("%x %X")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max Temperature in alt_binding</td>
|
||||
<td>$day($data_binding='alt_binding').outTemp.max</td>
|
||||
|
||||
@@ -100,6 +100,7 @@ agg_group = {'mintime' : "group_time",
|
||||
'maxtime' : "group_time",
|
||||
'minmaxtime' : "group_time",
|
||||
"maxsumtime" : "group_time",
|
||||
"lasttime" : "group_time",
|
||||
'count' : "group_count",
|
||||
'max_ge' : "group_count",
|
||||
'max_le' : "group_count",
|
||||
|
||||
@@ -17,9 +17,16 @@ Allow other databases to be used in images.
|
||||
|
||||
The archive interval can now change within a database without consequences.
|
||||
|
||||
Introduced a new tag $last, which uses the last available timestamp
|
||||
Introduced a new tag $latest, which uses the last available timestamp
|
||||
in a data binding (which may not be the same as the "current" timestamp).
|
||||
|
||||
Introduced a new aggregation type ".last", which returns the last
|
||||
value in an aggregation interval. E.g., $week.outTemp.last would
|
||||
return the last temperature seen in the week.
|
||||
|
||||
Introduced a new aggregation type ".lasttime" which returns
|
||||
the time of the above.
|
||||
|
||||
Total rewrite of how devices are configured. A single utility
|
||||
wee_config_device replaces each of the device-specific
|
||||
configuration utilities.
|
||||
|
||||
@@ -766,12 +766,10 @@ $month.outTemp.max</pre>
|
||||
</p>
|
||||
<p class="indent">
|
||||
<span class="code"><em>aggregation</em></span> is an aggregation type.
|
||||
This is something like '<span class="code">min</span>', '<span
|
||||
class="code">sum</span>', '<span class="code">mintime</span>'. If you
|
||||
If you
|
||||
ask for <span class="code">$month.outTemp.avg</span> you are asking for
|
||||
the <em>average</em> outside temperature for the month. The table <em>
|
||||
<a href="#statistical_types">Statistical Types</a>
|
||||
</em> shows what aggregation types are available for which types.
|
||||
the <em>average</em> outside temperature for the month. Possible
|
||||
aggregation types are given in <a href="#aggregation_types"><i>Appendix: Aggregation types</i></a>.
|
||||
</p>
|
||||
<p class="indent">
|
||||
<span class="code">optional_unit_conversion</span> is an optional unit
|
||||
@@ -787,6 +785,8 @@ $month.outTemp.max</pre>
|
||||
href="#formatting_options">Formatting Options</a></em> below.
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<h3 id="unit_conversion_options">Unit conversion options</h3>
|
||||
<p>The tag <span class="code"><em>optional_unit_conversion</em></span>
|
||||
can be used with either current observations or aggregations. If
|
||||
@@ -4285,7 +4285,134 @@ Options:
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h1 id="units">Appendix: Units</h1>
|
||||
<h1 id="aggregation_types">Appendix: Aggregation types</h1>
|
||||
|
||||
<table class="indent">
|
||||
<caption>
|
||||
<em>Aggregation types</em>
|
||||
</caption>
|
||||
<tbody>
|
||||
<tr class="first_row">
|
||||
<td><em>Aggregation type</em></td>
|
||||
<td>Meaning</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'avg'</td>
|
||||
<td>The average value in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'sum'</td>
|
||||
<td>The sum of values in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'count'</td>
|
||||
<td>The number of non-null values in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'min'</td>
|
||||
<td>The minimum value in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'mintime'</td>
|
||||
<td>The time of the minimum value.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'max'</td>
|
||||
<td>The maximum value in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'maxtime'</td>
|
||||
<td>The time of the maximum value.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'maxmin'</td>
|
||||
<td>The maximum daily minimum in the aggregation period. Aggregation period
|
||||
must be one day or longer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'maxmintime'</td>
|
||||
<td>The time of the maximum daily minimum.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'minmax'</td>
|
||||
<td>The minimum daily maximum in the aggregation period. Aggregation period
|
||||
must be one day or longer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'minmaxtime'</td>
|
||||
<td>The time of the minimum daily maximum.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'maxsum'</td>
|
||||
<td>The maximum daily sum in the aggregation period. Aggregation
|
||||
period must be one day or longer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'maxsumtime'</td>
|
||||
<td>The time of the maximum daily sum.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'meanmin'</td>
|
||||
<td>The average daily minimum in the aggregation period. Aggregation
|
||||
period must be one day or longer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'meanmax'</td>
|
||||
<td>The average daily maximum in the aggregation period. Aggregation
|
||||
period must be one day or longer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'gustdir'</td>
|
||||
<td>The direction of the max gust in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'last'</td>
|
||||
<td>The last value in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'lasttime'</td>
|
||||
<td>The time of the last value in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'max_ge(val)'</td>
|
||||
<td>The number of days where the maximum value is greater than or
|
||||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'max_le(val)'</td>
|
||||
<td>The number of days where the maximum value is less than or
|
||||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'min_le(val)'</td>
|
||||
<td>The number of days where the minimum value is less than or
|
||||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'sum_ge(val)'</td>
|
||||
<td>The number of days where the sum of value is greater than or
|
||||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'rms'</td>
|
||||
<td>The root mean square value in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'vecavg'</td>
|
||||
<td>The vector average magnitude in the aggregation period.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="first_col code">'vecdir'</td>
|
||||
<td>The direction of the average vector.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h1 id="units">Appendix: Units</h1>
|
||||
<p>Weewx offers three different <i>unit systems</i>:</p>
|
||||
|
||||
<table class="indent" style="width: 80%">
|
||||
|
||||
Reference in New Issue
Block a user