Files
weewx/docs/customizing.htm

3615 lines
149 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml">
<!-- $Revision$ -->
<!-- $Author$ -->
<!-- $Date$ -->
<!-- For some reason, the table of contents generator used in this document demands that all
heading elements be on one line. -->
<head>
<meta content="en-us" http-equiv="Content-Language" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Customizing weewx</title>
<!-- CSS -->
<link href="weewx_docs.css" rel="stylesheet" />
<!-- JavaScript -->
<script src="samaxesjs.toc-1.5.min.js" type="text/javascript"></script>
</head>
<body>
<h1 class="title">Customizing weewx<br />
Version 2.2</h1>
<h1>Table of contents</h1>
<div id="technical_content">
<div id="toc">
</div>
<h1 id="Copyright">Copyright</h1>
<p>(c) 2009, 2010, 2011, 2012, 2013 by Tom Keffer &lt;<a href="mailto:tkeffer@gmail.com">tkeffer@gmail.com</a>&gt;
</p>
<p>This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.
</p>
<p>This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
</p>
<p>You should have received a copy of the GNU General Public License along with
this program. If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses</a>.
</p>
<h1 id="Introduction">Introduction</h1>
<p>This document covers the customization of <span class="code">weewx</span>.
It assumes that you have read and are reasonably familiar with the
<a href="usersguide.htm">Users Guide</a>. </p>
<p>It starts with an overview of the architecture of weewx. If you are only
interested in customizing the generated reports you can probably skip the overview
and proceed directly to the section <em>
<a href="#The_Standard_skin_configuration_file">The Standard skin configuration
file</a></em>. With this approach you can easily add new plot images, change
the titles of images, change the units used in the reports, and so on. </p>
<p>However, if your goal is a specialized application, such as adding alarms,
RSS feeds, etc., then it would be worth your while to read about the internal
architecture and how to customize it. </p>
<p>Most of the guide will cover any weather hardware, but the exact data types
are specific to the Davis Vantage series. Unless you are using an unusual type
you are unlikely to run into trouble. </p>
<h2>Warning</h2>
<p><span class="code">weewx</span> is still an experimental system and, as such,
its internal design is subject to change. Be prepared to do updates to any code
or customization you do! </p>
<h2>Overview of the weewx architecture</h2>
<p>At a high-level, <span class="code">weewx</span> consists of an engine class
called <span class="code">StdEngine</span>. It is responsible for loading &quot;<em>services</em>&quot;,
then arranging for them to be called when key events occur, such as the arrival
of LOOP data. The default install of <span class="code">weewx</span> includes
the following services: </p>
<table class="center" style="width: 60%" summary="Overview of the weewx architecture">
<tr>
<td class="text_highlight">Service</td>
<td><strong>Function</strong></td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdConvert</td>
<td>Converts the units of the input to a target unit system (such as
US or Metric).</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdCalibrate</td>
<td>Adjust new LOOP and archive packets using calibration expressions.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdQC</td>
<td>Check quality of incoming data, making sure values fall within a
specified range.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdArchive</td>
<td>Archive any new data to the SQL databases.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdTimeSynch</td>
<td>Arrange to have the clock on the station synchronized at regular
intervals.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdPrint</td>
<td>Print out new LOOP and archive packets on the console.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdRESTful</td>
<td>Start a thread to manage
<a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">
RESTful</a> (simple stateless client-server protocols) connections;
such as those used by the Weather Underground or CWOP.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdReport</td>
<td>Launch a new thread to do report processing after a new archive
record arrives. Reports do things such as generate HTML files, generate
images, or FTP/rsync files to a web server. New reports can be added
easily by the user.</td>
</tr>
</table>
<p>It is easy to extend old services or to add new ones. The source distribution
includes an example new service called &quot;<span class="code">MyAlarm</span>,&quot;
which sends an email when an arbitrary expression evaluates
<span class="code">True</span>. These advanced topics are covered later in the
section <em><a href="#Customizing_the_weewx_service_engine">Customizing the
weewx service engine</a></em>. </p>
<h3 id="The_standard_reporting_service,_StdReportService">The standard reporting
service, <span class="code">StdReport</span></h3>
<p>For the moment, let us focus on the last service, <span class="code">weewx.wxengine.StdReport</span>,
the standard service for creating reports. This will be what most users will
want to customize even if it means changing just a few options. </p>
<h4>Reports</h4>
<p>The Standard Report Service runs zero or more <em>Reports.</em> Which reports
get run is set in the configuration file <span class="code">weewx.conf</span>,
in section <span class="code">[StdReport]</span>. </p>
<p>The default distribution of weewx includes two reports: </p>
<table class="center" style="width: 60%" summary="Standard reports included in weewx">
<tr>
<td class="text_highlight"><strong>Report</strong></td>
<td><strong>Default functionality</strong></td>
</tr>
<tr>
<td class="fixed_highlight">StandardReport</td>
<td>Generates day, week, month and year &quot;to-date&quot; summaries
in HTML, as well as the plot images to go along with them. Also generates
NOAA monthly and yearly summaries. </td>
</tr>
<tr>
<td class="fixed_highlight">FTP</td>
<td>Arranges to upload everything in the <span class="code">public_html</span>
subdirectory up to a remote webserver.</td>
</tr>
<tr>
<td class="fixed_highlight">RSYNC</td>
<td>Like FTP, but uses rsync for transferring files to a remote webserver.</td>
</tr>
</table>
<p>Note that the FTP and RSYNC &quot;reports&quot; are a funny kind of report
in that it they don&#39;t actually generate anything. Instead, they use the
reporting service engine to arrange for things to be transferred to a remote
server. </p>
<h4>Skins</h4>
<p>Each report has a <em>Skin</em> associated with it. For most reports, the
relationship with the skin is an obvious one: it contains the templates, any
auxiliary files such as background GIFs or CSS style sheets, and a <em>skin
configuration file</em>, <span class="code">skin.conf</span>. If you will, the
skin controls the <em>look and feel </em>of the report. Note that more than
one report can use the same skin. For example, you might want to run a report
that uses US Customary units, then run another report against the same skin,
but using metric units and put the results in a different place. All this is
possible by either overriding configuration options in the weewx configuration
file <span class="code">weewx.conf</span> or the skin configuration file
<span class="code">skin.conf</span>. </p>
<p>Like all reports, the FTP and RSYNC &quot;Reports&quot; also use a skin,
and include a skin configuration file, although they are quite minimal. </p>
<p>Skins live in their own subdirectory located in <span class="code"><em>$HTML_ROOT</em>/skins</span>.
</p>
<h4>Generators</h4>
<p>To create their output, skins rely on one or more <em>Generators, </em>code
that actually create useful things such as HTML files or plot images. Generators
can also copy files around or FTP/rsync them to remote locations. The default
install of <span class="code">weewx </span>includes the following generators:
</p>
<table class="center" style="width: 60%" summary="Generators included in weewx">
<tr>
<td class="text_highlight">Generator</td>
<td><strong>Function</strong></td>
</tr>
<tr>
<td class="fixed_highlight">weewx.filegenerator.FileGenerator</td>
<td>Generates files from templates. Used to generate HTML and text files.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.imagegenerator.ImageGenerator</td>
<td>Generates graph plots.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.reportengine.FtpGenerator</td>
<td>Uploads data to a remote server using FTP.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.reportengine.RsyncGenerator</td>
<td>Uploads data to a remote server using rsync.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.reportengine.CopyGenerator</td>
<td>Copies files locally.</td>
</tr>
</table>
<p>Note that the three generators <span class="code">FtpGenerator</span>,
<span class="code">RsyncGenerator</span>, and <span class="code">CopyGenerator</span>
don&#39;t actually generate anything having to do with the presentation layer.
Instead, they just move files around. </p>
<p>Which generators are to be run for a given skin is specified in the skin&#39;s
configuration file <span class="code">skin.conf</span>, in section
<span class="code">[Generators]</span>.</p>
<h2 id="Databases">Databases</h2>
<p>There are two databases used by <span class="code">weewx</span>, which can
be implemented either by using <a href="http://www.sqlite.org/">SQLITE3</a>,
an open-source, lightweight SQL database, or <a href="http://www.mysql.com/">
MySQL</a>, an open-source, full-featured database server, or some combination
of the two of them.</p>
<ul>
<li>The <em>archive database</em>, given symbolic name '<span class="code">archive_database</span>'.
It is a big flat table, one record for each archive interval, keyed by
<span class="code">dateTime</span>, the time at the end of the archive interval.
</li>
<li>The <em>statistical database</em>, given symbolic name '<span class="code">stats_database</span>'.
It consists of a separate table for each observation type (that is, one
for '<span class="code">outTemp</span>', one for '<span class="code">barometer</span>',
etc.), each containing one record per day, keyed by the start time of the
day. </li>
</ul>
<p>How these abstract databases are bound to the real database is covered in
the <a href="usersguide.htm">Weewx User's Guide</a>, in section '<a href="usersguide.htm#[StdArchive]">[StdArchive]</a>'.</p>
<p>The important thing to remember is that the archive database contains a record
for every archive interval and, as such, represents the c<em>urrent conditions</em>
at the time of the observation. By contrast, the statistical database represents
the <em>aggregation of conditions over a day</em>. That is, it contains the
daily minimum, maximum, and the time of the minimum and maximum, for each observation
type. As you can imagine, the statistical database is much smaller because it
represents only a summary of the data. </p>
<p>The archive database is used for both generating plot data and in template
generation (where it appears as tag <span class="code">$current</span>). The
statistical database is used only in template generation (where it appears as
tags <span class="code">$day</span>, <span class="code">$week</span>,
<span class="code">$month</span>, <span class="code">$year</span>, and
<span class="code">$rainyear</span>, depending on the aggregation time period).
</p>
<h1 id="Opportunities_for_customizing_reports">Opportunities for customizing
reports</h1>
<p>This section discusses the two general strategies for customizing reports:
by changing options in one or more configuration file, or by changing the template
files. The former is generally easier, but occasionally the latter is necessary.
</p>
<h2>Changing options</h2>
<p>Changing an option means either modifying the main configuration file
<span class="code">weewx.conf</span>, or the skin configuration file for the
standard skin that comes with the distribution (nominally, file
<span class="code">skins/Standard/skin.conf</span>). </p>
<h3>Changing options in <span class="code">skin.conf</span></h3>
<p>With this approach, the user edits the skin configuration file for the standard
skin that comes with <span class="code">weewx</span>, located in
<span class="code"><em>$WEEWX_ROOT</em>/skins/Standard/skin.conf</span>, using
a text editor. For example, suppose you wish to use metric units in the presentation
layer, instead of the default US Customary Units. The section that controls
units is <span class="code">[Units][[Groups]]</span>. It looks like this:
</p>
<pre>
[Units]
[[Groups]]
group_altitude = foot
group_degree_day = degree_F_day
group_direction = degree_compass
group_moisture = centibar
group_percent = percent
group_pressure = inHg
group_radiation = watt_per_meter_squared
group_rain = inch
group_rainrate = inch_per_hour
group_speed = mile_per_second
group_speed2 = mile_per_second2
group_temperature = degree_F
group_uv = uv_index
group_volt = volt</pre>
<p>&nbsp; </p>
<p>To use metric units, you would edit this section to read: </p>
<pre>
[Units]
[[Groups]]
<span class="highlight"> group_altitude = meter</span>
<span class="highlight"> group_degree_day = degree_C_day </span>
group_direction = degree_compass
group_moisture = centibar
group_percent = percent
<span class="highlight"> group_pressure = mbar</span>
group_radiation = watt_per_meter_squared
<span class="highlight"> group_rain = mm</span>
<span class="highlight"> group_rainrate = mm_per_hour</span>
<span class="highlight"> group_speed = meter_per_second</span>
<span class="highlight"> group_speed2 = meter_per_second2</span>
<span class="highlight"> group_temperature = degree_C</span>
group_uv = uv_index
group_volt = volt</pre>
<p>The options that were changed have been <span class="highlight">highlighted</span>.
Details of the various unit options are given in <em><a href="#Units">Appendix
B: Units</a></em>. </p>
<p>Other options are available, such as changing the text label for various
observation types. For example, suppose your weather console is actually located
in a barn, not indoors, and you want the plot for the temperature at the console
to be labeled &quot;Barn Temperature,&quot; rather than the default &quot;Inside
Temperature.&quot; This can be done by changing the &quot;<span class="code">inTemp</span>&quot;
option located in section <span class="code">[Labels][[Generic]]</span> from
the default </p>
<pre>
[Units]
[[Generic]]
inTemp = Inside Temperature
outTemp = Outside Temperature
...</pre>
<p>to: </p>
<pre>
[Units]
[[Generic]]
<span class="highlight"> inTemp = Barn Temperature</span>
outTemp = Outside Temperature
...</pre>
<h3>Overriding options in <span class="code">skin.conf</span> from
<span class="code">weewx.conf</span></h3>
<p>This approach is very similar, except that instead of changing the skin configuration
file directly, you override its options by editing the main configuration file,
<span class="code">weewx.conf</span>. The advantage of this approach is that
you can use the same skin to produce several different output, each with separate
options. </p>
<p>Revisiting our example, suppose you want two reports, one in US Customary,
the other in Metric. The former will go in the directory <span class="code">
public_html</span>, the latter in a subdirectory, <span class="code">public_html/metric</span>.
If you just simply modify <span class="code">skin.conf</span>, you can get one,
but not both at the same time. Alternatively, you could create a whole new skin
by copying all the files to a new skin subdirectory then editing the new
<span class="code">skin.conf</span>. The trouble with this approach is that
you would then have <em>two</em> skins you would have to maintain. If you change
something, you have to remember to change it in both places. </p>
<p>But, there's a better approach: reuse the same skin, but override some of
its options. Here&#39;s what your <span class="code">[StdReport]</span> section
in <span class="code">weewx.conf</span> would look like: </p>
<pre class="tty">[StdReport]
#
# This section specifies what reports, using which skins, are to be generated.
#
# Where the skins reside, relative to WEEWX_ROOT:
SKIN_ROOT = skins
# Where the generated reports should go, relative to WEEWX_ROOT:
HTML_ROOT = public_html
# This report will use US Customary Units
[[USReport]]
# It&#39;s based on the Standard skin
skin = Standard
# This report will use metric units:
[[MetricReport]]
# It&#39;s also based on the Standard skin:
skin = Standard
# However, override where the results will go and put them in a subdirectory:
HTML_ROOT = public_html/metric
# And override the options that were not in metric units
[[[Units]]]
[[[[Groups]]]]
group_altitude = meter
group_pressure = mbar
group_rain = mm
group_rainrate = mm_per_hour
group_speed = meter_per_second
group_speed2 = meter_per_second2
group_temperature = degree_C
[[FTP]]
...
... (as before) </pre>
<p>We have done two things different from the stock reports. First (1), we&#39;ve
renamed the first report from <span class="code">StandardReport </span>to
<span class="code">USReport </span>for clarity; and (2) we&#39;ve introduced
a new report <span class="code">MetricReport</span>, just like the first, except
it puts its results in a different spot and uses different units. Both use the
same skin, the <span class="code">Standard </span>skin. </p>
<h2 id="Customizing_templates">Customizing templates</h2>
<p>If you cannot achieve the results you need by changing a configuration option,
you may have to modify the templates that come with <span class="code">weewx</span>,
or write your own. </p>
<p>Template modifications are preserved across upgrades (indeed, everything
in the <span class="code">./skins</span> subdirectory is preserved), so you
don't have to worry about losing changes.</p>
<p>Template generation is done using the
<a href="http://www.cheetahtemplate.org/">Cheetah</a> templating engine. This
is a very powerful engine, which essentially lets you have the full semantics
of Python available in your templates. As this would make the templates incomprehensible
to anyone but a Python programmer, <span class="code">weewx</span> adopts a
very small subset of its power. </p>
<p>The key construct is a &#39;dot&#39; code, specifying what value you want.
For example: </p>
<pre class="tty">$month.outTemp.max
$month.outTemp.maxtime
$current.outTemp</pre>
<p>would code the max outside temperature for the month, the time it occurred,
and the current outside temperature, respectively. So, an HTML file that looks
like </p>
<pre class="tty">
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Current conditions&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Current temperature = $current.outTemp&lt;/p&gt;
&lt;p&gt;Max for the month is $month.outTemp.max, which occurred at $month.outTemp.maxtime&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>would be all you need for a very simple HTML page that would display the
text (assuming that the unit group for temperature is <span class="code">degree_F</span>):
</p>
<p class="Example_output">Current temperature = 51.0°F <br />
Max for the month is 68.8°F, which occurred at 07-Oct-2009 15:15 </p>
<p>The format that was used to format the temperature (<span class="code">51.0</span>)
is specified in section <span class="code"><a href="#Units_StringFormats">[Units][[StringFormat]]</a></span>.
The unit label <span class="code">°F</span> is from section
<span class="code"><a href="#[[Labels]]">[Units][[Labels]]</a></span>, while
the time format is from <span class="code"><a href="#TimeFormats">[Labels][[Time]]</a></span>.
</p>
<h3>The dot code</h3>
<p>As we saw above, the dot codes can be very simple: </p>
<pre class="tty">## Output max outside temperature using an appropriate format and label:
$month.outTemp.max</pre>
<p>Most of the time, the dot code will &quot;do the right thing&quot; and is
all you will need. However, <span class="code">weewx</span> offers extensive
customization of the generate output for specialized applications such as XML
RSS feeds, or ridgidly formatted reports (such as the NOAA reports). This section
specifies the various options available. </p>
<p>There are two different versions of the dot code, depending on whether the
data is &quot;current&quot;, or an aggregation over time. However, both versions
are very similar </p>
<h4>Time period <span class="code">$current</span></h4>
<p>Time period <span class="code">$current</span> represents a <em>current observation</em>.
An example would be the current barometric pressure: </p>
<pre>$current.barometer</pre>
<p>The dot code for a current observation looks like: </p>
<pre><em>$current.obstype[.optional_unit_conversion][.optional_formatting]</em></pre>
<p>Where: </p>
<p class="indent"><span class="code"><em>obstype</em></span> is an observation
type, such as <span class="code">barometer</span>. See <em>
<a href="#Archive_types">Appendix A, Archive Types</a></em> for a table of observation
types valid for time period <span class="code">current.</span> </p>
<p class="indent"><span class="code">optional_unit_conversion</span> is an optional
unit conversion tag. If provided, the results will be converted into the specified
units, otherwise the default units specified in the skin configuration file
(in section <span class="code">[Units][[Groups]]</span>) will be used. See the
section <em><a href="#Unit_conversion_options">Unit Conversion Options</a></em>
below. </p>
<p class="indent"><span class="code"><em>optional_formatting</em></span> is
an optional formatting tag that controls how the value will appear. See the
section <em><a href="#Formatting_options">Formatting Options</a></em> below.
</p>
<h4>Aggregation periods <span class="code">$day</span>, <span class="code">$week</span>,
<span class="code">$month</span>, <span class="code">$year</span>,
<span class="code">$rainyear</span></h4>
<p>The other time periods represent an <em>aggregation over time</em>. In addition
to the time period over which the aggregation will occur, they also require
an <em>aggregation type</em>. An example would be the week&#39;s total precipitation
(where the aggregation type is <span class="code"><em>sum</em></span>): </p>
<pre>$week.rain.sum</pre>
<p>The dot code for an aggregation over time looks like: </p>
<pre><em>$period.statstype.aggregation[.optional_unit_conversion][.optional_formatting]</em></pre>
<p>Where: </p>
<p class="indent"><span class="code"><em>period</em></span> is the time period
over which the aggregation is to be done. Possible choices are
<span class="code">day</span>, <span class="code">week</span>,
<span class="code">month</span>, <span class="code">year</span>,
<span class="code">rainyear</span>. </p>
<p class="indent"><span class="code"><em>statstype</em></span> is a statistical
type. See <em><a href="#Statistical_types">Appendix C, Statistical Types</a></em>,
for a table of statistical types. </p>
<p class="indent"><span class="code"><em>aggregation</em></span> is an aggregation
type. This is something like &#39;<span class="code">min</span>&#39;, &#39;<span class="code">sum</span>&#39;, &#39;<span class="code">mintime</span>&#39;.
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">Appendix C: Statistical types</a></em> shows what
aggregation types are available for which types. </p>
<p class="indent"><span class="code">optional_unit_conversion</span> is an optional
unit conversion tag. If provided, the results will be converted into the specified
units, otherwise the default units specified in the skin configuration file
(in section <span class="code">[Units][[Groups]]</span>) will be used. See the
section <em><a href="#Unit_conversion_options">Unit Conversion Options</a></em>
below. </p>
<p class="indent"><span class="code"><em>optional_formatting</em></span> is
an optional formatting tag that controls how the value will appear. See the
section <em><a href="#Formatting_options">Formatting Options</a></em> below.
</p>
<h4 id="Unit_conversion_options">Unit conversion options</h4>
<p>The tag <span class="code"><em>optional_unit_conversion</em></span> can be
used with either current observations or aggregations. If supplied, the results
will be converted to the specified units. For example, if you have set
<span class="code">group_pressure</span> to inches of mercury (<span class="code">inHg</span>),
then the tag </p>
<p class="tty">Today&#39;s average pressure=$day.barometer.avg </p>
<p>would normally give a result such as </p>
<p class="Example_output">Today&#39;s average pressure=30.05 inHg </p>
<p>However, if you add &quot;mbar&quot; to the end, </p>
<p class="tty">$day.barometer.avg.mbar </p>
<p>then the results will be in millibars: </p>
<p class="Example_output">Today&#39;s average pressure=1017.5 mbar </p>
<p>If an inappropriate conversion is asked for, <em>e.g.</em>, </p>
<p class="tty">Today&#39;s average pressure=$day.barometer.degree_C </p>
<p>then the offending tag will be put in the output: </p>
<p class="Example_output">Today&#39;s average pressure=$day.barometer.degree_C
</p>
<p>&nbsp; </p>
<h4 id="Formatting_options">Formatting options</h4>
<p>The tag <span class="code"><em>optional_formatting</em></span> can be used
with either current observations or aggregations. It can be one of: </p>
<table class="center" style="width: 80%" summary="Formatting options">
<tr>
<td class="text_highlight">
<p><strong>Optional formatting tag</strong> </p>
</td>
<td>
<p><strong>Comment</strong> </p>
</td>
</tr>
<tr>
<td class="text_highlight">
<p><em>(no tag)</em> </p>
</td>
<td>
<p>Value is returned as a string, formatted using an appropriate string
format from <span class="code">skin.conf</span>. A unit label from
<span class="code">skin.conf </span>is also attached at the end. </p>
</td>
</tr>
<tr>
<td class="fixed_highlight"><span class="code">.string(<em>NONE_string</em></span>)</td>
<td>Value is returned as a string, formatted using an appropriate string
format from <span class="code">skin.conf</span>. If the value is
<span class="code">None</span>, the string <span class="code">NONE_string</span>
will be substituted if given, otherwise the value for
<span class="code">NONE</span> in <span class="code">
<a href="#Units_StringFormats">[Units][[StringFormats]]</a></span> will
be used. A unit label from <span class="code">skin.conf</span> will
be attached at the end.</td>
</tr>
<tr>
<td class="fixed_highlight"><span class="code">.formatted</span></td>
<td>Value is returned as a string, formatted using an appropriate string
format and <span class="code">None</span> value from
<span class="code">skin.conf</span>. No label.</td>
</tr>
<tr>
<td class="fixed_highlight"><span class="code">.format(<em>string_format</em>, <em>NONE_string</em>)</span></td>
<td>Value is returned as a string, using the string format specified
with <em>string_format</em>. If the value is <span class="code">None</span>,
the string <span class="code">NONE_string</span> will be substituted
if given, otherwise the value for <span class="code">NONE</span> in
<span class="code"><a href="#Units_StringFormats">[Units][[StringFormats]]</a></span>
will be used. A unit label from <span class="code">skin.conf</span>
will be attached at the end.</td>
</tr>
<tr>
<td class="fixed_highlight">.nolabel(string_format, NONE_string)</td>
<td>Value is returned as a string, using the string format specified
with <em>string_format</em>. If the value is <span class="code">None</span>,
the string <span class="code">NONE_string</span> will be substituted
if given, otherwise the value for <span class="code">NONE</span> in
<span class="code"><a href="#Units_StringFormats">[Units][[StringFormats]]</a></span>
will be used. No label will be attached at the end.</td>
</tr>
<tr>
<td class="fixed_highlight">
<p><span class="code">.raw</span> </p>
</td>
<td>Value is returned &quot;as is&quot; without being converted to a
string and without any formatting applied. You must be prepared to deal
with a <span class="code">None</span> value unless the value is converted
directly to a string. In this case, it will be converted to the empty
string (<span class="code">&#39;&#39;</span>)</td>
</tr>
</table>
<p>Summary: </p>
<table class="center" style="width: 80%" summary="Summary of formatting options">
<tr>
<td class="text_highlight"><strong>Formatting tag</strong></td>
<td><strong>Format used</strong></td>
<td><strong>Label Used</strong></td>
<td><strong>NONE string</strong></td>
<td><strong>Returned value</strong></td>
</tr>
<tr>
<td class="text_highlight"><em>(no tag)</em></td>
<td>From <span class="code">skin.conf</span></td>
<td>From <span class="code">skin.conf</span></td>
<td>From <span class="code">skin.conf</span></td>
<td>string</td>
</tr>
<tr>
<td class="fixed_highlight">.string</td>
<td>From <span class="code">skin.conf</span></td>
<td>From <span class="code">skin.conf</span></td>
<td>Optional user-supplied</td>
<td>string</td>
</tr>
<tr>
<td class="fixed_highlight">.formatted</td>
<td>From <span class="code">skin.conf</span></td>
<td>No label</td>
<td>From <span class="code">skin.conf</span></td>
<td>string</td>
</tr>
<tr>
<td class="fixed_highlight">.format</td>
<td>User-supplied</td>
<td>From <span class="code">skin.conf</span></td>
<td>Optional user-supplied</td>
<td>string</td>
</tr>
<tr>
<td class="fixed_highlight">.nolabel</td>
<td>User-supplied</td>
<td>No label</td>
<td>Optional user-supplied</td>
<td>string</td>
</tr>
<tr>
<td class="fixed_highlight">.raw</td>
<td>None</td>
<td>No label</td>
<td>None</td>
<td>native value</td>
</tr>
</table>
<p>Here are some examples with the expected results: </p>
<table class="center" summary="Formatting options with expected results">
<tr>
<td class="text_highlight"><strong>Tag</strong></td>
<td><strong>Result</strong></td>
<td><strong>Comment</strong></td>
</tr>
<tr>
<td class="fixed_highlight">$current.outTemp </td>
<td class="code">45.2°F </td>
<td>String formatting and label from <span class="code">skin.conf</span></td>
</tr>
<tr>
<td class="fixed_highlight">$current.outTemp.string</td>
<td class="code">45.2°F</td>
<td>String formatting and label from <span class="code">skin.conf</span></td>
</tr>
<tr>
<td class="fixed_highlight">$current.UV.string</td>
<td class="code">N/A</td>
<td>This example assumes that the instrument has no UV sensor, resulting
in a <span class="code">None</span> value. The string specified by
<span class="code">NONE</span> in <span class="code">
<a href="#Units_StringFormats">[Units][[StringFormats]]</a></span> is
substituted.</td>
</tr>
<tr>
<td class="fixed_highlight">$current.UV.string(&quot;No UV&quot;)</td>
<td class="code">No UV</td>
<td>This example assumes that the instrument has no UV sensor, resulting
in a <span class="code">None</span> value. The string supplied by the
user is substituted.</td>
</tr>
<tr>
<td class="fixed_highlight">$current.outTemp.formatted </td>
<td class="code">45.2</td>
<td>String formatting from <span class="code">skin.conf</span>; no label</td>
</tr>
<tr>
<td class="fixed_highlight">$current.outTemp.format(&quot;%.3f&quot;) </td>
<td class="code">45.200°F</td>
<td>Specified string format used; label from <span class="code">skin.conf</span>.</td>
</tr>
<tr>
<td class="fixed_highlight">$current.dateTime</td>
<td class="code">02-Apr-2010 16:25</td>
<td>Time formatting and label from <span class="code">skin.conf</span></td>
</tr>
<tr>
<td class="fixed_highlight">$current.dateTime.format(&quot;%H:%M&quot;)</td>
<td class="code">16:25</td>
<td>Specified time format used; label from <span class="code">skin.conf</span>.</td>
</tr>
<tr>
<td class="fixed_highlight">$current.dateTime.raw</td>
<td class="code">1270250700</td>
<td>Unix epoch time, converted to string by template engine.</td>
</tr>
<tr>
<td class="fixed_highlight">$current.outTemp.raw</td>
<td class="code">45.2</td>
<td>Float returned, converted to string by template engine.</td>
</tr>
<tr>
<td class="fixed_highlight">$month.dateTime</td>
<td class="code">01-Apr-2010 00:00</td>
<td>Time formatting and label from <span class="code">skin.conf</span></td>
</tr>
<tr>
<td class="fixed_highlight">$month.outTemp.avg </td>
<td class="code">40.8°F</td>
<td>String formatting and label from <span class="code">skin.conf</span></td>
</tr>
<tr>
<td class="fixed_highlight">$month.outTemp.avg.string</td>
<td class="code">40.8°F</td>
<td>Time formatting and label from <span class="code">skin.conf</span></td>
</tr>
<tr>
<td class="fixed_highlight">$month.UV.avg.string</td>
<td class="code">N/A</td>
<td>This example assumes that the instrument has no UV sensor, resulting
in a <span class="code">None</span> value. The string specified by
<span class="code">NONE</span> in <span class="code">
<a href="#Units_StringFormats">[Units][[StringFormats]]</a></span> is
substituted.</td>
</tr>
<tr>
<td class="fixed_highlight">$month.UV.avg.string(&quot;No UV&quot;)</td>
<td class="code">No UV</td>
<td>This example assumes that the instrument has no UV sensor, resulting
in a <span class="code">None</span> value. The string supplied by the
user is substituted.</td>
</tr>
<tr>
<td class="fixed_highlight">$month.outTemp.avg.formatted </td>
<td class="code">40.8</td>
<td>String formatting from <span class="code">skin.conf</span>; no label</td>
</tr>
<tr>
<td class="fixed_highlight">$month.outTemp.avg.format(&quot;%.3f&quot;)</td>
<td class="code">40.759°F</td>
<td>Specified string format used; no label</td>
</tr>
<tr>
<td class="fixed_highlight">$month.outTemp.avg.raw </td>
<td class="code">40.7589690722</td>
<td>Float returned, converted to string by template engine</td>
</tr>
<tr>
<td class="fixed_highlight">$month.UV.avg.raw</td>
<td class="code"><em>(empty)</em></td>
<td><span class="code">None</span> value converted to empty string by
template engine.</td>
</tr>
</table>
<p>Note: </p>
<ul>
<li>Tags that take an argument (such as <span class="code">.string(NONE_string)</span>)
do not require parenthesis if the argument is omitted.Thus, you can specify
either <span class="code">$month.outTemp.string()</span> or
<span class="code">$month.outTemp.string</span>, if you want the default
value of <span class="code">NONE_string</span>. They produce the same results.
</li>
</ul>
<h3 id="Type_dateTime">Type <span class="code">dateTime</span></h3>
<p>While not an observation type, in many ways the time of an observation,
<span class="code">dateTime</span>, can be treated as one. A tag such as
<span class="code">$current.dateTime</span> represents the <em>current time</em>
(more properly, the time as of the end of the last archive interval). Similarly,
a tag such as <span class="code">$month.dateTime</span> represents the start
time of the month. Like true observation types, explicit formats can be specified,
except that they require a
<a href="http://docs.python.org/library/datetime.html#strftime-strptime-behavior">
strftime() <em>time format</em></a>, rather than a <em>string format:</em>
</p>
<pre>$month.dateTime.format(&quot;%B %Y)</pre>
<p>produces </p>
<pre>January 2010</pre>
<p>The returned string value will always be in <em>local time</em>. </p>
<p>The raw value of <span class="code">dateTime</span> is Unix Epoch Time (number
of seconds since 00:00:00 UTC 1 Jan 1970, <em>i.e.</em>, a large number), which
you must convert yourself to local time. It is guaranteed to never be
<span class="code">None</span>, so you don&#39;t worry have to worry about handling
a <span class="code">None</span> value. </p>
<h3>Tag <span class="code">$trend</span></h3>
<p>The tag <span class="code">$trend</span> is available for time trends, such
as barometer trends. Here are some examples:</p>
<table class="center" style="width: 40%" summary="Examples of using unit formats">
<tr>
<td class="text_highlight"><strong>Tag</strong></td>
<td><strong>Results</strong></td>
</tr>
<tr>
<td class="fixed_highlight">$trend.barometer</td>
<td class="code">-.02 inHg</td>
</tr>
<tr>
<td class="fixed_highlight">$trend.outTemp</td>
<td class="code">1.1 °C</td>
</tr>
<tr>
<td class="fixed_highlight">$trend.time_delta</td>
<td class="code">10800 secs</td>
</tr>
<tr>
<td class="fixed_highlight">$trend.time_delta.hour</td>
<td class="code">3 hrs</td>
</tr>
</table>
<p>Note that the time delta over which the trend is calculated is also available.
This time delta is set by an option in the skin configuration file,
<span class="code"><a href="#[[Trend]]">time_delta</a></span>.</p>
<p>As a summary, the template expression</p>
<p class="tty">&lt;p&gt;The barometer trend over $trend.time_delta.hour is $trend.barometer.format("%+.2f").&lt;/p&gt;</p>
<p>would result in</p>
<p class="Example_output">The barometer trend over 3 hrs is +.02 inHg.</p>
<h3>Tag <span class="code">$unit</span></h3>
<p>The unit type, label, and string formats are also available, allowing you
to do highly customized labels: </p>
<table class="center" style="width: 40%" summary="Examples of using unit formats">
<tr>
<td class="text_highlight"><strong>Tag</strong></td>
<td><strong>Results</strong></td>
</tr>
<tr>
<td class="fixed_highlight">$unit.unit_type.outTemp</td>
<td class="code">degree_C</td>
</tr>
<tr>
<td class="fixed_highlight">$unit.label.outTemp</td>
<td class="code">°C</td>
</tr>
<tr>
<td class="fixed_highlight">$unit.format.outTemp</td>
<td class="code">%.1f</td>
</tr>
</table>
<p>As a summary, the tag </p>
<pre>$day.outTemp.max.formatted$unit.label.outTemp</pre>
<p>would result in </p>
<pre>21.2°C</pre>
<p>(assuming metric values have been specified for <span class="code">group_temperature</span>),
essentially reproducing the results of the simpler tag <span class="code">$day.outTemp.max</span>.
</p>
<h3>Iteration</h3>
<p>For dot codes using an aggregation (<em>e.g.</em>, <span class="code">$day</span>,
<span class="code">$week</span>, <span class="code">$month</span>,
<span class="code">$year</span>, <span class="code">$rainyear</span>, then the
aggregation period can be iterated over by day or month. These are the only
two iteration periods available as of this version. </p>
<p>This example uses a Cheetah &#39;<span class="code">for</span>&#39; loop
to iterate over all months in a year, printing out each month&#39;s min and
max temperature (the iteration loop is highlighted): </p>
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Year stats by month&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Min, max temperatures by month:&lt;/p&gt;
<span class="highlight"> #for $month in $year.months</span>
&lt;p&gt;$month.dateTime.format(&quot;%B&quot;): Min, max temperatures: $month.outTemp.min $month.outTemp.max&lt;/p&gt;
<span class="highlight"> #end for </span>
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Produces results: </p>
<pre class="tty">
Min, max temperatures by month:
January: Min, max temperatures: 30.1°F 51.5°F
February: Min, max temperatures: 24.4°F 58.6°F
March: Min, max temperatures: 27.3°F 64.1°F
April: Min, max temperatures: 33.2°F 52.5°F
May: Min, max temperatures: N/A N/A
June: Min, max temperatures: N/A N/A
July: Min, max temperatures: N/A N/A
August: Min, max temperatures: N/A N/A
September: Min, max temperatures: N/A N/A
October: Min, max temperatures: N/A N/A
November: Min, max temperatures: N/A N/A
December: Min, max temperatures: N/A N/A</pre>
<p>See the NOAA template files <span class="code">NOAA/NOAA-YYYY.txt.tmpl</span>
and <span class="code">NOAA/NOAA-YYYY-MM.txt.tmpl</span> for examples using
iteration, as well as explicit formatting. </p>
<h3>Almanac</h3>
<p>If module <a href="http://rhodesmill.org/pyephem">pyephem</a> has been installed,
then <span class="code">weewx</span> can generate extensive almanac information
for the Sun, Moon, Venus, Mars, Jupiter, and other heavenly bodies, including
their rise, transit and set times, as well as their azimuth and altitude. Other
information is also available. </p>
<p>Here is a small sampling: </p>
<pre class="tty">
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Almanac data&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Current time is $current.dateTime&lt;p&gt;
#if $almanac.hasExtras
&lt;p&gt;Sunrise, transit, sunset: $almanac.sun.rise $almanac.sun.transit $almanac.sun.set&lt;/p&gt;
&lt;p&gt;Moonrise, transit, moonset: $almanac.moon.rise $almanac.moon.transit $almanac.moon.set&lt;/p&gt;
&lt;p&gt;Mars rise, transit, set: $almanac.mars.rise $almanac.mars.transit $almanac.mars.set&lt;/p&gt;
&lt;p&gt;Azimuth, altitude of mars: $almanac.mars.az $almanac.mars.alt&lt;/p&gt;
&lt;p&gt;Next new, full moon: $almanac.next_new_moon $almanac.next_full_moon&lt;/p&gt;
&lt;p&gt;Next summer, winter solstice: $almanac.next_summer_solstice $almanac.next_winter_solstice&lt;/p&gt;
#else
&lt;p&gt;Sunrise, sunset: $almanac.sunrise $almanac.sunset&lt;/p&gt;
#end if
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>If your installation has pyephem installed this would result in: </p>
<pre class="tty">
Current time is 29-Mar-2011 09:20
Sunrise, transit, sunset: 06:51 13:11 19:30
Moonrise, transit, moonset: 04:33 09:44 15:04
Mars rise, transit, set: 06:35 12:30 18:26
Azimuth, altitude of mars: 124.354959275 26.4808431952
Next new, full moon: 03-Apr-2011 07:32 17-Apr-2011 19:43
Next summer, winter solstice: 21-Jun-2011 10:16 21-Dec-2011 21:29</pre>
<p>Otherwise, a fallback position is used, resulting in </p>
<pre class="tty">
Current time is 29-Mar-2011 09:20
Sunrise, sunset: 06:51 19:30</pre>
<p>As shown in the example, you can test whether this extended almanac information
is available with the value <span class="code">$almanac.hasExtras</span>.
</p>
<p>The almanac information falls in two categories:</p>
<ul>
<li>Calendar events</li>
<li>Heavenly bodies</li>
</ul>
<p>We will cover each of these separately.</p>
<h4>Calendar events</h4>
<p>"Calendar events" do not require a heavenly body. They cover things such
as "<span class="code">next_solstice</span>", or "<span class="code">next_first_quarter_moon</span>".
The syntax here is </p>
<pre class="tty">$almanac.next_solstice </pre>
<p>or </p>
<pre class="tty">$almanac.next_first_quarter_moon</pre>
<p>&nbsp;Here's a table of the information that falls into this category:</p>
<table class="code" style="width: 60%">
<tr>
<td>previous_equinox</td>
<td>next_equinox</td>
<td>previous_solstice</td>
<td>next_solstice</td>
</tr>
<tr>
<td>previous_autumnal_equinox</td>
<td>next_autumnal_equinox</td>
<td>previous_vernal_equinox</td>
<td>next_vernal_equinox</td>
</tr>
<tr>
<td>previous_winter_solstice</td>
<td>next_winter_solstice</td>
<td>previous_summer_solstice</td>
<td>next_summer_solstice</td>
</tr>
<tr>
<td>previous_new_moon</td>
<td>next_new_moon</td>
<td>previous_first_quarter_moon</td>
<td>next_first_quarter_moon</td>
</tr>
<tr>
<td>previous_full_moon</td>
<td>next_full_moon</td>
<td>previous_last_quarter_moon</td>
<td>next_last_quarter_moon</td>
</tr>
</table>
<h4>Heavenly bodies</h4>
<p>The second category does require a heavenly body. This covers queries such
as, "When does Jupiter rise?" or, "When does the sun transit?" Examples are</p>
<p class="tty">$almanac.jupiter.rise</p>
<p>or</p>
<p class="tty">$almanac.sun.transit</p>
<p>To accurately calculate these times, <span class="code">weewx</span> automatically
uses the present temperature and pressure to calculate refraction effects. However,
you can override these values, which will be necessary if you wish to match
the almanac times published by the Naval Observatory
<a href="http://rhodesmill.org/pyephem/rise-set.html">as explained in the pyephem
documentation</a>. For example, to match the sunrise time as published by the
Observatory, instead of</p>
<p class="tty">$almanac.sun.rise</p>
<p>use</p>
<p class="tty">$almanac(pressure=0, horizon=-34.0/60.0).sun.rise</p>
<p>By setting pressure to zero we are bypassing the refraction calculations
and manually setting the horizon to be 34 arcminutes lower than the normal horizon.
This is what the Navy uses.</p>
<p>If you wish to calculate the start of civil twilight, you can set the horizon
to -6, and also tell <span class="code">weewx</span> to use the center of the
sun (instead of the upper limb, which it normally uses) to do the calcuation:</p>
<p class="tty">$almanac(pressure=0, horizon=-6.sun(use_center=1).rise</p>
<p>The general syntax is:</p>
<p class="tty">$almanac(pressure=<em>pressure</em>, horizon=<em>horizon</em>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; temperature=<em>temperature_C</em>).<em>heavenly_body</em>(use_center=[01]).<em>attribute</em></p>
<p>As you can see, in addition to the horizon angle, you can also override atmospheric
pressure and temperature (degrees Celsius).</p>
<p>PyEphem offers an extensive list of objects that can be used for the
<span class="code"><em>heavenly_body</em></span> tag. All the planets and many
stars are in the list.&nbsp;</p>
<p>The <span class="code">attribute</span> tag can be one of </p>
<table class="code" style="width: 60%">
<tr>
<td>az</td>
<td>alt</td>
<td>a_ra</td>
<td>a_dec</td>
</tr>
<tr>
<td>g_ra</td>
<td>ra</td>
<td>g_dec</td>
<td>dec</td>
</tr>
<tr>
<td>elong</td>
<td>radius</td>
<td>hlong</td>
<td>hlat</td>
</tr>
<tr>
<td>sublat</td>
<td>sublong</td>
<td>next_rising</td>
<td>next_setting</td>
</tr>
<tr>
<td>next_transit</td>
<td>next_antitransit</td>
<td>previous_rising</td>
<td>previous_setting</td>
</tr>
<tr>
<td>previous_transit</td>
<td>previous_antitransit</td>
<td>rise</td>
<td>set</td>
</tr>
<tr>
<td>transit</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
<h2>Writing a custom generator</h2>
<p>To do more sophisticated customization it may be necessary to extend an existing
generator, or write your own. </p>
<h4 id="Extending_an_existing_generator">Extending an existing report generator</h4>
<p>In the section on <em><a href="#Customizing_templates">Customizing templates</a></em>,
we have seen how you can change a template and make use of the various tags
available such as <span class="code">$day.outTemp.max</span> for the maximum
outside temperature for the day. But, what if you want to introduce some new
data for which no tag is available? </p>
<p>If you wish to introduce a static tag, that is, one that will not change
with time (such as a Google analytics Tracker ID, or your name), then this is
very easy: simply put it in section <span class="code"><a href="#[Extras]">[Extras]</a></span>
in the skin configuration file. More information on how to do this can be found
there. </p>
<p>But, what if you wish to introduce a more dynamic tag, one that requires
some calculation, or that uses the database? Simply putting it in the
<span class="code">[Extras]</span> section won&#39;t do, because then it cannot
change. </p>
<p>The answer is to extend the default file generator<span class="code"> weewx.filegenerator.FileGenerator</span>
by subclassing, then override the function that returns the <em>search list</em>.
The search list is a list of dictionaries that the template engine searches
through, trying all keys in each dictionary, looking for a match for your tag.
For example, for the &quot;ToDate&quot; generator, you would override function
<span class="code">getToDateSearchList()</span>, and add a small dictionary
with your tag as the key to the list returned by the superclass. </p>
<p>Let's look at an example. The regular version of <span class="code">weewx</span>
offers statistical summaries by day, week, month, and year. Suppose we would
like to add two more: </p>
<ul>
<li>All-time statistics. This would allow us to display statistics such
as the all-time high or low temperature seen at your station;</li>
<li>Seven days statistics. While <span class="code">weewx</span> offers
the tag <span class="code">$week</span>, this is statistics <em>since Sunday
at midnight</em>. We would like to have statistics for a full week, that
is since midnight seven days ago.</li>
</ul>
<p>This example is included in the distribution as <span class="code">bin/examples/mygenerator.py</span>:
</p>
<pre class="tty">
import datetime
import time
from weewx.filegenerator import FileGenerator
from weewx.stats import TimeSpanStats
from weeutil.weeutil import TimeSpan
class MyFileGenerator(FileGenerator): # 1
def getToDateSearchList(self, archivedb, statsdb, valid_timespan): # 2
# First, get a TimeSpanStats object for all time. This one is easy
# because the object valid_timespan already holds all valid times to be
# used in the report.
all_stats = TimeSpanStats(valid_timespan,
statsdb,
formatter=self.formatter,
converter=self.converter) # 3
# Now get a TimeSpanStats object for the last seven days. This one we
# will have to calculate. First, calculate the time at midnight, seven
# days ago. The variable week_dt will be an instance of datetime.date.
week_dt = datetime.date.fromtimestamp(valid_timespan.stop) - datetime.timedelta(weeks=1) # 4
# Now convert it to unix epoch time:
week_ts = time.mktime(week_dt.timetuple()) # 5
# Now form a TimeSpanStats object, using the time span we just calculated:
seven_day_stats = TimeSpanStats(TimeSpan(week_ts, valid_timespan.stop),
statsdb,
formatter=self.formatter,
converter=self.converter) # 6
# Get the superclass's search list:
search_list = FileGenerator.getToDateSearchList(self, archivedb, statsdb, valid_timespan) # 7
# Now tack on my two additions as a small dictionary with keys 'alltime' and 'seven_day':
search_list += [ {'alltime' : all_stats,
'seven_day' : seven_day_stats} ] # 8
return search_list</pre>
<p>Going through the example, line by line: </p>
<ol>
<li>Subclass from class <span class="code">FileGenerator</span>. The new
class will be caled <span class="code">MyFileGenerator</span> </li>
<li>Override member function <span class="code">getToDateSearchList()</span>.
The parameters that will be passed in are:
<ul>
<li><span class="code">self</span> Python's way of indicating the instance
we are working with;</li>
<li><span class="code">archivedb</span> An instance of
<span class="code">weewx.archive.Archive</span>, holding the archive
database;</li>
<li><span class="code">statsdb</span> An instance of
<span class="code">weewx.stats.StatsDb</span>, holding the statistical
database;</li>
<li><span class="code">valid_timespan</span> An instance of the utility
class <span class="code">TimeSpan</span>. This will contain the valid
start and ending times of the &quot;to date&quot; summary period; nominally
all possible times. </li>
</ul>
</li>
<li>The class <span class="code">TimeSpanStats</span> represents a statistical
calculation over a time period. In our case, we will set it up to represent
the statistics over all possible times. The class takes 4 parameters.
<ul>
<li>The first is the timespan over which the calculation is to be done.
Here, we have a lucky coincidence: the variable <span class="code">valid_timespan</span>
already holds a <span class="code">TimeSpan</span> object representing
the domain of valid timespans, so we simply pass it in.</li>
<li>The second is the statistical database the calculation is to be
run against. We simply pass in <span class="code">statsdb</span>.</li>
<li>The third should be an instance of class <span class="code">weewx.units.Formatter</span>,
which contains information about how the results should be formatted.
We just pass in the formatter set up by our superclass,
<span class="code">self.formatter</span>.</li>
<li>The fourth should be an instance of <span class="code">weewx.units.Converter</span>,
which contains information about the target units (<em>e.g.</em>, &quot;<span class="code">degree_C</span>&quot;)
that are to be used. Again, we just pass in the instance set up by our
superclass, <span class="code">self.converter</span>.</li>
</ul>
</li>
</ol>
<p>That one was relatively easy because we already had an instance of
<span class="code">TimeSpan</span>, <span class="code">valid_timespan</span>,
that represented the time over which we wanted to do the calculations. Setting
up an instance that will work for the last seven days is a bit trickier. Continuing
our example...</p>
<ol start="4">
<li>The object <span class="code">valid_timespan</span> holds the domain
of valid times, but we need not the time of the report, which will be
<span class="code">valid_timespan.stop</span>, but the time at midnight
seven days ago. So, we do a little Python date arithmetic to calculate this.
The object <span class="code">week_dt</span> will be an instance of
<span class="code">datetime.date</span>.</li>
<li>We convert it to unix epoch time.</li>
<li>Now we are ready to initialize an appropriate <span class="code">TimeSpanStats</span>
object. It's the same as in step #3, except we use our new timespan object.</li>
<li>Get the search list from the superclass. </li>
<li>Tack on our addition and return the results. The search list will now
consist of a list of dictionaries, including a small one we added on the
end that has two keys, &#39;<span class="code">alltime</span>', and '<span class="code">seven_day</span>'.
If one of these keys is used, the appropriate <span class="code">TimeSpanStats</span>
object will be returned.</li>
</ol>
<p>With this approach, you can now include &quot;all time&quot; or "seven day"
statistics in your HTML templates: </p>
<pre class="tty">
...
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;Maximum temperature to date: &lt;/td&gt;
&lt;td&gt;$alltime.outTemp.max&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimum temperature to date: &lt;/td&gt;
&lt;td&gt;$alltime.outTemp.min
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rain over the last seven days: &lt;/td&gt;
&lt;td&gt;$seven_day.rain.sum
&lt;/tr&gt;
... (more table entries)</pre>
<p>One additonal step is required: to tell the report service to run your generator
instead of the default generator. Modify option <span class="code">[Generators]generator_list</span>
in the skin configuration file <span class="code">skin.conf</span> to read:
</p>
<pre>generator_list = examples.mygenerator.MyFileGenerator, weewx.imagegenerator.ImageGenerator, weewx.reportengine.CopyGenerator</pre>
<p>NB: If you create a custom generator some place other than where
<span class="code">weewxd.py</span> resides, you may have to specify its location
in the environment variable <span class="code">PYTHONPATH</span>: </p>
<pre>export PYTHONPATH=/home/me/secret_location</pre>
<h2>Upgrades and user extensions</h2>
<p>In the examples above, we subclassed <span class="code">weewx</span> classes
to add functionality. Where should you put your new code? If you simply modify
the examples in place, then your changes will get overwritten the next time
you do an upgrade, forcing you to cut and paste any changes you have made.
</p>
<p>A better idea is to copy over the examples to the subdirectory
<span class="code"><em>$WEEWX_ROOT</em>/bin/user</span>, then modify them there.
This subdirectory is preserved through upgrades, so you won&#39;t have to redo
any changes you might have made. </p>
<h1 id="The_Standard_skin_configuration_file">Reference: The Standard skin configuration
file</h1>
<p>This section is a reference to the options appearing in the Standard skin
configuration file, found in <span class="code"><em>$WEEWX_ROOT</em>/skins/Standard/skin.conf</span>.
</p>
<p>It is worth noting that, like the main configuration file
<span class="code">weewx.conf</span>, UTF-8 is used throughout. The most important
options are up near the top of the file.&nbsp; The truly important ones, the
ones you are likely to have to customize for your station, are shown in
<span class="bold_n_blue"><strong>bold face and in blue</strong></span>. </p>
<h2 id="[Extras]" class="config_section">[Extras]</h2>
<p>This section is available to you to add any static tags that you might want
to be available in the templates. As an example, the stock
<span class="code">skin.conf</span> file includes two options:
<span class="code">radar_url</span>, which is available as tag
<span class="code">$Extras.radar_url</span>, and <span class="code">googleAnalyticsId</span>,
available as tag <span class="code">$Extras.googleAnalyticsId</span>. If you
take a look at the template <span class="code">index.html.tmpl</span> you will
see examples of testing for these tags (search the file for the string
<span class="code">radar_url</span> or <span class="code">googleAnalyticsId</span>
to find them). </p>
<p class="config_option">radar_url </p>
<p>If set, the NOAA radar image will be displayed. If commented out, no image
will be displayed. </p>
<p class="config_option">googleAnalyticsId </p>
<p>If you have a <a href="http://www.google.com/analytics/">Google Analytics
ID</a>, you can set it here. The Google Analytics Javascript code will then
be included, enabling analytics of your website usage. If commented out, the
code will not be included. </p>
<h4>Extending <span class="code">[Extras]</span></h4>
<p>Other tags can be added in a similar manner, including subsections. For example,
say you have added a video camera and you would like to add a still image with
a hyperlink to a page with the video. You want all of these options to be neatly
contained in a subsection. </p>
<pre>
[Extras]
[[video]]
still = video_capture.jpg
hyperlink = <a href="http://www.eatatjoes.com/video.html">http://www.eatatjoes.com/video.html</a></pre>
<p>Then in your template you could refer to these as: </p>
<pre>
&lt;a href=&quot;$Extras.video.hyperlink&quot;&gt;
&lt;img src=&quot;$Extras.video.still&quot; alt=&quot;Video capture&quot;/&gt;
&lt;/a&gt;</pre>
<h2 class="config_section">[Units]</h2>
<p>This section deals with Units and their formatting. </p>
<h3 class="config_section">[[Groups]]</h3>
<p>This subsection lists all the <em>Unit Groups</em> and specifies which unit
system is to be used for each one of them. </p>
<p>As there are many different observational measurement types (such as &#39;<span class="code">outTemp</span>&#39;, &#39;<span class="code">barometer</span>&#39;,
etc.) used in <span class="code">weewx</span> (more than 50 at last count),
it would be tedious, not to say possibly inconsistent, to specify a different
measurement system for each one of them. At the other extreme, requiring all
of them to be &quot;U.S. Customary&quot; or &quot;Metric&quot; seems overly
restrictive. <span class="code">Weewx</span> has taken a middle route and divided
all the different observation types into 12 different &quot;<em>unit groups</em>.&quot;
A unit group is something like &quot;<span class="code">group_temperature</span>.&quot;
It represents the measurement system to be used by all observation types that
are measured in temperature, such as inside temperature (type &#39;<span class="code">inTemp</span>&#39;),
outside temperature (&#39;<span class="code">outTemp</span>&#39;), dewpoint
(&#39;<span class="code">dewpoint</span>&#39;), wind chill (&#39;<span class="code">windchill</span>&#39;),
and so on. If you decide that you want unit group <span class="code">group_temperature</span>
to be measured in &quot;<span class="code">degree_C</span>&quot; then you are
saying <em>all</em> members of its group will be reported in degrees Celsius.
</p>
<p>Note that the unit system is always specified in the singular. That is, specify &quot;<span class="code">degree_C</span>&quot;
or &quot;<span class="code">foot</span>&quot;, not &quot;<span class="code">degrees_C</span>&quot;
or &quot;<span class="code">feet</span>&quot;. See the Appendix <em>
<a href="#Units">Units</a></em> for more information, including a concise summary
of the groups, their members, and which options can be used for each group.
</p>
<p class="config_important"><a class="config_option" name="group_altitude">group_altitude</a>
</p>
<p>Which measurement unit to be used for altitude. Possible options are &#39;<span class="code">foot</span>&#39;
or &#39;<span class="code">meter</span>&#39;. </p>
<p class="config_option">group_direction </p>
<p>Which measurement unit to be used for direction. The only option is &quot;<span class="code">degree_compass</span>&quot;.
</p>
<p class="config_option">group_moisture </p>
<p>The measurement unit to be used for soil moisture. The only option is &quot;<span class="code">centibar</span>.&quot;
</p>
<p class="config_option">group_percent </p>
<p>The measurement unit to be used for percentages. The only option is &quot;<span class="code">percent</span>&quot;.
</p>
<p class="config_important">group_pressure </p>
<p>The measurement unit to be used for pressure. Possible options are one of &quot;<span class="code">inHg</span>&quot;
(inches of mercury), &quot;<span class="code">mbar</span>&quot;, or &quot;<span class="code">hPa</span>.&quot;
</p>
<p class="config_option">group_radiation </p>
<p>The measurement unit to be used for radiation. The only option is &quot;<span class="code">watt_per_meter_squared</span>.&quot;
</p>
<p class="config_important">group_rain </p>
<p>The measurement unit to be used for precipitation. Options are &quot;<span class="code">inch</span>&quot;, &quot;<span class="code">cm</span>,&quot;
or &quot;<span class="code">mm</span>.&quot; </p>
<p class="config_important">group_rainrate </p>
<p>The measurement unit to be used for rate of precipitation. Possible options
are one of &quot;<span class="code">inch_per_hour</span>&quot;, &quot;<span class="code">cm_per_hour</span>&quot;,
or &quot;<span class="code">mm_per_hour</span>&quot;. </p>
<p class="config_important">group_speed </p>
<p>The measurement unit to be used for wind speeds. Possible options are one
of &quot;<span class="code">mile_per_hour</span>&quot;, &quot;<span class="code">km_per_hour</span>&quot;, &quot;<span class="code">knot</span>&quot;,
or &quot;<span class="code">meter_per_second</span>.&quot; </p>
<p class="config_important">group_speed2 </p>
<p>This group is similar to <span class="code">group_speed</span>, but is used
for calculated wind speeds which typically have a slightly higher resolution.
Possible options are one &quot;<span class="code">mile_per_hour2</span>&quot;, &quot;<span class="code">km_per_hour2</span>&quot;, &quot;<span class="code">knot2</span>&quot;,
or &quot;<span class="code">meter_per_second2</span>&quot;. </p>
<p><a class="config_important" name="group_temperature">group_temperature</a>
</p>
<p>The measurement unit to be used for temperatures. Options are &quot;<span class="code">degree_F</span>&quot;
or &quot;<span class="code">degree_C</span>.&quot; </p>
<p class="config_option">group_volt </p>
<p>The measurement unit to be used for voltages. The only option is &quot;<span class="code">volt</span>.&quot;
</p>
<h3 id="Units_StringFormats" class="config_section">[[StringFormats]]</h3>
<p>This sub-section is used to specify what string format is to be used for
each unit when a quantity needs to be converted to a string. Typically, this
happens with y-axis labeling on plots and for statistics in HTML file generation.
For example, the options </p>
<pre>
degree_C = %.1f
inch = %.2f</pre>
<p>would specify that the given string formats are to be used when formatting
any temperature measured in degrees Celsius or any precipitation amount measured
in inches, respectively. The
<a href="http://docs.python.org/library/string.html#format-specification-mini-language">
formatting codes are those used by Python</a>, a, and are very similar to C&#39;s
<span class="code">sprintf()</span> codes. </p>
<p>You can also specify what string to use for an invalid or unavailable measurement
(value &#39;<span class="code">None</span>&#39;). For example, </p>
<pre>NONE = &quot; N/A &quot;</pre>
<h3 id="[[Labels]]" class="config_section">[[Labels]]</h3>
<p>This subsection specifies what label is to be used for each measurement unit
type. For example, the options </p>
<pre>
degree_F = °F
inch = &#39; in&#39;</pre>
<p>would cause all temperatures to have unit labels &#39;<span class="code">°F</span>&#39;
and all precipitation to have labels&nbsp; &#39;<span class="code"> in</span>&#39;.
If any special symbols are to be used (such as the degree sign above) they should
be encoded in UTF-8. This is generally what most text editors use if you cut-and-paste
from a character map. Labels used in plot images will be converted to Latin-1
first (this is all the Python Imaging Library can handle). </p>
<h3 id="TimeFormats" class="config_section">[[TimeFormats]]</h3>
<p>This sub-section is used for time labels. It uses
<a href="http://docs.python.org/library/datetime.html#strftime-behavior">strftime()</a>
formats. For example </p>
<pre>
week = %H:%M on %A
month = %d-%b-%Y %H:%M</pre>
<p>would specify that week data should use a format such as &quot;<span class="code">15:20
on Sunday</span>&quot;, while month data should look like &quot;<span class="code">06-Oct-2009
15:20</span>&quot; </p>
<p>It also allows the formatting to be set for almanac times: </p>
<pre>
ephem_day = %H:%M
ephem_year = %d-%b-%Y %H:%M</pre>
<p>The first of these, <span class="code">ephem_day</span>, is used for almanac
times within the day, such as sunrise or sunset. The second,
<span class="code">ephem_year</span>, is used for almanac times within the year,
such as the next equinox or full moon. </p>
<h3 class="config_section">[[DegreeDays]]</h3>
<p class="config_important">heating_base <br />
cooling_base </p>
<p>Set to the base temperature for calculating heating and cooling degree-days,
along with the unit to be used. Examples:</p>
<pre>
heating_base = 65.0, degree_F
cooling_base = 20.0, degree_C</pre>
<h3 id="[[Trend]]" class="config_section">[[Trend]]</h3>
<p class="config_option">time_delta</p>
<p>Set to the time difference over which you want trends to be calculated. The
default is 3 hours.</p>
<h2 class="config_section">[Labels]</h2>
<p>This section sets the various labels to use. </p>
<p class="config_option">hemispheres </p>
<p>Comma separated list for the labels to be used for the four hemispheres.
The default is &quot;<span class="code">N, S, E, W</span>&quot;. </p>
<h3 class="config_section">[[Generic]]</h3>
<p>This sub-sections specifies default labels to be used for each SQL type.
For example, options </p>
<pre>
inTemp = Temperature inside the house
outTemp = Outside Temperature</pre>
<p>would cause the given labels to be used for plots involving SQL types
<span class="code">inTemp </span>and <span class="code">outTemp</span>. </p>
<h2 class="config_section">[Almanac]</h2>
<p>This section controls what text to use for the almanac. It consists of only
one entry </p>
<p class="config_option">moon_phases </p>
<p>This option is a comma separated list of labels to be used for the eight
phases of the moon. Default is &quot;<span class="code">New, Waxing crescent,
First quarter, Waxing gibbous, Full, Waning gibbous, Last quarter, Waning crescent</span>&quot;.
</p>
<h2 class="config_section">[FileGenerator]</h2>
<p>This section is used by generator <span class="code">weewx.reportengine.FileGenerator</span>
and controls text generation from templates, specifically which files are to
be produced from which template. </p>
<h3>Overview of file generation</h3>
<p>Customization of file generation consists of playing with the various options
offered below and, failing that, modifying the template files that come with
the distribution. </p>
<p>Each template file is named something like <span class="code"><em>D/F.E.tmpl</em></span>,
where <span class="code">D</span> is the subdirectory the template sits in and
will also be the subdirectory the results will be put in, and
<span class="code">F.E</span> is the generated file name. So, given a template
file with name <span class="code">Acme/index.html.tmpl</span>, the results will
be put in <span class="code"><em>$HTML_ROOT</em>/Acme/index.html</span>. </p>
<p>The skin that comes with the standard distribution of <span class="code">
weewx</span> contains three different kinds of generated output: </p>
<ol>
<li>Summary by month. In addition to the naming rules above, if the template
file has the letters <span class="code">YYYY</span> and
<span class="code">MM</span> in its name, these will be substituted for
the year and month, respectively. So, a template with the name
<span class="code">summary-YYYY-MM.html.tmpl</span> would have name
<span class="code">summary-2010-03.html</span> for the month of March, 2010.
The default distribution has been set up to produce NOAA monthly summaries,
one for each month, as a simple text file (no HTML). </li>
<li>Summary by year.&nbsp; In addition to the naming rules above, if the
template file has the letters <span class="code">YYYY</span> in its name,
the year will be substituted. The default distribution has been set up to
produce NOAA yearly summaries, one for each year, as a simple text file
(no HTML). </li>
<li>Summary &quot;To Date&quot;. The default distribution has been set up
to produce reports for the day, week, month, and year-to-date observations.
These four files are all HTML files. The first, the daily summary (output
file i<span class="code">ndex.html</span>), includes a drop-down list that
allows the NOAA month and yearly summaries to be displayed. </li>
</ol>
<h3>General</h3>
<p class="config_option">encoding </p>
<p>This option controls which encoding is to be used for the generated output.
There are 3 possible choices: </p>
<table class="center" style="width: 60%">
<tr>
<td class="text_highlight">Encoding</td>
<td><strong>ComComments</strong></td>
</tr>
<tr>
<td class="fixed_highlight">html_entities</td>
<td>Non 7-bit characters will be represented as HTML entities (<em>e.g.</em>
the degree sign will be represented as <span class="code">&amp;#176;</span>)</td>
</tr>
<tr>
<td class="fixed_highlight">utf8</td>
<td>Non 7-bit characters will be represented in UTF-8.</td>
</tr>
<tr>
<td class="fixed_highlight">strict_ascii</td>
<td>Non 7-bit characters will be ignored.</td>
</tr>
</table>
<p>By default, the encoding <span class="code">html_entities</span> is used
for HTML files, <span class="code">strict_ascii</span> for the NOAA template
files. </p>
<h3 class="config_section">[[SummaryByMonth]]</h3>
<p>This section controls which summaries-by-month are generated. For each such
summary, it should have its own sub-subsection, with option
<span class="code">template</span> listing the template to be used. The default
configuration generates NOAA-by-month summaries and is summarized below as an
example. Additional &quot;by month&quot; summaries can be added easily by following
the same pattern. </p>
<h4 class="config_section">[[[NOAA_month]]]</h4>
<p class="config_option">encoding </p>
<p>Set to <span class="code">strict_ascii</span> for the NOAA monthly summary.
</p>
<p class="config_option">template </p>
<p>This option is set to the source template for the NOAA monthly summary,
<span class="code">NOAA/NOAA-YYYY-MM.txt.tmpl</span>. </p>
<h3 class="config_section">[[SummaryByYear]]</h3>
<p>This section controls which summaries-by-year are generated. For each such
summary, it should have its own sub-subsection, with option
<span class="code">template</span> listing the template to be used. The default
configuration generates NOAA-by-year summaries and is summarized below as an
example. Additional &quot;by year&quot; summaries can be added easily by following
the pattern. </p>
<h4 class="config_section">[[[NOAA_year]]]</h4>
<p class="config_option">encoding </p>
<p>Set to <span class="code">strict_ascii</span> for the NOAA year summary.
</p>
<p class="config_option">template </p>
<p>This option is set to the source template for the NOAA yearly summary,
<span class="code">NOAA/NOAA-YYYY.txt.tmpl</span>. </p>
<h3 class="config_section">[[ToDate]]</h3>
<p>This section controls which observations-to-date are generated. The default
configuration generates four files: one for day, week, month, and year. Although
the sub-subsections below have names such as &#39;week&#39; or &#39;month&#39;,
this is not used in their generation.&nbsp; Output is set by the template
<em>content</em>, not the name of the sub-subsection — the names below could
as easily have been&#39;Fred&#39;, &#39;Mary&#39;, &#39;Peter&#39;, and &#39;George&#39;
and had the same output. </p>
<p>Additional observations-to-date pages can be created easily by adding a new
sub-subsection and giving it a unique name (&quot;Jill&quot;?), then giving
the path to its template as option <span class="code">template</span>. </p>
<h4 class="config_section">[[[day]]]</h4>
<p class="config_option">template </p>
<p>Set to <span class="code">index.html.tmpl</span>, which contains the template
for the day summary. </p>
<h4 class="config_section">[[[week]]]</h4>
<p class="config_option">template </p>
<p>Set to <span class="code">week.html.tmpl</span>, which contains the template
for the week summary. </p>
<h4 class="config_section">[[[month]]]</h4>
<p class="config_option">template </p>
<p>Set to <span class="code">month.html.tmpl</span>, which contains the template
for the month summary. </p>
<h4 class="config_section">[[[year]]]</h4>
<p class="config_option">template </p>
<p>Set to <span class="code">year.html.tmpl</span>, which contains the template
for the year summary. </p>
<h4 class="config_section">[[[RSS]]]</h4>
<p class="config_option">template </p>
<p>Set to <span class="code">RSS/weewx_rss.xml.tmpl</span>, which contains a
template for an RSS feed. </p>
<h4 class="config_section">[[[Mobile]]]</h4>
<p class="config_option">template </p>
<p>Set to <span class="code">mobile.html.tmpl</span>, which contains a template
for a page formatted for mobile phones. </p>
<h2 class="config_section">[CopyGenerator]</h2>
<p>This section is used by generator <span class="code">weewx.reportengine.CopyGenerator</span>
and controls which files are to be copied over from the skin subdirectory to
the destination directory. Think of it as &quot;file generation,&quot; except
that rather than going through the template engine, the files are simply copied
over. </p>
<p class="config_option">copy_once </p>
<p>This option controls which files get copied over on the first invocation
of the report engine service. Typically, this is things such as style sheets
or background GIFs. Wildcards can be used. </p>
<p class="config_option">copy_always </p>
<p>This is a list of files that should be copied on every invocation. Wildcards
can be used. </p>
<h2 class="config_section">[ImageGenerator]</h2>
<p>This section is used by generator <span class="code">weewx.reportengine.ImageGenerator</span>
and controls which images (plots) get generated and with which options. While
complicated, it is extremely flexible and powerful. </p>
<h3>Time periods</h3>
<p>The section consists of one or more sub-sections, one for each time period
(day, week, month, and year). These sub-sections define the nature of aggregation
and plot types for the time period. For example, here&#39;s a typical set of
options for sub-section <span class="code">[[month_images]]</span>, controlling
how images that cover a month period are generated: </p>
<pre>
[[month_images]]
x_label_format = %d
bottom_label_format = %m/%d/%y %H:%M
time_length = 2592000 # == 30 days
aggregate_type = avg
aggregate_interval = 10800 # == 3 hours</pre>
<p>The option <span class="code">x_label_format</span> gives a
<a href="http://docs.python.org/library/datetime.html#strftime-behavior">strftime()</a>
type format for the x-axis. In this example, it will only show days (format
option &quot;<span class="code">%d</span>&quot;). The <span class="code">bottom_label_format</span>
is the format used to time stamp the image at the bottom. In this example, it
will show the time as <span class="code">10/25/09 15:35</span>. A plot will
cover a nominal 30 days, and all items included in it will use an aggregate
type of averaging over 3 hours. </p>
<h3>Image files</h3>
<p>Within each sub-section is another nesting, one for each image to be generated.
The title of each sub-sub-section is the filename to be used for the image.
Finally, at one additional nesting level (!) are the logical names of all the
line types to be drawn in the image.&nbsp; Values specified in the level above
can be overridden. For example, here&#39;s a typical set of options for sub-sub-section
<span class="code">[[[monthrain]]]</span>: </p>
<pre>
[[[monthrain]]]
plot_type = bar
yscale = None, None, 0.02
[[[[rain]]]]
aggregate_type = sum
aggregate_interval = 86400
label = Rain (daily avg)</pre>
<p>This will generate an image file with name <span class="code">monthrain.png</span>.
It will be a bar plot. Option <span class="code">yscale</span> controls the
y-axis scaling — if left out, the scale will automatically be chosen. However,
in this example we are choosing to exercise some degree of control by specifying
values explicitly. The option takes a 3-way tuple (<span class="code">ylow</span>,
<span class="code">yhigh</span>, <span class="code">min_interval</span>), where
<span class="code">ylow</span> and <span class="code">yhigh</span> are the minimum
and maximum y-axis values, respectively, and <span class="code">min_interval</span>
is the minimum tick interval. If set to &#39;<span class="code">None</span>',
the corresponding value will be automatically chosen. So, in this example, the
setting</p>
<p class="tty">yscale = None, None, 0.02</p>
<p>will cause <span class="code">weewx</span> to pick sensible y minimum and
maximum values, but require that the tick increment (<span class="code">min_interval</span>)
be at least 0.02. </p>
<p>Continuing on with the example above, there will be only one plot &quot;line&quot;
(it will actually be a series of bars) and it will have logical name &quot;<span class="code">rain</span>&quot;.
Because we haven&#39;t said otherwise, the SQL data type to be used for this
line will be the same as its logical name, that is, <span class="code">rain</span>,
but this can be overridden (see below). The aggregation type will be summing
(overriding the averaging specified in sub-section <span class="code">[[month_images]]</span>),
so you get the total rain over the aggregate period (rather than the average)
over an aggregation interval of 86,400 seconds (one day). The plot line will
be titled with the indicated label (&#39;<span class="code">Rain (daily avg)</span>&#39;)
</p>
<p>If there is a time gap in the data, the options <span class="code">line_gap_fraction</span> and
<span class="code">bar_gap_fraction</span>
control how it will be drawn. The former, <span class="code">line_gap_fraction</span>, is used for line
graphs, the latter, <span class="code">bar_gap_fraction</span>, for bar graphs. Here's what the resultant
plots look like without and with this option being specified:</p>
<table class="center">
<tr>
<td>
<div class="image">
<img alt="Gap not shown" height="197" src="day-gap-not-shown.png" width="334" /></div>
<div class="caption">
With no <span class="code">line_gap_fraction</span> specified</div>
</td>
<td>
<div class="image">
<img alt="Gap showing" height="197" src="day-gap-showing.png" width="334" />
</div>
<div class="caption">
With <span class="code">line_gap_fraction=0.01</span></div>
</td>
</tr>
</table>
<h3>Including more than one SQL type in a plot</h3>
<p>More than one SQL type can be included in a plot. For example, here&#39;s
how to generate a plot with the week&#39;s outside temperature as well as dewpoint:
</p>
<pre>
[[[monthtempdew]]]
[[[[outTemp]]]]
[[[[dewpoint]]]]</pre>
<p>This would create an image in file <span class="code">monthtempdew.png</span>
that includes a line plot of both outside temperature and dewpoint. </p>
<h3>Including the same SQL type more than once in a plot</h3>
<p>Another example. Say you want a plot of the day&#39;s temperature, overlaid
with hourly averages. Here, you are using the same data type (&#39;<span class="code">outTemp</span>&#39;)
for both plot lines, the first with averages, the second without. If you do
the obvious it won&#39;t work: </p>
<pre>
## WRONG ##
[[[daytemp_with_avg]]]
[[[[outTemp]]]]
aggregate_type = avg
aggregate_interval = 3600
[[[[outTemp]]]] # OOPS! The same section name appears more than once!</pre>
<p>The option parser does not allow the same section name (&#39;<span class="code">outTemp</span>&#39;
in this case) to appear more than once at a given level in the configuration
file, so an error will be declared (technical reason: formally, the sections
are an unordered dictionary). If you wish for the same SQL type to appear more
than once in a plot then there is a trick you must know: use option
<span class="code">data_type</span>. This will override the default action that
the logical line name is used for the SQL type. So, our example would look like
this: </p>
<pre>
[[[daytemp_with_avg]]]
[[[[a_logical_name]]]]
data_type = outTemp
aggregate_type = avg
aggregate_interval = 3600
label = Avg. Temp.
[[[[outTemp]]]]</pre>
<p>Here, the first logical line has been given the name &quot;<span class="code">a_logical_name</span>&quot;
to distinguish it from the second line &quot;<span class="code">outTemp</span>&quot;.
We have specified that the first line will use data type <span class="code">
outTemp</span> and that it will use averaging over a one hour period. The second
also uses <span class="code">outTemp</span>, but will not use averaging. </p>
<p>The result is a nice plot of the day&#39;s temperature, overlaid with a 3-hour
smoothed average: </p>
<p class="center">
<img alt="Daytime temperature with running average" height="180" src="daytemp_with_avg.png" width="300" />
</p>
<p>One more example. This one shows daily high and low temperatures for a year:</p>
<p class="tty">
[[year_images]]<br />
&nbsp; ...<br />
&nbsp; [[[yearhilow]]]<br />
&nbsp;&nbsp;&nbsp; [[[[hi]]]]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data_type = outTemp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aggregate_type = max<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label = High<br />
&nbsp;&nbsp;&nbsp; [[[[low]]]]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date_type = outTemp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aggregate_type = min<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label = Low Temperature</p>
<p>This results in the plot <span class="code">yearhilow.png</span>:</p>
<p class="center"><img alt="Daily highs and lows" src="yearhilow.png" /> </p>
<h3>Progressive vector plots</h3>
<p><span class="code">Weewx</span> can produce progressive vector plots as well
as the more conventional x-y plots. To produce these, use plot type &#39;<span class="code">vector</span>&#39;.
You need a vector type to produce this kind of plot. There are two: &#39;<span class="code">windvec</span>&#39;,
and &#39;<span class="code">windgustvec</span>&#39;. While they don&#39;t actually
appear in the SQL database, <span class="code">weewx</span> understands that
they represent special vector-types. The first, &#39;<span class="code">windvec</span>&#39;,
represents the average wind in an archive period, the second, &#39;<span class="code">windgustvec</span>&#39;
the max wind in an archive period. Here&#39;s how to produce a progressive vector
for one week that shows the hourly biggest wind gusts, along with hourly averages:
</p>
<pre>
[[[weekgustoverlay]]]
aggregate_interval = 3600
[[[[windvec]]]]
label = Hourly Wind
plot_type = vector
aggregate_type = avg
[[[[windgustvec]]]]
label = Gust Wind
plot_type = vector
aggregate_type = max</pre>
<p>This will produce an image file with name <span class="code">weekgustoverlay.png</span>.
It will consist of two progressive vector plots, both using hourly aggregation
(3,600 seconds). For the first set of vectors, the hourly average will be used.
In the second, the max of the gusts will be used: </p>
<p class="center">
<img alt="hourly average wind vector overlaid with gust vectors" height="180" src="weekgustoverlay.png" width="300" />
</p>
<p>By default, the sticks in the progressive wind plots point towards the wind
source. That is, the stick for a wind from the west will point left. If you
have a chronic wind direction (as I do), you may want to rotate the default
direction so that all the vectors don&#39;t line up over the x-axis, overlaying
each other. Do this by using option <span class="code">vector_rotate</span>.
For example, with my chronic westerlies, I set <span class="code">vector_rotate</span>
to 90.0 for the plot above, so winds out of the west point straight up. </p>
<p>If you use this kind of plot (the out-of-the-box version of
<span class="code">weewx</span> includes daily, weekly, monthly, and yearly
progressive wind plots), a small compass rose will be put in the lower-left
corner of the image to show the orientation of North. </p>
<h3>Overriding values</h3>
<p>Remember that values at any level can override values specified at a higher
level. For example, say you want to generate the standard plots, but for a few
key observation types such as barometer, you want to also generate some oversized
plots to give you extra detail, perhaps for an HTML popup. The standard
<span class="code">weewx.conf</span> file specifies plot size of 300x180 pixels,
which will be used for all plots unless overridden: </p>
<pre>
[Images]
...
image_width=300
image_height = 180</pre>
<p>The standard plot of barometric pressure will appear in
<span class="code">daybarometer.png</span>: </p>
<pre>
[[[daybarometer]]]
[[[[barometer]]]] </pre>
<p>We now add our special plot of barometric pressure, but specify a larger
image size. This image will be put in file an class=&quot;code&quot; daybarometer_big.png.
</p>
<pre>
[[[daybarometer_big]]]
image_width = 600
image_height = 360
[[[[barometer]]]]</pre>
<h2 class="config_section">[Generators]</h2>
<p class="config_option">generator_list </p>
<p>This option controls which generators get run for this skin. It is a comma
separated list. The generators will be run in this order. </p>
<h1 id="Customizing_the_weewx_service_engine">Customizing the
<span class="code">weewx</span> service engine</h1>
<p>This is an advance topic intended for those who wish to try their hand at
extending the internal engine in weewx. You should have a passing familiarity
with Python or, at least, be willing to learn it. </p>
<p><em>Please note that the service engine is likely to change in future versions!
</em></p>
<p>At a high level, <span class="code">weewx</span> consists of an <em>engine</em>
that is responsible for managing a set of <em>services</em>. A service consists
of a Python class which binds its member functions to various <em>events</em>.
The engine arranges to have the bound member function called when a specific
event happens, such as a new LOOP packet arriving. </p>
<p>To customize, you can </p>
<ul>
<li>Customize a service </li>
<li>Add a service </li>
</ul>
<p>The default install of <span class="code">weewx</span> includes the following
services, shown in the order they are normally run:</p>
<table class="center" style="width: 60%">
<tr>
<td class="text_highlight"><strong>Service</strong></td>
<td><strong>Function</strong></td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdConvert</td>
<td>Converts the units of the input to a target unit system (such as
US or Metric).</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdCalibrate</td>
<td>Adjust new LOOP and archive packets using calibration expressions.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdQC</td>
<td>Check that observation values fall within a specified range.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdArchive</td>
<td>Archive any new data to the SQL databases.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdTimeSynch</td>
<td>Arrange to have the clock on the console synchronized at regular
intervals.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdPrint</td>
<td>Print out new LOOP and archive packets on the console.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdRESTful</td>
<td>Start a thread to manage
<a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">
RESTful</a> (simple stateless client-server protocols) connections;
such as those used by the Weather Underground or PWSweather.</td>
</tr>
<tr>
<td class="fixed_highlight">weewx.wxengine.StdReport</td>
<td>Launch a new thread to do report processing after a new archive
record arrives. Reports do things such as generate HTML files, generate
images, or FTP/rsync files to a web server. New reports can be added
easily by the user.</td>
</tr>
</table>
<h2 id="Preserving_your_changes_across_an_upgrade">Preserving your changes across
an upgrade</h2>
<p>Generally, if you change the code in <span class="code">weewx</span> you
will have to cut-and-paste any changes you have made to the new code. However,
if you put the changes in the special directory <span class="code"><em>$WEEWX_ROOT</em>/bin/user</span>
(usually, <span class="code">/home/weewx/bin/user</span>) the setup routines
arranges for the changes to be preserved across an upgrade. </p>
<h2 id="Customizing_a_service">Customizing a Service</h2>
<p>The service <span class="code">weewx.wxengine.StdPrint</span> prints out
new LOOP and archive packets to the console when they arrive. By default, it
prints out the entire record, which generally includes a lot of possibly distracting
information and can be rather messy. Suppose you don&#39;t like this, and want
it to print out only the time, barometer reading, and the outside temperature
whenever a new LOOP packet arrives. This could be done by subclassing the default
print service <span class="code">StdPrint</span> and overriding member function
<span class="code">new_loop_packet()</span>. </p>
<p>In file <span class="code">bin/user/myprint.py</span>: </p>
<pre>
from weewx.wxengine import StdPrint
from weeutil.weeutil import timestamp_to_string
class MyPrint(StdPrint):
# Override the default new_loop_packet member function:
def new_loop_packet(self, event):
packet = event.packet
print &quot;LOOP: &quot;, timestamp_to_string(packet[&#39;dateTime&#39;]),
"BAR=", packet.get(&#39;barometer&#39;, 'N/A'),
"TEMP=", packet.get(&#39;outTemp&#39;, 'N/A')</pre>
<p>This service substitutes a new implementation for the member function
<span class="code">new_loop_packet</span>. This implementation prints out the
time, then the barometer reading (or '<span class="code">N/A</span>' if it is
not available) and the outside temperature (or '<span class="code">N/A</span>').</p>
<p>You then need to specify that your print service class should be loaded instead
of the default <span class="code">StdPrint</span> service. This is done by substituting
your service name for <span class="code">StdPrint</span> in
<span class="code">service_list</span>, located in <span class="code">[Engines][[WxEngine]]</span>:
</p>
<pre>
[Engines]
[[WxEngine]]
service_list = weewx.wxengine.StdConvert, weewx.wxengine.StdCalibrate, weewx.wxengine.StdQC, weewx.wxengine.StdArchive, weewx.wxengine.StdTimeSynch, user.myprint.MyPrint, weewx.wxengine.StdRESTful, weewx.wxengine.StdReport</pre>
<p>(Note that this list must be all on one line. Unfortunately, the parser
<span class="code">ConfigObj</span> does not allow options to be continued on
to following lines.) </p>
<h2 id="Adding_a_Service">Adding a Service</h2>
<p>Suppose there is no service that can be easily customized for your needs.
In this case, a new one can easily be created by subclassing off the abstract
base class <span class="code">StdService</span>, and then adding the functionality
you need. Here&#39;s an example that implements an alarm that sends off an email
when an arbitrary expression evaluates <span class="code">True</span>. This
example is included in the standard distribution in subdirectory &quot;<span class="code">bin/examples</span>&quot;.
</p>
<p>File <span class="code">examples/alarm.py</span>: </p>
<pre class="tty">
import time
import smtplib
from email.mime.text import MIMEText
import threading
import syslog
import weewx
from weewx.wxengine import StdService
from weeutil.weeutil import timestamp_to_string, option_as_list
# Inherit from the base class StdService:
class MyAlarm(StdService):
"""Custom service that sounds an alarm if an arbitrary expression evaluates true"""
def __init__(self, engine, config_dict):
# Pass the initialization information on to my superclass:
super(MyAlarm, self).__init__(engine, config_dict)
# This will hold the time when the last alarm message went out:
self.last_msg_ts = 0
try:
# Dig the needed options out of the configuration dictionary.
# If a critical option is missing, an exception will be thrown and
# the alarm will not be set.
self.expression = config_dict['Alarm']['expression']
self.time_wait = int(config_dict['Alarm'].get('time_wait', 3600))
self.smtp_host = config_dict['Alarm']['smtp_host']
self.smtp_user = config_dict['Alarm'].get('smtp_user')
self.smtp_password = config_dict['Alarm'].get('smtp_password')
self.SUBJECT = config_dict['Alarm'].get('subject', "Alarm message from weewx")
self.FROM = config_dict['Alarm'].get('from', 'alarm@weewx.com')
self.TO = option_as_list(config_dict['Alarm']['mailto'])
syslog.syslog(syslog.LOG_INFO, "alarm: Alarm set for expression: \"%s\"" % self.expression)
# If we got this far, it's ok to start intercepting events:
self.bind(weewx.NEW_ARCHIVE_RECORD, self.newArchiveRecord) # NOTE 1
except Exception, e:
syslog.syslog(syslog.LOG_INFO, "alarm: No alarm set. %s" % e)
def newArchiveRecord(self, event):
"""Gets called on a new archive record event."""
# To avoid a flood of nearly identical emails, this will do
# the check only if we have never sent an email, or if we haven't
# sent one in the last self.time_wait seconds:
if not self.last_msg_ts or abs(time.time() - self.last_msg_ts) &gt;= self.time_wait :
# Get the new archive record:
record = event.record
# Evaluate the expression in the context of the event archive record.
# Sound the alarm if it evaluates true:
if eval(self.expression, None, record): # NOTE 2
# Sound the alarm!
# Launch in a separate thread so it doesn't block the main LOOP thread:
t = threading.Thread(target = MyAlarm.soundTheAlarm, args=(self, record))
t.start()
# Record when the message went out:
self.last_msg_ts = time.time()
def soundTheAlarm(self, rec):
"""This function is called when the given expression evaluates True."""
# Get the time and convert to a string:
t_str = timestamp_to_string(rec['dateTime'])
# Log it in the system log:
syslog.syslog(syslog.LOG_INFO, "alarm: Alarm expression \"%s\" evaluated True at %s" % (self.expression, t_str))
# Form the message text:
msg_text = "Alarm expression \"%s\" evaluated True at %s\nRecord:\n%s" % (self.expression, t_str, str(rec))
# Convert to MIME:
msg = MIMEText(msg_text)
# Fill in MIME headers:
msg['Subject'] = self.SUBJECT
msg['From'] = self.FROM
msg['To'] = ','.join(self.TO)
# Create an instance of class SMTP for the given SMTP host:
s = smtplib.SMTP(self.smtp_host)
try:
# Some servers (eg, gmail) require encrypted transport.
# Be prepared to catch an exception if the server
# doesn't support it.
s.ehlo()
s.starttls()
s.ehlo()
syslog.syslog(syslog.LOG_DEBUG, " **** using encrypted transport")
except smtplib.SMTPException:
syslog.syslog(syslog.LOG_DEBUG, " **** using unencrypted transport")
try:
# If a username has been given, assume that login is required for this host:
if self.smtp_user:
s.login(self.smtp_user, self.smtp_password)
syslog.syslog(syslog.LOG_DEBUG, " **** logged in with user name %s" % (self.smtp_user,))
# Send the email:
s.sendmail(msg['From'], self.TO, msg.as_string())
# Log out of the server:
s.quit()
except Exception, e:
syslog.syslog(syslog.LOG_ERR, "alarm: SMTP mailer refused message with error %s" % (e,))
raise
# Log sending the email:
syslog.syslog(syslog.LOG_INFO, " **** email sent to: %s" % self.TO) </pre>
<p>This service expects all the information it needs to be in the configuration
file <span class="code">weewx.conf</span> in a new section called
<span class="code">[Alarm]</span>. So, add the following lines to your configuration
file: </p>
<pre class="tty">
[Alarm]
expression = &quot;outTemp &lt; 40.0&quot;
time_wait = 3600
smtp_host = smtp.mymailserver.com
smtp_user = myusername
smtp_password = mypassword
mailto = auser@adomain.com, anotheruser@someplace.com
from = me@mydomain.com
subject = &quot;Alarm message from weewx!&quot;</pre>
<p>There are two important points to be noted in this example, each marked with
a "<span class="code">NOTE</span>" flag in the code.</p>
<ol>
<li>Here is where the binding happens between an event, weewx.NEW_ARCHIVE_RECORD
in this example, and a member function, self.newArchiveRecord. There are
other events that can be interecepted. Look in the file ./bin/weewx/__init__.py.</li>
<li>This is where the test is done of whether or not to sound the alarm.
The <span class="code">[Alarm]</span> configuration options specify that
the alarm be sounded when &quot;<span class="code">outTemp &lt; 40.0</span>&quot;
evaluates <span class="code">True</span>, that is when the outside temperature
is below 40.0 degrees. Any valid Python expression can be used, although
the only variables available are those in the current archive record.</li>
</ol>
<p>Another example expression could be: </p>
<pre>
expression = &quot;outTemp &lt; 32.0 and windSpeed &gt; 10.0&quot;</pre>
<p>In this case, the alarm is sounded if the outside temperature drops below
freezing and the wind speed is greater than 10.0. </p>
<p>Option <span class="code">time_wait</span> is used to avoid a flood of nearly
identical emails. The new service will wait this long before sending another
email out. </p>
<p>Email will be sent through the SMTP host specified by option
<span class="code">smtp_host</span>. The recipient(s) are specified by the comma
separated option <span class="code">mailto</span>. </p>
<p>Many SMTP hosts require user login. If this is the case, the user and password
are specified with options <span class="code">smtp_user</span> and
<span class="code">smtp_password</span>, respectively. </p>
<p>The last two options, &quot;<span class="code">from</span>&quot; and &quot;<span class="code">subject</span>&quot;
are optional. If not supplied, <span class="code">weewx</span> will supply something
sensible. Note, however, that some mailers require a valid &quot;from&quot;
email address and the one <span class="code">weewx</span> supplies may not satisfy
its requirements. </p>
<p>To make this all work, you must tell the engine to load this new service.
This is done by adding your service name to the list <span class="code">service_list</span>,
located in <span class="code">[Engines][[WxEngine]]</span>: </p>
<pre>
[Engines]
[[WxEngine]]
service_list = weewx.wxengine.StdConvert, weewx.wxengine.StdCalibrate, weewx.wxengine.StdQC, weewx.wxengine.StdArchive, weewx.wxengine.StdTimeSynch, weewx.wxengine.StdPrint, weewx.wxengine.StdRESTful, weewx.wxengine.StdReport, examples.alarm.MyAlarm</pre>
<p>(Note that this list must be all on one line. Unfortunately, the parser
<span class="code">ConfigObj</span> does not allow options to be continued on
to following lines.) </p>
<p>In addition to the example above, the distribution also includes a low-battery
alarm (<span class="code">lowBattery.py</span>), which is very similar, except
that it intercepts LOOP events (instead of archiving events). </p>
<h1>Customizing the archive database</h1>
<p>For most users the default database will work just fine. It has the added
advantage of being compatible with the wview database. Nevertheless, there may
be occasions where you may want to add a SQL type to your database, or change
its unit system. This section shows you how to do this, using the utility
<span class="code">./bin/config_database.py</span>.</p>
<p>Before starting, it's worth running the utility with the
<span class="code">--help</span> flag to see how it is used:</p>
<p class="tty">cd /home/weewx<br />
./bin/config_database.py --help</p>
<h2>Adding a new observation type</h2>
<p>Suppose you have installed an electric meter at your house and you wish to
correlate electrical usage with the weather. The meter has some sort of connection
to your computer, allowing you to download the consumption. At the end of every
archive interval you want to sample the meter for the electricity consumed during
the interval, then store the results in the archive database, along with the
weather data. How would you do this?</p>
<p>First, you would write a custom service that retrieves the electrical consumption
data and adds it to the archive record. See the section
<a href="#Customizing_the_weewx_service_engine">Customizing the weewx service
engine</a> for details on how to write a custom service. However, when you are
done it will look something like this:</p>
<p class="tty">from weewx.wxengine import StdService<br />
<br />
class AddElectricity(StdService):<br />
<br />
&nbsp; def new_archive_packet(self, event):<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; (code that downloads the consumption data from the connection
to the meter)<br />
<br />
&nbsp;&nbsp;&nbsp; event.record['electricity'] = retrieved_value</p>
<p>This adds a new key '<span class="code">electricity</span>' to the record
dictionary and sets it equal to some value. As an aside, if you do something
like this, you would want to make sure that the code to retrieve the current
electrical consumption does not delay very long so it does not slow down the
main loop. If it's going to cause a delay of more than a couple seconds you
might want to put it in a separate thread and feed the results to
<span class="code">AddElectricity</span> through a queue.</p>
<p>As usual, you would add your new service to the option <span class="code">
service_list</span> in <span class="code">weewx.conf</span>, making sure it
appears before <span class="code">StdArchive</span> so your new value is inserted
into the record <em>before</em> the data is archived.</p>
<h3><a id="Adding_a_new_type_to_the_archive_database">Adding a new type to the
archive database</a></h3>
<p>So, now you have created a new observation type, '<span class="code">electricity</span>'.
Trouble is, there is no corresponding type in the schema of the SQL database
and, therefore, it won't be stored there. How would you add such a type?</p>
<p>Here's our general strategy:</p>
<ol>
<li>Add a new type to the database schema.</li>
<li>Make sure you have the necessary permissions to create the new database.</li>
<li>Populate it with data from the old database.</li>
<li>Shuffle databases around so <span class="code">weewx</span> will use
the new database.</li>
<li>Modify the stats database so it includes the new type as well (Optional).</li>
</ol>
<p>1. <strong>Adding a new type to the schema.</strong> When creating a database
the schema is obtained from file <span class="code">./bin/user/schemas.py</span>.
Take a look at it now. You will see a list called <span class="code">defaultArchiveSchema</span>
that holds all the observation names and their SQL types. It looks something
like:</p>
<pre class="tty">defaultArchiveSchema = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'),
('usUnits', 'INTEGER NOT NULL'),
('interval', 'INTEGER NOT NULL'),
('barometer', 'REAL'),
('pressure', 'REAL'),
('altimeter', 'REAL'),
('inTemp', 'REAL'),
('outTemp', 'REAL'),
...
('inTempBatteryStatus', 'REAL')]</pre>
<p>Let's modify it to add our new type, '<span class="code">electricity</span>'.
Now it looks like this:</p>
<pre class="tty">defaultArchiveSchema = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'),
('usUnits', 'INTEGER NOT NULL'),
('interval', 'INTEGER NOT NULL'),
('barometer', 'REAL'),
('pressure', 'REAL'),
('altimeter', 'REAL'),
('inTemp', 'REAL'),
('outTemp', 'REAL'),
...
<span class="highlight"> ('electricity', 'REAL'),</span>
('inTempBatteryStatus', 'REAL')]</pre>
<p>The new line has been <span class="highlight">highlighted</span>.</p>
<p>2. <strong>Check permissions.</strong> The reconfiguration utility will create
a new database with the same name as the old, except with the suffix '<span class="code">_new</span>'
attached to the end. Make sure you have the necessary permissions to do this.
In particular, if you are using MySQL, you will need '<span class="code">CREATE</span>'
privileges.</p>
<p>3. <strong>Run <span class="code">config_database.py</span>.</strong> Now
run the utility <span class="code">config_database.py</span> with the
<span class="code">--reconfigure</span> option and the path to the configuration
file:</p>
<p class="tty">prompt: <strong>cd /home/weewx<br />
</strong>prompt: <strong>./bin/config_database.py --reconfigure ./weewx.conf</strong></p>
<p>This will create a new database (nominally, <span class="code">weewx.sdb_new</span>
if you are using sqlite, <span class="code">weewx_new</span> if you are using
MySQL) using the new schema and populate it with data from the old database.
</p>
<p>4. <strong><a name="Shuffle_the_databases">Shuffle the databases</a>.</strong>
Now arrange things so <span class="code">weewx</span> can find the new database.
You can either shuffle the databases around so the new database has the same
name as the old database, or edit <span class="code">weewx.conf</span> to use
the new database name. To do the former:</p>
<p><em>First do a backup!</em></p>
<p>For sqlite:</p>
<p class="tty">prompt: <strong>cd /home/weewx/archive<br />
</strong>prompt: <strong>mv weewx.sdb_new weewx.sdb</strong></p>
<p>For MySQL:</p>
<p class="tty">prompt: <strong>mysql -u &lt;username&gt; --password=&lt;mypassword&gt;<br />
</strong>mysql&gt; <strong>DROP DATABASE weewx;&nbsp;&nbsp; # Drops the old
database<br />
</strong>mysql&gt; <strong>CREATE DATABASE weewx; # Create a new one with the
same name<br />
</strong>mysql&gt; <strong>RENAME TABLE weewx_new.archive TO weewx.archive;&nbsp;&nbsp;&nbsp;
# Rename to the nominal name</strong></p>
<p>5. <strong>Modify the stats database.</strong> At this point, you can use
the new observation type in the plots. However, if you wish to use it in the
statistical summaries, you will also have to add it to the stats database.
To do this, add the type to the Python list <span class="code">stats_types</span>,
which can be found in <span class="code">bin/user/schemas.py</span>, so it reads something like this:</p>
<p class="tty">stats_types = ['barometer', 'inTemp', 'outTemp',
'inHumidity', 'outHumidity', <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
'rainRate', 'rain', 'dewpoint', 'windchill', 'heatindex', 'ET', <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
'radiation', 'UV', 'extraTemp1', 'rxCheckPercent', 'wind',
<span class="highlight">'electricity'</span>]&nbsp;</p>
<p>Now delete the stats database (nominally <span class="code">stats.sdb</span>
for sqlite, <span class="code">stats</span> for MySQL). Weewx will automatically
rebuild it, including your new type.</p>
<h3>Using the new type</h3>
<p>Now you've added a new type. How do you use it? </p>
<p>Pretty much like any other type. For example, to do a plot of the month's
electric consumption, totaled by day, add this section to the
<span class="code">[[month_images]]</span> section of <span class="code">skin.conf</span>:</p>
<p class="tty">[[[monthelectric]]]<br />
&nbsp; [[[[electricity]]]]<br />
&nbsp;&nbsp;&nbsp; aggregate_type = sum<br />
&nbsp;&nbsp;&nbsp; aggregate_interval = 86400<br />
&nbsp;&nbsp;&nbsp; label = Electric consumption (daily total)</p>
<p>This will cause the generation of an image <span class="code">monthelectric.png</span>,
showing a plot of each day's consumption for the past month.</p>
<p>If you wish to use the new type in the templates, it will be available using
the same syntax as any other type. Here are some other tags that might be useful:</p>
<table style="width: 70%">
<tr>
<td class="text_highlight"><strong>Tag</strong></td>
<td><strong>Meaning</strong></td>
</tr>
<tr>
<td class="fixed_highlight">$day.electricity.sum</td>
<td>Total consumption since midnight</td>
</tr>
<tr>
<td class="fixed_highlight">$year.electricity.sum</td>
<td>Total consumption since the first of the year</td>
</tr>
<tr>
<td class="fixed_highlight">$year.electricity.max</td>
<td>The most consumed during any archive period</td>
</tr>
<tr>
<td class="fixed_highlight">$year.electricity.maxsum</td>
<td>The most consumed during a day</td>
</tr>
<tr>
<td class="fixed_highlight">$year.electricity.maxsumtime</td>
<td>The day it happened.</td>
</tr>
<tr>
<td class="fixed_highlight">$year.electricity.sum_ge(5.0)</td>
<td>The number of days where more than 5.0 kWH of energy was consumed.</td>
</tr>
</table>
<h2 id="Changing_the_unit_system">Changing the unit system</h2>
<p>Normally, data is stored in the databases using US Customary units and, normally,
you don't care --- data can always be displayed using any units you choose.
It's an "implementation detail." Nevertheless, there may be special situations
where you wish to store the data in Metric units. For example, you may need
to allow direct programmatic access to the databases from another piece of software
that expects metric units. </p>
<p>Weewx does not allow you to change the database unit system midstream. You
can't start with one unit system then, in the middle of the database, switch
to another. See the section <span class="code">
<a href="usersguide.htm#[StdConvert]">[StdConvert]</a></span> in the Weewx User's
Guide. However, you can reconfigure the database by coping it to a new database,
performing the unit conversion along the way. You then use this new database.</p>
<p>The steps are pretty much the same as
<a href="#Adding_a_new_type_to_the_archive_database">Adding a New Type to the
ArchiveDatabase</a>, described above.</p>
<ol>
<li>Modify <span class="code">weewx.conf</span> to reflect your choice of
the new unit system to use.</li>
<li>Make sure you have the necessary permissions to create the new database.</li>
<li>Populate it with data from the old database.</li>
<li>Shuffle databases around so <span class="code">weewx</span> will use
the new database.</li>
<li>Rebuild the stats database to use the new unit system.</li>
</ol>
<p>1. <strong>Modify <span class="code">weewx.conf</span>.</strong> Edit the
configuration file to change option <span class="code">target_unit</span> in
section <span class="code"><a href="usersguide.htm#[StdConvert]">[StdConvert]</a></span>
to reflect your choice. If you are switching to metric units, the option will
look like</p>
<p class="tty">[StdConvert]<br />
&nbsp; target_unit = METRIC</p>
<p>2. <strong>Check permissions.</strong> The reconfiguration utility will create
a new database with the same name as the old, except with the suffix '<span class="code">_new</span>'
attached to the end. Make sure you have the necessary permissions to do this.
In particular, if you are using MySQL, you will need '<span class="code">CREATE</span>'
privileges.</p>
<p>3. <strong>Run <span class="code">config_database.py</span>.</strong> Now
run the utility <span class="code">config_database.py</span> with the
<span class="code">--reconfigure</span> option:</p>
<p class="tty">prompt: <strong>cd /home/weewx<br />
</strong>prompt: <strong>./bin/config_database.py --reconfigure ./weewx.conf</strong></p>
<p>This will create a new database (nominally, <span class="code">weewx.sdb_new</span>
if you are using sqlite, <span class="code">weewx_new</span> if you are using
MySQL), using the schema found in <span class="code">./bin/user/schemas.py</span>,
and populate it with data from the old database, while performing the unit conversion.</p>
<p>4. <strong>Shuffle the databases.</strong> This is identical to the description
<a href="#Shuffle_the_databases">above</a>.</p>
<p>5. <strong>Recreate the stats database.</strong> Delete the stats database,
then let <span class="code">weewx</span> regenerate it. It will use the new
unit system.</p>
<h1>Porting to new weather station hardware</h1>
<p>Naturally, this is an advanced topic but, nevertheless, I'd really like to
encourage any Python wizards out there to give it a try. Of course, I have selfish
reasons for encouraging you: I don't want to have to go out and buy every type
of hardware there is! It's expensive and my roof would look like a weather station
farm.</p>
<p>Here's the general strategy for doing a port:</p>
<p>Inherit from the abstract base class <span class="code">weewx.abstractstation.AbstractStation</span>.
Try to implement as many of its methods as you can. At the very minimum, you
must implement the following two: </p>
<p><span class="code">hardware_name</span>: Return a string with a short nickname
for the hardware, such as "<span class="code">ACME X90</span>"</p>
<p><span class="code">genLoopPackets</span>:&nbsp; This should be a generator
function that yields loop packets, one after another. Don't worry about stopping
it: the engine will do this when an archive record is due. A loop packet is
a dictionary. At the very minimum it must contain keys</p>
<table style="width: 50%; margin-left: 10%;">
<tr>
<td class="code">dateTime</td>
<td>The time of the observation in unix epoch time.</td>
</tr>
<tr>
<td class="code">usUnits</td>
<td>The unit system used. <span class="code">weewx.US</span> for US
customary, <span class="code">weewx.METRIC</span> for metric. See the
file <span class="code">bin/weewx/units.py</span>, dictionaries
<span class="code">USUnits</span> and <span class="code">MetricUnits</span>
for the exact definition of each.</td>
</tr>
</table>
<p>Then include any observation types you have in the dictionary. Every packet
need not contain the same set of observation types. Different packets can use
different unit systems, but all observations within a packet must use the same
unit system. If your hardware has an error and you don't have a value, you can
either leave it out of the dictionary or (preferred) set its value to
<span class="code">None</span>.</p>
<p>If your hardware does not have an archive record logger, then
<span class="code">weewx</span> can do the record generation for you. It will
automatically collect all the types it sees in your loop packets then emit a
record with the averages (in some cases the sum or max value) of all those types.
If it doesn't see a type, then it won't appear in the emitted record. If your
hardware does have a logger, then you should implement method
<span class="code">genArchiveRecords</span> as well. It should be a generator
function that returns all the records since a given time. </p>
<p>A couple of observation types are tricky. In particular, rain. Generally,
<span class="code">weewx</span> expects to see a packet with the amount of rain
that fell in that packet period included as observation '<span class="code">rain</span>'.
It then sums up all the values to get the total rainfall and emits that in the
archive record. If your hardware does not provide this value, you might have
to infer it from changes in whatever value it provides, for example changes
in the daily or monthly rainfall. I know this is not the best solution, but
it is the most general solution. Any alternatives are welcome!</p>
<p>Wind is another tricky one. It is actually broken up into four different
observations: '<span class="code">windSpeed</span>', '<span class="code">windDir</span>',
'<span class="code">windGust</span>', and '<span class="code">windGustDir</span>'.
Supply as many as you can. The directions should be compass directions in degrees
(0=North, 90=East, etc.).</p>
<p>To load your driver, you should also include a function called '<span class="code">loader</span>'.
It is a factory function that will return an instance of your driver. Its only
argument is the configuration dictionary. </p>
<p>You then include a new section in the configuration file
<span class="code">weewx.conf</span> that includes any options your driver needs.
It should also include an entry '<span class="code">driver</span>' that points
to where your driver can be found. Set option <span class="code">station_type</span>
to your new section type and your driver will be loaded.</p>
<p>Take a look at the simulator code in <span class="code">bin/weewx/simulator.py</span>
for a dirt simple example of a driver. The next most complicated is the driver
for the WMR-USB series, located in <span class="code">bin/weewx/wmrx.py</span>.
The driver for the Vantage series is by far the most complicated.</p>
<p>Naturally, there are a lot of subtleties that I've glossed over in this high-level
description. If you're game, give it a try &mdash; I'm happy to help you out!</p>
<h1 id="Archive_types">Appendix A: Archive types</h1>
<p><em>Archive types</em> are weather observations that have come from your
instrument and been stored in the <em>archive database, </em>&nbsp;a SQL database.
They represent the <em>current conditions</em> as of some time. They are available
to be used in two places: </p>
<ul>
<li>In your template files as a tag with period <span class="code">$current</span>.
Hence, the tag <span class="code">$current.outTemp</span> represents the
latest current outside temperature. There is no aggregation involved (see
<a href="#Statistical_types">statistical types</a> for aggregation).
</li>
<li>In your plot graphs. Here, a line in the graph represents the set of
current observations over a time period. While each plot point in a graph
may represent an aggregation, do not confuse this aggregation with the statistical
aggregation. The former is done with the archive database, the latter with
the statistical database. </li>
</ul>
<p>The following table shows all the possible archive types and whether they
can be used in tag <span class="code">$current</span> or in a plot. Note that
just because a type appears in the table does not necessarily mean that it is
available for <em>your</em> station setup. That would depend on whether your
instrument supports the type. </p>
<table class="center" style="width: 80%">
<tr>
<td><strong>Archive Type</strong></td>
<td style="width: 200px"><strong>SQL Type</strong> <br />
<span class="xxsmall">(appears in archive database)</span></td>
<td><strong>Can be used <br />
in plots</strong></td>
<td><strong>Can be used <br />
in tag <span class="code">$current</span></strong></td>
</tr>
<tr>
<td class="code">altimeter</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">barometer</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">consBatteryVoltage</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">dateTime</td>
<td>X</td>
<td></td>
<td>X (represents current time)</td>
</tr>
<tr>
<td class="code">dewpoint</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">ET</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">extraHumid1</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">extraHumid2</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">extraTemp1</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">extraTemp2</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">extraTemp3</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">hail</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">hailRate</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">heatindex</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">heatingTemp</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">heatingVoltage</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">inHumidity</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">inTemp</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">inTempBatteryStatus</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">interval</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">leafTemp2</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">leafWet2</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">outHumidity</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">outTemp</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">outTempBatteryStatus</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">pressure</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">radiation</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">rain</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">rainBatteryStatus</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">rainRate</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">referenceVoltage</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">rxCheckPercent</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">soilMoist1</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">soilMoist2</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code" style="height: 33px">soilMoist3</td>
<td style="height: 33px">X</td>
<td style="height: 33px">X</td>
<td style="height: 33px">X</td>
</tr>
<tr>
<td class="code">soilMoist4</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">soilTemp1</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">soilTemp2</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">soilTemp3</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">soilTemp4</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">supplyVoltage</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">txBatteryStatus</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">usUnits</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">UV</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">windvec</td>
<td>&nbsp;</td>
<td>X (special vector type)</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">windBatteryStatus</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">windDir</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">windGust</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">windGustDir</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">windSpeed</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">windchill</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
</table>
<h1 id="Units">Appendix B: Units</h1>
<p>The table below lists all the unit groups, their members, and which units
are options for the group. </p>
<table class="center" style="width: 60%">
<tr>
<td><strong>Group</strong></td>
<td><strong>Members</strong></td>
<td><strong>Unit options</strong></td>
</tr>
<tr>
<td class="code">group_altitude</td>
<td class="code">altitude</td>
<td class="code">foot <br />
meter</td>
</tr>
<tr class="code">
<td>group_degree_day</td>
<td>cooldeg<br />
heatdeg</td>
<td>degree_F_day<br />
degree_C_day</td>
</tr>
<tr class="code">
<td>group_direction</td>
<td>gustdir <br />
vecdir <br />
windDir <br />
windGustDir</td>
<td>degree_compass</td>
</tr>
<tr class="code">
<td>group_interval</td>
<td>interval</td>
<td>minute</td>
</tr>
<tr class="code">
<td>group_moisture</td>
<td>soilMoist1 <br />
soilMoist2 <br />
soilMoist3 <br />
soilMoist4</td>
<td>centibar</td>
</tr>
<tr class="code">
<td>group_percent</td>
<td>extraHumid1 <br />
extraHumid2 <br />
inHumidity <br />
outHumidity <br />
rxCheckPercent</td>
<td>percent</td>
</tr>
<tr class="code">
<td>group_pressure</td>
<td>barometer <br />
altimeter <br />
pressure</td>
<td>inHg <br />
mbar <br />
hPa</td>
</tr>
<tr class="code">
<td>group_radiation</td>
<td>UV <br />
radiation</td>
<td>watt_per_meter_squared</td>
</tr>
<tr class="code">
<td>group_rain</td>
<td>rain <br />
ET <br />
hail</td>
<td>in <br />
cm <br />
mm</td>
</tr>
<tr class="code">
<td>group_rainrate</td>
<td>rainRate <br />
hailRate</td>
<td>in_per_hour <br />
cm_per_hour <br />
mm_per_hour</td>
</tr>
<tr class="code">
<td>group_speed</td>
<td>wind <br />
windGust <br />
windSpeed <br />
windgustvec <br />
windvec</td>
<td>mile_per_hour <br />
km_per_hour <br />
knot <br />
meter_per_second</td>
</tr>
<tr class="code">
<td>group_speed2</td>
<td>rms <br />
vecavg</td>
<td>mile_per_hour2 <br />
km_per_hour2 <br />
knot2 <br />
meter_per_second2</td>
</tr>
<tr class="code">
<td>group_temperature</td>
<td>dewpoint <br />
extraTemp1 <br />
extraTemp2 <br />
extraTemp3 <br />
heatindex <br />
heatingTemp <br />
inTemp <br />
leafTemp1 <br />
leafTemp2 <br />
outTemp <br />
soilTemp1 <br />
soilTemp2 <br />
soilTemp3 <br />
soilTemp4 <br />
windchill</td>
<td>degree_F <br />
degree_C</td>
</tr>
<tr class="code">
<td>group_time</td>
<td>dateTime</td>
<td>unix_epoch</td>
</tr>
<tr class="code">
<td>group_uv</td>
<td>UV</td>
<td>uv_index</td>
</tr>
<tr class="code">
<td>group_volt</td>
<td>consBatteryVoltage <br />
heatingVoltage <br />
referenceVoltage <br />
supplyVoltage</td>
<td>volt</td>
</tr>
<tr class="code">
<td>group_NONE</td>
<td>NONE</td>
<td>NONE</td>
</tr>
</table>
<h1 id="Statistical_types">Appendix C: Statistical types</h1>
<p>Most of the templates are devoted to reporting <em>statistical types</em>,
such as temperature, wind, or rainfall, using various <em>aggregates</em>, such
as min, max, or sum. These are called <em>aggregations</em>, because they are
a summary of lots of underlying data. However, only certain aggregates make
sense for certain statistical types. For example, heat degree days is defined
on a daily basis, so while the day&#39;s average temperature is meaningful,
the day&#39;s heating degree days do not. </p>
<p>The following table defines which aggregates are available to be used in
your template for which statistical types (assuming your station supports them
and you have specified that it be stored in your stats database. See section
<span class="code"><a href="usersguide.htm#[Stats]">[Stats]</a></span> in the
<span class="code">weewx.conf</span> configuration file). </p>
<table style="width: 100%">
<tr>
<td><em>Stats Type</em></td>
<td class="code">min</td>
<td class="code">mintime</td>
<td class="code">max</td>
<td class="code">maxtime</td>
<td class="code">avg</td>
<td class="code">sum</td>
<td class="code">rms</td>
<td class="code">vecavg</td>
<td class="code">vecdir</td>
</tr>
<tr>
<td class="code">barometer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">inTemp</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">outTemp</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">inHumidity</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">outHumidity</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">wind</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td class="code">rain</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">dewpoint</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">windchill</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">heatindex</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">heatdeg</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">cooldeg</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">ET</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">radiation</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">UV</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">extraTemp1 <br />
extraTemp2 <br />
extraTemp3</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">soilTemp1 <br />
soilTemp2 <br />
soilTemp3</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">leafTemp1 <br />
leafTemp2</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">extraHumid1 <br />
extraHumid2</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">soilMoist1 <br />
soilMoist2 <br />
soilMoist3 <br />
soilMoist4</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">leafWet1 <br />
leafWet2</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="code">rxCheckPercent</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
<p>&nbsp; </p>
<h1 id="Packet_types">Appendix D: Packet types</h1>
<p><em>Packets</em> are the raw data coming off the instrument (as opposed to
<em>records</em>, which are stored on the database). The observation types available
in a packet are useful when setting <em><a href="usersguide.htm#QC">quality
control rules</a></em> and when doing <em>
<a href="usersguide.htm#Calibrate">calibrations</a></em>. </p>
<p>They may also be useful if you are writing your own custom service. In particular,
for subclasses of <span class="code">StdService</span>, member function
<span class="code">newLoopPacket</span> is called when new LOOP packets arrive,
and member function <span class="code">newArchivePacket</span> is called when
new archive packets arrive. For both functions, the only argument (besides
<span class="code">self</span>) is a dictionary, where the key is the type listed
below, and the value is the observation value. </p>
<p>See the guide from <em>
<a href="http://www.davisnet.com/support/weather/download/VantageSerialProtocolDocs_v250.pdf">
Vantage Pro and Pro2 Serial Communications Reference</a></em> (available on
the Davis website) for more information about these types. </p>
<table class="center" style="width: 50%">
<tr>
<td><strong><em>Type</em></strong></td>
<td><strong>Loop packet</strong></td>
<td><strong>Archive Packet</strong></td>
</tr>
<tr>
<td><span class="code">barometer</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">consBatteryVoltage</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">dateTime</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">dayET</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">dayRain</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">dewpoint</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">ET</span> (hourly)</td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">extraAlarm1</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm2</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm3</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm4</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm5</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm6</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm7</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraAlarm8</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraHumid1</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">extraHumid2</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">extraHumid3</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraHumid4</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraHumid5</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraHumid6</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraHumid7</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraTemp1</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">extraTemp2</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">extraTemp3</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">extraTemp4</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraTemp5</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraTemp6</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">extraTemp7</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">forecastIcon</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">forecastRule</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">heatIndex</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">highOutTemp</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">highRadiation</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">highUV</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">inHumidity</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">inTemp</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">interval</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">insideAlarm</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">leafTemp1</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">leafTemp2</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">leafTemp3</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">leafTemp4</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">leafWet1</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">leafWet2</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">leafWet3</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">leafWet4</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">lowOutTemp</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">monthET</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">monthRain</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">outHumidity</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">outTemp</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">outsideAlarm1</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">outsideAlarm2</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">radiation</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">rain</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">rainAlarm</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">rainRate</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">rxCheckPercent</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilLeafAlarm1</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">soilLeafAlarm2</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">soilLeafAlarm3</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">soilLeafAlarm4</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">soilMoist1</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilMoist2</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilMoist3</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilMoist4</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilTemp1</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilTemp2</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilTemp3</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">soilTemp4</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">stormRain</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">stormStart</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">sunrise</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">sunset</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">txBatteryStatus</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">usUnits</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">UV</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">windChill</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">windDir</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">windGust</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">windGustDir</span></td>
<td>&nbsp;</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">windSpeed10</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">windSpeed</span></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><span class="code">yearET</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
<tr>
<td><span class="code">yearRain</span></td>
<td>X</td>
<td>&nbsp;</td>
</tr>
</table>
</div>
<script type="text/javascript">
samaxesJS.toc({
exclude : 'h4, h5, h6',
autoId : true,
context : 'technical_content'
});
</script>
</body>
</html>