StdWXCalculate can now do calculations for only LOOP packets, only archive

records, or both. PR #630.
This commit is contained in:
Tom Keffer
2021-01-06 05:49:46 -08:00
parent b5ca7e15fc
commit 34f401e718
3 changed files with 119 additions and 63 deletions

View File

@@ -1,5 +1,5 @@
#
# Copyright (c) 2009-2020 Tom Keffer <tkeffer@gmail.com>
# Copyright (c) 2009-2021 Tom Keffer <tkeffer@gmail.com>
#
# See the file LICENSE.txt for your full rights.
#
@@ -13,6 +13,7 @@ from __future__ import absolute_import
import logging
import weewx.engine
import weeutil.weeutil
log = logging.getLogger(__name__)
@@ -20,36 +21,55 @@ log = logging.getLogger(__name__)
class StdWXCalculate(weewx.engine.StdService):
def __init__(self, engine, config_dict):
"""Initialize an instance of StdWXXTypes"""
"""Initialize an instance of StdWXCalculate and determine the calculations to be done.
Directives look like:
obs_type = [prefer_hardware|hardware|software], [loop|archive]
where:
obs_type is an observation type to be calculated, such as 'heatindex'
The choice [prefer_hardware|hardware|software] determines how the value is to be
calculated. Option "prefer_hardware" means that if the hardware supplies a value, it will
be used, otherwise the value will be calculated in software.
The choice [loop|archive] indicates whether the calculation is to be done for only LOOP
packets, or only archive records. If left out, it will be done for both.
Examples:
cloudbase = software,loop
The derived type 'cloudbase' will always be calculated in software, but only for LOOP
packets
cloudbase = software, record
The derived type 'cloudbase' will always be calculated in software, but only for archive
records.
cloudbase = software
The derived type 'cloudbase' will always be calculated in software, for both LOOP packets
and archive records"""
super(StdWXCalculate, self).__init__(engine, config_dict)
# determine the calculations to be done and when
#
# create calc_dicts for LOOP and for ARCHIVE holding the calculations
# to be done at those times. the configuration indicates the bindings,
# and thus into which or both calc_dicts that each calculation should
# be placed. no bindings mentioned means 'loop' and 'archive' e.g.
# 'cloudbase = software' same as 'cloudbase = software,loop,archive'
# (backwards compatability with weewx 4.2 configuration files).
# TODO document in User and/or Customisation Guide
#
# Default to no calculations.
#
self.loop_calc_dict = dict() # map {obs->directive} for LOOP
self.archive_calc_dict = dict() # map {obs->directive} for ARCHIVE
for obs, rule in config_dict.get('StdWXCalculate', {}).get('Calculations', {}).items():
# ensure we have a list, not a (possibly comma-separated) string
words = rule if isinstance(rule, list) else rule.split(',')
# canonicalise to trimmed lower case
words = [w.strip().lower() for w in words]
self.loop_calc_dict = dict() # map {obs->directive} for LOOP packets
self.archive_calc_dict = dict() # map {obs->directive} for archive records
# the first word is the directive, the rest are bindings (if any)
if len(words) == 1 or 'loop' in words:
for obs_type, rule in config_dict.get('StdWXCalculate', {}).get('Calculations', {}).items():
# Ensure we have a list:
words = weeutil.weeutil.option_as_list(rule)
# Split the list up into a directive, and (optionally) which bindings it applies to
# (loop or archive).
directive = words[0].lower()
bindings = [w.lower() for w in words[1:]]
if not bindings or 'loop' in bindings:
# no bindings mentioned, or 'loop' plus maybe others
self.loop_calc_dict[obs] = words[0]
if len(words) == 1 or 'archive' in words:
self.loop_calc_dict[obs_type] = directive
if not bindings or 'archive' in bindings:
# no bindings mentioned, or 'archive' plus maybe others
self.archive_calc_dict[obs] = words[0]
self.archive_calc_dict[obs_type] = directive
# Backwards compatibility for configuration files v4.1 or earlier:
self.loop_calc_dict.setdefault('windDir', 'software')
@@ -58,8 +78,8 @@ class StdWXCalculate(weewx.engine.StdService):
self.archive_calc_dict.setdefault('windGustDir', 'software')
if weewx.debug > 1:
log.debug(f"Calculations for LOOP: {self.loop_calc_dict}")
log.debug(f"Calculations for ARCHIVE: {self.archive_calc_dict}")
log.debug("Calculations for LOOP packets: %s", self.loop_calc_dict)
log.debug("Calculations for archive records: %s", self.archive_calc_dict)
# Get the data binding. Default to 'wx_binding'.
data_binding = config_dict.get('StdWXCalculate',

View File

@@ -1,6 +1,12 @@
weewx change history
--------------------
4.4.0 MM/DD/YYYY
StdWXCalculate can now do calculations for only LOOP packets, only archive
records, or both. PR #630. Thanks to user g-eddy!
4.3.0 01/04/2020
Version 4.2.0 had a bug, which caused the sums in the daily summary to be

View File

@@ -2601,7 +2601,7 @@ longitude = -77.0366</pre>
<p>
The service <span class="code">StdWXCalculate</span> can be extended by the user to add new, derived types
using the XTypes system. See the wiki article <a
by using the XTypes system. See the wiki article <a
href="https://github.com/weewx/weewx/wiki/WeeWX-V4-user-defined-types"><em>Extensible types
(XTypes)</em></a> for how to do this.
</p>
@@ -2609,9 +2609,71 @@ longitude = -77.0366</pre>
<h3 class="config_section">[[Calculations]]</h3>
<p>
This subsection specifies which strategy is to be used to provide values for derived variables.
This subsection specifies which strategy is to be used to provide values for derived variables. It consists
of zero or more options with the syntax:
</p>
<pre class="tty"><em>obs_type</em> = <em>directive</em>[, <em>optional_bindings</em>]...</pre>
<p>where</p>
<ul style="list-style-type:none;">
<li>
<p><span class="code"><em>directive</em></span> is one of <span class="code">prefer_hardware</span>,
<span class="code">hardware</span>, or <span class="code">software</span>:
</p>
<table class="indent">
<tr>
<td class="code">prefer_hardware</td>
<td>Calculate the value in software only if it is not provided by hardware.</td>
</tr>
<tr>
<td class="code">hardware</td>
<td>Hardware values only are accepted: never calculate the value in software.</td>
</tr>
<tr>
<td class="code">software</td>
<td>Always calculate the value in software.</td>
</tr>
</table>
</li>
<li>
<span class="code"><em>optional_binding</em></span> is optional, and consists of either <span
class="code">loop</span>, or <span class="code">archive</span>. If <span class="code">loop</span>, then the
calculation will be done only for LOOP packets. If <span class="code">archive</span>, then the calculation
will be done only for archive records. If no binding is specified, then it will be done for both LOOP
packets and archive records.
</li>
</ul>
<p>
Example 1: if your weather station calculates windchill using the pre-2001 algorithm, and you prefer to
have WeeWX calculate it using a modern algorithm, specify the following:
</p>
<pre class="tty">[StdWXCalculate]
[[Calculations]]
windchill = software</pre>
<p>
This will force WeeWX to always calculate a value for <span class="code">windchill</span>, irregardless
of whether the hardware provides one.
</p>
<p>
Example 2: suppose you want ET to be calculated, but only for archive records. The option would look like:
</p>
<pre class="tty">[StdWXCalculate]
[[Calculations]]
ET = software, archive</pre>
<h4>Defaults</h4>
<p class="note">
<b>Note:</b><br/>
In the absence of a <span class="code">[[Calculations]]</span> section, <em>no</em> values will be
calculated. However, the version of <span class="code">weewx.conf</span> that comes with the WeeWX
calculated!
</p>
<p>
However, the version of <span class="code">weewx.conf</span> that comes with the WeeWX
distribution comes with a version of <span class="code">[[Calculations]]</span> that looks like this:
</p>
@@ -2632,38 +2694,6 @@ longitude = -77.0366</pre>
windchill = prefer_hardware
windrun = prefer_hardware</pre>
<p>
The options for each quantity are <span class='code'>hardware</span>, <span class='code'>software</span>, or
<span class='code'>prefer_hardware</span></p>
<table class="indent">
<tr>
<td class="code">hardware</td>
<td>Never calculate the value.</td>
</tr>
<tr>
<td class="code">software</td>
<td>Always calculate the value.</td>
</tr>
<tr>
<td class="code">prefer_hardware</td>
<td>Calculate the value only if it is not provided by hardware.</td>
</tr>
</table>
<p>
For example, if your weather station calculates windchill using the pre-2001 algorithm, and you prefer to
have WeeWX calculate it using a current algorithm, specify the following:
</p>
<pre class="tty">[StdWXCalculate]
[[Calculations]]
windchill = software</pre>
<p>
This will force WeeWX to always calculate a value for <span class="code">windchill</span>, irregardless
of whether the hardware provides one.
</p>
<h3 class="config_section">[[WXXTypes]]</h3>
<p>