mirror of
https://github.com/weewx/weewx.git
synced 2026-04-19 00:56:54 -04:00
5431 lines
254 KiB
HTML
5431 lines
254 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">
|
||
<!-- $Id$ -->
|
||
<head>
|
||
<meta content="en-us" http-equiv="Content-Language" />
|
||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
||
<title>weewx: Customization Guide</title>
|
||
<link href="css/ui-lightness/jquery-ui-1.10.4.custom.min.css" rel="stylesheet" />
|
||
<link href="css/jquery.tocify.css" rel="stylesheet" />
|
||
<link href="css/weewx_docs.css" rel="stylesheet" />
|
||
<script src="js/jquery-1.11.1.min.js" type="text/javascript"></script>
|
||
<script src="js/jquery-ui-1.10.4.custom.min.js"></script>
|
||
<script src="js/jquery.tocify-1.9.0.min.js"></script>
|
||
<script src="js/weewx.js"></script>
|
||
<script>
|
||
$(function() {
|
||
var level = get_default_level();
|
||
create_toc_control(level);
|
||
generate_toc(level);
|
||
})
|
||
|
||
$(window).scroll(function(){
|
||
$('#toc_controls').css({
|
||
'left': 8 - $(this).scrollLeft()
|
||
});
|
||
$('#toc').css({
|
||
'left': 8 - $(this).scrollLeft()
|
||
});
|
||
});
|
||
</script>
|
||
</head>
|
||
<body>
|
||
|
||
<div id="toc_parent">
|
||
<div id="toc_controls">
|
||
</div>
|
||
<div id="toc">
|
||
<!-- The table of contents will get injected here -->
|
||
</div>
|
||
</div>
|
||
|
||
<div id="technical_content">
|
||
|
||
<a href='http://weewx.com'>
|
||
<img src='images/logo-weewx.png' class='logo' align='right' />
|
||
</a>
|
||
<h1 class="title">Customizing weewx<br />
|
||
<span class="version">
|
||
Version: 3.0.0b1
|
||
</span>
|
||
</h1>
|
||
|
||
<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="#standard_skin">The Standard <span class="code">skin.conf</span></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>
|
||
<p class="warning"><strong>Warning!</strong><br />
|
||
<span class="code">weewx</span> is still an experimental system and, as
|
||
such, its internal design is subject to change. Future upgrades may
|
||
break any customizations you have done, particularly if they involve
|
||
the API (skin customizations tend to be more stable). </p>
|
||
|
||
<h2>Where to put customizations</h2>
|
||
<p>For configuration changes, simply modify the
|
||
<span class="code">weewx</span> configuration file
|
||
<span class="code">weewx.conf</span>, and possibly modify the
|
||
skin configuration file <span class="code">skin.conf</span> as
|
||
described later in this document. These files and template files
|
||
in the <span class='code'>skins</span> directory will be preserved
|
||
when you upgrade.</p>
|
||
<p>Other customizations require new Python code or modifications of
|
||
example code. Where should you put the code? If you simply modify
|
||
the examples in place, then your changes will be overwritten the
|
||
next time you do an upgrade.</p>
|
||
<p>A better idea is to put the code in the
|
||
<span class="symcode">$BIN_ROOT</span><span class="code">/user</span>,
|
||
directory. For example, copy example code from the
|
||
<span class="code">examples</span> directory to the
|
||
<span class="code">user</span> directory, then modify it
|
||
there. If your modification does not contain much code,
|
||
consider putting it in the
|
||
file <span class="code">extensions.py</span> in the
|
||
<span class="code">user</span> directory. Because
|
||
the <span class="code">user</span> directory is preserved
|
||
through upgrades, you won't have to redo any changes you might
|
||
have made.</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 <em>services</em>, 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 id='default_services' class="indent" summary="Overview of the weewx architecture">
|
||
<caption>The standard weewx services</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Service</td>
|
||
<td>Function</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.StdTimeSynch</td>
|
||
<td>Arrange to have the clock on the station synchronized at regular
|
||
intervals.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.StdConvert</td>
|
||
<td>Converts the units of the input to a target unit system (such as
|
||
US or Metric).</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.StdCalibrate</td>
|
||
<td>Adjust new LOOP and archive packets using calibration
|
||
expressions.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.StdQC</td>
|
||
<td>Check quality of incoming data, making sure values fall within a
|
||
specified range.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.wxservices.StdWXCalculate</td>
|
||
<td>Calculate any missing, derived weather observation types, such a dewpoint,
|
||
windchill, or altimeter-corrected pressure.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.StdArchive</td>
|
||
<td>Archive any new data to the SQL databases.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.restx.StdStationRegistry<br/>
|
||
weewx.restx.StdWunderground<br/>
|
||
weewx.restx.StdPWSweather<br/>
|
||
weewx.restx.StdCWOP<br/>
|
||
weewx.restx.StdWOW<br/>weewx.restx.StdAWEKAS
|
||
</td>
|
||
<td>Various <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">
|
||
RESTful services</a> (simple stateless client-server protocols),
|
||
such as the Weather Underground, CWOP, etc. Each launches its own, independent
|
||
thread, which manages the post.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.StdPrint</td>
|
||
<td>Print out new LOOP and archive packets on the console.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.engine.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>
|
||
</tbody>
|
||
</table>
|
||
<p>It is easy to extend old services or to add new ones. The source
|
||
distribution includes an example new service called <span class="code">MyAlarm</span>,
|
||
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="#service_engine">Customizing
|
||
the weewx service engine</a></em>. </p>
|
||
|
||
|
||
<h2>The standard reporting service, <span class="code">StdReport</span></h2>
|
||
<p>For the moment, let us focus on the last service, <span class="code">weewx.engine.StdReport</span>,
|
||
the standard service for creating reports. This will be what most users
|
||
will want to customize, even if it means just changing a few options. </p>
|
||
<h3>Reports</h3>
|
||
<p>The Standard Report Service runs zero or more <em>Reports</em>. The
|
||
specific reports which get run are set in the configuration file <span
|
||
class="code">weewx.conf</span>, in section <span class="code">[StdReport]</span>.
|
||
</p>
|
||
<p>The default distribution of <span class="code">weewx</span> includes
|
||
three reports: </p>
|
||
<table class="indent" summary="Standard reports included in weewx">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Report</td>
|
||
<td>Default functionality</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">StandardReport</td>
|
||
<td>Generates day, week, month and year "to-date" 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="code first_col">FTP</td>
|
||
<td>Arranges to upload everything in the <span class="symcode">$HTML_ROOT</span>
|
||
directory up to a remote webserver.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">RSYNC</td>
|
||
<td>Like FTP, but uses rsync for transferring files to a remote
|
||
webserver.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Note that the FTP and RSYNC "reports" are a funny kind of report in
|
||
that it they do not actually generate anything. Instead, they use the
|
||
reporting service engine to arrange for things to be transferred to a
|
||
remote server. </p>
|
||
|
||
<h3>Skins</h3>
|
||
<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 <span class="code">weewx</span>
|
||
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 "Reports" also use a skin, and
|
||
include a skin configuration file, although they are quite minimal. </p>
|
||
<p>Skins live in their own directory located in <a href="#" id="skin-root-description-target">
|
||
<span class="symcode">$SKIN_ROOT</span></a>.
|
||
</p>
|
||
|
||
<div id="skin-root-description" title="$SKIN_ROOT" style="display:none"><p>The symbol <span class='code'>
|
||
$SKIN_ROOT</span> is a symbolic name to the location of the directory where
|
||
your skins are located. It is not to be taken literally. Consult the
|
||
<a href="usersguide.htm#dir-layout-table">directory layout table</a> in
|
||
the User's Guide for its exact location, dependent
|
||
on how you installed weewx and what operating system you are using</p></div>
|
||
<script type="text/javascript">
|
||
$("#skin-root-description-target").click(
|
||
function () {
|
||
$("#skin-root-description").dialog({position: {my:"left top", at:"right bottom", of: "#skin-root-description-target"}});
|
||
return false; // Insures that the "link" isn't followed
|
||
});
|
||
</script>
|
||
|
||
<h3>Generators</h3>
|
||
<p>
|
||
To create their output, skins rely on one or more <em>Generators</em>,
|
||
which are what do the actual work, such as creating 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="indent" summary="Generators included in weewx">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Generator</td>
|
||
<td>Function</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.cheetahgenerator.CheetahGenerator</td>
|
||
<td>Generates files from templates, using the Cheetah template engine. Used to generate HTML and text
|
||
files.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.imagegenerator.ImageGenerator</td>
|
||
<td>Generates graph plots.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.reportengine.FtpGenerator</td>
|
||
<td>Uploads data to a remote server using FTP.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.reportengine.RsyncGenerator</td>
|
||
<td>Uploads data to a remote server using rsync.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">weewx.reportengine.CopyGenerator</td>
|
||
<td>Copies files locally.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Note that the three generators <span class="code">FtpGenerator</span>,
|
||
<span class="code">RsyncGenerator</span>, and <span class="code">CopyGenerator</span>
|
||
do not 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's configuration file <span class="code">skin.conf</span>, in
|
||
section <a href="#generators_section"><span class="code">[Generators]</span></a>.</p>
|
||
|
||
<h3>Templates</h3>
|
||
<p>
|
||
A template is a text file that is processed by a <em>template engine</em>
|
||
to create a new file. <span class="code">Weewx</span>
|
||
uses the <a href="http://www.cheetahtemplate.org">Cheetah</a>
|
||
template engine. The generator <span class="code">weewx.cheetahgenerator.CheetahGenerator</span>
|
||
is responsible for running Cheetah at appropriate times.
|
||
</p>
|
||
<p>A template may be used to generate HTML, XML, CSV,
|
||
Javascript, or any other type of text file. A template typically
|
||
contains variables that are replaced when creating the new file.
|
||
Templates may also contain simple programming logic.</p>
|
||
<p>
|
||
Each template file lives in the skin directory of the skin that
|
||
uses it. By convention, a template file ends with the <span
|
||
class="code">.tmpl</span> extension.
|
||
</p>
|
||
|
||
<h2 id="wee_reports">The tool wee_reports</h2>
|
||
<p>If you make changes, how do you know what the results will look like?
|
||
You could just run weewx and wait until the next reporting cycle kicks
|
||
off but, depending on your archive interval, that could be a 30 minute
|
||
wait or more.</p>
|
||
<p>The tool <span class="code">wee_reports</span> allows you to run a
|
||
report whenever you like. To use it, just run it from a command line,
|
||
with the location of your configuration file
|
||
<span class="code">weewx.conf</span> as the first argument. Optionally,
|
||
if you include a unix epoch timestamp as a second argument, then the
|
||
report will use that as the "Current" time; otherwise, the time of the
|
||
last record in the archive database will be used. Here is an example,
|
||
using 1 May 2014 00:00 PDT as the "Current" time. NB: this example
|
||
assumes you used the <span class="code">setup.py</span> install
|
||
method. Adjust paths as necessary if you used another method.</p>
|
||
<pre class="tty">cd /home/weewx
|
||
./bin/wee_reports weewx.conf 1398927600</pre>
|
||
|
||
<h2>The database</h2>
|
||
<p>
|
||
<span class='code'>Weewx</span> uses a single database to store and retrieve the records it needs.
|
||
It can be implemented by using either
|
||
<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.
|
||
</p>
|
||
<p>
|
||
If you are familiar with the old, Version 2.X data architecture, you may find this white paper <a
|
||
href="https://docs.google.com/document/d/1CzuCPu7MsV3Rc3J6GbaMVxtrQ6z5F-xz0glvg3sUWjA/edit?usp=sharing"><i>V3 Database architecture</i></a> useful.
|
||
</p>
|
||
|
||
<h3>Structure</h3>
|
||
<p>
|
||
Inside this database are several tables. The most important is the
|
||
<em>archive table</em>, a big flat table, holding one record for each
|
||
archive interval, keyed by <span class="code">dateTime</span>, the
|
||
time at the end of the archive interval. It looks something like this:
|
||
</p>
|
||
<table class="indent" style="text-align:right">
|
||
<caption>Structure of the <span class="code">archive</span> database table</caption>
|
||
<tr class="code first_row">
|
||
<td>dateTime</td>
|
||
<td>usUnits</td>
|
||
<td>interval</td>
|
||
<td>barometer</td>
|
||
<td>pressure</td>
|
||
<td>altimeter</td>
|
||
<td>inTemp</td>
|
||
<td>outTemp</td>
|
||
<td>inHumidity</td>
|
||
<td>outHumidity</td>
|
||
<td>windSpeed</td>
|
||
<td>windDir</td>
|
||
<td>windGust</td>
|
||
<td>windGustDir</td>
|
||
<td>rainRate</td>
|
||
<td>...</td>
|
||
</tr>
|
||
|
||
<tr class="code">
|
||
<td>1413937800</td>
|
||
<td>1</td>
|
||
<td>5</td>
|
||
<td>29.938</td>
|
||
<td><i>null</i></td>
|
||
<td><i>null</i></td>
|
||
<td>71.2</td>
|
||
<td>56.0</td>
|
||
<td>54.0</td>
|
||
<td>78.0</td>
|
||
<td>3.0</td>
|
||
<td>270.0</td>
|
||
<td>9.0</td>
|
||
<td>270.0</td>
|
||
<td>0.0</td>
|
||
</tr>
|
||
<tr class="code">
|
||
<td>1413938100</td>
|
||
<td>1</td>
|
||
<td>5</td>
|
||
<td>29.941</td>
|
||
<td><i>null</i></td>
|
||
<td><i>null</i></td>
|
||
<td>71.2</td>
|
||
<td>55.9</td>
|
||
<td>54.0</td>
|
||
<td>78.0</td>
|
||
<td>2.0</td>
|
||
<td>247.5</td>
|
||
<td>5.0</td>
|
||
<td>225.0</td>
|
||
<td>0.0</td>
|
||
</tr>
|
||
<tr class="code">
|
||
<td>...</td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>The first three columns are <em>required.</em> Here's what they mean:</p>
|
||
<table class="indent">
|
||
<tr class="first_row">
|
||
<td>Name</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">dateTime</span></td>
|
||
<td>The time at the end of the archive interval in <a
|
||
href="http://en.wikipedia.org/wiki/Unix_time">unix epoch
|
||
time</a>. This is the <em>primary key</em> in the database. It
|
||
must be unique, and it cannot be null.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">usUnits</span></td>
|
||
<td>The unit system the record is in. It cannot be null. See the
|
||
<em><a href="#units">Appendix: Units</a></em> for how these
|
||
systems are encoded.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">interval</span></td>
|
||
<td>The length of the archive interval in <em>minutes</em>.
|
||
It cannot be null.</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>
|
||
In addition to the main archive table, there are a number of
|
||
smaller tables inside the database, one for each observation type,
|
||
that hold <em>daily summaries</em> of the type. For example, the
|
||
minimum and maximum value seen during the day, and at what time.
|
||
These tables have names such as <span class="code">archive_day_outTemp</span>
|
||
or <span class="code">archive_day_barometer</span>. Their existence
|
||
is generally transparent to the user.
|
||
</p>
|
||
|
||
<h3 id="binding_names">Binding names</h3>
|
||
<p>
|
||
While most users will only need the one weather database that comes with <span
|
||
class="code">weewx</span>, the reporting engine allows you to use
|
||
multiple databases in the same report. For example, if you have installed
|
||
the <a href="https://sourceforge.net/p/weewx/wiki/monitor/"><span
|
||
class="code">cmon</span></a> computer monitoring package, which uses its own
|
||
database, you may want to include some statistics or graphs about your
|
||
server in your reports, using that database.
|
||
</p>
|
||
<p>
|
||
An additional complication is that <span class="code">weewx</span> can use
|
||
more than one database implementation: SQLite or MySQL. Making
|
||
users specify in the templates not only which database to use,
|
||
but also which implementation, would be unreasonable.
|
||
</p>
|
||
<p>
|
||
The solution, like so many other problems in computer science, is to introduce
|
||
another level of indirection, a <em>database binding</em>. Rather than
|
||
specify which database to use, you specify which <em>binding</em> to use.
|
||
Bindings do not change with the database implementation, so, for example,
|
||
you know that <span class="code">wx_binding</span> will always point to
|
||
the weather database. Bindings are listed in section <a
|
||
href="usersguide.htm#DataBindings"><span class="code">[DataBindings]</span></a>
|
||
in <span class="code">weewx.conf</span>.
|
||
</p>
|
||
<p>
|
||
The standard weather database binding that <span class="code">weewx</span>
|
||
uses is <span class="code">wx_binding</span>. This is the binding that you
|
||
will be using most of the time and, indeed, it is the default. You rarely
|
||
have to specify it explicitly.
|
||
</p>
|
||
|
||
<h3>Programming interface</h3>
|
||
<p><span class='code'>weewx</span> includes a module called
|
||
<span class='code'>weedb</span> that provides a single interface for
|
||
many of the differences between database implementations such as SQLite
|
||
and MySQL. However, it is not uncommon to make direct SQL queries
|
||
within services or search list extensions. In such cases, the SQL
|
||
should be generic so that it will work with every type of database.</p>
|
||
<p>The database manager class provides methods to create, open, and
|
||
query a database. These are the canonical forms for obtaining a
|
||
database manager.</p>
|
||
<p>If you are opening a database from within a weewx service:</p>
|
||
<pre class='tty'>db_manager = self.engine.db_binder.get_manager(data_binding='name_of_binding', initialize=True)
|
||
|
||
# Sample query:
|
||
db_manager.getSql("SELECT SUM(rain) FROM %s "\
|
||
"WHERE dateTime>? AND dateTime<=?" % db_manager.table_name, (start_ts, stop_ts))</pre>
|
||
<p>If you are opening a database from within a weewx search list extension:</p>
|
||
<pre class='tty'>db_manager = self.generator.db_binder.get_manager(data_binding='name_of_binding')
|
||
|
||
# Sample query:
|
||
db_manager.getSql("SELECT SUM(rain) FROM %s "\
|
||
"WHERE dateTime>? AND dateTime<=?" % db_manager.table_name, (start_ts, stop_ts))</pre>
|
||
<p>If opening a database from somewhere other than a service, and there
|
||
is no DBBinder available:</p>
|
||
<pre class='tty'>db_manager = weewx.manager.open_manager_with_config(config_dict, data_binding='name_of_binding', initialize=)
|
||
|
||
# Sample query:
|
||
db_manager.getSql("SELECT SUM(rain) FROM %s "\
|
||
"WHERE dateTime>? AND dateTime<=?" % db_manager.table_name, (start_ts, stop_ts))</pre>
|
||
<p>The DBBinder caches managers, and thus database connections. It cannot
|
||
be shared between threads.</p>
|
||
|
||
<h2>Units</h2>
|
||
<p>The unit architecture in <span class='code'>weewx</span> is designed to
|
||
make basic unit conversions and display of units easy. It is not
|
||
designed to provide dimensional analysis, arbitrary conversions, and
|
||
indications of compatibility.</p>
|
||
<p>The <i>driver</i> reads observations from an instrument and converts
|
||
them, as necessary, into a standard set of units. The actual units
|
||
used by each instrument vary widely; some instruments use Metric
|
||
units, others use US Customary units, and many use a mixture. The
|
||
driver ensures that the units are consistent for storage in the
|
||
<span class='code'>weewx</span> database. By default, and to maintain
|
||
compatibility with <span class='code'>wview</span>, the database
|
||
units are US Customary.</p>
|
||
<p>Much of the <span class='code'>weewx</span> unit architecture is focused
|
||
on presenting data with the appropriate units. Although the units of the
|
||
data in the database are US Customary, they can be displayed in any
|
||
combination of unit systems.</p>
|
||
<p>Each <i>observation type</i> such as <span class='code'>outTemp</span>
|
||
or <span class='code'>pressure</span> may be associated with a
|
||
<i>unit group</i> such as <span class='code'>group_temperature</span> or
|
||
<span class='code'>group_pressure</span>. Each
|
||
unit group is associated with a <i>unit type</i> such
|
||
as <span class='code'>degree_F</span> or
|
||
<span class='code'>mbar</span>. The
|
||
<a href="#customizing_templates">template system</a>
|
||
uses this architecture to display the names of units and to convert
|
||
observations from one unit to another.</p>
|
||
<p>With this architecture one can easily create reports with, say, wind
|
||
measured in knots, rain measured in mm, and temperatures in degree
|
||
Celsius. Or one can create a single set of templates, but display
|
||
data in different unit systems with only a few stanzas in a configuration
|
||
file.</p>
|
||
|
||
<h1 id="customizing_reports">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
|
||
<span class="code">skin.conf</span>.</p>
|
||
<p>Each skin will have a <span class="code">skin.conf</span> that defines
|
||
its default configuration. The examples in this guide refer to the
|
||
standard skin that comes with the distribution.</p>
|
||
<h3>
|
||
Changing options in <span class="code">skin.conf</span>
|
||
</h3>
|
||
<p>
|
||
With this approach, edit the skin configuration file with a text
|
||
editor. Changes made in this way will be used by <span
|
||
class="code">weewx</span> the next time it generates reports,
|
||
which is typically the next archive interval; there is no need to
|
||
restart <span class="code">weewx</span> to see the results of the
|
||
changes.
|
||
</p>
|
||
<p>
|
||
For the standard skin that comes with <span class="code">weewx</span>,
|
||
the file is <span class="symcode">$SKIN_ROOT</span><span
|
||
class="code">/Standard/skin.conf</span>. It includes many, many
|
||
options that can be changed. For a complete list, see the section
|
||
<em><a href="#standard_skin">The Standard <span class="code">skin.conf</span></a></em>.
|
||
</p>
|
||
<p>
|
||
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 class="tty">[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>To use metric units, you would edit this section to read: </p>
|
||
<pre class="tty">[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 the
|
||
<em><a href="#units">Appendix: 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 "Barn Temperature," rather than
|
||
the default "Inside Temperature." This can be done by changing the <span
|
||
class="code">inTemp</span> option located in section <span class="code">[Labels][[Generic]]</span>
|
||
from the default </p>
|
||
<pre class="tty">[Units]
|
||
[[Generic]]
|
||
inTemp = Inside Temperature
|
||
outTemp = Outside Temperature
|
||
...</pre>
|
||
<p>to: </p>
|
||
<pre class="tty">[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>With this approach, you must restart <span class="code">weewx</span>
|
||
to see the effects of any changes.</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="symcode"> $HTML_ROOT</span>, the latter in a directory,
|
||
<span class="symcode"> $HTML_ROOT</span><span class="code">/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 directory
|
||
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 is 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 is based on the Standard skin
|
||
skin = Standard
|
||
|
||
# This report will use metric units:
|
||
[[MetricReport]]
|
||
# It is also based on the Standard skin:
|
||
skin = Standard
|
||
# However, override where the results will go and put them in a directory:
|
||
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
|
||
</pre>
|
||
<p>We have done two things different from the stock reports. First (1),
|
||
we have renamed the first report from <span class="code">StandardReport</span> to
|
||
<span class="code">USReport</span> for clarity; and second (2), we have
|
||
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> directory is
|
||
preserved), so you don't have to worry about losing changes after an upgrade.</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>
|
||
|
||
<h3>The dot code</h3>
|
||
<p>The key construct is a 'dot' 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 a
|
||
template file that contains:</p>
|
||
<pre class="tty"><html>
|
||
<head>
|
||
<title>Current conditions</title>
|
||
</head>
|
||
<body>
|
||
<p>Current temperature = $current.outTemp</p>
|
||
<p>Max for the month is $month.outTemp.max, which occurred at $month.outTemp.maxtime</p>
|
||
</body>
|
||
</html></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="#Units_Labels">[Units][[Labels]]</a></span>, while the time
|
||
format is from <span class="code"><a href="#Units_TimeFormats">[Units][[TimeFormats]]</a></span>.
|
||
</p>
|
||
<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 "do the right thing" and is all you
|
||
will need. However, <span class="code">weewx</span> offers extensive
|
||
customization of the generated 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 "current", or an aggregation over time. However, both
|
||
versions are similar.</p>
|
||
|
||
<h3>Time period <span class="code">$current</span></h3>
|
||
<p>Time period <span class="code">$current</span> represents a
|
||
<em>current observation</em>. An example would be the current
|
||
barometric pressure:
|
||
</p>
|
||
<pre class="tty">$current.barometer</pre>
|
||
<p>The most general dot code for a "current" observation looks like: </p>
|
||
<pre class="tty">$current($data_binding=<em>binding_name</em>).<em>obstype</em>[.<em>optional_unit_conversion</em>][.<em>optional_formatting</em>]</pre>
|
||
<p>Where:</p>
|
||
<p class="indent">
|
||
<span class="code">binding_name</span> is a <em>binding name</em>
|
||
to a database. An example would be <span class="code">wx_binding</span>.
|
||
See the section <em><a href="#binding_names">Binding names</a></em>
|
||
for more details.
|
||
</p>
|
||
<p class="indent">
|
||
<span class="code">obstype</span> is an observation type, such as
|
||
<span class="code">barometer</span>. See
|
||
<em><a href="#archive_types">Appendix: 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>.
|
||
</p>
|
||
<p class="indent">
|
||
<span class="code">optional_formatting</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>.
|
||
</p>
|
||
|
||
<h3>Time period <span class="code">$latest</span></h3>
|
||
<p>Time period <span class="code">$latest</span> is very similar
|
||
to <span class="code">$current</span>, except that it uses
|
||
the last available timestamp in a database. Usually,
|
||
<span class="code">$current</span> and <span class="code">$latest</span> are the same,
|
||
but if a data binding points to a remote database, they may not be. See
|
||
the section <em><a href="#stupid_detail">Using multiple bindings</a></em>
|
||
for an example where this happened.</p>
|
||
|
||
<h3 id="general_aggregation_periods">Aggregation periods</h3>
|
||
|
||
<p>A dot code such as</p>
|
||
<pre class="tty">$week.rain.sum</pre>
|
||
<p>represents an <em>aggregation over time</em>, using a certain <em>aggregation type</em>.
|
||
In this example, the aggregation time is a week, and the aggregation type is summation.
|
||
So, this tag represents the total rainfall over a week.
|
||
</p>
|
||
<p>The most general dot code for an aggregation over time looks like:</p>
|
||
<pre class="tty">$<em>period</em>($data_binding=<em>binding_name</em>).<em>statstype</em>.<em>aggregation</em>[.<em>optional_unit_conversion</em>][.<em>optional_formatting</em>]</pre>
|
||
<p>Where:</p>
|
||
<p class="indent">
|
||
<span class="code">period</span> is the time period over which
|
||
the aggregation is to be done. Possible choices are listed in a table below.
|
||
</p>
|
||
<p class="indent">
|
||
<span class="code">binding_name</span> is a <em>binding name</em>
|
||
to a database. An example would be <span class="code">wx_binding</span>.
|
||
See the section <em><a href="#binding_names">Binding names</a></em>
|
||
for more details.
|
||
</p>
|
||
<p class="indent">
|
||
<span class="code">statstype</span> is a <em>statistical type</em>. This
|
||
is generally any observation type that appears in the database, as well
|
||
as a few synthetic types (such as heating and cooling degree-days). Not
|
||
all aggregations are supported for all types.
|
||
</p>
|
||
<p class="indent">
|
||
<span class="code">aggregation</span> is an <em>aggregation type</em>.
|
||
If you
|
||
ask for <span class="code">$month.outTemp.avg</span> you are asking for
|
||
the <em>average</em> outside temperature for the month. Possible
|
||
aggregation types are given in
|
||
<em><a href="#aggregation_types">Appendix: Aggregation types</a></em>.
|
||
</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>.
|
||
</p>
|
||
<p class="indent">
|
||
<span class="code">optional_formatting</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>.
|
||
</p>
|
||
|
||
<p>
|
||
There are several different <em>aggregation periods</em> that can be used:
|
||
</p>
|
||
<table class="indent" style="width:80%">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td><i>Aggregation period</i></td>
|
||
<td>Example</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$hours_ago($hours_ago=<i>h</i>)</td>
|
||
<td class="code">$hours_ago($hours_ago=1).outTemp.avg</td>
|
||
<td>The average temperature last hour (1 hour ago).</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$hour</td>
|
||
<td class="code">$hour.outTemp.maxtime</td>
|
||
<td>The time of the maximum temperature this hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day</td>
|
||
<td class="code">$day.outTemp.max</td>
|
||
<td>Max temperature since midnight today.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$days_ago($days_ago=<i>d</i>)</td>
|
||
<td class="code">$days_ago($days_ago=2).outTemp.avg</td>
|
||
<td>The average temperature day before yesterday (2 days ago).</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$yesterday</td>
|
||
<td class="code">$yesterday.outTemp.maxtime</td>
|
||
<td>The time of yesterday's maximum temperature.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$week</td>
|
||
<td class="code">$week.outTemp.max</td>
|
||
<td>This week's max temperature. The start of the week is set by option
|
||
<a href="usersguide.htm#week_start"><span class="code">week_start</span></a></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$month</td>
|
||
<td class="code">$month.outTemp.min</td>
|
||
<td>The minimum temperature since the start of the month.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$year</td>
|
||
<td class="code">$year.outTemp.max</td>
|
||
<td>The max temperature since the start of the year.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$rainyear</td>
|
||
<td class="code">$rainyear.rain.sum</td>
|
||
<td>The total rainfall for this rain year. The start of the rain year is
|
||
set by option <a href="usersguide.htm#rain_year_start"><span class="code">rain_year_start</span></a>.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="unit_conversion_options">Unit conversion options</h3>
|
||
<p>The tag <span class="code">optional_unit_conversion</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>
|
||
<pre class="tty">Today's average pressure=$day.barometer.avg </pre>
|
||
<p>would normally give a result such as </p>
|
||
<p class="example_output">Today's average pressure=30.05 inHg </p>
|
||
<p>However, if you add <span class="code">mbar</span> to the end, </p>
|
||
<pre class="tty">$day.barometer.avg.mbar </pre>
|
||
<p>then the results will be in millibars: </p>
|
||
<p class="example_output">Today's average pressure=1017.5 mbar </p>
|
||
<h4>Wind ordinals</h4>
|
||
<p>Using this method, you can output compass ordinals for wind direction.
|
||
For example, the template</p>
|
||
<pre class="tty">Current wind direction is $current.windDir ($current.windDir.ordinal_compass)</pre>
|
||
<p>would result in:</p>
|
||
<p class="example_output">Current wind direction is 138° (SW)</p>
|
||
<p>The ordinal abbreviations are set by option <span class="code">directions</span>
|
||
in the skin configuration file <span class="code">skin.conf</span>.</p>
|
||
<h4>Illegal conversions</h4>
|
||
<p>If an inappropriate or nonsense conversion is asked for, <em>e.g.</em>, </p>
|
||
<pre class="tty">Today's minimum pressure in mbars: $day.barometer.min.mbar
|
||
or in degrees C: $day.barometer.min.degree_C
|
||
or in foobar units: $day.barometer.min.foobar
|
||
</pre>
|
||
<p>then the offending tag(s) will be put in the output: </p>
|
||
<p class="example_output">Today's minimum pressure in mbars: 1015.3<br/>
|
||
or in degrees C: $day.barometer.min.degree_C<br/>
|
||
or in foobar units: $day.barometer.min.foobar
|
||
</p>
|
||
|
||
<h3 id="formatting_options">Formatting options</h3>
|
||
<p>The tag <span class="code">optional_formatting</span> can be
|
||
used with either current observations or aggregations. It can be one of:
|
||
</p>
|
||
<table class="indent" summary="Formatting Options">
|
||
<caption>Optional formatting tags</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Optional formatting tag</td>
|
||
<td>Comment</td>
|
||
</tr>
|
||
<tr>
|
||
<td class='text_highlight'>(no tag)</td>
|
||
<td>Value is returned as a string, formatted using an appropriate
|
||
string format from <span class="code">skin.conf</span>. A unit
|
||
label (e.g., <span class='code'>°F</span>) from <span class="code">skin.conf</span> is also attached
|
||
at the end.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">.string(<em>NONE_string</em>)</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 (e.g., <span class='code'>°F</span>)
|
||
from <span class="code">skin.conf</span> will be attached at the end.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_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 unit label will be attached.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">.format(<em>string_format</em>, <em>NONE_string</em>)</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 (e.g., <span class='code'>°F</span>)
|
||
from <span class="code">skin.conf</span> will be attached at the end.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">.nolabel(<em>string_format, NONE_string</em>)</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 unit label will be attached at the end.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight"> <span class="code">.raw</span> </td>
|
||
<td>Value is returned "as is" without being converted to a string
|
||
and without any formatting applied. This can be useful for doing
|
||
arithmetic directly within the templates. 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">''</span>)
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p> </p>
|
||
<table class="indent" summary="Summary of formatting options">
|
||
<caption>Summary of formatting options</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Formatting Tag</td>
|
||
<td>Format Used</td>
|
||
<td>Label Used</td>
|
||
<td>NONE String</td>
|
||
<td>Returned Value</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">(no tag)</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="code first_col">.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="code first_col">.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="code first_col">.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="code first_col">.nolabel</td>
|
||
<td>User-supplied</td>
|
||
<td>No label</td>
|
||
<td>Optional user-supplied</td>
|
||
<td>string</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.raw</td>
|
||
<td>None</td>
|
||
<td>No label</td>
|
||
<td>None</td>
|
||
<td>native value</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Here are some examples with the expected results: </p>
|
||
<table class="indent" summary="Formatting options with expected results">
|
||
<caption>Formatting options with expected results</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag</td>
|
||
<td>Result</td>
|
||
<td>Comment</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$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="code first_col">$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="code first_col">$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="code first_col">$current.UV.string("No UV")</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="code first_col">$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="code first_col">$current.outTemp.format("%.3f") </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="code first_col">$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="code first_col">$current.dateTime.format("%H:%M")</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="code first_col">$current.dateTime.raw</td>
|
||
<td class="code">1270250700</td>
|
||
<td>Unix epoch time, converted to string by template engine.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.raw</td>
|
||
<td class="code">45.2</td>
|
||
<td>Float returned, converted to string by template engine.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$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="code first_col">$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="code first_col">$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="code first_col">$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="code first_col">$month.UV.avg.string("No UV")</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="code first_col">$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="code first_col">$month.outTemp.avg.format("%.3f")</td>
|
||
<td class="code">40.759°F</td>
|
||
<td>Specified string format used; no label</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$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="code first_col">$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>
|
||
</tbody>
|
||
</table>
|
||
<p>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.</p>
|
||
|
||
<h3>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>
|
||
<p> For example, </p>
|
||
<pre class="tty">$month.dateTime.format("%B %Y")</pre>
|
||
<p>produces </p>
|
||
<p class="example_output">January 2010</p>
|
||
<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'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="indent" style="width: 50%" summary="Examples of using unit formats">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag</td>
|
||
<td>Results</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$trend.barometer</td>
|
||
<td class="code">-.05 inHg</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$trend($time_delta=3600).barometer</td>
|
||
<td class="code">-.02 inHg</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$trend.outTemp</td>
|
||
<td class="code">1.1 °C</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$trend.time_delta</td>
|
||
<td class="code">10800 secs</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$trend.time_delta.hour</td>
|
||
<td class="code">3 hrs</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>
|
||
Not how you can explicitly specify a value in the tag itself (2nd example
|
||
above). If you do not specify a value, then a default time
|
||
interval, set by option <span class="code"><a href="#trend">time_delta</a></span>
|
||
in the skin configuration file, will be used. This value can be retrieved
|
||
by using the syntax <span class="code">$trend.time_delta</span> (3rd
|
||
example above).
|
||
</p>
|
||
<p>For example, the template expression</p>
|
||
<pre class="tty">The barometer trend over $trend.time_delta.hour is $trend.barometer.format("%+.2f")</pre>
|
||
<p>would result in</p>
|
||
<p class="example_output">The barometer trend over 3 hrs is +.03 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="indent" style="width: 50%" summary="Examples of using unit formats">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag</td>
|
||
<td>Results</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$unit.unit_type.outTemp</td>
|
||
<td class="code">degree_C</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$unit.label.outTemp</td>
|
||
<td class="code">°C</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$unit.format.outTemp</td>
|
||
<td class="code">%.1f</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>For example, the tag </p>
|
||
<pre class="tty">$day.outTemp.max.formatted$unit.label.outTemp</pre>
|
||
<p>would result in </p>
|
||
<p class="example_output">21.2°C</p>
|
||
<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. </p>
|
||
<p>For example, the following template uses a Cheetah
|
||
<span class="code">for</span> loop to iterate over all months in
|
||
a year, printing out each month's min and max temperature. The
|
||
iteration loop is
|
||
<span class="highlight"> highlighted </span>.</p>
|
||
<pre class="tty">Min, max temperatures by month
|
||
<span class="highlight">#for $month in $year.months</span>
|
||
$month.dateTime.format("%B"): Min, max temperatures: $month.outTemp.min $month.outTemp.max
|
||
<span class="highlight">#end for</span></pre>
|
||
<p>The result is:</p>
|
||
<p class="example_output">Min, max temperatures by month:<br/>
|
||
January: Min, max temperatures: 30.1°F 51.5°F<br/>
|
||
February: Min, max temperatures: 24.4°F 58.6°F<br/>
|
||
March: Min, max temperatures: 27.3°F 64.1°F<br/>
|
||
April: Min, max temperatures: 33.2°F 52.5°F<br/>
|
||
May: Min, max temperatures: N/A N/A<br/>
|
||
June: Min, max temperatures: N/A N/A<br/>
|
||
July: Min, max temperatures: N/A N/A<br/>
|
||
August: Min, max temperatures: N/A N/A<br/>
|
||
September: Min, max temperatures: N/A N/A<br/>
|
||
October: Min, max temperatures: N/A N/A<br/>
|
||
November: Min, max temperatures: N/A N/A<br/>
|
||
December: Min, max temperatures: N/A N/A</p>
|
||
<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 an example template:</p>
|
||
<p class="tty">Current time is $current.dateTime
|
||
#if $almanac.hasExtras
|
||
Sunrise, transit, sunset: $almanac.sun.rise $almanac.sun.transit $almanac.sun.set
|
||
Moonrise, transit, moonset: $almanac.moon.rise $almanac.moon.transit $almanac.moon.set
|
||
Mars rise, transit, set: $almanac.mars.rise $almanac.mars.transit $almanac.mars.set
|
||
Azimuth, altitude of mars: $almanac.mars.az $almanac.mars.alt
|
||
Next new, full moon: $almanac.next_new_moon $almanac.next_full_moon
|
||
Next summer, winter solstice: $almanac.next_summer_solstice $almanac.next_winter_solstice
|
||
#else
|
||
Sunrise, sunset: $almanac.sunrise $almanac.sunset
|
||
#end if</p>
|
||
<p>If pyephem is installed this would result in: </p>
|
||
<p class="example_output">Current time is 29-Mar-2011 09:20<br/>
|
||
Sunrise, transit, sunset: 06:51 13:11 19:30<br/>
|
||
Moonrise, transit, moonset: 04:33 09:44 15:04<br/>
|
||
Mars rise, transit, set: 06:35 12:30 18:26<br/>
|
||
Azimuth, altitude of mars: 124.354959275 26.4808431952<br/>
|
||
Next new, full moon: 03-Apr-2011 07:32 17-Apr-2011 19:43<br/>
|
||
Next summer, winter solstice: 21-Jun-2011 10:16 21-Dec-2011 21:29</p>
|
||
<p>Otherwise, a fallback of basic calculations is used, resulting in:</p>
|
||
<p class="example_output">Current time is 29-Mar-2011 09:20<br/>
|
||
Sunrise, sunset: 06:51 19:30</p>
|
||
<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>Here is a table of the information that falls into this category:</p>
|
||
<table class="indent" style="width:60%">
|
||
<caption>Calendar events</caption>
|
||
<tbody class="code">
|
||
<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>
|
||
</tbody>
|
||
</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>
|
||
<pre class="tty">$almanac.jupiter.rise</pre>
|
||
<p>or</p>
|
||
<pre class="tty">$almanac.sun.transit</pre>
|
||
<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>
|
||
<pre class="tty">$almanac.sun.rise</pre>
|
||
<p>use</p>
|
||
<pre class="tty">$almanac(pressure=0, horizon=-34.0/60.0).sun.rise</pre>
|
||
<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 degrees, 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>
|
||
<pre class="tty">$almanac(pressure=0, horizon=-6).sun(use_center=1).rise</pre>
|
||
<p>The general syntax is:</p>
|
||
<pre class="tty">$almanac(pressure=<em>pressure</em>, horizon=<em>horizon</em>,
|
||
temperature=<em>temperature_C</em>).<em>heavenly_body</em>(use_center=[01]).<em>attribute</em></pre>
|
||
<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.</p>
|
||
<p>The possible values for the <span class="code">attribute</span> tag
|
||
are listed in the following table:</p>
|
||
<table class="indent" style="width: 80%">
|
||
<caption>Attributes that can be used with heavenly bodies</caption>
|
||
<tbody class="code">
|
||
<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> </td>
|
||
<td> </td>
|
||
<td> </td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
|
||
<h3>Wind</h3>
|
||
<p>
|
||
Wind deserves a few comments because it is stored in the database in two
|
||
different ways: as a set of scalars, and as a <em>vector</em> of speed and
|
||
direction. Here are the four wind-related scalars stored in the main archive
|
||
database:
|
||
</p>
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td><i>Archive type</i></td>
|
||
<td>Meaning</td>
|
||
<td>Valid contexts</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">windSpeed</span></td>
|
||
<td>The average wind speed seen during the archive period.</td>
|
||
<td rowspan='4'>
|
||
<span class='code'>$current</span>,
|
||
<span class='code'>$latest</span>,
|
||
<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>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">windDir</span></td>
|
||
<td>If software record generation is used, this is the vector
|
||
average over the archive period. If hardware record generation is
|
||
used, the value is hardware dependent.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">windGust</span></td>
|
||
<td>The maximum (gust) wind speed seen during the archive period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">windGustDir</span></td>
|
||
<td>The direction of the wind when the gust was observed.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>In addition, a wind vector is stored in the daily summaries.</p>
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td><i>Daily summary type</i></td>
|
||
<td>Meaning</td>
|
||
<td>Valid contexts</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">wind</span></td>
|
||
<td>A vector composite of the wind. It includes information such
|
||
as the direction of the maximum gust, and the x- and y-vector
|
||
wind run.</td>
|
||
<td>
|
||
<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>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="note" style="display:inline-block">
|
||
<b>Note</b><br/>The vector is only stored in the daily
|
||
<em>summaries</em>, so unlike the scalar tags such as
|
||
<span class="code">windSpeed</span> or
|
||
<span class="code">windGust</span>, the tag
|
||
<span class="code">wind</span> can only be used in aggregations such as
|
||
<span class="code">$day</span>, <span class="code">$month</span>,
|
||
<i>etc.</i>
|
||
</p>
|
||
|
||
<p>Any of these can be used in your tags. Here are some examples:</p>
|
||
|
||
<table class="indent" style="width: 50%;">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td><i>Tag</i></td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$current.windSpeed</span></td>
|
||
<td>The average wind speed over the most recent archive interval.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$current.windDir</span></td>
|
||
<td>If software record generation is used, this is the vector
|
||
average over the archive interval. If hardware record generation is
|
||
used, the value is hardware dependent.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$current.windGust</span></td>
|
||
<td>The maximum wind speed (gust) over the most recent archive interval.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$current.windGustDir</span></td>
|
||
<td>The direction of the gust.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.windSpeed.avg</span></td>
|
||
<td>The average wind speed since midnight. If the wind blows east
|
||
at 5 m/s for 2 hours, then west at 5 m/s for 2 hours, the average
|
||
wind speed is 5 m/s.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.wind.avg</span></td>
|
||
<td>The average wind speed since midnight. Same as
|
||
<span class="code">$day.windSpeed.avg</span> above.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.wind.vecavg</span></td>
|
||
<td>The <em>vector average</em> wind speed since midnight. If the
|
||
wind blows east at 5 m/s for 2 hours, then west at 5 m/s for 2
|
||
hours, the vector average wind speed is zero.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.windSpeed.max</span></td>
|
||
<td>The max average wind speed. The wind is averaged over each of
|
||
the archive intervals. Then these numbers are averaged. Note that
|
||
this is <em>not</em> the same as the maximum observed wind speed.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.windGust.max</span></td>
|
||
<td>The maximum observed wind speed since midnight, <i>i.e.,</i>
|
||
the maximum gust.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.windDir.avg</span></td>
|
||
<td>Not a very useful quantity. This is the strict, arithmetic
|
||
average of all the compass wind direction. Probably not what you
|
||
want.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">$day.wind.vecdir</span></td>
|
||
<td>The direction of the vector averaged wind speed. If the wind
|
||
blows northwest for two hours, then southwest for two hours, the
|
||
vector averaged direction is west.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 id="defining_new_tags">Defining new tags</h2>
|
||
|
||
<p>
|
||
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 perhaps uses the database? Simply
|
||
putting it in the <span class="code">[Extras]</span> section
|
||
won't do, because then it cannot change.
|
||
</p>
|
||
<p>
|
||
The answer is to write a <em>search list extension</em>.
|
||
</p>
|
||
|
||
<h3>How the search list works</h3>
|
||
<p>
|
||
Let's start by taking a look at how the Cheetah <em>search list</em>
|
||
works.
|
||
</p>
|
||
<p>
|
||
The Cheetah template engine finds tags by scanning a search list, a Python
|
||
list of objects. For example, for a tag <span class="code">$foo</span>,
|
||
the engine will scan down the list, trying each object in the
|
||
list in turn. For each object, it will first try using <span
|
||
class="code">foo</span> as an attribute, that is, it will try
|
||
evaluating <span class="code"><i>obj</i>.foo</span>. If that
|
||
raises an <span class="code">AttributeError</span> exception,
|
||
then it will try <span class="code">foo</span> as a key, that is
|
||
<span class="code"><i>obj</i>[key]</span>. If that raises a <span
|
||
class="code">KeyError</span> exception, then it moves on to
|
||
the next item in the list. The first match that does not raise
|
||
an exception is used. If no match is found, Cheetah raises a <span
|
||
class="code">NameMapper.NotFound</span> exception.
|
||
</p>
|
||
|
||
<h3 id="how_tags_work">How tags work</h3>
|
||
<p>
|
||
Now let's take a look at how the search list interacts with <span
|
||
class="code">weewx</span> tags. Let's start by looking at a
|
||
simple example: station altitude, available as the tag
|
||
</p>
|
||
<pre class="tty">
|
||
$station.altitude</pre>
|
||
|
||
<p>
|
||
As we saw in the previous section, Cheetah will run down the
|
||
search list, looking for an object with a key or attribute <span
|
||
class="code">station</span>. In the default search list, <span
|
||
class="code">weewx</span> includes one such object, an
|
||
instance of the class <span class="code">weewx.cheetahgenerator.Station</span>,
|
||
which has an attribute <span class="code">station</span>, so it
|
||
gets a hit on this object.
|
||
</p>
|
||
<p>
|
||
Cheetah will then try to evaluate the attribute <span
|
||
class="code">altitude</span> on this object. Class <span
|
||
class="code">Station</span> has such an attribute, so Cheetah
|
||
evaluates it.
|
||
</p>
|
||
|
||
<p>
|
||
What this attribute returns is not a raw value, say <span
|
||
class="code">700</span>, nor even a string. Instead, it
|
||
returns an instance of the class <span class="code">ValueHelper</span>,
|
||
a special class defined in module <span class="code">weewx.units</span>.
|
||
Internally, it holds not only the raw value, but also references
|
||
to the formats, labels, and conversion targets
|
||
you specified in your configuration file. Its job is to make sure
|
||
that the final output reflects these preferences. Cheetah doesn't know
|
||
anything about this class. What it needs, when it has finished
|
||
evaluating the expression <span class="code">$day.outTemp.max</span>
|
||
is a <em>string</em>. In order to convert the <span class="code">ValueHelper</span>
|
||
it has into a string, it does what every other Python object does when
|
||
faced with this problem: it calls the special method <span
|
||
class="code"><a style="text-decoration: none"
|
||
href="https://docs.python.org/2/reference/datamodel.html#object.__str__">__str__</a></span>.
|
||
Class <span class="code">ValueHelper</span> has a definition for
|
||
this method. Evaluating this function triggers the final steps
|
||
in this process. Any necessary unit conversions are done, then
|
||
formatting occurs and, finally, a label is attached. The result
|
||
is a string something like
|
||
</p>
|
||
<p class="example_output">700 feet</p>
|
||
<p>which is what Cheetah actually puts in the generated HTML
|
||
file. This is a good example of <em>lazy evaluation</em>. The
|
||
tags gather all the information they need, but don't do the final
|
||
evaluation until the last final moment, when the most
|
||
context is understood. Weewx uses this technique extensively.
|
||
</p>
|
||
|
||
<p>
|
||
Now let's look at a more complicated example, say the maximum temperature since midnight:
|
||
</p>
|
||
<pre class="tty">$day.outTemp.max</pre>
|
||
<p>
|
||
When this is evaluated by Cheetah, it actually produces a chain of
|
||
objects. At the top of this chain is class <span class="code">weewx.tags.TimeBinder</span>,
|
||
an instance of which is included in the default search list. Internally,
|
||
this instance stores the time of the desired report (usually the time of
|
||
the last archive record), a cache to the databases, a default data
|
||
binding, as well as references to the formatting and labelling options you
|
||
have chosen.
|
||
</p>
|
||
<p>
|
||
This instance is examined by Cheetah to see if it has an attribute <span
|
||
class="code">day</span>. It does and, when it is evaluated, it returns
|
||
the next class in the chain, an instance of <span class="code">weewx.tags.TimespanBinder</span>.
|
||
In addition to all the other things contained in its parent <span
|
||
class="code">TimeBinder</span>, class <span class="code">TimespanBinder</span> adds the desired time
|
||
period, that is, the time span from midnight to the current time.
|
||
</p>
|
||
<p>
|
||
Cheetah then continues on down the chain and tries to find the next
|
||
attribute, <span class="code">outTemp</span>. There is no such hard coded
|
||
attribute (hard coding all the different observation types would be
|
||
impossible!). Instead, class <span class="code">TimespanBinder</span>
|
||
defines the method <span class="code">
|
||
<a style="text-decoration: none"
|
||
href="https://docs.python.org/2/reference/datamodel.html#object.__getattr__">__getattr__</a></span>. Any unknown attribute is passed to this
|
||
special method. It returns an instance of the next class in the chain, <span
|
||
class="code">weewx.tags.ObservationBinder</span>, which not only
|
||
remembers all the previous stuff, but also adds the observation type, <span
|
||
class="code">outTemp</span>.
|
||
</p>
|
||
<p>
|
||
Cheetah then tries to evaluate an attribute <span class="code">max</span>
|
||
of this class. Now, finally, the chain ends. The attribute <span
|
||
class="code">max</span> triggers the actual calculation of the
|
||
value, using all the known parameters: the database binding to be hit,
|
||
the time span of interest, the observation type, and the type of
|
||
aggregation, querying the database as necessary. The database is not
|
||
actually hit until the last possible moment, after everything
|
||
needed to do the evalation is known.
|
||
</p>
|
||
<p>
|
||
Like our previous example, the results of the evaluation are then
|
||
packaged up in an instance of <span class="code">ValueHelper</span>,
|
||
which does the final conversion to the desired units, formats
|
||
the string, then adds a label. The results, something like
|
||
</p>
|
||
<p class="example_output">12°C</p>
|
||
<p>
|
||
are put in the generated HTML file. As you can see, a lot of
|
||
machinery is hidden behind the deceptively simple expression <span
|
||
class="code">$day.outTemp.max</span>!
|
||
</p>
|
||
|
||
<h3 id="extending_the_list">Extending the list</h3>
|
||
<p>
|
||
As mentioned, <span class="code">weewx</span> comes with a
|
||
number of objects already in the search list, but you can extend
|
||
it. To do so, you should have some familiarity with Python, in
|
||
particular, how to write new classes and member functions for
|
||
them.
|
||
</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="symcode">
|
||
$BIN_ROOT</span><span class="code">/examples/xsearch.py</span>: </p>
|
||
<pre class="tty">import datetime
|
||
import time
|
||
|
||
from weewx.cheetahgenerator import SearchList
|
||
from weewx.tags import TimespanBinder
|
||
from weeutil.weeutil import TimeSpan
|
||
|
||
class MyXSearch(SearchList): # 1
|
||
"""My search list extension"""
|
||
|
||
def __init__(self, generator): # 2
|
||
SearchList.__init__(self, generator)
|
||
|
||
def get_extension_list(self, timespan, db_lookup): # 3
|
||
"""Returns a search list extension with two additions.
|
||
|
||
Parameters:
|
||
timespan: An instance of weeutil.weeutil.TimeSpan. This will
|
||
hold the start and stop times of the domain of
|
||
valid times.
|
||
|
||
db_lookup: This is a function that, given a data binding
|
||
as its only parameter, will return a database manager
|
||
object.
|
||
"""
|
||
|
||
# First, create TimespanBinder object for all time. This one is easy
|
||
# because the object timespan already holds all valid times to be
|
||
# used in the report.
|
||
all_stats = TimespanBinder(timespan,
|
||
db_lookup,
|
||
formatter=self.generator.formatter,
|
||
converter=self.generator.converter) # 4
|
||
|
||
# Now get a TimespanBinder 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(timespan.stop) - \
|
||
datetime.timedelta(weeks=1) # 5
|
||
# Convert it to unix epoch time:
|
||
week_ts = time.mktime(week_dt.timetuple()) # 6
|
||
# Form a TimespanBinder object, using the time span we just
|
||
# calculated:
|
||
seven_day_stats = TimespanBinder(TimeSpan(week_ts, timespan.stop),
|
||
db_lookup,
|
||
formatter=self.generator.formatter,
|
||
converter=self.generator.converter) # 7
|
||
|
||
# Now create a small dictionary with keys 'alltime' and 'seven_day':
|
||
search_list_extension = {'alltime' : all_stats,
|
||
'seven_day' : seven_day_stats} # 8
|
||
|
||
# Finally, return our extension as a list:
|
||
return [search_list_extension] # 9</pre>
|
||
|
||
<p>Going through the example, line by line: </p>
|
||
<ol>
|
||
<li>Create a new class called <span class="code">MyXSearch</span>,
|
||
which will inherit from class <span class="code">SearchList</span>. All
|
||
search list extensions inherit from this class.
|
||
</li>
|
||
<li>Create an initializer for our new class. In this case, the
|
||
initializer is not really necessary and does nothing except pass its
|
||
only parameter, <span class="code">generator</span>, a reference to the
|
||
calling generator, on to its superclass, <span class="code">SearchList</span>.
|
||
The superclass will store it in <span class="code">self</span>.
|
||
</li>
|
||
<li>Override member function <span class="code">get_extension_list()</span>.
|
||
This function will be called when the generator is ready to accept your
|
||
new search list extension. 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">timespan</span> An instance of the
|
||
utility class <span class="code">TimeSpan</span>. This will contain
|
||
the valid start and ending times used by the template. Normally,
|
||
this is all valid times;</li>
|
||
<li><span class="code">db_lookup</span> This is a function
|
||
supplied by the generator. It takes a single argument, a
|
||
name of a binding. When called, it will return an instance of the database manager
|
||
class for that binding. The default for the function is whatever
|
||
binding you set with the option <span class="code">data_binding</span>
|
||
for this report, usually <span class="code">wx_binding</span>.
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>The class <span class="code">TimespanBinding</span> represents a
|
||
statistical calculation over a time period. We have already met it in
|
||
the introduction <em><a href="#how_tags_work">How tags work</a></em>.
|
||
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">timespan</span> already holds a <span
|
||
class="code">TimeSpan</span> object representing the domain of all
|
||
valid timespans, so we simply pass it in.
|
||
</li>
|
||
<li>The second is the database lookup function to be used. We simply pass in
|
||
<span class="code">db_lookup</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 the generator, <span
|
||
class="code">self.generator.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>, <span
|
||
class="code">degree_C</span>) that are to be used. Again, we just
|
||
pass in the instance set up by the generator, <span class="code">self.generator.converter</span>.
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<p>That one was relatively easy because we already had an instance of
|
||
<span class="code">TimeSpan</span>, that is,
|
||
<span class="code">timespan</span>,
|
||
which 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="5">
|
||
<li>The object <span class="code">timespan</span> holds the
|
||
domain of all valid times, but in order to calculate statistics for
|
||
the last seven days, we need not the earliest valid time, 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">TimespanBinder</span> object. It's the same as in
|
||
step #4, except we use our new timespan object.</li>
|
||
<li>Create a small dictionary with two keys,
|
||
<span class="code">alltime</span>, and
|
||
<span class="code">seven_day</span>.</li>
|
||
<li>Return the dictionary in a list</li>
|
||
</ol>
|
||
<p>The final step that we need to do is to tell the template engine where to find our
|
||
extension. You do that by going into the skin configuration file,
|
||
<span class="code">skin.conf</span>, and adding the option
|
||
<span class="code">search_list_extensions</span> with our new
|
||
extension. When you're done, it will look something like this:</p>
|
||
<pre class="tty">[CheetahGenerator]
|
||
# This section is used by the generator CheetahGenerator, and specifies
|
||
# which files are to be generated from which template.
|
||
|
||
# Possible encodings are 'html_entities', 'utf8', or 'strict_ascii'
|
||
encoding = html_entities
|
||
<span class="highlight">search_list_extensions = examples.xsearch.MyXSearch</span>
|
||
|
||
[[SummaryByMonth]]
|
||
...
|
||
</pre>
|
||
<p>Our addition has been <span class="highlight">highlighted</span>. Note that it is in the section
|
||
<span class="code">[CheetahGenerator]</span>.
|
||
</p>
|
||
<p>Now, if the Cheetah engine encounters the tag <span class="code">
|
||
$alltime</span>, it will scan the search list, looking for an
|
||
attribute or key that matches <span class="code">alltime</span>. When
|
||
it gets to the little dictionary we provided, it will find a matching
|
||
key, allowing it to retrieve the appropriate
|
||
<span class="code">TimespanBinding</span> object.</p>
|
||
<p>With this approach, you can now include "all time" or "seven day"
|
||
statistics in your HTML templates: </p>
|
||
<pre class="tty">
|
||
<table>
|
||
<tr>
|
||
<td>Maximum temperature to date: </td>
|
||
<td>$alltime.outTemp.max</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Minimum temperature to date: </td>
|
||
<td>$alltime.outTemp.min
|
||
</tr>
|
||
<tr>
|
||
<td>Rain over the last seven days: </td>
|
||
<td>$seven_day.rain.sum
|
||
</tr>
|
||
</table></pre>
|
||
<p>If you place a custom generator somewhere other than the
|
||
<span class="symcode">$BIN_ROOT</span> hierarchy where
|
||
<span class="code">weewxd</span> resides, you may have to specify its
|
||
location in the environment variable
|
||
<span class="code">PYTHONPATH</span>
|
||
in the shell where you start weewx:
|
||
</p>
|
||
<pre class="tty">export PYTHONPATH=/home/me/secret_location</pre>
|
||
|
||
|
||
<h2>Customizing images</h2>
|
||
<p>
|
||
The installed version of <span class="code">weewx</span> is configured to
|
||
generate a set of useful plots. But, what if you don't like how they look,
|
||
or you want to generate different plots, perhaps with different
|
||
aggregation types? This section covers how to do this.
|
||
</p>
|
||
<p>
|
||
Image generation is controlled by the section <span class="code">[ImageGenerator]</span>
|
||
in the skin configuration file <span class="code">skin.conf</span>. Let's
|
||
take a look at the beginning part of this section. It looks like this:
|
||
</p>
|
||
<pre class="tty">[ImageGenerator]
|
||
...
|
||
image_width = 300
|
||
image_height = 180
|
||
image_background_color = 0xf5f5f5
|
||
|
||
chart_background_color = 0xd8d8d8
|
||
chart_gridline_color = 0xa0a0a0
|
||
...</pre>
|
||
<p>
|
||
The options right under the section name <span class="code">[ImageGenerator]</span>
|
||
will apply to <em>all</em> plots, unless overridden in subsections. So,
|
||
unless otherwise changed, all plots will be 300 pixels in width, 180
|
||
pixels in height, and will have an RGB background color of 0xf5f5f5, a
|
||
very light gray (HTML color "WhiteSmoke"). The chart itself will have a
|
||
background color of 0xd8d8d8 (a little darker gray), and the gridlines
|
||
will be 0xa0a0a0 (still darker). The other options farther (not shown)
|
||
will also apply to all plots.
|
||
</p>
|
||
|
||
<h3>Time periods</h3>
|
||
<p>
|
||
After the "global" options at the top of section <span class="code">[ImageGenerator]</span>,
|
||
comes a set of sub-sections, one for each time period (day, week, month,
|
||
and year). These sub-sections define the nature of aggregation and plot
|
||
types for that time period. For example, here is a typical set of options
|
||
for sub-section <span class="code">[[month_images]]</span>. It controls
|
||
which "monthly" images will get generated, and what they will look like:
|
||
</p>
|
||
<pre class="tty"> [[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
|
||
show_daynight = false
|
||
</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 <span class="code">%d</span>). 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 something like<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. Finally, by setting
|
||
option <span class="code">show_daynight</span> to <span class="code">false</span>,
|
||
we are requesting that day-night, shaded bands not be shown.
|
||
</p>
|
||
|
||
<h3>Image files</h3>
|
||
<p>
|
||
Within each time period 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. Like
|
||
elsewhere, the values specified in the level above can be overridden. For
|
||
example, here is a typical set of options for sub-sub-section <span
|
||
class="code">[[[monthrain]]]</span>:
|
||
</p>
|
||
<pre class="tty"> [[[monthrain]]]
|
||
plot_type = bar
|
||
yscale = None, None, 0.02
|
||
[[[[rain]]]]
|
||
aggregate_type = sum
|
||
aggregate_interval = 86400
|
||
label = Rain (daily total)</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 is 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 <span class="code">None</span>, the
|
||
corresponding value will be automatically chosen. So, in this example, the
|
||
setting
|
||
</p>
|
||
<pre class="tty">yscale = None, None, 0.02</pre>
|
||
<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 "line"
|
||
(it will actually be a series of bars) and it will have logical name <span
|
||
class="code">rain</span>. Because we have not 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.
|
||
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 of 'Rain (daily total)'.
|
||
The result of all this is the following plot:
|
||
</p>
|
||
<p>
|
||
<img src="images/sample_monthrain.png" alt="Sample monthly rain plot" />
|
||
</p>
|
||
|
||
<h3 id="line_gaps">Line gaps</h3>
|
||
<p id="line_gap_fraction">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>
|
||
<div class="center" style="width:80%;margin:0;">
|
||
<div style="float:left">
|
||
<img src="images/day-gap-not-shown.png" alt="Gap not shown" />
|
||
<p class="image_caption"> No <span class="code">line_gap_fraction</span> specified</p>
|
||
</div>
|
||
<div>
|
||
<img src="images/day-gap-showing.png" alt="Gap showing" />
|
||
<p class="image_caption"> With <span class="code">line_gap_fraction=0.01</span></p>
|
||
</div>
|
||
</div>
|
||
<div style="clear:both"></div>
|
||
<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 is
|
||
how to generate a plot with the week's outside temperature as well as
|
||
dewpoint: </p>
|
||
<pre class="tty">[[[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 id="including_same_sql_type_2x">Including the same SQL type more than once in a plot</h3>
|
||
<p>Another example. Say you want a plot of the day's temperature, overlaid
|
||
with hourly averages. Here, you are using the same data type (<span class="code">outTemp</span>)
|
||
for both plot lines, the first with averages, the second without. If you
|
||
do the obvious it won't work: </p>
|
||
<pre class="tty">## WRONG ##
|
||
[[[daytemp_with_avg]]]
|
||
[[[[outTemp]]]]
|
||
aggregate_type = avg
|
||
aggregate_interval = 3600
|
||
<span style="text-decoration:line-through; color:red">[[[[outTemp]]]]</span> # OOPS! The same section name appears more than once!</pre>
|
||
<p>The option parser does not allow the same section name (<span class="code">outTemp</span>
|
||
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 class="tty">[[[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 <span class="code">a_logical_name</span>
|
||
to distinguish it from the second line <span class="code">outTemp</span>.
|
||
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's temperature, overlaid with a
|
||
3-hour smoothed average: </p>
|
||
<p>
|
||
<img alt="Daytime temperature with running average" src="images/daytemp_with_avg.png" />
|
||
</p>
|
||
<p>One more example. This one shows daily high and low temperatures for a
|
||
year:</p>
|
||
<pre class="tty">[[year_images]]
|
||
[[[yearhilow]]]
|
||
[[[[hi]]]]
|
||
data_type = outTemp
|
||
aggregate_type = max
|
||
label = High
|
||
[[[[low]]]]
|
||
data_type = outTemp
|
||
aggregate_type = min
|
||
label = Low Temperature</pre>
|
||
<p>This results in the plot <span class="code">yearhilow.png</span>:</p>
|
||
<p>
|
||
<img width="300" height="180" alt="Daily highs and lows"
|
||
src="images/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
|
||
<span class="code">vector</span>. You need a vector type to produce
|
||
this kind of plot. There are two: <span class="code">windvec</span>,
|
||
and <span class="code">windgustvec</span>. While they do not actually
|
||
appear in the SQL database, <span class="code">weewx</span> understands
|
||
that they represent special vector-types. The first, <span class="code">windvec</span>,
|
||
represents the average wind in an archive period, the second, <span class="code">windgustvec</span>
|
||
the max wind in an archive period. Here's how to produce a progressive
|
||
vector for one week that shows the hourly biggest wind gusts, along with
|
||
hourly averages: </p>
|
||
<pre class="tty">[[[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>
|
||
<img alt="hourly average wind vector overlaid with gust vectors"
|
||
src="images/weekgustoverlay.png" />
|
||
</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 do not 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 class="tty">[ImageGenerator]
|
||
...
|
||
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 class="tty">[[[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 <span class="code">daybarometer_big.png</span>.
|
||
</p>
|
||
<pre class="tty">[[[daybarometer_big]]]
|
||
image_width = 600
|
||
image_height = 360
|
||
[[[[barometer]]]]</pre>
|
||
|
||
|
||
<h2>Using multiple bindings</h2>
|
||
<p>
|
||
It's easy to use more than one database in your reports. Here's an
|
||
example. In my office I have two consoles: a VantagePro2 connected to a
|
||
Dell Optiplex, and a WMR100N, connected to a Raspberry Pi. Each is
|
||
running <span class="code">weewx</span>. The Dell is using SQLite, the
|
||
RPi, MySQL.
|
||
</p>
|
||
<p>Suppose I wish to compare the inside temperatures of the two
|
||
consoles. How would I do that?</p>
|
||
<p>
|
||
It's easier to access MySQL across a network than SQLite, so let's run the
|
||
reports on the Dell, but access the RPi's MySQL database remotely. Here's
|
||
how the bindings and database sections of <span class="code">weewx.conf</span>
|
||
would look on the Dell:
|
||
</p>
|
||
<pre class="tty">[DataBindings]
|
||
# This section binds a data store to an actual database
|
||
|
||
[[wx_binding]]
|
||
# The database to be used - it should match one of the sections in [Databases]
|
||
database = archive_sqlite
|
||
# The name of the table within the database
|
||
table_name = archive
|
||
# The class to manage the database
|
||
manager = weewx.wxmanager.WXDaySummaryManager
|
||
# The schema defines to structure of the database contents
|
||
schema = schemas.wview.schema
|
||
|
||
<span class="highlight"> [[wmr100_binding]]
|
||
# Binding for my WMR100 on the RPi
|
||
database = rpi_mysql
|
||
# The name of the table within the database
|
||
table_name = archive
|
||
# The class to manage the database
|
||
manager = weewx.wxmanager.WXDaySummaryManager
|
||
# The schema defines to structure of the database contents
|
||
schema = schemas.wview.schema</span>
|
||
|
||
[Databases]
|
||
# This section binds to the actual database to be used
|
||
|
||
[[archive_sqlite]]
|
||
root = %(WEEWX_ROOT)s
|
||
database_name = archive/weewx.sdb
|
||
driver = weedb.sqlite
|
||
|
||
<span class="highlight"> [[rpi_mysql]]
|
||
host = rpi-bug
|
||
user = weewx
|
||
password = weewx
|
||
database_name = weewx
|
||
driver = weedb.mysql</span>
|
||
</pre>
|
||
|
||
<p>
|
||
The two additions have been <span class="highlight">highlighted</span>.
|
||
The first, in section <span class="code">[DataBindings]</span>, adds a new
|
||
binding called <span class="code">wmr10_binding</span>. It links ("binds")
|
||
to the new database, called <span class="code">rpi_mysql</span>, through
|
||
the option <span class="code">database</span>. The new database is a MySQL
|
||
database, running on the remote host <span class="code">rpi-bug</span>,
|
||
the name of my Raspberry Pi.
|
||
</p>
|
||
|
||
<h3>Explicit binding in tags</h3>
|
||
<p>How do we use this new binding? First, let's do a text comparison,
|
||
using tags. Here's what our template looks like:</p>
|
||
<pre class="tty"><table>
|
||
<tr>
|
||
<td class="stats_label">Inside Temperature, Vantage</td>
|
||
<td class="stats_data">$current.inTemp</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="stats_label">Inside Temperature, WMR100</td>
|
||
<td class="stats_data">$latest<span class="highlight">($data_binding='wmr100_binding')</span>.inTemp</td>
|
||
</tr>
|
||
</table></pre>
|
||
|
||
<p>
|
||
The explicit binding to <span class="code">wmr100_binding</span> is
|
||
highlighted. This tells the reporting engine to override the default
|
||
binding specifed in <span class="code">[StdReport]</span>, generally <span
|
||
class="code">wx_binding</span>, and use <span class="code">wmr100_binding</span>
|
||
instead.
|
||
</p>
|
||
<p>This results in an HTML output that looks like:</p>
|
||
|
||
<div id="stats_group" class="indent">
|
||
<div class="stats example_output">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="stats_label">Inside Temperature, Vantage</td>
|
||
<td class="stats_data">68.7°F</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="stats_label">Inside Temperature, WMR100</td>
|
||
<td class="stats_data">68.9°F</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Explicit binding in images</h3>
|
||
<p>How would we produce a graph of the two different temperatures? Here's
|
||
what the relevant section of the <span class="code">skin.conf</span> file would look like.</p>
|
||
<pre class="tty">[[[daycompare]]]
|
||
[[[[inTemp]]]]
|
||
label = Vantage inTemp
|
||
[[[[WMR100Temp]]]]
|
||
data_type = inTemp
|
||
data_binding = wmr100_binding
|
||
label = WMR100 inTemp</pre>
|
||
|
||
<p>
|
||
This will produce an image with name <span class="code">daycompare.png</span>,
|
||
with two plot lines. The first will be of the temperature from the
|
||
Vantage. It uses the default binding, <span class="code">wx_binding</span>,
|
||
and will be labeled <span class="code">Vantage inTemp</span>. The second
|
||
explicitly uses the <span class="code">wmr100_binding</span>. Because it
|
||
uses the same variable name (<span class="code">inTemp</span>) as the
|
||
first line, we had to explicitly specify it using option <span
|
||
class="code">data_type</span>, in order to avoid using the same
|
||
sub-section name twice (see the section <em><a
|
||
href="#including_same_sql_type_2x">Including the same SQL
|
||
type more than once in a plot</a></em> for details). It will be labeled <span
|
||
class="code">WMR100 inTemp</span>. The results look like this:
|
||
</p>
|
||
<img src='images/daycompare.png' />
|
||
|
||
<h3 id="stupid_detail">Stupid detail</h3>
|
||
<p>
|
||
At first, I could not get this example to work. The problem turned out to
|
||
be that the RPi was processing things just a beat behind the Dell, so the
|
||
temperature for the "current" time wasn't ready when the Dell needed it. I
|
||
kept getting <span class="code">N/A</span>. To avoid this, I introduced
|
||
the tag <span class="code">$latest</span>, which uses the last available
|
||
timestamp in the binding, which may or may not be the same as what <span
|
||
class="code">$current</span> uses.
|
||
</p>
|
||
|
||
|
||
|
||
<h1 id="standard_skin">The Standard <span class="code">skin.conf</span></h1>
|
||
<p>This section is a reference to the options appearing in the skin
|
||
configuration file. The default skin is the Standard skin, with a
|
||
skin configuration file located at
|
||
<span class="symcode">$SKIN_ROOT</span><span class="code">/Standard/skin.conf</span>. </p>
|
||
<p>The most important options, the ones you are likely to have to
|
||
customize, are
|
||
<span class="config_important"><strong>highlighted</strong></span>.</p>
|
||
<p>It is worth noting that, like the main configuration file
|
||
<span class="code">weewx.conf</span>, UTF-8 is used throughout.
|
||
</p>
|
||
|
||
<h2 class="config_section" id="Extras">[Extras]</h2>
|
||
<p>This section is available to add any static tags you
|
||
might want to use in your templates.</p>
|
||
|
||
<h3>Example</h3>
|
||
<p>As an example, the Standard <span class="code">skin.conf</span>
|
||
file includes three options: </p>
|
||
<table class="indent" style="width:50%" summary="Tag Extras">
|
||
<tr class="first_row">
|
||
<td>Skin option</td>
|
||
<td>Template tag</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="code">radar_img</span></td>
|
||
<td><span class="code">$Extras.radar_img</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="code">radar_url</span></td>
|
||
<td><span class="code">$Extras.radar_url</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="code">googleAnalyticsId</span></td>
|
||
<td><span class="code">$Extras.googleAnalyticsId</span></td>
|
||
</tr>
|
||
</table>
|
||
<p>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_img</span> to find them).
|
||
</p>
|
||
<p class="config_option">radar_img</p>
|
||
<p>Set to an URL to show a local radar image for you.</p>
|
||
<p class="config_option">radar_url</p>
|
||
<p>If the above radar image is clicked, the browser will go to
|
||
this URL. This is usually used to show a more detailed,
|
||
close-up, radar picture.
|
||
</p>
|
||
<p>For me in Oregon, setting the above two options to:</p>
|
||
<pre class="tty">
|
||
[Extras]
|
||
radar_img = http://radar.weather.gov/ridge/lite/N0R/RTX_loop.gif
|
||
radar_url = http://radar.weather.gov/ridge/radar.php?product=NCR&rid=RTX&loop=yes</pre>
|
||
<p>results in a nice image of a radar centered on Portland,
|
||
Oregon. When you click on it, it gives you a detailed, animated view.
|
||
If you live in the USA, take a look at
|
||
the <a href="http://radar.weather.gov/">NOAA radar website</a>
|
||
to find a nice one that will work for you. In other countries, you
|
||
will have to consult your local weather service.
|
||
</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>
|
||
|
||
<h3>Extending <span class="code">[Extras]</span></h3>
|
||
<p>Other tags can be added in a similar manner, including sub-sections.
|
||
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 sub-section. </p>
|
||
<pre class="tty">[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 class="tty"><a href="$Extras.video.hyperlink">
|
||
<img src="$Extras.video.still" alt="Video capture"/>
|
||
</a></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 sub-section 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
|
||
<span class="code">outTemp</span>, <span class="code">barometer</span>,
|
||
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 "U.S. Customary" or "Metric"
|
||
seems overly restrictive. <span class="code">Weewx</span> has taken a
|
||
middle route and divided all the different observation types into 12
|
||
different <em>unit groups</em>. A unit group is something like <span
|
||
class="code">group_temperature</span>. It represents the measurement
|
||
system to be used by all observation types that are measured in
|
||
temperature, such as inside temperature
|
||
(type <span class="code">inTemp</span>),
|
||
outside temperature (<span class="code">outTemp</span>),
|
||
dewpoint (<span class="code">dewpoint</span>),
|
||
wind chill (<span class="code">windchill</span>),
|
||
and so on. If you decide that you want unit group <span class="code">group_temperature</span>
|
||
to be measured in <span class="code">degree_C</span> 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 <span class="code">degree_C</span> or <span class="code">foot</span>,
|
||
not <span class="code">degrees_C</span> or <span class="code">feet</span>.
|
||
See the <em><a href="#units">Appendix: 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" id="group_altitude">group_altitude</a>
|
||
</p>
|
||
<p>Which measurement unit to be used for altitude. Possible options are
|
||
<span class="code">foot</span> or <span class="code">meter</span>.</p>
|
||
<p class="config_option">group_direction </p>
|
||
<p>Which measurement unit to be used for direction. The only option is <span
|
||
class="code">degree_compass</span>. </p>
|
||
<p class="config_option">group_moisture </p>
|
||
<p>The measurement unit to be used for soil moisture. The only option is <span
|
||
class="code">centibar</span>. </p>
|
||
<p class="config_option">group_percent </p>
|
||
<p>The measurement unit to be used for percentages. The only option is <span
|
||
class="code">percent</span>. </p>
|
||
<p class="config_important">group_pressure </p>
|
||
<p>The measurement unit to be used for pressure. Possible options are one
|
||
of <span class="code">inHg</span> (inches of mercury), <span class="code">mbar</span>,
|
||
or <span class="code">hPa</span>. </p>
|
||
<p class="config_option">group_radiation </p>
|
||
<p>The measurement unit to be used for radiation. The only option is <span
|
||
class="code">watt_per_meter_squared</span>. </p>
|
||
<p class="config_important">group_rain </p>
|
||
<p>The measurement unit to be used for precipitation. Options are <span class="code">inch</span>,
|
||
<span class="code">cm</span>, or <span class="code">mm</span>. </p>
|
||
<p class="config_important">group_rainrate </p>
|
||
<p>The measurement unit to be used for rate of precipitation. Possible
|
||
options are one of <span class="code">inch_per_hour</span>, <span class="code">cm_per_hour</span>,
|
||
or <span class="code">mm_per_hour</span>. </p>
|
||
<p class="config_important">group_speed </p>
|
||
<p>The measurement unit to be used for wind speeds. Possible options are
|
||
one of <span class="code">mile_per_hour</span>, <span class="code">km_per_hour</span>,
|
||
<span class="code">knot</span>, or <span class="code">meter_per_second</span>.
|
||
</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 <span class="code">mile_per_hour2</span>,
|
||
<span class="code">km_per_hour2</span>, <span class="code">knot2</span>,
|
||
or <span class="code">meter_per_second2</span>. </p>
|
||
<p><a class="config_important" id="group_temperature">group_temperature</a>
|
||
</p>
|
||
<p>The measurement unit to be used for temperatures. Options are <span class="code">degree_F</span>
|
||
or <span class="code">degree_C</span>. </p>
|
||
<p class="config_option">group_volt </p>
|
||
<p>The measurement unit to be used for voltages. The only option is <span
|
||
class="code">volt</span>. </p>
|
||
<h3 class="config_section" id="Units_StringFormats">[[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 class="tty">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>, and are very similar
|
||
to C's <span class="code">sprintf()</span> codes. </p>
|
||
<p>You can also specify what string to use for an invalid or unavailable
|
||
measurement (value <span class="code">None</span>). For example, </p>
|
||
<pre class="tty">NONE = " N/A "</pre>
|
||
|
||
<h3 class="config_section" id="Units_Labels">[[Labels]]</h3>
|
||
<p>This sub-section specifies what label is to be used for each
|
||
measurement unit type. For example, the options </p>
|
||
<pre class="tty">degree_F = °F
|
||
inch = ' in'</pre>
|
||
<p>would cause all temperatures to have unit labels <span class="code">°F</span>
|
||
and all precipitation to have labels <span class="code">in</span>. 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.</p>
|
||
|
||
<p> If the label includes two values, then the first is assumed to be the
|
||
singular form, the second the plural form. For example,</p>
|
||
<pre class="tty">foot = " foot", " feet"
|
||
...
|
||
day = " day", " days"
|
||
hour = " hour", " hours"
|
||
minute = " minute", " minutes"
|
||
second = " second", " seconds"</pre>
|
||
|
||
<p>This is particularly useful when <a href="#l11n_unit_labels">localizing the weewx and server uptimes</a>.</p>
|
||
|
||
<h3 class="config_section" id="Units_TimeFormats">[[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. The default looks like this:</p>
|
||
<pre class='tty'>
|
||
[[TimeFormats]]
|
||
# This section sets the string format to be used for each time scale.
|
||
# The values below will work in every locale, but may not look
|
||
# particularly attractive. See the Customizing Guide for alternatives.
|
||
|
||
day = %X
|
||
week = %X (%A)
|
||
month = %x %X
|
||
year = %x %X
|
||
rainyear = %x %X
|
||
current = %x %X
|
||
ephem_day = %X
|
||
ephem_year = %x %X</pre>
|
||
|
||
<p>The specifiers <span class='code'>%x</span>, <span class='code'>%X</span>,
|
||
and <span class='code'>%A</span>
|
||
code locale dependent date, time, and weekday names, respectively.
|
||
Hence, if you set an appropriate environment variable <span class='code'>LANG</span>,
|
||
then the date and times should follow local conventions (see section
|
||
<a href="#environment_variable_LANG">Environment variable LANG</a>
|
||
for details on how to do this). However, they will not look particularly pretty
|
||
and you may want to change them. For example, I use this in the U.S.:
|
||
</p>
|
||
<pre class="tty">
|
||
[[TimeFormats]]
|
||
#
|
||
# More attractive formats that work in most Western countries.
|
||
#
|
||
day = %H:%M
|
||
week = %H:%M on %A
|
||
month = %d-%b-%Y %H:%M
|
||
year = %d-%b-%Y %H:%M
|
||
rainyear = %d-%b-%Y %H:%M
|
||
current = %d-%b-%Y %H:%M
|
||
ephem_day = %H:%M
|
||
ephem_year = %d-%b-%Y %H:%M</pre>
|
||
|
||
<p>The last two formats, <span class='code'>ephem_day</span> and
|
||
<span class='code'>ephem_year</span> allow the formatting to be set for almanac times
|
||
The first, <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">[[Ordinates]]</h3>
|
||
<p class="config_option">directions</p>
|
||
<p>Set to the abbreviations to be used for ordinal directions. By default,
|
||
this is <span class="code">N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW,
|
||
SW, WSW, W, WNW, NW, NNW, N</span>.</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 class="tty">heating_base = 65.0, degree_F
|
||
cooling_base = 20.0, degree_C</pre>
|
||
<h3 class="config_section" id="trend">[[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>
|
||
<p class="config_option">time_grace</p>
|
||
<p>When searching for a previous record to be used in calculating a trend,
|
||
a record within this amount of <span class="code">time_delta</span>
|
||
will be accepted. Default is 300 seconds.</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 <span class="code">N, S, E, W</span>.</p>
|
||
<p class="config_option">latlon_formats</p>
|
||
<p>Comma separated list for the formatting to be used when converting
|
||
latitude and longitude to strings. There should be three elements:</p>
|
||
<ol>
|
||
<li>The format to be used for whole degrees of latitude</li>
|
||
<li>The format to be used for whole degrees of longitude</li>
|
||
<li>The format to be used for minutes.</li>
|
||
</ol>
|
||
<p>This allows you to decide whether or not you want leading zeroes. The
|
||
default includes leading zeroes and is "%02d", "%03d", "%05.2f"</p>
|
||
<h3 class="config_section">[[Generic]]</h3>
|
||
<p>This sub-section specifies default labels to be used for each observation
|
||
type. For example, options </p>
|
||
<pre class="tty">inTemp = Temperature inside the house
|
||
outTemp = Outside Temperature</pre>
|
||
<p>would cause the given labels to be used for plots of <span
|
||
class="code">inTemp</span> and <span class="code">outTemp</span>.
|
||
If no option is given, then the observation type itself will
|
||
be used (<em>e.g., </em><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 <span class="code">New, Waxing
|
||
crescent, First quarter, Waxing gibbous, Full, Waning gibbous, Last
|
||
quarter, Waning crescent</span>. </p>
|
||
|
||
<h2 class="config_section">[CheetahGenerator]</h2>
|
||
<p>This section is used by generator
|
||
<span class="code">weewx.cheetahgenerator.CheetahGenerator</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>Files are generated from templates, and each template is identified
|
||
by the <span class="config_option">template</span> parameter.</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 (optional) directory the
|
||
template sits in and will also be the directory 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="symcode">$HTML_ROOT</span><span class="code">/Acme/index.html</span>. </p>
|
||
<p>The configuration for a group of templates will look something like this:</p>
|
||
<pre class="tty">[CheetahGenerator]
|
||
[[index]]
|
||
template = index.html.tmpl
|
||
[[textfile]]
|
||
template = filename.txt.tmpl
|
||
[[xmlfile]]
|
||
template = filename.xml.tmpl</pre>
|
||
<p>There can be only one <span class="config_option">template</span> in
|
||
each block. In most cases, the block name does not matter — it is
|
||
used only to isolate each template. However, there are two block names
|
||
that have special meaning: <span class='code'>SummaryByMonth</span> and
|
||
<span class='code'>SummaryByYear</span>. They are described below.</p>
|
||
<p>The file generator runs on each new archive record. In a default
|
||
weewx installation, that would be every 5 minutes.</p>
|
||
<p>Cheetah processes each template to generate a file. Cheetah follows
|
||
any logic defined by directives such as <span class="code">for</span>
|
||
or <span class="code">if ... else</span>, and it replaces variables
|
||
such as <span class="code">$Extras.radar_url</span> or
|
||
<span class="code">$current.outTemp.max</span>.</p>
|
||
<p>Variables are defined by objects in weewx. Some variables are static,
|
||
others are linked to data in databases. The list of variables can be
|
||
extended.</p>
|
||
|
||
<h3>File generation options</h3>
|
||
<p class="config_option">search_list</p>
|
||
<p>This is the list of search list objects that will be scanned by
|
||
the template engine, looking for tags. See the section
|
||
<em><a href="#defining_new_tags">Defining new tags</a></em> and the
|
||
<a href="http://cheetahtemplate.org/docs/users_guide_html/users_guide.html">Cheetah documentation</a> for details on
|
||
search lists. If no <span class="config_option">search_list</span>
|
||
is specified, a default list will be
|
||
used. The default list is:</p>
|
||
<pre class="tty">search_list = weewx.cheetahgenerator.Almanac, weewx.cheetahgenerator.Station, weewx.cheetahgenerator.Stats, weewx.cheetahgenerator.UnitInfo, weewx.cheetahgenerator.Extras</pre>
|
||
<p class="config_option">search_list_extensions</p>
|
||
<p>This defines one or more search list objects that will be appended to
|
||
the <span class="config_option">search_list</span>. For example, the
|
||
following adds alltime and forecast variables to the search list.</p>
|
||
<pre class="tty">search_list_extensions = examples.xsearch.MyXSearch, user.forecast.ForecastVariables</pre>
|
||
<p class="config_option">encoding </p>
|
||
<p>This option controls which encoding is to be used for the generated
|
||
output. The encoding can be specified for individual files. There are
|
||
3 possible choices: </p>
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Encoding</td>
|
||
<td>Comments</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">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">&#176;</span>)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">utf8</td>
|
||
<td>Non 7-bit characters will be represented in UTF-8.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">strict_ascii</td>
|
||
<td>Non 7-bit characters will be ignored.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>The encoding <span class="code">html_entities</span> is the
|
||
default.</p>
|
||
<p class="config_option">template</p>
|
||
<p>The name of a template file. A template filename must end with
|
||
<span class="code">.tmpl</span>. Filenames are case-sensitive.
|
||
If the template filename has the letters <span class="code">YYYY</span>
|
||
or <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.</p>
|
||
<p class="config_option">stale_age</p>
|
||
<p>
|
||
File staleness age, in seconds. If the file is older than this age it will
|
||
be generated from the template. If no <span class="code">stale_age</span>
|
||
is specified, then the file will be generated every time the generator
|
||
runs.
|
||
</p>
|
||
<p class="config_option">[[SummaryByMonth]]</p>
|
||
<p>The <span class="code">SummaryByMonth</span> section defines some
|
||
special behavior. Each template in this section will be used
|
||
multiple times, each time with a different per-month timespan.
|
||
Be sure to include <span class="code">YYYY</span> and
|
||
<span class="code">MM</span> in the filename of any template in this
|
||
section.</p>
|
||
<p class="config_option">[[SummaryByYear]]</p>
|
||
<p>The <span class="code">SummaryByYear</span> section defines some
|
||
special behavior. Each template in this section will be used
|
||
multiple times, each time with a different per-year timespan.
|
||
Be sure to include <span class="code">YYYY</span> in the filename
|
||
of any template in this section.</p>
|
||
|
||
<h3>Customizing file generation</h3>
|
||
<p>The best way to customize file generation is to make a copy of
|
||
a working report/skin, then make incremental changes.</p>
|
||
<p>When there is an error during template generation, the error will
|
||
show up in the log file. Many errors are obvious — Cheetah will
|
||
display a line number and list the template file in which the error
|
||
occurred. In some cases the error reporting is rather obscure. So
|
||
make small changes and test often. Use the tool
|
||
<span class="code"><a href="#wee_reports">wee_reports</a></span>
|
||
to test modifications to the generator configuration and/or the
|
||
template contents.</p>
|
||
|
||
<h3>The Standard skin templates</h3>
|
||
<p>Here is the <span class="code">[CheetahGenerator]</span> section from
|
||
the Standard <span class="code">skin.conf</span></p>
|
||
|
||
<pre class="tty">[CheetahGenerator]
|
||
# This section is used by the generator CheetahGenerator, and specifies
|
||
# which files are to be generated from which template.
|
||
|
||
encoding = html_entities
|
||
|
||
[[SummaryByMonth]]
|
||
# Reports that summarize "by month"
|
||
[[[NOAA_month]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-YYYY-MM.txt.tmpl
|
||
|
||
[[SummaryByYear]]
|
||
# Reports that summarize "by year"
|
||
[[[NOAA_year]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-YYYY.txt.tmpl
|
||
|
||
[[ToDate]]
|
||
# Reports that show statistics "to date", such as day-to-date,
|
||
# week-to-date, month-to-date, etc.
|
||
[[[day]]]
|
||
template = index.html.tmpl
|
||
|
||
[[[week]]]
|
||
template = week.html.tmpl
|
||
|
||
[[[month]]]
|
||
template = month.html.tmpl
|
||
|
||
[[[year]]]
|
||
template = year.html.tmpl
|
||
|
||
[[[RSS]]]
|
||
template = RSS/weewx_rss.xml.tmpl
|
||
|
||
[[[Mobile]]]
|
||
template = mobile.html.tmpl</pre>
|
||
|
||
<p>The Standard skin contains three different kinds of generated
|
||
output: </p>
|
||
<ol>
|
||
<li>Summary by Month. The Standard skin uses
|
||
<span class="code">SummaryByMonth</span> to produce NOAA summaries,
|
||
one for each month, as a simple text file.</li>
|
||
<li>Summary by Year. The Standard skin uses
|
||
<span class="code">SummaryByYear</span> to produce NOAA summaries,
|
||
one for each year, as a simple text file.</li>
|
||
<li>Summary "To Date". The Standard skin produce reports for the day,
|
||
week, month, and year-to-date observations. These files are HTML.
|
||
The first, the daily summary (output filename is
|
||
<span class="code">index.html</span>),
|
||
includes a drop-down list that displays the NOAA month and yearly
|
||
summaries. </li>
|
||
</ol>
|
||
<p>The encoding for text files is <span class="code">strict_ansii</span>,
|
||
whereas the encoding for html files is
|
||
<span class="code">html_entities</span>. In the Standard skin this is
|
||
specified by declaring
|
||
<span class="code">encoding = html_entities</span> at the top level
|
||
of <span class="code">[CheetahGenerator]</span> then
|
||
<span class="code">encoding = strict_ansii</span> for each text file.
|
||
</p>
|
||
<p>Other than <span class="code">SummaryByMonth</span> and
|
||
<span class="code">SummaryByYear</span>, the section names are
|
||
arbitrary. <span class="code">ToDate</span> could just as well have
|
||
been called <span class="code">files_to_date</span>, and the sections
|
||
<span class="code">day</span>, <span class="code">week</span>, and
|
||
<span class="code">month</span> could just as well have been called
|
||
<span class="code">tom</span>, <span class="code">dick</span>, and
|
||
<span class="code">harry</span>.</p>
|
||
|
||
<h2 class="config_section">[ImageGenerator]</h2>
|
||
<p>This section describes the various options available to the image
|
||
generator.</p>
|
||
<div class="image image-right">
|
||
<img src="images/image_parts.png"
|
||
alt="Part names in a weewx image" />
|
||
<div class="image_caption">Part names in a weewx image</div>
|
||
</div>
|
||
|
||
|
||
<h3>Overall options</h3>
|
||
<p>These are options that affect the overall image.</p>
|
||
<p class="config_option">
|
||
image_width<br /> image_height
|
||
</p>
|
||
<p>The width and height of the image in pixels. Optional. Default is 300
|
||
x 180 pixels.</p>
|
||
<p class="config_option">image_background_color</p>
|
||
<p>The background color of the whole image. Optional. Default is
|
||
<span class='code'>0xf5f5f5</span> ("SmokeGray")</p>
|
||
<p class="config_option">chart_background_color</p>
|
||
<p>The background color of the chart itself. Optional. Default is
|
||
<span class='code'>0xd8d8d8</span>.</p>
|
||
<p class="config_option">chart_gridline_color</p>
|
||
<p>The color of the chart grid lines. Optional. Default is
|
||
<span class='code'>0xa0a0a0</span></p>
|
||
|
||
<div class="image image-right" style="clear:right">
|
||
<img src="images/weektempdew.png" alt="Example of day/night bands" />
|
||
<div class="image_caption">Example of day/night bands in a one
|
||
week image</div>
|
||
</div>
|
||
<p class="config_option">show_daynight</p>
|
||
<p>
|
||
Set to <span class="code">true</span> to show day/night bands in an image.
|
||
Otherwise, set to false. This only looks good with day or week plots.
|
||
Optional. Default is <span class="code">false</span>.
|
||
</p>
|
||
<p class="config_option">daynight_day_color</p>
|
||
<p>
|
||
The color to be used for the daylight band. Optional. Default is <span
|
||
class="code">0xffffff</span>.
|
||
</p>
|
||
<p class="config_option">daynight_night_color</p>
|
||
<p>
|
||
The color to be used for the nighttime band. Optional. Default is <span
|
||
class="code">0xf0f0f0</span>, a dark gray.
|
||
</p>
|
||
<p class="config_option">daynight_edge_color</p>
|
||
<p>
|
||
The color to be used in the transition zone between night and day.
|
||
Optional. Default is <span class="code">0xefefef</span>, a mid-gray.
|
||
</p>
|
||
|
||
|
||
<h3>Various label options</h3>
|
||
<p>These are options for the various labels used in the image.</p>
|
||
<p class="config_option">top_label_font_path</p>
|
||
<p>
|
||
The path to the font to be use for the top label. Optional. If not given,
|
||
or if <span class="code">weewx</span> cannot find the font, then the
|
||
default PIL font will be used.
|
||
</p>
|
||
<p class="config_option">top_label_font_size</p>
|
||
<p>The size of the top label in pixels. Optional. The default is
|
||
<span class='code'>10</span>.</p>
|
||
<p class="config_option">unit_label_font_path</p>
|
||
<p>
|
||
The path to the font to be use for the unit label. Optional. If not given,
|
||
or if <span class="code">weewx</span> cannot find the font, then the
|
||
default PIL font will be used.
|
||
</p>
|
||
<p class="config_option">unit_label_font_size</p>
|
||
<p>The size of the unit label in pixels. Optional. The default is
|
||
<span class='code'>10</span>.</p>
|
||
<p class="config_option">unit_label_font_color</p>
|
||
<p>The color of the unit label font. Optional. Default is
|
||
<span class='code'>black</span>.</p>
|
||
<p class="config_option">bottom_label_font_path</p>
|
||
<p>
|
||
The path to the font to be use for the bottom label. Optional. If not
|
||
given, or if <span class="code">weewx</span> cannot find the font, then
|
||
the default PIL font will be used.
|
||
</p>
|
||
<p class="config_option">bottom_label_font_size</p>
|
||
<p>The size of the bottom label in pixels. Optional. The default is
|
||
<span class='code'>10</span>.</p>
|
||
<p class="config_option">bottom_label_font_color</p>
|
||
<p>The color of the bottom label font. Optional. Default is
|
||
<span class='code'>black</span>.</p>
|
||
<p class="config_option">bottom_label_format</p>
|
||
<p>
|
||
The format to be used for the bottom label. It should be a <a
|
||
href="http://docs.python.org/library/datetime.html#strftime-strptime-behavior">
|
||
strftime format</a>. Optional. Default is
|
||
<span class="code">'%m/%d/%y %H:%M'</span>.
|
||
</p>
|
||
<p class="config_option">axis_label_font_path</p>
|
||
<p>
|
||
The path to the font to be use for the x- and y-axis labels. Optional. If not given,
|
||
or if <span class="code">weewx</span> cannot find the font, then the
|
||
default PIL font will be used.
|
||
</p>
|
||
<p class="config_option">axis_label_font_size</p>
|
||
<p>The size of the x- and y-axis labels in pixels. Optional. The default is
|
||
<span class='code'>10</span>.</p>
|
||
<p class="config_option">axis_label_font_color</p>
|
||
<p>The color of the x- and y-axis label font. Optional. Default is
|
||
<span class='code'>black</span>.</p>
|
||
<p class="config_option">x_label_format</p>
|
||
<p>The format to be used for the time labels on the x-axis. It should be a <a
|
||
href="http://docs.python.org/library/datetime.html#strftime-strptime-behavior">
|
||
strftime format</a>. Optional. If not given, a sensible format will be
|
||
chosen automatically.
|
||
</p>
|
||
|
||
|
||
<h3>Plot scaling options</h3>
|
||
<p class="config_option">time_length</p>
|
||
<p>
|
||
The nominal length of the time period to be covered in seconds. The exact
|
||
length of the x-axis is chosen by the plotting engine to cover this
|
||
period. Optional. Default is <span class="code">86400</span> (one day).
|
||
</p>
|
||
<p class="config_option">yscale</p>
|
||
<p>
|
||
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 <span class="code">None</span>, the
|
||
corresponding value will be automatically chosen. Optional. Default is
|
||
<span class="code">None, None, None</span>. (Choose the y-axis minimum,
|
||
maximum, and minimum increment automatically.)
|
||
</p>
|
||
|
||
|
||
<h3>Compass rose options</h3>
|
||
<div class="image image-right" style="width:300px">
|
||
<img src="images/daywindvec.png"
|
||
alt="Example of a progressive vector plot" />
|
||
<div class="image_caption">Example of a vector plot with a compass rose in the lower-left</div>
|
||
</div>
|
||
|
||
<p class="config_option">rose_label</p>
|
||
<p>
|
||
The label to be used in the compass rose to indicate due North. Optional.
|
||
Default is <span class="code">N</span>.
|
||
</p>
|
||
<p class="config_option">rose_label_font_path</p>
|
||
<p>
|
||
The path to the font to be use for the rose label (the letter "N,"
|
||
indicating North). Optional. If not given, or if <span class="code">weewx</span>
|
||
cannot find the font, then the default PIL font will be used.
|
||
</p>
|
||
<p class="config_option">rose_label_font_size</p>
|
||
<p>The size of the compass rose label in pixels. Optional. The default
|
||
is <span class="code">10</span>.</p>
|
||
<p class="config_option">rose_label_font_color</p>
|
||
<p>The color of the compass rose label. Optional. Default is the same
|
||
color as the rose itself.</p>
|
||
<p class="config_option">vector_rotate</p>
|
||
<p>
|
||
Causes the vectors to be rotated by this many degrees. Positive is clockwise.
|
||
If westerly winds dominate at your location (as they do at mine),
|
||
then you may want to specify <span
|
||
class="code">+90</span> for this option. This will cause the average vector
|
||
to point straight up, rather than lie flat against the x-axis. Optional.
|
||
The default is <span class='code'>0</span>.
|
||
</p>
|
||
|
||
|
||
<h3>Shared plot line options</h3>
|
||
<p>These are options shared by all the plot lines.</p>
|
||
<p class="config_option">chart_line_colors</p>
|
||
<p>
|
||
Each chart line is drawn in a different color. This option is a list of
|
||
those colors. If the number of lines exceeds the length of the list, then
|
||
the colors wrap around to the beginning of the list. NB: individual line
|
||
color can be overridden by using option <span class="code">color</span>.
|
||
Optional. In the case of bar charts, this is the color
|
||
of the outline of the bar. Default is
|
||
<span class="code">0xff0000, 0x00ff00, 0x0000ff</span>.
|
||
</p>
|
||
<p class="config_option">chart_fill_colors</p>
|
||
<p>
|
||
A list of the color to be used as the fill of the bar charts. Optional.
|
||
The default is to use the same color as the outline color (option
|
||
<span class="code">chart_line_colors</span>) above.
|
||
</p>
|
||
<p class="config_option">chart_line_width</p>
|
||
<p>
|
||
Each chart line can be drawn using a different line width. This option is a list of
|
||
these widths. If the number of lines exceeds the length of the list, then
|
||
the widths wrap around to the beginning of the list. NB: individual line
|
||
widths can be overridden by using option <span class="code">width</span>.
|
||
Optional. Default is <span class="code">1, 1, 1</span>.
|
||
</p>
|
||
|
||
|
||
<h3>Individual line options</h3>
|
||
<p>These are options that are set for individual lines.</p>
|
||
<p class="config_option">aggregate_type</p>
|
||
<p>
|
||
The default is to plot every data point, but this is
|
||
probably not a good idea for any plot longer than a day. By setting this
|
||
option, you can <em>aggregate</em> data by a set time interval. Available
|
||
aggregation types include <span class="code">avg</span>, <span
|
||
class="code">sum</span>, <span class="code">max</span>, <span
|
||
class="code">min</span>, <span class="code">count</span>, and
|
||
<span class="code">last</span>.
|
||
</p>
|
||
<p class="config_option">aggregate_interval</p>
|
||
<p>The time period over which the data should be aggregated. Required if
|
||
<span class="code">aggregate_type</span> has been set. </p>
|
||
<p class="config_option">plot_type</p>
|
||
<p>
|
||
The type of plot for this line. Choices are <span class="code">line</span>,
|
||
<span class="code">bar</span>, or <span class="code">vector</span>.
|
||
Optional. Default is <span class="code">line</span>.
|
||
</p>
|
||
<p class="config_option">color</p>
|
||
<p>
|
||
This option is to override the color for an individual line. Optional.
|
||
Default is to use the color in <span class="code">chart_line_colors</span>.
|
||
</p>
|
||
<p class="config_option">line_type</p>
|
||
<p>
|
||
The type of line to be used. Choices are <span class="code">solid</span>
|
||
or <span class="code">none</span>. Optional. Default is
|
||
<span class="code">solid</span>.
|
||
</p>
|
||
<p class="config_option">marker_type</p>
|
||
<p>
|
||
The type of marker to be used to marke each data point. Choices are <span
|
||
class="code">cross</span>, <span class="code">x</span>, <span
|
||
class="code">circle</span>, <span class="code">box</span>, or <span
|
||
class="code">none</span>. Optional. Default is
|
||
<span class="code">none</span>.
|
||
</p>
|
||
<p class="config_option">marker_size</p>
|
||
<p>
|
||
The size of the marker. Optional. Default is <span class="code">8</span>.
|
||
</p>
|
||
<p class="config_option">line_gap_fraction</p>
|
||
<p>
|
||
If there is a gap between data points bigger than this fractional amount
|
||
of the x-axis, then a gap will be drawn, rather than a connecting line.
|
||
See Section <em><a href="#line_gaps">Line gaps</a></em>. Optional. The
|
||
default is to always draw the line.
|
||
</p>
|
||
<p class="config_option">bar_gap_fraction</p>
|
||
<p>
|
||
If there is a gap between bar graphs bigger than this fractional amount of
|
||
the x-axis, then a gap will be drawn, rather than a fat bar. See Section
|
||
<em><a href="#line_gaps">Line gaps</a></em>. Optional. The default is to
|
||
always draw the bar.
|
||
</p>
|
||
|
||
<p class="config_option">width</p>
|
||
<p>
|
||
This option is to override the line widthfor an individual line. Optional.
|
||
Default is to use the width in <span class="code">chart_line_width</span>.
|
||
</p>
|
||
|
||
<p class="config_option">label</p>
|
||
<p>The label to be used for this plot line in the top label. Optional.
|
||
The default is to use the SQL variable name.</p>
|
||
<p class="config_option">data_type</p>
|
||
<p>
|
||
The SQL data type to be used for this plot line. For more information,
|
||
see the section
|
||
<em><a href="#including_same_sql_type_2x">Including the same SQL type more than once in a plot</a></em>. Optional. The default is to use the
|
||
section name.
|
||
</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
|
||
directory to the destination directory. Think of it as "file
|
||
generation," 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>
|
||
|
||
<p>Here is the <span class="code">[CopyGenerator]</span> section from
|
||
the Standard <span class="code">skin.conf</span></p>
|
||
<pre class="tty">[CopyGenerator]
|
||
# This section is used by the generator CopyGenerator
|
||
|
||
# List of files to be copied only the first time the generator runs
|
||
copy_once = backgrounds/*, weewx.css, mobile.css, favicon.ico
|
||
|
||
# List of files to be copied each time the generator runs
|
||
# copy_always = </pre>
|
||
<p>The Standard skin includes some background images, CSS files, and
|
||
icons that need to be copied once. There are no files that need
|
||
to be copied every time the generator runs.</p>
|
||
|
||
|
||
|
||
<h2 class="config_section" id="generators_section">[Generators]</h2>
|
||
<p>This section defines the list of generators that should be run.</p>
|
||
|
||
<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>
|
||
|
||
<p>Here is the <span class="code">[Generators]</span> section from the
|
||
Standard <span class="code">skin.conf</span></p>
|
||
<pre class="tty">[Generators]
|
||
generator_list = weewx.cheetahgenerator.CheetahGenerator, weewx.imagegenerator.ImageGenerator, weewx.reportengine.CopyGenerator</pre>
|
||
<p>The Standard skin uses three generators: CheetahGenerator, ImageGenerator, and CopyGenerator.</p>
|
||
|
||
<h1 id="localization">Localization</h1>
|
||
<p>What follows is a guide to localizing to a non-English language
|
||
and/or locale. There are two parts: translating to different languages
|
||
and modifying to reflect local conventions for displaying data.</p>
|
||
|
||
<h2>Translate the templates</h2>
|
||
<p>First, you will need to go through the templates and translate to your
|
||
target language. Obvious text strings such as
|
||
<span class="code">"Current Weather Conditions"</span>
|
||
will need to be translated.</p>
|
||
|
||
<h2>Modify the skin configuration</h2>
|
||
<p>Next, you will need to go through <span class="code">skin.conf</span>
|
||
to translate labels and modify formats to follow local conventions.
|
||
</p>
|
||
|
||
<p>You will probably want to change the generic labels used for the
|
||
observation types:</p>
|
||
<pre class="tty">[Labels]
|
||
...
|
||
[[Generic]]
|
||
barometer = Barometer
|
||
dewpoint = Dew Point
|
||
heatindex = Heat Index
|
||
inHumidity = Inside Humidity
|
||
inTemp = Inside Temperature
|
||
outHumidity = Outside Humidity
|
||
outTemp = Outside Temperature
|
||
radiation = Radiation
|
||
rain = Rain
|
||
rainRate = Rain Rate
|
||
rxCheckPercent = ISS Signal Quality
|
||
windDir = Wind Direction
|
||
windGust = Gust Speed
|
||
windGustDir = Gust Direction
|
||
windSpeed = Wind Speed
|
||
windchill = Wind Chill
|
||
windgustvec = Gust Vector
|
||
windvec = Wind Vector
|
||
extraTemp1 = Pond Temperature</pre>
|
||
<p>The hemisphere abbreviations may have to be changed: </p>
|
||
<pre class="tty">[Labels]
|
||
hemispheres = N, S, E, W</pre>
|
||
<p>The wind ordinal directions may have to be changed: </p>
|
||
<pre class='tty'>[Units]
|
||
...
|
||
[[Ordinates]]
|
||
# The ordinal directions. The last one should be for no wind direction
|
||
directions = N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW, N/A </pre>
|
||
<p>Don't forget the moon phases:</p>
|
||
<pre class="tty">[Almanac]
|
||
moon_phases = New, Waxing crescent, First quarter, Waxing gibbous, Full, Waning gibbous, Last quarter, Waning crescent</pre>
|
||
<p id="l11n_unit_labels">Most of the unit labels either follow
|
||
ISO conventions, or are unlikely to be used outside English
|
||
speaking countries (an example would be
|
||
"foot"). But, there are a few exceptions, used to
|
||
label the weewx and server "uptimes",
|
||
which can be found in sub-section
|
||
<span class="code">[Units][[Labels]]</span></p>
|
||
<pre class="tty">[Units]
|
||
...
|
||
[[Labels]]
|
||
...
|
||
day = " day", " days"
|
||
hour = " hour", " hours"
|
||
minute = " minute", " minutes"
|
||
second = " second", " seconds"</pre>
|
||
<p>By default, the time formats will use the local convention specified
|
||
by the LANG environment variable. These can be modified individually
|
||
in the <span class='code'>[Units][[TimeFormats]]</span> section.</p>
|
||
<pre class='tty'>[Units]
|
||
[[TimeFormats]]
|
||
day = %X
|
||
week = %X (%A)
|
||
month = %x %X
|
||
year = %x %X
|
||
rainyear = %x %X
|
||
current = %x %X
|
||
ephem_day = %X
|
||
ephem_year = %x %X</pre>
|
||
|
||
<h2 id="environment_variable_LANG">Environment variable <span class="code">LANG</span></h2>
|
||
<p>Finally, you will need to set the environment variable <span class="code">LANG</span>
|
||
to reflect your locale. For example, assuming you set</p>
|
||
<pre class="tty">$ export LANG=es_ES.UTF-8</pre>
|
||
<p>before running <span class="code">weewx</span>, then the local Spanish
|
||
names for days of the week and months of the year will be used. The
|
||
decimal point for numbers will also be modified appropriately.</p>
|
||
|
||
<h1 id="service_engine">Customizing the engine</h1>
|
||
<p>This is an advanced 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 class="warning">Please note that the API to the service engine may change in future versions!</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>See the table <a href="#default_services">Default services</a> above for a list
|
||
of the services that are normally run.</p>
|
||
|
||
<h2>Customizing a service</h2>
|
||
<p>The service <span class="code">weewx.engine.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
|
||
do not 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>Create the file <span class="symcode">$BIN_ROOT</span><span class="code">/user/myprint.py</span>:
|
||
</p>
|
||
<pre class="tty">from weewx.engine 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 "LOOP: ", timestamp_to_string(packet['dateTime']),
|
||
"BAR=", packet.get('barometer', 'N/A'),
|
||
"TEMP=", packet.get('outTemp', '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">[Engine][[Services]]</span>:
|
||
</p>
|
||
<pre class="tty">[Engine]
|
||
[[Services]]
|
||
...
|
||
report_services = <span class="highlight">user.myprint.MyPrint</span>, weewx.engine.StdReport</pre>
|
||
<p>Note that the <span class="code">report_services</span> 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>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 is an example that implements an
|
||
alarm, which sends off an email when an arbitrary expression evaluates <span
|
||
class="code">True</span>. This example is included in the standard
|
||
distribution in directory <span class="symcode">$BIN_ROOT</span><span
|
||
class="code">/examples</span>.</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.engine 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 raised 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 KeyError, 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) ≥ 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 = "outTemp < 40.0"
|
||
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 = "Alarm message from weewx!"</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, <span
|
||
class="code">weewx.NEW_ARCHIVE_RECORD</span> in this example, and a
|
||
member function, <span class="code">self.newArchiveRecord</span>. When
|
||
the event <span class='code'>NEW_ARCHIVE_RECORD</span> occurs,
|
||
the function <span class="code">self.newArchiveRecord</span> will be called. There
|
||
are many other events that can be interecepted. Look in the file <span
|
||
class="symcode">$BIN_ROOT</span><span class="code">/weewx/__init__.py</span>.
|
||
</li>
|
||
<li>This is where the test is done for whether or not to sound the
|
||
alarm. The <span class="code">[Alarm]</span> configuration options
|
||
specify that the alarm be sounded when <span class="code">outTemp
|
||
< 40.0</span> 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 class="tty">expression = "outTemp < 32.0 and windSpeed > 10.0"</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>Note that units must be the same as whatever is being used in your database.
|
||
That is, the same as what you specified in option
|
||
<a href="usersguide.htm#option_target_unit"><span class="code">target_unit</span></a>.</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, <span class="code">from</span> and <span class="code">subject</span>
|
||
are optional. If not supplied, <span class="code">weewx</span> will
|
||
supply something sensible. Note, however, that some mailers require a
|
||
valid "from" 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">report_services</span>,
|
||
located in <span class="code">[Engine][[Services]]</span>: </p>
|
||
<pre class="tty">[Engine]
|
||
[[Services]]
|
||
report_services = weewx.engine.StdPrint, weewx.engine.StdReport<span class="highlight">, examples.alarm.MyAlarm</span></pre>
|
||
<p>Again, note that the option <span class="code">report_services</span> must be all on
|
||
one line — 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
|
||
similar, except that it intercepts LOOP events (instead of
|
||
archiving events). </p>
|
||
|
||
<h1 id ="archive_database">Customizing the 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="symcode">$BIN_ROOT</span><span
|
||
class="code">/wee_config_database</span>.</p>
|
||
<p>This utility also has the ability to check a SQLite version of the archive
|
||
database for embedded strings (where a float is expected).</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>
|
||
<pre class="tty"><span class="symcode">$BIN_ROOT</span>/wee_config_database --help</pre>
|
||
<p>This will result in an output that looks something like this:</p>
|
||
<pre class="tty">
|
||
Usage: wee_config_database: [config_path]
|
||
[--config=CONFIG_PATH] [--help]
|
||
[--create-archive] [--drop-daily]
|
||
[--backfill-daily] [--reconfigure]
|
||
[--string-check] [--fix]
|
||
[--binding=BINDING_NAME]
|
||
|
||
The path to the config file can be specified as either a
|
||
command-line argument, or by using option --config.
|
||
|
||
Configure the weewx databases. Most of these functions are handled
|
||
automatically by weewx, but they may be useful as a utility in special cases.
|
||
In particular, the 'reconfigure' option can be useful if you decide to add or
|
||
drop data types from the database schema or change unit systems.
|
||
|
||
Options:
|
||
-h, --help show this help message and exit
|
||
--config=CONFIG_PATH Use configuration file CONFIG_PATH. Default is
|
||
/etc/weewx/weewx.conf or /home/weewx/weewx.conf.
|
||
--create-archive Create the archive database.
|
||
--drop-daily Drop the daily summary tables from a database.
|
||
--backfill-daily Backfill a database with daily summaries.
|
||
--reconfigure Create a new archive database using configuration
|
||
information found in the configuration file. In
|
||
particular, the new database will use the unit system
|
||
found in option [StdConvert][target_unit]. The new
|
||
database will have the same name as the old database,
|
||
with a '_new' on the end.
|
||
--string-check Check a sqlite version of the archive database for
|
||
embedded strings in it.
|
||
--fix If a string is found, fix it.
|
||
--binding=BINDING The database binding to be used. Default is
|
||
'wx_binding'.
|
||
|
||
If you are using the MySQL database it is assumed that you have the
|
||
appropriate permissions for the requested operation.</pre>
|
||
|
||
<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="#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>File <span class="code">user/electricity.py</span></p>
|
||
<pre class="tty">import weewx
|
||
from weewx.engine import StdService
|
||
|
||
class AddElectricity(StdService):
|
||
|
||
def __init__(self, engine, config_dict):
|
||
# Initialize my superclass first:
|
||
super(AddElectricity, self).__init__(engine, config_dict)
|
||
# Bind to any new archive record events:
|
||
self.bind(weewx.NEW_ARCHIVE_RECORD, self.new_archive_packet)
|
||
|
||
def new_archive_packet(self, event):
|
||
|
||
(code that downloads the consumption data from the connection to the meter)
|
||
|
||
event.record['electricity'] = retrieved_value</pre>
|
||
<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>To make sure your service gets run, you need to add it to one of the
|
||
service lists in section <span class="code">[Engine]</span> in <span class="code">weewx.conf</span>. But where? You want
|
||
to make sure it runs before the archiving service, so it must be
|
||
before option <span class="code">archive_services</span>. You do not want it to run
|
||
before the main loop runs, so it can't be in <span class="code">prep_services</span>. Probably
|
||
the best place is at the end of <span class="code">process_services</span>. When you're
|
||
done, your section <span class="code">[Engine]</span> will look something like this:</p>
|
||
<pre class="tty">
|
||
[Engine]
|
||
# This section configures the maine engine. It is for advanced customization.
|
||
|
||
[[Services]]
|
||
# These are the services the main engine should run:
|
||
prep_services = weewx.engine.StdTimeSynch
|
||
process_services = weewx.engine.StdConvert, weewx.engine.StdCalibrate, weewx.engine.StdQC, weewx.wxservices.StdWXCalculate<span class="highlight">, user.electricity.AddElectricity</span>
|
||
archive_services = weewx.engine.StdArchive
|
||
restful_services = weewx.restx.StdStationRegistry, weewx.restx.StdWunderground, weewx.restx.StdPWSweather, weewx.restx.StdCWOP, weewx.restx.StdWOW, weewx.restx.StdAWEKAS
|
||
report_services = weewx.engine.StdPrint, weewx.engine.StdReport</pre>
|
||
|
||
<h3 id="add_archive_type">Adding a new type to the archive database</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, <span class="code">weewx</span> won't know
|
||
where to store it. How would you add such
|
||
a type?
|
||
</p>
|
||
<p>The utility <span class="code">wee_config_database</span> can be used to do this. It will
|
||
create a new database that is similar to the old database, except it has the new type in its
|
||
schema.</p>
|
||
<p>Here's our general strategy:</p>
|
||
<ol>
|
||
<li>Extend the existing schema with the new type <span class="code">electricity</span>.</li>
|
||
<li>Modify the <span class="code">wx_binding</span> to use the new schema
|
||
instead of the old.
|
||
</li>
|
||
<li>Make sure you have the necessary permissions to create a new
|
||
database.</li>
|
||
<li>Use the utility <span class="code">wee_config_database</span> to create the
|
||
new database and 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>
|
||
</ol>
|
||
<p>Here is the recipe that follows that strategy:</p>
|
||
<ol>
|
||
<li>
|
||
<p>
|
||
<strong>Add the new type to our existing schema.</strong> The weather
|
||
schema that comes with <span class="code">weewx</span> is the same as
|
||
what wview uses. It's located in the file <span class="code">schemas/wview.py</span>
|
||
— take a look at it now. We could just modify it <em>in situ</em>,
|
||
but that would run the risk of confusing the two versions.
|
||
Alternatively, we could copy the file over to a new location, and then
|
||
modify that. But, because our change is just a simple addition, we're
|
||
going to import the wview schema and just add on our new type. There's
|
||
also no reason to create a new file. Why not just do it in the file we
|
||
already have, <span class="code">user/electricity.py</span>? Add to
|
||
the bottom of the file:
|
||
</p> <pre class="tty">import schemas.wview
|
||
schema_with_electricity = schemas.wview.schema + [('electricity', 'REAL')]</pre>
|
||
<p>
|
||
This creates a new schema (it will have the name <span class="code">user.electricity.schema_with_electricity</span>),
|
||
that is just like the old one, except it has a new type <span
|
||
class="code">electricity</span> tacked on to the end.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<strong>Modify <span class="code">wx_binding</span>.
|
||
</strong> When it creates the new, modified database, <span class="code">wee_config_database</span>
|
||
needs to know to use your new schema instead of the old, wview schema.
|
||
You do this by changing the option <span class="code">schema</span> in
|
||
section <span class="code">[DataBindings]</span> in <span class="code">weewx.conf</span>.
|
||
It will look like this when you're done:
|
||
</p>
|
||
<p class="tty">[DataBindings]
|
||
[[wx_binding]]
|
||
database = archive_sqlite
|
||
table_name = archive
|
||
manager = weewx.wxmanager.WXDaySummaryManager
|
||
<span class="highlight">schema = user.electricity.schema_with_electricity</span></p>
|
||
</li>
|
||
|
||
<li>
|
||
<p>
|
||
<strong>Check permissions.</strong> <span class="code">wee_config_database</span> 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 create it. In particular, if you
|
||
are using MySQL, you will need <span class="code">CREATE</span>
|
||
privileges:
|
||
</p>
|
||
<pre class="tty">mysql> GRANT select, update, create, delete, insert ON weewx_new.* TO weewx@localhost;</pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<strong>Create and populate the new database.</strong>
|
||
Now run the utility <span class="code">wee_config_database</span>
|
||
with the <span class="code">--reconfigure</span> option and the path
|
||
to the configuration file:
|
||
</p>
|
||
<p class="tty"><span class="symcode">$BIN_ROOT</span>/wee_config_database --reconfigure <span class="symcode">$CONFIG_ROOT</span>/weewx.conf</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>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<strong>Shuffle the databases.</strong> Now arrange things so <span
|
||
class="code">weewx</span> can find the new database.
|
||
</p>
|
||
<p class="warning">
|
||
<strong>Warning!</strong><br /> Make a backup of the data before
|
||
doing any of the next steps!
|
||
</p>
|
||
<p>
|
||
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>For SQLite:</p> <pre class="tty">cd <span class="symcode">$SQLITE_ROOT</span>
|
||
mv weewx.sdb_new weewx.sdb</pre>
|
||
<p>For MySQL:</p> <pre class="tty">mysql -u <username> --password=<mypassword>
|
||
<span class="prompt">mysql></span> DROP DATABASE weewx; # Delete the old database
|
||
<span class="prompt">mysql></span> CREATE DATABASE weewx; # Create a new one with the same name
|
||
<span class="prompt">mysql></span> RENAME TABLE weewx_new.archive TO weewx.archive; # Rename to the nominal name</pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
It's worth noting that there's actually a hidden, last step:
|
||
recreating the daily summaries inside the new database. This will be
|
||
done automatically by <span class="code">weewx</span> at the next
|
||
startup. Alternatively, it can be done manually using the <span
|
||
class="code">wee_config_database</span> utility and the <span
|
||
class="code">--backfill-daily</span> option:
|
||
</p> <pre class="tty"><span class="symcode">$BIN_ROOT</span>/wee_config_database --backfill-daily <span
|
||
class="symcode">$CONFIG_ROOT</span>/weewx.conf</pre>
|
||
</li>
|
||
</ol>
|
||
|
||
<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>
|
||
<pre class="tty">[[[monthelectric]]]
|
||
[[[[electricity]]]]
|
||
aggregate_type = sum
|
||
aggregate_interval = 86400
|
||
label = Electric consumption (daily total)</pre>
|
||
<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 class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">$day.electricity.sum</td>
|
||
<td>Total consumption since midnight</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">$year.electricity.sum</td>
|
||
<td>Total consumption since the first of the year</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">$year.electricity.max</td>
|
||
<td>The most consumed during any archive period</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">$year.electricity.maxsum</td>
|
||
<td>The most consumed during a day</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">$year.electricity.maxsumtime</td>
|
||
<td>The day it happened.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">$year.electricity.sum_ge(5.0)</td>
|
||
<td>The number of days where more than 5.0 kWH of energy was
|
||
consumed.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 id="Changing_the_unit_system">Changing the unit system</h2>
|
||
<p>Normally, data are stored in the databases using US Customary units
|
||
and, normally, you don't care; it is an "implementation detail".
|
||
Data can always be displayed using any units you want. The
|
||
<a href="#customizing_reports">Customizing reports</a> section explains
|
||
how to do this. 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 copying it to a new
|
||
database, performing the unit conversion along the way. You then use this
|
||
new database.
|
||
</p>
|
||
<p>Here is the general strategy:</p>
|
||
<ol>
|
||
<li>Modify <span class="code">weewx.conf</span> to reflect your
|
||
choice of the new unit system to use. Your choices are <span
|
||
class='code'>US</span>, <span class="code">METRIC</span>, or <span
|
||
class="code">METRICWX</span>. See the
|
||
<em><a href="#units">Appendix: Units</a></em>
|
||
for the exact differences between these three choices.
|
||
</li>
|
||
<li>Make sure you have the necessary permissions to create the new
|
||
database.</li>
|
||
<li>Use the utility <span class='code'>wee_config_database</span> to
|
||
create the new database and 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>
|
||
</ol>
|
||
<p>Here is the recipe that follows that strategy:</p>
|
||
<ol>
|
||
<li>
|
||
<p>
|
||
<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>
|
||
<pre class="tty">[StdConvert]
|
||
target_unit = METRICWX</pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<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>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<strong>Create and populate the new database.</strong>
|
||
Now run the utility <span class="code">wee_config_database</span>
|
||
with the <span class="code">--reconfigure</span> option:
|
||
</p>
|
||
<p class="tty"><span class="symcode">$BIN_ROOT</span>/wee_config_database --reconfigure <span class="symcode">$CONFIG_ROOT</span>/weewx.conf</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="symcode">$BIN_ROOT</span><span class="code">/user/schemas.py</span>, and populate it with data from
|
||
the old database, while performing the unit conversion.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<strong>Shuffle the databases.</strong> Now arrange things so <span
|
||
class="code">weewx</span> can find the new database.
|
||
</p>
|
||
<p class="warning">
|
||
<strong>Warning!</strong><br /> Make a backup of the data before
|
||
doing any of the next steps!
|
||
</p>
|
||
<p>
|
||
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>For SQLite:</p> <pre class="tty">cd <span class="symcode">$SQLITE_ROOT</span>
|
||
mv weewx.sdb_new weewx.sdb</pre>
|
||
<p>For MySQL:</p> <pre class="tty">mysql -u <username> --password=<mypassword>
|
||
<span class="prompt">mysql></span> DROP DATABASE weewx; # Delete the old database
|
||
<span class="prompt">mysql></span> CREATE DATABASE weewx; # Create a new one with the same name
|
||
<span class="prompt">mysql></span> RENAME TABLE weewx_new.archive TO weewx.archive; # Rename to the nominal name</pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
It's worth noting that there's actually a hidden, last step:
|
||
recreating the daily summaries inside the new database. This will be
|
||
done automatically by <span class="code">weewx</span> at the next
|
||
startup. Alternatively, it can be done manually using the <span
|
||
class="code">wee_config_database</span> utility and the <span
|
||
class="code">--backfill-daily</span> option:
|
||
</p> <pre class="tty"><span class="symcode">$BIN_ROOT</span>/wee_config_database --backfill-daily <span
|
||
class="symcode">$CONFIG_ROOT</span>/weewx.conf</pre>
|
||
</li>
|
||
</ol>
|
||
|
||
|
||
<h1 id="porting">Porting to new hardware</h1>
|
||
<p>Naturally, this is an advanced topic but, nevertheless, I'd
|
||
like to encourage any Python wizards out there to give it a try. Of
|
||
course, I have selfish reasons for this: I don't want to
|
||
have to buy every weather station ever invented, and I don't want
|
||
my roof to look like a weather station farm!</p>
|
||
<p>Here's the general strategy for doing a port.</p>
|
||
<h2>Implement the driver</h2>
|
||
<p>Inherit from the abstract base class
|
||
<span class="code">weewx.drivers.AbstractDevice</span>.
|
||
Try to implement as many of its methods as you can. At the
|
||
very minimum, you must implement the first three
|
||
methods, <span class="code">loader</span>,
|
||
<span class="code">hardware_name</span>,
|
||
and <span class="code">genLoopPackets</span>. </p>
|
||
<h3><span class="code">loader</span></h3>
|
||
<p>This is a factory function that returns an instance of your
|
||
driver. It has two arguments: the configuration dictionary,
|
||
and a reference to the weewx engine.</p>
|
||
<h3><span class="code">hardware_name</span></h3>
|
||
<p>Return a string with a short nickname for the hardware, such
|
||
as <span class="code">"ACME X90"</span></p>
|
||
<h3><span class="code">genLoopPackets</span></h3>
|
||
<p>This should be
|
||
a <a href="https://wiki.python.org/moin/Generators">generator
|
||
function</a> 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 for the
|
||
observation time and for the units used within the packet.</p>
|
||
<table class="indent" style="width: 60%">
|
||
<caption>Required keys</caption>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code first_col">dateTime</td>
|
||
<td>The time of the observation in unix epoch time.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">usUnits</td>
|
||
<td>The unit system used. <span class="code">weewx.US</span> for US
|
||
customary, <span class="code">weewx.METRICWX</span>, or
|
||
<span class="code">weewx.METRIC</span> for metric. See
|
||
the file <span class="code">units.py</span>, dictionaries <span
|
||
class="code">USUnits</span>, <span class="code">MetricWXUnits</span>,
|
||
and <span class="code">MetricUnits</span>
|
||
for the exact definition of each.</td>
|
||
</tr>
|
||
</tbody>
|
||
</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>A couple of observation types are tricky. In particular, <span class="code">rain</span>.
|
||
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>Be careful when reporting pressure. There are three observations
|
||
related to pressure. Some stations report only the station pressure,
|
||
others calculate and report sea level pressures. </p>
|
||
<table class="indent" style="width: 60%">
|
||
<caption>Pressure types</caption>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code first_col">pressure</td>
|
||
<td>The <em>Station Pressure</em> (SP), which is the raw, absolute
|
||
pressure measured by the station. This is the true barometric
|
||
pressure for the station.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">barometer</td>
|
||
<td>The <em>Sea Level Pressure</em> (SLP) obtained by correcting
|
||
the <em>Station Pressure</em> for altitude and local temperature.
|
||
This is the pressure reading most commonly used by meteorologist
|
||
to track weather systems at the surface, and this is the pressure
|
||
that is uploaded to weather services by <span class="code">weewx</span>.
|
||
It is the station pressure reduced to mean sea level using local
|
||
altitude and local temperature. </td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">altimeter</td>
|
||
<td>The <em>Altimeter Setting</em> (AS) obtained by correcting the
|
||
<em>Station Pressure</em> for altitude. This is the pressure
|
||
reading most commonly heard in weather reports. It is not the true
|
||
barometric pressure of a station, but rather the station pressure
|
||
reduced to mean sea level using altitude and an assumed
|
||
temperature average.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3><span class="code">genArchiveRecords()</span></h3>
|
||
<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.</p>
|
||
<p>However, 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>
|
||
|
||
<h3><span class="code">archive_interval</span></h3>
|
||
<p>If you implement function <span class="code">genArchiveRecords()</span>
|
||
above, then you should also implement <span class='code'>archive_interval</span>
|
||
as either an attribute, or as a <a
|
||
href="https://docs.python.org/2/library/functions.html#property">property
|
||
function</a>. It should return the archive
|
||
interval in seconds.</p>
|
||
|
||
<h3><span class="code">getTime()</span></h3>
|
||
<p>If your hardware has an onboard clock and supports reading
|
||
the time from it, then you may want to implement this
|
||
method. It takes no argument. It should return the time in
|
||
Unix Epoch Time. </p>
|
||
|
||
<h3><span class="code">setTime()</span></h3>
|
||
<p>If your hardware has an onboard clock and supports <em>setting</em>
|
||
it, then you may want to implement this method. It takes no
|
||
argument and does not need to return anything.</p>
|
||
|
||
<h3><span class="code">closePort()</span></h3>
|
||
<p>If the driver needs to close a serial port, terminate a
|
||
thread, close a database, or perform any other activity before
|
||
the application terminates, then you must supply this
|
||
function. <span class='code'>Weewx</span> will call it if it
|
||
needs to shut down your console (usually in the case of an
|
||
error).</p>
|
||
|
||
<h2>Define the configuration</h2>
|
||
<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>
|
||
<h2>Examples</h2>
|
||
<p>Before starting, take a look at the simulator code
|
||
in <span class='code'>bin/weewx/drivers/simulator.py</span>. It's
|
||
dirt simple and you can easily play with it. Many people have
|
||
successfully used it as a starting point for writing their own
|
||
custom driver.</p>
|
||
<p>The next most complicated is the
|
||
driver for the WMR100 series, located in <span class="code">wmr100.py</span>.
|
||
It reads from a USB port and has to do some tricky buffer decoding. Nevertheless,
|
||
it's general architecture is fairly straightforward.</p>
|
||
<p>The driver for the Vantage series is by far the most complicated. It
|
||
actually multi-inherits from not only <span class="code">AbstractDevice</span>,
|
||
but also <span class="code">StdService</span>. That is, it also
|
||
participates in the engine as a service.</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 — I'm happy to
|
||
help you out!</p>
|
||
|
||
<h1 id="extensions">Extensions</h1>
|
||
<p>Now that you have made some customizations, you might want to share
|
||
those changes with other <span class='code'>weewx</span> users. Put
|
||
your customizations into an extension to make installation, removal,
|
||
and distribution easier.</p>
|
||
<p>Customizations typically fall into one of these categories:</p>
|
||
<ul>
|
||
<li>search list extension</li>
|
||
<li>template</li>
|
||
<li>skin</li>
|
||
<li>service</li>
|
||
<li>generator</li>
|
||
<li>driver</li>
|
||
</ul>
|
||
<p>Extensions are a way to package one or more customizations so they
|
||
can be installed and distributed as a functional group.</p>
|
||
|
||
<h2>Extension guidelines</h2>
|
||
<p>Here are a few guidelines for creating extensions:</p>
|
||
<ul>
|
||
<li>Extensions should not modify or depend upon existing skins.
|
||
An extension should include its own, standalone skin to illustrate
|
||
any templates, search list extension, or generator features.</li>
|
||
<li>Extensions should not modify the database schemas.
|
||
If it requires data not found in the default databases, an
|
||
extension should provide its own database and schema.</li>
|
||
</ul>
|
||
|
||
<h2>How to package an extension</h2>
|
||
<p>The structure of an extension mirrors that of
|
||
<span class='code'>weewx</span> itself. If the customizations include
|
||
a skin, the extension will have a skins directory. If the
|
||
customizations include python code, the extension will have a
|
||
<span class='code'>bin/user</span> directory.
|
||
</p>
|
||
<p>Each extension should also include:</p>
|
||
<ul>
|
||
<li><span class='code'>readme.txt</span> - a summary of
|
||
what the extension does, list of pre-requisites (if any), and
|
||
instructions for installing the extension manually</li>
|
||
<li><span class='code'>changelog</span> - an enumeration of
|
||
changes in each release</li>
|
||
<li><span class='code'>install.py</span> - python code used by the
|
||
<span class='code'>weewx</span> ExtensionInstaller</li>
|
||
</ul>
|
||
<p>For example, here is the structure of a skin called
|
||
<span class='code'>basic</span>:</p>
|
||
<p class='tty'>basic/
|
||
basic/changelog
|
||
basic/install.py
|
||
basic/readme.txt
|
||
basic/skins/
|
||
basic/skins/basic/
|
||
basic/skins/basic/basic.css
|
||
basic/skins/basic/current.inc
|
||
basic/skins/basic/favicon.ico
|
||
basic/skins/basic/hilo.inc
|
||
basic/skins/basic/index.html.tmpl
|
||
basic/skins/basic/skin.conf</p>
|
||
<p>Here is the structure of a search list extension called
|
||
<span class='code'>xstats</span>:</p>
|
||
<p class='tty'>xstats/
|
||
xstats/changelog
|
||
xstats/install.py
|
||
xstats/readme.txt
|
||
xstats/bin/
|
||
xstats/bin/user/
|
||
xstats/bin/user/xstats.py</p>
|
||
<p>See the <span class='code'>extensions</span> directory of the
|
||
<span class='code'>weewx</span> source for examples.</p>
|
||
<p>To distribute an extension, simply create a compressed archive
|
||
of the extension directory.</p>
|
||
<p>For example, create the compressed archive for the
|
||
<span class='code'>basic</span> skin like this:</p>
|
||
<p class='tty'>tar cvfz basic.tar.gz basic</p>
|
||
|
||
<h2>The extension (un)installer</h2>
|
||
<p>The ExtensionInstaller is built in to
|
||
<span class='code'>setup.py</span>. It can install new extensions,
|
||
uninstall installed extensions, or enumerate installed extensions.</p>
|
||
<p>To install an extension:</p>
|
||
<p class='tty'>./setup.py install --extension extensions/basic
|
||
./setup.py install --extension basic.tar.gz</p>
|
||
<p>To uninstall an extension:</p>
|
||
<p class='tty'>./setup.py uninstall --extension basic</p>
|
||
<p>To list installed extensions:</p>
|
||
<p class='tty'>./setup.py list-extensions</p>
|
||
<p>Other options:</p>
|
||
<p class='tty'>./setup.py --help --extension
|
||
Usage: setup.py install --extension (filename|directory)
|
||
uninstall --extension extension_name
|
||
list-extensions
|
||
|
||
install/remove/list extensions to weewx
|
||
|
||
Options:
|
||
-h, --help show this help message and exit
|
||
--extension=EXT extension name, archive file, or directory
|
||
--layout=LAYOUT layout is deb, rpm, or py
|
||
--tmpdir=DIR temporary directory
|
||
--dry-run print what would happen but do not do it
|
||
--verbosity=N how much status to spew, 0-3</p>
|
||
<p>The ExtensionInstaller will make only the following changes:</p>
|
||
<ul>
|
||
<li>Modifications to <span class='code'>weewx.conf</span></li>
|
||
<li>Add/Remove directories in <span class='code'>skins</span></li>
|
||
<li>Add/Remove directories in <span class='code'>user</span></li>
|
||
</ul>
|
||
<p>The ExtensionInstaller makes a copy of any file or directory that it
|
||
modifies or replaces.</p>
|
||
<p>If <span class='code'>weewx</span> was installed using
|
||
<span class='code'>setup.py</span>,
|
||
the ExtensionInstaller depends upon
|
||
<span class='code'>setup.cfg</span> to locate the
|
||
<span class='code'>weewx</span> installation. If
|
||
<span class='code'>weewx</span> was installed using a DEB or RPM
|
||
package,
|
||
<span class='code'>setup.cfg</span> is not used.</p>
|
||
<p>The ExtensionInstaller creates a directory called
|
||
<span class='code'>installer</span> in the
|
||
<span class='code'>user</span> directory. The contents of the
|
||
<span class='code'>installer</span> directory are
|
||
used to enumerate and uninstall extensions.</p>
|
||
|
||
<h1 id="archive_types">Appendix: 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>, 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="indent">
|
||
<caption>Archive types</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Archive Type</td>
|
||
<td style="width: 200px">SQL Type<br />
|
||
<span style="font-size:80%">(appears in archive database)</span></td>
|
||
<td>Can be used <br />
|
||
in plots</td>
|
||
<td>Can be used <br />
|
||
in tag <span class="code">$current</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">altimeter</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">barometer</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">consBatteryVoltage</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">dateTime</td>
|
||
<td>X</td>
|
||
<td><br />
|
||
</td>
|
||
<td>X (represents current time)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">dewpoint</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">ET</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">extraHumid1</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">extraHumid2</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">extraTemp1</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">extraTemp2</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">extraTemp3</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">hail</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">hailRate</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">heatindex</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">heatingTemp</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">heatingVoltage</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">inHumidity</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">inTemp</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">inTempBatteryStatus</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">interval</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">leafTemp2</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">leafWet2</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">outHumidity</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">outTemp</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">outTempBatteryStatus</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">pressure</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">radiation</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">rain</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">rainBatteryStatus</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">rainRate</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">referenceVoltage</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">rxCheckPercent</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">soilMoist1</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">soilMoist2</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col 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="first_col code">soilMoist4</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">soilTemp1</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">soilTemp2</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">soilTemp3</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">soilTemp4</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">supplyVoltage</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">txBatteryStatus</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">usUnits</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">UV</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windvec</td>
|
||
<td> </td>
|
||
<td>X (special vector type)</td>
|
||
<td> </td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windBatteryStatus</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windDir</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windGust</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windGustDir</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windSpeed</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windchill</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h1 id="aggregation_types">Appendix: Aggregation types</h1>
|
||
|
||
<table class="indent">
|
||
<caption>Aggregation types</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Aggregation type</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">avg</td>
|
||
<td>The average value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">sum</td>
|
||
<td>The sum of values in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">count</td>
|
||
<td>The number of non-null values in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">min</td>
|
||
<td>The minimum value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">mintime</td>
|
||
<td>The time of the minimum value.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">max</td>
|
||
<td>The maximum value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">maxtime</td>
|
||
<td>The time of the maximum value.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">maxmin</td>
|
||
<td>The maximum daily minimum in the aggregation period. Aggregation period
|
||
must be one day or longer.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">maxmintime</td>
|
||
<td>The time of the maximum daily minimum.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">minmax</td>
|
||
<td>The minimum daily maximum in the aggregation period. Aggregation period
|
||
must be one day or longer.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">minmaxtime</td>
|
||
<td>The time of the minimum daily maximum.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">maxsum</td>
|
||
<td>The maximum daily sum in the aggregation period. Aggregation
|
||
period must be one day or longer.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">maxsumtime</td>
|
||
<td>The time of the maximum daily sum.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">meanmin</td>
|
||
<td>The average daily minimum in the aggregation period. Aggregation
|
||
period must be one day or longer.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">meanmax</td>
|
||
<td>The average daily maximum in the aggregation period. Aggregation
|
||
period must be one day or longer.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">gustdir</td>
|
||
<td>The direction of the max gust in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">last</td>
|
||
<td>The last value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">lasttime</td>
|
||
<td>The time of the last value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">max_ge(val)</td>
|
||
<td>The number of days where the maximum value is greater than or
|
||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">max_le(val)</td>
|
||
<td>The number of days where the maximum value is less than or
|
||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">min_le(val)</td>
|
||
<td>The number of days where the minimum value is less than or
|
||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">sum_ge(val)</td>
|
||
<td>The number of days where the sum of value is greater than or
|
||
equal to <em>val</em>. Aggregation period must be one day or longer.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">rms</td>
|
||
<td>The root mean square value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">vecavg</td>
|
||
<td>The vector average speed in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">vecdir</td>
|
||
<td>The vector averaged direction during the aggregation period.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h1 id="units">Appendix: Units</h1>
|
||
<p>Weewx offers three different <em>unit systems</em>:</p>
|
||
|
||
<table class="indent" style="width: 80%">
|
||
<caption>The standard unit systems used within weewx</caption>
|
||
<tr class="first_row">
|
||
<td>Name</td>
|
||
<td>Encoded value</td>
|
||
<td>Note</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">US</span></td>
|
||
<td>0x01</td>
|
||
<td>U.S. Customary</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">METRICWX</span></td>
|
||
<td>0x11</td>
|
||
<td>Metric, with rain related measurements in
|
||
<span class="code">mm</span> and speeds in
|
||
<span class="code">m/s</span>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col"><span class="code">METRIC</span></td>
|
||
<td>0x10</td>
|
||
<td>Metric, with rain related measurements in
|
||
<span class="code">cm</span> and speeds in
|
||
<span class="code">km/hr</span>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>The table below lists all the unit groups, their members, which
|
||
units are options for the group, and what the defaults are
|
||
for each standard unit system. </p>
|
||
<table class="indent">
|
||
<caption>Unit groups, members and options</caption>
|
||
<tbody class="code">
|
||
<tr class="first_row">
|
||
<td>Group</td>
|
||
<td>Members</td>
|
||
<td>Unit options</td>
|
||
<td><span class="code">US</span></td>
|
||
<td><span class="code">METRICWX</span></td>
|
||
<td><span class="code">METRIC</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_altitude</td>
|
||
<td>altitude</td>
|
||
<td>foot <br />
|
||
meter</td>
|
||
<td>foot</td>
|
||
<td>meter</td>
|
||
<td>meter</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_degree_day</td>
|
||
<td>cooldeg<br />
|
||
heatdeg</td>
|
||
<td>degree_F_day<br />
|
||
degree_C_day</td>
|
||
<td>degree_F_day</td>
|
||
<td>degree_C_day</td>
|
||
<td>degree_C_day</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_direction</td>
|
||
<td>gustdir <br />
|
||
vecdir <br />
|
||
windDir <br />
|
||
windGustDir</td>
|
||
<td>degree_compass</td>
|
||
<td>degree_compass</td>
|
||
<td>degree_compass</td>
|
||
<td>degree_compass</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_interval</td>
|
||
<td>interval</td>
|
||
<td>minute</td>
|
||
<td>minute</td>
|
||
<td>minute</td>
|
||
<td>minute</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_moisture</td>
|
||
<td>soilMoist1 <br />
|
||
soilMoist2 <br />
|
||
soilMoist3 <br />
|
||
soilMoist4</td>
|
||
<td>centibar</td>
|
||
<td>centibar</td>
|
||
<td>centibar</td>
|
||
<td>centibar</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_percent</td>
|
||
<td>extraHumid1 <br />
|
||
extraHumid2 <br />
|
||
inHumidity <br />
|
||
outHumidity <br />
|
||
rxCheckPercent</td>
|
||
<td>percent</td>
|
||
<td>percent</td>
|
||
<td>percent</td>
|
||
<td>percent</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_pressure</td>
|
||
<td>barometer <br />
|
||
altimeter <br />
|
||
pressure</td>
|
||
<td>inHg <br />
|
||
mbar <br />
|
||
hPa</td>
|
||
<td>inHg</td>
|
||
<td>mbar</td>
|
||
<td>mbar</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_radiation</td>
|
||
<td>UV <br />
|
||
radiation</td>
|
||
<td>watt_per_meter_squared</td>
|
||
<td>watt_per_meter_squared</td>
|
||
<td>watt_per_meter_squared</td>
|
||
<td>watt_per_meter_squared</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_rain</td>
|
||
<td>rain <br />
|
||
ET <br />
|
||
hail</td>
|
||
<td>inch <br />
|
||
cm <br />
|
||
mm</td>
|
||
<td>inch</td>
|
||
<td>mm</td>
|
||
<td>cm</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_rainrate</td>
|
||
<td>rainRate <br />
|
||
hailRate</td>
|
||
<td>inch_per_hour <br />
|
||
cm_per_hour <br />
|
||
mm_per_hour</td>
|
||
<td>inch_per_hour</td>
|
||
<td>mm_per_hour</td>
|
||
<td>cm_per_hour</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">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>
|
||
<td>mile_per_hour</td>
|
||
<td>meter_per_second</td>
|
||
<td>km_per_hour</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_speed2</td>
|
||
<td>rms <br />
|
||
vecavg</td>
|
||
<td>mile_per_hour2 <br />
|
||
km_per_hour2 <br />
|
||
knot2 <br />
|
||
meter_per_second2</td>
|
||
<td>mile_per_hour2</td>
|
||
<td>meter_per_second2</td>
|
||
<td>km_per_hour2</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">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>
|
||
<td>degree_F</td>
|
||
<td>degree_C</td>
|
||
<td>degree_C</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_time</td>
|
||
<td>dateTime</td>
|
||
<td>unix_epoch <br />
|
||
dublin_jd</td>
|
||
<td>unix_epoch</td>
|
||
<td>unix_epoch</td>
|
||
<td>unix_epoch</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_uv</td>
|
||
<td>UV</td>
|
||
<td>uv_index</td>
|
||
<td>uv_index</td>
|
||
<td>uv_index</td>
|
||
<td>uv_index</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_volt</td>
|
||
<td>consBatteryVoltage <br />
|
||
heatingVoltage <br />
|
||
referenceVoltage <br />
|
||
supplyVoltage</td>
|
||
<td>volt</td>
|
||
<td>volt</td>
|
||
<td>volt</td>
|
||
<td>volt</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_NONE</td>
|
||
<td>NONE</td>
|
||
<td>NONE</td>
|
||
<td>NONE</td>
|
||
<td>NONE</td>
|
||
<td>NONE</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h1 id="station_data">Appendix: Station Data</h1>
|
||
<p>The following tables show which data are provided by the station
|
||
hardware and which are calculated by <span class='code'>weewx</span>.
|
||
</p>
|
||
<p class='station_data_key'>
|
||
<b>H</b> indicates data provided by <b>H</b>ardware<br/>
|
||
<b>D</b> indicates data calculated by the <b>D</b>river<br/>
|
||
<b>S</b> indicates data calculated by the StdWXCalculate <b>S</b>ervice<br/>
|
||
</p>
|
||
|
||
<h2 id="cc3000_station_data">CC3000</h2>
|
||
<table class='station_data'>
|
||
<caption>CC3000 station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>radiation</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td>H</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
The <span class='code'>radiation</span> and <span class='code'>UV</span>
|
||
data are available only with the optional solar radiation sensor.
|
||
</p>
|
||
|
||
<h2 id="fo_station_data">Fine Offset</h2>
|
||
<table class='station_data'>
|
||
<caption>Fine Offset station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGustDir</td> <td>D</td><td>D</td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>H/S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>H/S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>H/S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>radiation</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td>H</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
The <span class='code'>radiation</span> and <span class='code'>UV</span>
|
||
data are available only from 30xx stations.
|
||
</p>
|
||
|
||
<h2 id="te923_station_data">TE923</h2>
|
||
<table class='station_data'>
|
||
<caption>TE923 station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windGustDir</td> <td>D</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>H/S</td><td> </td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp4</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid4</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>txBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>windBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>rainBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>outTempBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>extraBatteryStatus1</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>extraBatteryStatus2</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>extraBatteryStatus3</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>extraBatteryStatus4</td> <td>H</td><td></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
Some stations support up to 5 remote temperature/humidity sensors. The
|
||
<span class='code'>UV</span> data are available only with the optional
|
||
solar radiation sensor.
|
||
</p>
|
||
|
||
<h2 id="ultimeter_station_data">Ultimeter</h2>
|
||
<table class='station_data'>
|
||
<caption>Ultimeter station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td> </td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
The <span class='code'>rain</span> and <span class='code'>rainRate</span> are
|
||
available only on stations with the optional rain bucket.
|
||
</p>
|
||
<p class='station_data_key'>
|
||
Pressure, inside temperature, and inside humidity data are not available on
|
||
all types of Ultimeter stations.
|
||
</p>
|
||
|
||
<h2 id="vantage_station_data">Vantage</h2>
|
||
<table class='station_data'>
|
||
<caption>Vantage station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGustDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>radiation</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraTemp1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraTemp2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraTemp3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraTemp4</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp5</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp6</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp7</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>soilTemp1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>soilTemp2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>soilTemp3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>soilTemp4</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafTemp1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafTemp2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafTemp3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafTemp4</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraHumid1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraHumid2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraHumid3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid4</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid5</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid6</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid7</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>soilMoist1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>soilMoist2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>soilMoist3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>soilMoist4</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafWet1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafWet2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafWet3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>leafWet4</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>txBatteryStatus</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>consBatteryVoltage</td> <td>H</td><td>H</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 id="wmr100_station_data">WMR100</h2>
|
||
<table class='station_data'>
|
||
<caption>WMR100 station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTempBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTempBatteryStatus</td><td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>uvBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
Each packet contains a subset of all possible readings. For example, a temperature packet contains <span class='code'>extraTempN</span> and <span class='code'>batteryStatusN</span>, a rain packet contains <span class='code'>totalRain</span> and <span class='code'>rainRate</span>.
|
||
</p>
|
||
|
||
<h2 id="wmr200_station_data">WMR200</h2>
|
||
<table class='station_data'>
|
||
<caption>WMR200 station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>H/S</td><td>H/S</td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>H/S</td><td>H/S</td></tr>
|
||
<tr><td class='first_col'>extraTemp1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraTemp2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraTemp3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraHumid1</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraHumid2</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>extraHumid3</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTempBatteryStatus</td><td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>uvBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
Each packet contains a subset of all possible readings. For example, a temperature packet contains <span class='code'>extraTempN</span> and <span class='code'>batteryStatusN</span>, a rain packet contains <span class='code'>totalRain</span> and <span class='code'>rainRate</span>.
|
||
</p>
|
||
|
||
<h2 id="wmr9x8_station_data">WMR9x8</h2>
|
||
<table class='station_data'>
|
||
<caption>WMR9x8 station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windGustDir</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraTemp3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>extraHumid3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>UV</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTempBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTempBatteryStatus</td><td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rainBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windBatteryStatus</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>batteryStatusTH1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>batteryStatusTH2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>batteryStatusTH3</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>batteryStatusT1</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>batteryStatusT2</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>batteryStatusT3</td> <td>H</td><td> </td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class='station_data_key'>
|
||
Each packet contains a subset of all possible readings. For example, a temperature packet contains <span class='code'>extraTempN</span> and <span class='code'>batteryStatusN</span>, a rain packet contains <span class='code'>totalRain</span> and <span class='code'>rainRate</span>.
|
||
</p>
|
||
|
||
<h2 id="ws1_station_data">WS1</h2>
|
||
<table class='station_data'>
|
||
<caption>WS1 station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>S</td><td> </td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>S</td><td> </td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 id="ws23xx_station_data">WS23xx</h2>
|
||
<table class='station_data'>
|
||
<caption>WS23xx station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>D</td><td>D</td></tr>
|
||
<tr><td class='first_col'>windGustDir</td> <td>D</td><td>D</td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>H/S</td><td>H/S</td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>H/S</td><td>H/S</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 id="ws28xx_station_data">WS28xx</h2>
|
||
<table class='station_data'>
|
||
<caption>WS28xx station data</caption>
|
||
<tbody class='code'>
|
||
<tr class="first_row">
|
||
<td style='width:200px'>Observation</td>
|
||
<td>Loop</td>
|
||
<td>Archive</td>
|
||
</tr>
|
||
<tr><td class='first_col'>barometer</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>pressure</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>altimeter</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>inTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outTemp</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>inHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>outHumidity</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windSpeed</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windDir</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGust</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>windGustDir</td> <td>D</td><td>D</td></tr>
|
||
<tr><td class='first_col'>rainRate</td> <td>H</td><td> </td></tr>
|
||
<tr><td class='first_col'>rain</td> <td>H</td><td>H</td></tr>
|
||
<tr><td class='first_col'>dewpoint</td> <td>S</td><td>S</td></tr>
|
||
<tr><td class='first_col'>windchill</td> <td>H/S</td><td>H/S</td></tr>
|
||
<tr><td class='first_col'>heatindex</td> <td>H/S</td><td>H/S</td></tr>
|
||
<tr><td class='first_col'>rxCheckPercent</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>windBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>rainBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>outTempBatteryStatus</td> <td>H</td><td></td></tr>
|
||
<tr><td class='first_col'>inTempBatteryStatus</td> <td>H</td><td></td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p class="copyright"> © <a href="copyright.htm">Copyright</a> Tom Keffer </p>
|
||
</div> <!-- #technical_content -->
|
||
|
||
</body>
|
||
</html>
|