mirror of
https://github.com/weewx/weewx.git
synced 2026-04-18 08:36:54 -04:00
7201 lines
327 KiB
HTML
7201 lines
327 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<title>WeeWX: Customization Guide</title>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||
<link rel="icon" href="images/favicon.png" type="image/png"/>
|
||
<link rel="stylesheet" href="css/tocbot-4.3.1.css">
|
||
<link rel="stylesheet" href="css/weewx_ui.css"/>
|
||
<script src="js/cash.js"></script>
|
||
<script src="js/tocbot-4.3.1.min.js"></script>
|
||
<script src="js/weewx.js"></script>
|
||
<script>
|
||
$(function () {
|
||
make_ids('#technical_content');
|
||
let level = get_level_from_cookie();
|
||
create_toc_level_control(level);
|
||
create_toc(level);
|
||
})
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<div class="sidebar">
|
||
<div class="doclist">
|
||
<a href="usersguide.htm">User's Guide</a><br/> <a href="customizing.htm">Customization Guide</a><br/> <a
|
||
href="hardware.htm">Hardware Guide</a><br/> <a href="utilities.htm">Utilities Guide</a><br/> <a
|
||
href="upgrading.htm">Upgrade Guide</a><br/> <a href="devnotes.htm">Notes for Developers</a>
|
||
</div>
|
||
<div id="toc_controls">
|
||
<!-- The TOC select list will be injected here -->
|
||
</div>
|
||
<div id="toc_parent">
|
||
<div id="toc-location" class="toc">
|
||
<!-- The table of contents will be injected here -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="main">
|
||
|
||
<div class="header">
|
||
<div class="logoref">
|
||
<a href='http://weewx.com'> <img src='images/logo-weewx.png' class='logo' style="float:right"
|
||
alt="weewx logo"/> </a><br/> <span class='version'>
|
||
Version: 4.0
|
||
</span>
|
||
</div>
|
||
<div class="title">WeeWX Customization Guide</div>
|
||
</div>
|
||
|
||
<div id="technical_content" class="content">
|
||
|
||
<p>
|
||
This document covers the customization of WeeWX. It assumes that you have read, and are
|
||
reasonably familiar with, the <a href="usersguide.htm">Users Guide</a>.
|
||
</p>
|
||
<p>
|
||
The introduction contains an overview of the architecture. If you are only interested
|
||
in customizing the generated reports you can probably skip the introduction and proceed
|
||
directly to the section <a href="#customizing_reports"><em>Customizing reports</em></a>.
|
||
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,
|
||
<i>etc.</i>, then it would be worth your while to read about the internal architecture.
|
||
</p>
|
||
|
||
<p>
|
||
Most of the guide applies to any hardware, but the exact data types are
|
||
hardware-specific. See the <a href="hardware.htm"><em>WeeWX Hardware Guide</em></a>
|
||
for details of how different observation types are handled by different types hardware.
|
||
</p>
|
||
|
||
<p class="warning">
|
||
<strong>Warning!</strong><br/> WeeWX 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>
|
||
|
||
|
||
<h1 id="introduction">Introduction</h1>
|
||
|
||
<h2>Overall system architecture</h2>
|
||
|
||
<p>
|
||
Below is a brief overview of the WeeWX system architecture, which is covered in much
|
||
more detail in the rest of this document.
|
||
</p>
|
||
|
||
<div class="image image-right" style="width: 30%">
|
||
<img src="images/pipeline.png" alt="The WeeWX pipeline"/>
|
||
|
||
<div class="image_caption">A typical WeeWX pipeline. The actual pipeline depends
|
||
on what extensions are in use. Data, in the form of LOOP packets and archive
|
||
records, flows from top to bottom.</div>
|
||
</div>
|
||
<ul>
|
||
<li>
|
||
A WeeWX process normally handles the monitoring of one station — <i>e.g.</i> a
|
||
weather station. The process is configured using a file with the name
|
||
<span class="code">weewx.conf</span>.
|
||
</li>
|
||
|
||
<li>
|
||
A WeeWX process has at most one "driver" to communicate with the station hardware
|
||
and receive "high resolution" (<i>i.e.</i> every few seconds) measurement data in
|
||
the form of LOOP packets. The driver is single-threaded and blocking, so no more
|
||
than one driver can run in a WeeWX process.
|
||
</li>
|
||
|
||
|
||
<li>
|
||
LOOP packets may contain arbitrary data from the station/driver in the form of a
|
||
Python dictionary. Each LOOP packet must contain a time stamp, and a unit system,
|
||
in addition to any number of observations, such as temperature or humidity.
|
||
For extensive types, such as rain, the packet contains the total amount of
|
||
rain that fell during the observation period.
|
||
</li>
|
||
<li>
|
||
WeeWX then compiles these LOOP packets into regularly spaced "archive records."
|
||
For most types, the archive record contains the average value seen in all of the
|
||
LOOP packets over the archive interval (typically 5 minutes). For extensive types,
|
||
such as rain, it is the sum of all values over the archive interval.
|
||
</li>
|
||
<li>
|
||
Internally, the WeeWX engine uses a <em>pipeline</em> architecture, consisting
|
||
of many <em>services</em>. Services bind to events of interest, such as new
|
||
LOOP packets, or new archive records. Events are then run down the pipeline
|
||
in order — services at the top of the pipeline act on the data
|
||
before services farther down the pipe.
|
||
</li>
|
||
|
||
<li>
|
||
Services can do things such as check the data quality, apply corrections, or save
|
||
data to a database. Users can easily add new services.
|
||
</li>
|
||
|
||
<li>
|
||
WeeWX includes an ability to customize behavior by installing <em>extensions</em>.
|
||
Extensions may consist of one or more drivers, services, and/or skins, all in an
|
||
easy-to-install package.
|
||
</li>
|
||
</ul>
|
||
|
||
|
||
<h2 id="Data_architecture">Data architecture</h2>
|
||
|
||
<p>
|
||
WeeWX is data-driven. When the sensors spit out some data, WeeWX does something. The
|
||
"something" might be to print out the data, or to generate an HTML report, or to use
|
||
FTP to copy a report to a web server, or to perform some calculations using the data.
|
||
</p>
|
||
|
||
<p>
|
||
A driver is Python code that communicates with the hardware. The driver reads data from
|
||
a serial port or a device on the USB or a network interface. It handles any decoding of
|
||
raw bits and bytes, and puts the resulting data into LOOP packets. The drivers for
|
||
some kinds of hardware (most notably, Davis Vantage) are capable of emitting archive
|
||
records as well.
|
||
</p>
|
||
<p>
|
||
In addition to the primary observation types such as temperature, humidity, or solar
|
||
radiation, there are also many useful dependent types, such as wind chill, heat index,
|
||
or ET, which are calculated from the primary data. The firmware in some weather
|
||
stations are capable of doing many of these calculations on their own. For the rest,
|
||
should you choose to do so, the WeeWX service <a
|
||
href="usersguide.htm#StdWXCalculate"><span class="code">StdWXCalculate</span></a> can
|
||
fill in the gaps. Sometimes the firmware simply does it wrong, and you may choose to
|
||
have WeeWX do the calculation, despite the type's presence in LOOP packets.
|
||
</p>
|
||
|
||
<h2>LOOP packets <em>vs.</em> archive records </h2>
|
||
|
||
<p>
|
||
Generally, there are two types of data that flow through WeeWX: LOOP packets, and
|
||
archive records. Both are represented as Python dictionaries.
|
||
</p>
|
||
|
||
<h3>LOOP packets</h3>
|
||
<p>
|
||
LOOP packets are the raw data generated by the device driver. They get their name from the Davis Instruments
|
||
documentation. For some devices they are generated at rigid intervals, such as every 2 seconds for the Davis
|
||
Vantage series, for others, irregularly, every 20 or 30 seconds or so. LOOP packets may or may not contain
|
||
all the data types. For example, a packet may contain only temperature data, another only barometric data,
|
||
<em>etc</em>. These kinds of packet are called <em>partial record packets</em>. By contrast, other types of
|
||
hardware (notably the Vantage series), every LOOP packet contains every data type.
|
||
</p>
|
||
|
||
<p>In summary, LOOP packets can be highly irregular, but they come in frequently.</p>
|
||
|
||
<h3>Archive records</h3>
|
||
|
||
<p>
|
||
By contrast, archive records are highly regular. They are generated at regular intervals (generally every 5
|
||
to 30 minutes), and all contain the same data types. They represent an <em>aggregation</em> of the LOOP
|
||
packets over the archive interval. The exact kind of aggregation depends on the data type. For example, for
|
||
temperature, it's generally the average temperature over the interval. For rain, it's the sum of rain over
|
||
the interval. For battery status it's the last value in the interval.
|
||
</p>
|
||
|
||
<p>
|
||
Some hardware is capable of generating their own archive records (the Davis Vantage and
|
||
Oregon Scientific WMR200, for example), but for hardware that cannot, WeeWX generates
|
||
them.
|
||
</p>
|
||
|
||
<p>It is the archive data that is put in the SQL database, although, occasionally, the LOOP packets can be
|
||
useful (such as for the Weather Underground's "Rapidfire" mode).
|
||
</p>
|
||
|
||
<h2>What to customize</h2>
|
||
|
||
<p>
|
||
For configuration changes, such as which skins to use, or enabling posts to the
|
||
Weather Underground, simply modify the WeeWX configuration file
|
||
<span class="code">weewx.conf</span>. Any changes you make will be preserved during
|
||
an upgrade.
|
||
</p>
|
||
<p>
|
||
Customization of reports may require changes to a skin configuration file <span
|
||
class="code">skin.conf</span> or template files ending in <span
|
||
class="code">.tmpl</span> or <span class="code">.inc</span>. Anything in the <span
|
||
class="code">skins</span> subdirectory is also preserved across upgrades.
|
||
</p>
|
||
<p>
|
||
You may choose to install one of the many <a
|
||
href="https://github.com/weewx/weewx/wiki#extensions-to-weewx">third-party
|
||
extensions</a> that are available for WeeWX. These are typically installed in either
|
||
the <span class="code">skins</span> or <span class="code">user</span> subdirectories,
|
||
both of which are preserved across upgrades.
|
||
</p>
|
||
|
||
<p>
|
||
More advanced customizations may require new Python code or modifications of
|
||
example code. These should be placed in the <span class="code">user</span> directory,
|
||
where they will be preserved across upgrades. For example, if you wish to modify one of
|
||
the examples that comes with WeeWX, copy it from the <span class="code">examples</span>
|
||
directory to the <span class="code">user</span> directory, then modify it there. This
|
||
way, your modifications will not be touched if you upgrade.
|
||
</p>
|
||
<p>
|
||
For code that must run before anything else in WeeWX runs (for example, to set up an
|
||
environment), put it in the file <span class="code">extensions.py</span> in the <span
|
||
class="code">user</span> directory. It is always run before the WeeWX engine starts up.
|
||
Because it is in the <span class="code">user</span> subdirectory, it is preserved
|
||
between upgrades.
|
||
</p>
|
||
|
||
<h2>Do I need to restart WeeWX?</h2>
|
||
<p>
|
||
If you make a change in <span class="code">weewx.conf</span>, you will need to restart
|
||
WeeWX.
|
||
</p>
|
||
<p>
|
||
If you modify Python code in the <span class="code">user</span> directory or elsewhere,
|
||
you will need to restart WeeWX.
|
||
</p>
|
||
<p>
|
||
If you install an extension, you will need to restart WeeWX.
|
||
</p>
|
||
<p>
|
||
If you make a change to a template or to a <span class="code">skin.conf</span> file,
|
||
you do not need to restart WeeWX. The change will be adopted at the next reporting
|
||
cycle, typically at the end of an archive interval.
|
||
</p>
|
||
<h2 id="wee_reports">
|
||
The utility <span class="code">wee_reports</span>
|
||
</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 utility <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.
|
||
</p>
|
||
<pre class="tty"><span class="cmd">wee_reports weewx.conf 1398927600</span></pre>
|
||
|
||
<p>
|
||
For more information about <span class="code">wee_reports</span>, see the <a
|
||
href="utilities.htm#wee_reports_utility">Utilities Guide</a>
|
||
</p>
|
||
|
||
<h2>The WeeWX service architecture</h2>
|
||
|
||
<p>
|
||
At a high-level, WeeWX 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 or archive data. The default install of WeeWX includes the following services:
|
||
</p>
|
||
<table id='default_services' class="indent">
|
||
<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 or CSV files, generate images, or transfer files using FTP/rsync.
|
||
</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 reporting service, <span class="code">StdReport</span>, 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 WeeWX includes six reports:
|
||
</p>
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Report</td>
|
||
<td>Default functionality</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">SeasonsReport</td>
|
||
<td>Introduced with WeeWX V3.9, this report generates a single HTML file with day, week, month and year
|
||
"to-date" summaries, as well as the plot images to go along with them. Buttons select which time
|
||
scale the user wants. It also generates HTML files with more details on celestial bodies and
|
||
statistics. Also generates NOAA monthly and yearly summaries.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">SmartphoneReport</td>
|
||
<td>A simple report that generates an HTML file, which allows "drill down" to show more detail about
|
||
observations. Suitable for smaller devices, such as smartphones.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">MobileReport</td>
|
||
<td>A super simple HTML file that just shows the basics. Suitable for low-powered or
|
||
bandwidth-constrained devices.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">StandardReport</td>
|
||
<td>This is an older report that has been used for many years in WeeWX. It 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. It typically loads faster than the
|
||
<em>SeasonsReport</em>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">FTP</td>
|
||
<td>Transfer everything in the <span class="symcode">HTML_ROOT</span> directory to a remote server using
|
||
ftp.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">RSYNC</td>
|
||
<td>Transfer everything in the <span class="symcode">HTML_ROOT</span> directory to a remote server using
|
||
rsync.
|
||
</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 transfer files and folders 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 WeeWX configuration file <span class="code">weewx.conf</span> or the skin
|
||
configuration file <span class="code">skin.conf</span>.
|
||
</p>
|
||
|
||
<p>Like all reports, the FTP and RSYNC "reports" also use a skin, and include a skin configuration file,
|
||
although they are quite minimal.
|
||
</p>
|
||
|
||
<p>
|
||
Skins live in their own directory called <span class='code'>skins</span>, whose location is referred to as
|
||
<a href="#skin-root-description"> <span class="symcode">SKIN_ROOT</span></a>.
|
||
|
||
</p>
|
||
<div id="skin-root-description" class="modal-dialog">
|
||
<div>
|
||
<!--suppress HtmlUnknownAnchorTarget -->
|
||
<a href="#close" title="Close" class="close-dialog">X</a>
|
||
<h4>SKIN_ROOT</h4>
|
||
<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>
|
||
</div>
|
||
|
||
<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 WeeWX includes the following generators:
|
||
</p>
|
||
<table class="indent">
|
||
<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. WeeWX uses
|
||
the <a href="https://pythonhosted.org/Cheetah/">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. There are also template files that end with the <span
|
||
class="code">.inc</span> extension. These templates are included in other templates.
|
||
</p>
|
||
|
||
<h2>The database</h2>
|
||
|
||
<p>
|
||
WeeWX 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>
|
||
|
||
<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 fixed_width">
|
||
<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>...</td>
|
||
</tr>
|
||
|
||
<tr class="code">
|
||
<td>1413937800</td>
|
||
<td>1</td>
|
||
<td>5</td>
|
||
<td>29.938</td>
|
||
<td><em>null</em></td>
|
||
<td><em>null</em></td>
|
||
<td>71.2</td>
|
||
<td>56.0</td>
|
||
<td>...</td>
|
||
</tr>
|
||
<tr class="code">
|
||
<td>1413938100</td>
|
||
<td>1</td>
|
||
<td>5</td>
|
||
<td>29.941</td>
|
||
<td><em>null</em></td>
|
||
<td><em>null</em></td>
|
||
<td>71.2</td>
|
||
<td>55.9</td>
|
||
<td>...</td>
|
||
</tr>
|
||
<tr class="code">
|
||
<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 code">dateTime</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 code">usUnits</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 code">interval</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 WeeWX, the reporting engine allows
|
||
you to use multiple databases in the same report. For example, if you have installed the <a
|
||
href="https://github.com/weewx/weewx/wiki/cmon"><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 WeeWX 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, no matter if its implementation is
|
||
a sqlite database or a MySQL 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 WeeWX 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>
|
||
WeeWX 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, you will be passed in a function
|
||
<span class="code">db_lookup()</span> as a parameter, which can be used to bind to a database. By default,
|
||
it returns a manager bound to <span class="code">wx_binding</span>:
|
||
</p>
|
||
<pre class='tty'>wx_manager = db_lookup() # Get default binding
|
||
other_manager = db_lookup(data_binding='some_other_binding') # Get an explicit binding
|
||
|
||
# Sample queries:
|
||
wx_manager.getSql("SELECT SUM(rain) FROM %s "\
|
||
"WHERE dateTime>? AND dateTime<=?" % wx_manager.table_name, (start_ts, stop_ts))
|
||
other_manager.getSql("SELECT SUM(power) FROM %s"\
|
||
"WHERE dateTime>? AND dateTime<=?" % other_manager.table_name, (start_ts, stop_ts))</pre>
|
||
<p>
|
||
If opening a database from somewhere other than a service, and there is no <span
|
||
class="code">DBBinder</span> available:
|
||
</p>
|
||
<pre class='tty'>db_manager = weewx.manager.open_manager_with_config(config_dict, 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>
|
||
The <span class="code">DBBinder</span> caches managers, and thus database connections. It cannot be shared
|
||
between threads.
|
||
</p>
|
||
|
||
<h2>Units</h2>
|
||
|
||
<p>
|
||
The unit architecture in WeeWX 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 <em>driver</em> 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 WeeWX database. By default, and to maintain compatibility with <span
|
||
class='code'>wview</span>, the default database units are US Customary, although this can be changed.
|
||
</p>
|
||
|
||
<p>
|
||
Note that whatever unit system is used in the database, data can be <em>displayed</em> using any unit
|
||
system. So, in practice, it does not matter what unit system is used in the database.
|
||
</p>
|
||
|
||
<p>
|
||
Each <em>observation type</em>, such as <span class='code'>outTemp</span> or <span
|
||
class='code'>pressure</span>, is associated with a <em>unit group</em>, such as <span class='code'>group_temperature</span>
|
||
or <span class='code'>group_pressure</span>. Each unit group is associated with a <em>unit type</em> such as
|
||
<span class='code'>degree_F</span> or <span class='code'>mbar</span>. The reporting service uses this
|
||
architecture to convert observations into a target unit system, to be displayed in your reports.
|
||
</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>
|
||
There are two general mechanisms for customizing reports: change options in one or more configuration files,
|
||
or change the template files. The former is generally easier, but occasionally the latter is necessary.
|
||
</p>
|
||
|
||
<p>
|
||
Options are specified in configuration files and are organized hierarchically into stanzas. For example, the
|
||
<span class="code">[Labels]</span> stanza contains the text that should be displayed for each observation.
|
||
The <span class="code">[Units]</span> stanza contains other stanzas, each of which contains parameters that
|
||
control the display of units.
|
||
</p>
|
||
|
||
<p class="note">
|
||
For a complete listing of the report options, see the section <a href="#report_options"><em>Reference:
|
||
report options</em></a>.
|
||
</p>
|
||
|
||
<h2 id="How_options_work">How options work</h2>
|
||
|
||
<p>
|
||
Options are used in WeeWX to specify how your reports will look and what they will contain. For example,
|
||
they control what units to use, how to format a string, which plot lines to include, and what color they
|
||
should be, <em>etc</em>. They all work the same way and obey a hierarchy, allowing skin authors to specify a
|
||
look and feel of a report, while ensuring that you still have the final say of how it will come out.
|
||
</p>
|
||
|
||
<p>
|
||
Here are the places where options are specified, including their <em>scope</em> and <em>precedence</em>,
|
||
listed in order of decreasing precedence.
|
||
</p>
|
||
|
||
<table class="indent" style="width: 90%">
|
||
<caption>Option hierarchy, highest to lowest</caption>
|
||
<tr class="first_row">
|
||
<td>File</td>
|
||
<td>Section</td>
|
||
<td>Scope</td>
|
||
<td>Nesting example</td>
|
||
<td>Comments</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">weewx.conf</td>
|
||
<td class="code">[StdReport] / [[<span class="symcode">report_name</span>]]
|
||
</td>
|
||
<td>Affects only the report <span class="symcode">report_name</span>.</td>
|
||
<td class="code">[[[Labels]]] / [[[[Generic]]]]</td>
|
||
<td>Highest precedence. Has the final say.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">weewx.conf</td>
|
||
<td class="code"><a href="#change_defaults">[StdReport] / [[Defaults]]</a></td>
|
||
<td>Affects <em>all</em> reports.</td>
|
||
<td class="code">[[[Labels]]] / [[[[Generic]]]]</td>
|
||
<td>Normal mechanism for an user to modify the parameters in a report, such as units.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">skins/<span class="symcode">report_name</span>/skin.conf</td>
|
||
<td></td>
|
||
<td>Affects only the report <span class="symcode">report_name</span>.</td>
|
||
<td class="code">[Labels] / [[Generic]]</td>
|
||
<td>Generally supplied by the skin author, not the user. Parameters specified here define the baseline
|
||
behavior.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">weewx/defaults.py</td>
|
||
<td class="code"></td>
|
||
<td>Affects <em>all</em> reports.</td>
|
||
<td class="code">[Labels] / [[Generic]]</td>
|
||
<td>Acts as a backstop, in the case an option is not specified anywhere else. Not generally modified by
|
||
the user, although this could change in the future.
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>
|
||
You must pay attention to the number of brackets! In the table above, there are two different nesting depths
|
||
used: one for <span class="code">weewx.conf</span>, and one for <span class="code">weewx/defaults.py</span>
|
||
and <span class="code">skin.conf</span>. This is because the stanzas defined in <span class="code">weewx.conf</span>
|
||
start two levels down in the hierarchy <span class="code">[StdReport]</span>, whereas the stanzas defined in
|
||
<span class="code">skin.conf</span> and <span class="code">defaults.py</span> are at the root level.
|
||
</p>
|
||
|
||
<h2 id="how_to_change_labels">Changing labels</h2>
|
||
<p>
|
||
Let's look at an example. If you take a look inside the file <span class="code">weewx/defaults.py</span>,
|
||
you will see it contains what looks like a big configuration file. Among other things, it has two entries
|
||
that look like this:
|
||
</p>
|
||
<pre class="tty">
|
||
...
|
||
[Labels]
|
||
...
|
||
[[Generic]]
|
||
...
|
||
inTemp = Inside Temperature
|
||
outTemp = Outside Temperature
|
||
...</pre>
|
||
|
||
<p>
|
||
This tells the report generators that when it comes time to label the observation variables <span
|
||
class="code">inTemp</span> and <span class="code">outTemp</span>, use the strings <span class="code">InsideTemperature</span>
|
||
and <span class="code">Outside Temperature</span>, respectively. Because <span class="code">weewx/defaults.py</span>
|
||
lowest precedence, these strings will be used only when nothing else is available.
|
||
</p>
|
||
<p>
|
||
Now suppose we have a skin called <em>Life</em> . Its configuration file will be located at <span
|
||
class="code">skins/Life/skin.conf</span>. Suppose, among other things, it contains an excerpt
|
||
</p>
|
||
|
||
<pre class="tty">
|
||
...
|
||
[Labels]
|
||
...
|
||
[[Generic]]
|
||
...
|
||
outTemp = Exterior Temperature
|
||
</pre>
|
||
|
||
<p>
|
||
What this says is that the author of <span class="code">Life</span>, for whatever reasons, decided that s/he
|
||
wants to use the string <span class="code">Exterior Temperature</span>, instead of <span class="code">Outside Temperature</span>
|
||
for the label for <span class="code">outTemp</span>. The file includes no definition for <span class="code">inTemp</span>.
|
||
</p>
|
||
<p>
|
||
Finally, for purposes of illustrating precedence, suppose the <span class="code">[StdReport]</span> section
|
||
of <span class="code">weewx.conf</span> contains this:
|
||
</p>
|
||
|
||
<pre class="tty">
|
||
[StdReport]
|
||
...
|
||
|
||
[[LifeA]]
|
||
skin = Seasons
|
||
|
||
[[LifeB]]
|
||
skin = Life
|
||
[[[Labels]]]
|
||
[[[[Generic]]]]
|
||
outTemp = Barn Temperature
|
||
</pre>
|
||
|
||
<p>
|
||
This will result in reports with the following values:
|
||
</p>
|
||
|
||
<table class="indent" style="width: 80%">
|
||
<tr class="first_row">
|
||
<td>Report</td>
|
||
<td>Label for <span class="code">inTemp</span></td>
|
||
<td>Label for <span class="code">outTemp</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>LifeA</td>
|
||
<td>Inside Temperature</td>
|
||
<td>Exterior Temperature</td>
|
||
</tr>
|
||
<tr>
|
||
<td>LifeB</td>
|
||
<td>Inside Temperature</td>
|
||
<td>Barn Temperature</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>
|
||
Note how the values specified for <span class="code">inTemp</span> are not overridden anywhere, so the value
|
||
specified in <span class="code">weewx/defaults.py</span>, that is, <span
|
||
class="code">Inside Temperature</span>, is used. By contrast, a value for <span class="code">outTemp</span>
|
||
was specified in the skin so, in the absence of any user override, its value, <span class="code">ExteriorTemperature</span>
|
||
will be used as the new default. Finally, for the report <span class="code">LifeB</span>, the user
|
||
<em>has</em> specified an override for <span class="code">outTemp</span>, so that value, <span class="code">Barn Temperature</span>,
|
||
is used.
|
||
</p>
|
||
|
||
<p>
|
||
One more example. This time, suppose the <span class="code">[StdReport]</span> section of <span
|
||
class="code">weewx.conf</span> contains this:
|
||
</p>
|
||
|
||
<pre class="tty">
|
||
[StdReport]
|
||
...
|
||
|
||
<span class="highlight"> [[Defaults]]
|
||
[[[Labels]]]
|
||
[[[[Generic]]]]
|
||
outTemp = Shed Temperature</span>
|
||
|
||
[[LifeA]]
|
||
skin = Seasons
|
||
|
||
[[LifeB]]
|
||
skin = Life
|
||
[[[Labels]]]
|
||
[[[[Generic]]]]
|
||
outTemp = Barn Temperature
|
||
</pre>
|
||
<p>
|
||
We have added a new section (<span class="highlight">highlighted</span>), where the user has specified a new
|
||
default for the observation type <span class="code">outTemp</span>, that is, <span class="code">Shed Temperature</span>.
|
||
Unless overridden, this is the value that will now be used instead of what the skin author specified. The
|
||
final tally looks like this:
|
||
</p>
|
||
|
||
<table class="indent" style="width: 80%">
|
||
<tr class="first_row">
|
||
<td>Report</td>
|
||
<td>Label for <span class="code">inTemp</span></td>
|
||
<td>Label for <span class="code">outTemp</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>LifeA</td>
|
||
<td>Inside Temperature</td>
|
||
<td>Shed Temperature</td>
|
||
</tr>
|
||
<tr>
|
||
<td>LifeB</td>
|
||
<td>Inside Temperature</td>
|
||
<td>Barn Temperature</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h2 id="how_to_change_units">How to change units</h2>
|
||
|
||
<p>
|
||
Some users prefer to see metric units, others prefer US customary units. And there are other cases where
|
||
metric/US is not enough; some sites need metric units for most measurements, but wind speeds in <span
|
||
class="code">knots</span>, or some sites need rainfall in <span class="code">mm</span> whereas others need
|
||
<span class="code">cm</span>.
|
||
</p>
|
||
<p>
|
||
This section shows how to specify exactly what units you want to use for which reports. The examples use the
|
||
skin <em>Seasons</em>, which comes with the distribution.
|
||
</p>
|
||
|
||
<h3 id="change_defaults">Change units for all reports </h3>
|
||
<p>
|
||
With this approach, you change an option under the <span class="code">[[Defaults]]</span> subsection,
|
||
located under <span class="code">[StdReport]</span> in <span class="code">weewx.conf.</span> Changes here
|
||
will affect <em>all</em> reports.
|
||
</p>
|
||
|
||
<p>
|
||
For example, suppose you wish to use metric units for all your reports, instead of the default US Customary
|
||
Units. The section that controls units is <span class="code">[StdReport] / [[Defaults]] / [[[Units]]] / [[[[Groups]]]]</span>.
|
||
It looks like this:
|
||
</p>
|
||
<pre class="tty">
|
||
[StdReport]
|
||
|
||
# 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
|
||
|
||
# The database binding indicates which data should be used in reports.
|
||
data_binding = wx_binding
|
||
|
||
# The following section contains defaults that will apply to *all* skins
|
||
[[Defaults]]
|
||
|
||
# The following section determines the selection and formatting of units.
|
||
[[[Units]]]
|
||
|
||
# The following section sets what unit to use for each unit group.
|
||
# NB: The unit is always in the singular. I.e., 'mile_per_hour',
|
||
# NOT 'miles_per_hour'
|
||
[[[[Groups]]]]
|
||
|
||
group_altitude = foot # Options are 'foot' or 'meter'
|
||
group_degree_day = degree_F_day # Options are 'degree_F_day' or 'degree_C_day'
|
||
group_distance = mile # Options are 'mile' or 'km'
|
||
group_pressure = inHg # Options are 'inHg', 'mmHg', 'mbar', or 'hPa'
|
||
group_rain = inch # Options are 'inch', 'cm', or 'mm'
|
||
group_rainrate = inch_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour'
|
||
group_speed = mile_per_hour # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second'
|
||
group_speed2 = mile_per_hour2 # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2'
|
||
group_temperature = degree_F # Options are 'degree_F' or 'degree_C'
|
||
</pre>
|
||
|
||
<p>
|
||
To use metric units for all your skins, you would edit this section to read:
|
||
</p>
|
||
<pre class="tty">
|
||
[StdReport]
|
||
|
||
# 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
|
||
|
||
# The database binding indicates which data should be used in reports.
|
||
data_binding = wx_binding
|
||
|
||
# The following section contains defaults that will apply to *all* skins
|
||
[[Defaults]]
|
||
|
||
# The following section determines the selection and formatting of units.
|
||
[[[Units]]]
|
||
|
||
# The following section sets what unit to use for each unit group.
|
||
# NB: The unit is always in the singular. I.e., 'mile_per_hour',
|
||
# NOT 'miles_per_hour'
|
||
[[[[Groups]]]]
|
||
|
||
group_altitude = <span class="highlight">meter</span> # Options are 'foot' or 'meter'
|
||
group_degree_day = <span class="highlight">degree_C_day</span> # Options are 'degree_F_day' or 'degree_C_day'
|
||
group_distance = <span class="highlight">km</span>span> # Options are 'mile' or 'km'
|
||
group_pressure = <span class="highlight">mbar</span> # Options are 'inHg', 'mmHg', 'mbar', or 'hPa'
|
||
group_rain = <span class="highlight">mm</span> # Options are 'inch', 'cm', or 'mm'
|
||
group_rainrate = <span class="highlight">mm_per_hour</span> # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour'
|
||
group_speed = <span class="highlight">meter_per_second</span> # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second'
|
||
group_speed2 = <span class="highlight">meter_per_second2</span> # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2'
|
||
group_temperature = <span class="highlight">degree_C</span> # Options are 'degree_F' or 'degree_C'
|
||
</pre>
|
||
<p>
|
||
The options that were changed have been <span class="highlight"> highlighted </span>. Note that
|
||
the changes occurred under the subsection <span class="code">[[Defaults]]</span>, so they will affect <em>all</em>
|
||
reports.
|
||
</p>
|
||
|
||
<h3 id="change_units">Change units for a single report </h3>
|
||
|
||
<p>
|
||
With this approach you can change an option for a single report.
|
||
</p>
|
||
|
||
<p>
|
||
Suppose you want two reports, one in US Customary, the other in Metric. The first, call it <em>SeasonsUSReport</em>,
|
||
will go in the regular directory <span class="symcode">HTML_ROOT</span>. However, the latter, call it <em>SeasonsMetricReport</em>,
|
||
will go in a subdirectory, <span class="symcode">HTMLROOT</span><span class="code">/metric</span>.
|
||
</p>
|
||
<p>
|
||
To accomplish this, we will generate two reports, one using the defaults, the other using overrides to
|
||
change the target unit system and the target directory. The section <span class="code">[StdReport]</span>
|
||
will look like this:
|
||
</p>
|
||
<pre class="tty">
|
||
[StdReport]
|
||
|
||
# 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
|
||
|
||
# The database binding indicates which data should be used in reports.
|
||
data_binding = wx_binding
|
||
|
||
# The following section contains defaults that will apply to *all* skins
|
||
[[Defaults]]
|
||
[[[Units]]]
|
||
[[[[Groups]]]]
|
||
group_altitude = meter # Options are 'foot' or 'meter'
|
||
group_degree_day = degree_C_day # Options are 'degree_F_day' or 'degree_C_day'
|
||
group_distance = km # Options are 'mile' or 'km'
|
||
group_pressure = mbar # Options are 'inHg', 'mmHg', 'mbar', or 'hPa'
|
||
group_rain = mm # Options are 'inch', 'cm', or 'mm'
|
||
group_rainrate = mm_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour'
|
||
group_speed = meter_per_second # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second'
|
||
group_speed2 = meter_per_second2 # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2'
|
||
group_temperature = degree_C # Options are 'degree_F' or 'degree_C'
|
||
|
||
<span class="highlight">[[SeasonsUSReport]]</span>
|
||
skin = Seasons
|
||
enable = true
|
||
|
||
<span class="highlight"> [[SeasonsMetricReport]]
|
||
skin = Seasons
|
||
enable = true
|
||
HTML_ROOT = skins/metric
|
||
[[[Units]]]
|
||
[[[[Groups]]]]
|
||
group_altitude = foot # Options are 'foot' or 'meter'
|
||
group_degree_day = degree_F_day # Options are 'degree_F_day' or 'degree_C_day'
|
||
group_distance = mile # Options are 'mile' or 'km'
|
||
group_pressure = inHg # Options are 'inHg', 'mmHg', 'mbar', or 'hPa'
|
||
group_rain = inch # Options are 'inch', 'cm', or 'mm'
|
||
group_rainrate = inch_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour'
|
||
group_speed = mile_per_hour # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second'
|
||
group_speed2 = mile_per_hour2 # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2'
|
||
group_temperature = degree_F # Options are 'degree_F' or 'degree_C'</span>
|
||
</pre>
|
||
<p>
|
||
Two things are different from the stock section <span class="code">[StdReport]</span>. First (1), we have
|
||
renamed the first report from <em>SeasonsReport</em> to <em>SeasonsUSReport</em> for clarity; and second
|
||
(2), we have introduced a new report <em>SeasonsMetricReport</em>, which is just like the first, except it
|
||
puts its results in a different subdirectory and uses different units. Both use the same skin, the <em>Seasons</em>
|
||
skin.
|
||
</p>
|
||
|
||
<p>
|
||
The reason this works is that the report <em>SeasonsUSReport</em> uses all of the defaults, which include US
|
||
Customary units, and the default value for <a href="usersguide.htm#HTML_ROOT"><span
|
||
class="code">HTML_ROOT</span></a> (which specifies the location for where HTML files are to be put).
|
||
</p>
|
||
|
||
<p>
|
||
By contrast, <em>SeasonsMetricReport</em> cannot use these defaults, so it overrides the units to be used,
|
||
and the value of <span class="code">HTML_ROOT</span>.
|
||
</p>
|
||
|
||
|
||
<h2 id="customizing_gen_time">Scheduling report generation</h2>
|
||
|
||
<p>
|
||
Normal WeeWX operation is to run each <em><a href="usersguide.htm#Reports">report</a></em> defined in <span
|
||
class="code">weewx.conf</span> every archive period. Whilst this may suit most situations, there may be
|
||
occasions when it is desirable to run a report less frequently than every archive period. For example, the
|
||
archive interval might be 5 minutes, but you only want to FTP files every 30 minutes, once per day or at a
|
||
set time each day. Weewx has two mechanisms that provide the ability to control when files are generated.
|
||
The <em><a href="#stale_age"><span class="code">stale_age</span></a></em> option allows control over the age
|
||
of a file before it is regenerated and the <span class="code">report_timing</span> option allows precise
|
||
control over when individual reports are run.
|
||
</p>
|
||
|
||
<p class="note" style="display: inline-block; width: 70%">
|
||
<strong>Note</strong><br/>Whilst <span class="code">report_timing</span> specifies when a given report
|
||
should be generated, the generation of reports is still controlled by the WeeWX report cycle, so reports can
|
||
never be generated more frequently than once every archive period.
|
||
</p>
|
||
|
||
<h3>The <span class="code">report_timing</span> option </h3>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> option uses a CRON-like format to control when a report is to be
|
||
run. Whilst a CRON-like format is used, the control of WeeWX report generation using the <span class="code">report_timing</span>
|
||
option is confined completely to WeeWX and has no interraction with the system CRON service.
|
||
</p>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> option consists of five, space separated parameters as follows:
|
||
</p>
|
||
|
||
<pre class="tty">report_timing = minutes hours day_of_month months day_of_week</pre>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> parameters are summarised in the following table:
|
||
</p>
|
||
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Parameter</td>
|
||
<td style="width:20%">Function</td>
|
||
<td>Allowable values</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">minutes</td>
|
||
<td>Specifies the minutes of the hour when the report will be run
|
||
</td>
|
||
<td>*, or<br/>numbers in the range 0..59 inclusive
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">hours</td>
|
||
<td>Specifies the hours of the day when the report will be run
|
||
</td>
|
||
<td>*, or<br/>numbers in the range 0..23 inclusive
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">day_of_month</td>
|
||
<td>Specifies the days of the month when the report will be run
|
||
</td>
|
||
<td>*, or<br/>numbers in the range 1..31 inclusive
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">months</td>
|
||
<td>Specifies the months of the year when the report will be run
|
||
</td>
|
||
<td>*, or<br/>numbers in the range 1..12 inclusive, or<br/>abbreviated names in the range jan..dec
|
||
inclusive
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">day_of_week</td>
|
||
<td>Specifies the days of the week when the report will be run
|
||
</td>
|
||
<td>*, or<br/>numbers in the range 0..7 inclusive (0,7 = Sunday, 1 = Monday etc), or<br/>abbreviated
|
||
names in the range sun..sat inclusive
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> option may only be used in <span class="code">weewx.conf</span>.
|
||
When set in the <span class="code">[StdReport]</span> section of <span class="code">weewx.conf</span> the
|
||
option will apply to all reports listed under <span class="code">[StdReport]</span>. When specified within a
|
||
report section, the option will override any setting in <span class="code">[StdReport]</span> for that
|
||
report. In this manner it is possible to have different reports run at different times. The following sample
|
||
<span class="code">weewx.conf</span> excerpt illustrates this:
|
||
</p>
|
||
|
||
<pre class="tty">
|
||
[StdReport]
|
||
|
||
# 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
|
||
|
||
# The database binding indicates which data should be used in reports.
|
||
data_binding = wx_binding
|
||
|
||
# Report timing parameter
|
||
report_timing = 0 * * * *
|
||
|
||
# Each of the following subsections defines a report that will be run.
|
||
|
||
[[AReport]]
|
||
skin = SomeSkin
|
||
|
||
[[AnotherReport]]
|
||
skin = SomeOtherSkin
|
||
report_timing = */10 * * * *</pre>
|
||
|
||
<p>
|
||
In this case, the <span class="code">[[AReport]]</span> report would be run under under control of the <span
|
||
class="code">0 * * * *</span> setting (on the hour) under <span class="code">[StdReport]</span> and the
|
||
<span class="code">[[AnotherReport]]</span> report would be run under control of the <span class="code">*/10 * * * *</span>
|
||
setting (every 10 minutes) which has overriden the <span class="code">[StdReport]</span> setting.
|
||
</p>
|
||
|
||
<h3>How <span class="code">report_timing</span> controls reporting </h3>
|
||
|
||
<p>
|
||
The syntax and interpretation of the <span class="code">report_timing</span> parameters are largely the same
|
||
as those of the CRON service in many Unix and Unix-like operating systems. The syntax and interpretation are
|
||
outlined below.
|
||
</p>
|
||
|
||
<p>
|
||
When the <span class="code">report_timing</span> option is in use WeeWX will run a report when the minute,
|
||
hour and month of year parameters match the report time, and at least one of the two day parameters (day of
|
||
month or day of week) match the report time. This means that non-existent times, such as "missing hours"
|
||
during daylight savings changeover, will never match, causing reports scheduled during the "missing times"
|
||
not to be run. Similarly, times that occur more than once (again, during daylight savings changeover) will
|
||
cause matching reports to be run more than once.
|
||
</p>
|
||
|
||
<p class="note" style="display: inline-block; width: 70%">
|
||
<strong>Note</strong><br/>Report time does not refer to the time at which the report is run, but rather the
|
||
date and time of the latest data the report is based upon. If you like, it is the effective date and time of
|
||
the report. For normal WeeWX operation, the report time aligns with the <span class="code">dateTime</span>
|
||
of the most recent archive record. When reports are run using the <span class="code">wee_reports</span>
|
||
utility, the report time is either the <span class="code">dateTime</span> of the most recent archive record
|
||
(the default) or the optional timestamp command line argument.
|
||
</p>
|
||
|
||
<p class="note" style="display: inline-block; width: 70%">
|
||
<strong>Note</strong><br/>The day a report is to be run can be specified by two parameters; day of month
|
||
and/or day of week. If both parameters are restricted (i.e., not an asterisk), the report will be run when
|
||
either field matches the current time. For example,<br/> <span class="code">report_timing = 30 4
|
||
1,15 * 5</span><br/> would cause the report to be run at 4:30am on the 1st and 15th of each month as well as
|
||
4:30am every Friday.
|
||
</p>
|
||
|
||
<h3>The relationship between <span class="code">report_timing</span> and archive period </h3>
|
||
|
||
<p>
|
||
A traditional CRON service has a resolution of one minute, meaning that the CRON service checks each minute
|
||
as to whether to execute any commands. On the other hand, the WeeWX report system checks which reports are
|
||
to be run once per archive period, where the archive period may be one minute, five minutes or some other
|
||
user defined period. Consequently, the <span class="code">report_timing</span> option may specify a report
|
||
to be run at some time that does not align with the WeeWX archive period. In such cases cases the <span
|
||
class="code">report_timing</span> option does not cause a report to be run outside of the normal WeeWX
|
||
report cycle, rather it will cause the report to be run during the next report cycle. At the start of each
|
||
report cycle, and provided a <span class="code">report_timing</span> option is set, WeeWX will check each
|
||
minute boundary from the current report time back until the report time of the previous report cycle. If a
|
||
match is found on <strong>any</strong> of these one minute boundaries the report will be run during the
|
||
report cycle. This may be best described through some examples:
|
||
</p>
|
||
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td class="code">report_timing</td>
|
||
<td>Archive period</td>
|
||
<td>When the report will be run</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">0 * * * *</td>
|
||
<td>5 minutes</td>
|
||
<td>The report will be run only during the report cycle commencing on the hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">5 * * * *</td>
|
||
<td>5 minutes</td>
|
||
<td>The report will be run only during the report cycle commencing at 5 minutes past the hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">3 * * * *</td>
|
||
<td>5 minutes</td>
|
||
<td>The report will be run only during the report cycle commencing at 5 minutes past the hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">10 * * * *</td>
|
||
<td>15 minutes</td>
|
||
<td>The report will be run only during the report cycle commencing at 15 minutes past the hour</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">10,40 * * * *</td>
|
||
<td>15 minutes</td>
|
||
<td>The report will be run only during the report cycles commencing at 15 minutes past the hour and 45
|
||
minutes past the hour.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">5,10 * * * *</td>
|
||
<td>15 minutes</td>
|
||
<td>The report will be run once only during the report cycle commencing at 15 minutes past the hour.
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3>Lists, ranges and steps</h3>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> option supports lists, ranges and steps for all parameters.
|
||
Lists, ranges and steps may be used as follows:
|
||
</p>
|
||
|
||
<ul>
|
||
<li>Lists. A list is a set of numbers (or ranges) separated by commas, for example 1,2,5,9 or 0-4,8-12. A
|
||
match with any of the elements of the list will result in a match for that particular parameter. If the
|
||
examples were applied to the minutes parameter, and subject to other parameters in the <span
|
||
class="code">report_timing</span> option, the report would be run at minutes 1,2,5 and 9 and
|
||
0,1,2,3,4,8,9,10,11 and 12 respectively. Abbreviated month and day names cannot be used in a list.
|
||
</li>
|
||
|
||
<li>Ranges. Ranges are two numbers separated with a hyphen, for example 8-11. The specified range is
|
||
inclusive. A match with any of the values included in the range will result in a match for that
|
||
particular parameter. If the example was applied to the hours parameter, and subject to other parameters
|
||
in the <span class="code">report_timing</span> option, the report would be run at hours 8,9,10 and 11. A
|
||
range may be included as an element of a list. Abbreviated month and day names cannot be used in a
|
||
range.
|
||
</li>
|
||
|
||
<li>Steps. A step can be used in conjunction with a range or asterisk and are denoted by a '/' followed by a
|
||
number. Following a range with a step specifies skips of the step number's value through the range. For
|
||
example, 0-12/2 used in the hours parameter would, subject to other parameter in the <span class="code">report_timing</span>
|
||
option, run the report at hours 0,2,4,6,8,12. Steps are also permitted after an asterisk in which case
|
||
the skips of the step number's value occur through the all possible values of the parameter. For
|
||
example, */3 can be used in the hours parameter to, subject to other parameter in the <span
|
||
class="code">report_timing</span> option, run the report at hours 0,3,6,9,12,15,18 and 21.
|
||
</li>
|
||
</ul>
|
||
|
||
<h3>Nicknames</h3>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> option supports a number of time specification 'nicknames'.
|
||
These nicknames are prefixed by the '@' character and replace the five parameters in the <span class="code">report_timing</span>
|
||
option. The nicknames supported are:
|
||
</p>
|
||
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Nickname</td>
|
||
<td>Equivalent setting
|
||
</td>
|
||
<td>When the report will be run</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">@yearly<br/>@annually
|
||
</td>
|
||
<td>0 0 1 1 *</td>
|
||
<td>Once per year at midnight on 1 January.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">@monthly</td>
|
||
<td>0 0 1 * *</td>
|
||
<td>Monthly at midnight on the 1st of the month.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">@weekly</td>
|
||
<td>0 0 * * 0</td>
|
||
<td>Every week at midnight on Sunday.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">@daily</td>
|
||
<td>0 0 * * *</td>
|
||
<td>Every day at midnight.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">@hourly</td>
|
||
<td>0 * * * *</td>
|
||
<td>Every hour on the hour.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3>Examples of <span class="code">report_timing</span></h3>
|
||
|
||
<p>
|
||
Numeric settings for <span class="code">report_timing</span> can be at times difficult to understand due to
|
||
the complex combinations of parameters. The following table shows a number of example <span class="code">report_timing</span>
|
||
options and the corresponding times when the report would be run.
|
||
</p>
|
||
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td class="code">report_timing</td>
|
||
<td>When the report will be run</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">* * * * *</td>
|
||
<td>Every archive period. This setting is effectively the default WeeWX method of operation.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">25 * * * *</td>
|
||
<td>25 minutes past every hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">0 * * * *</td>
|
||
<td>Every hour on the hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">5 0 * * *</td>
|
||
<td>00:05 daily.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">25 16 * * *</td>
|
||
<td>16:25 daily.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">25 16 1 * *</td>
|
||
<td>16:25 on the 1st of each month.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">25 16 1 2 *</td>
|
||
<td>16:25 on the 1st of February.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">25 16 * * 0</td>
|
||
<td>16:25 each Sunday.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">*/10 * * * *</td>
|
||
<td>On the hour and 10, 20, 30, 40 and 50 mnutes past the hour.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">*/9 * * * *</td>
|
||
<td>On the hour and 9, 18, 27, 36, 45 and 54 minutes past the hour.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">*/10 */2 * * *</td>
|
||
<td>0, 10, 20, 30, 40 and 50 minutes after the even hour.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">* 6-17 * * *</td>
|
||
<td>Every archive period from 06:00 (inclusive) up until, but excluding, 18:00.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">* 1,4,14 * * *</td>
|
||
<td>Every archive period in the hour starting 01:00 to 01:59, 04:00 to 04:59 amd 14:00 to 14:59 (Note
|
||
excludes report times at 02:00, 05:00 and 15:00).
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">0 * 1 * 0,3</td>
|
||
<td>On the hour on the first of the month and on the hour every Sunday and Wednesday.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">* * 21,1-10/3 6 *</td>
|
||
<td>Every archive period on the 1st, 4th, 7th, 10th and 21st of June.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">@monthly</td>
|
||
<td>Midnight on the 1st of the month.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3>
|
||
The <span class="code">wee_reports</span> utility and the <span class="code">report_timing</span> option
|
||
</h3>
|
||
|
||
<p>
|
||
The <span class="code">report_timing</span> option is ignored when using the <a href="#wee_reports">wee_reports</a>
|
||
utility.
|
||
</p>
|
||
|
||
|
||
<h1 id="customizing_templates">The Cheetah generator</h1>
|
||
|
||
<p class="note">
|
||
This section gives an overview of the Cheetah generator. For details about each of its various options, see
|
||
the section <a href="#CheetahGenerator"><em>[CheetahGenerator]</em></a> in the <a
|
||
href="#report_options"><em>Reference: report options</em></a>.
|
||
</p>
|
||
|
||
<p>
|
||
File generation is done using the <a href="https://pythonhosted.org/Cheetah/">Cheetah</a> templating engine,
|
||
which processes a <em>template</em>, replacing any symbolic <em>tags</em>, then produces an output file.
|
||
Typically, it runs after each new archive record (usually about every five minutes), but it can also run on
|
||
demand using the <span class="code">wee_reports</span> utility.
|
||
</p>
|
||
<p>
|
||
The Cheetah engine is very powerful, essentially letting you have the full semantics of Python available in
|
||
your templates. As this would make the templates incomprehensible to anyone but a Python programmer, WeeWX
|
||
adopts a very small subset of its power.
|
||
</p>
|
||
<p>
|
||
The Cheetah generator is controlled by the section <a href="#CheetahGenerator"><span class="code">[CheetahGenerator]</span></a>.
|
||
Let's take a look at how this works.
|
||
</p>
|
||
|
||
<h2>Which files get processed?</h2>
|
||
|
||
<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 four block names
|
||
that have special meaning: <span class="code">SummaryByDay</span>, <span class='code'>SummaryByMonth</span>,
|
||
<span class='code'>SummaryByYear</span>, and <span class='code'>ToDate</span>.
|
||
</p>
|
||
|
||
<h3>Specifying template files</h3>
|
||
|
||
<p>
|
||
By way of example, here is the <span class="code">[CheetahGenerator]</span> section from the <span
|
||
class="code">skin.conf</span> for the skin <em>Seasons</em>.
|
||
</p>
|
||
|
||
<pre class="tty">[CheetahGenerator]
|
||
# The CheetahGenerator creates files from templates. This section
|
||
# specifies which files will be generated from which template.
|
||
|
||
# Possible encodings are 'html_entities', 'utf8', or 'strict_ascii'
|
||
encoding = html_entities
|
||
|
||
[[SummaryByMonth]]
|
||
# Reports that summarize "by month"
|
||
[[[NOAA_month]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-%Y-%m.txt.tmpl
|
||
|
||
[[SummaryByYear]]
|
||
# Reports that summarize "by year"
|
||
[[[NOAA_year]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-%Y.txt.tmpl
|
||
|
||
[[ToDate]]
|
||
# Reports that show statistics "to date", such as day-to-date,
|
||
# week-to-date, month-to-date, etc.
|
||
[[[index]]]
|
||
template = index.html.tmpl
|
||
[[[statistics]]]
|
||
template = statistics.html.tmpl
|
||
[[[telemetry]]]
|
||
template = telemetry.html.tmpl
|
||
[[[tabular]]]
|
||
template = tabular.html.tmpl
|
||
[[[celestial]]]
|
||
template = celestial.html.tmpl
|
||
# Uncomment the following to have WeeWX generate a celestial page only once an hour:
|
||
# stale_age = 3600
|
||
[[[RSS]]]
|
||
template = rss.xml.tmpl
|
||
</pre>
|
||
|
||
<p>The skin contains three different kinds of generated output:</p>
|
||
<ol>
|
||
<li>Summary by Month. The 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 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 skin produces an HTML <span class="code">index.html</span> page, as well as HTML
|
||
files for detailed statistics, telemetry, and celestial information. It also includes a master page
|
||
(<span class="code">tabular.html</span>) in which NOAA information is displayed. All these files are
|
||
HTML.
|
||
</li>
|
||
</ol>
|
||
<p>
|
||
The encoding for text files is <span class="code">strict_ascii</span>, whereas the encoding for html files
|
||
is <span class="code">html_entities</span>. This was 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_ascii</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">index</span>, <span class="code">statistics</span>,
|
||
and <span class="code">telemetry</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>
|
||
|
||
<h3><span class="code" id="SummaryByYear">[[SummaryByYear]]</span></h3>
|
||
|
||
<p>
|
||
Use <span class="code">SummaryByYear</span> to generate a set of files, one file per year. The name of the
|
||
template file should contain a <a
|
||
href="https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior"> strftime()</a> code for
|
||
the year; this will be replaced with the year of the data in the file.
|
||
</p>
|
||
<pre class="tty">
|
||
[CheetahGenerator]
|
||
[[SummaryByYear]]
|
||
# Reports that summarize "by year"
|
||
[[[NOAA_year]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-%Y.txt.tmpl
|
||
</pre>
|
||
|
||
<p>
|
||
The template <span class="code">NOAA/NOAA-%Y.txt.tmpl</span> might look something like this:
|
||
</p>
|
||
<pre class="tty">
|
||
SUMMARY FOR YEAR $year.dateTime
|
||
|
||
MONTHLY TEMPERATURES AND HUMIDITIES:
|
||
#for $record in $year.records
|
||
$record.dateTime $record.outTemp $record.outHumidity
|
||
#end for
|
||
</pre>
|
||
|
||
<h3><span class="code" id="SummaryByMonth">[[SummaryByMonth]]</span></h3>
|
||
|
||
<p>
|
||
Use <span class="code">SummaryByMonth</span> to generate a set of files, one file per month. The name of the
|
||
template file should contain a <a
|
||
href="https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior"> strftime()</a> code for
|
||
year and month; these will be replaced with the year and month of the data in the file.
|
||
</p>
|
||
<pre class="tty">
|
||
[CheetahGenerator]
|
||
[[SummaryByMonth]]
|
||
# Reports that summarize "by month"
|
||
[[[NOAA_month]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-%Y-%m.txt.tmpl
|
||
</pre>
|
||
|
||
<p>
|
||
The template <span class="code">NOAA/NOAA-%Y-%m.txt.tmpl</span> might look something like this:
|
||
</p>
|
||
<pre class="tty">
|
||
SUMMARY FOR MONTH $month.dateTime
|
||
|
||
DAILY TEMPERATURES AND HUMIDITIES:
|
||
#for $record in $month.records
|
||
$record.dateTime $record.outTemp $record.outHumidity
|
||
#end for
|
||
</pre>
|
||
|
||
<h3><span class="code" id="SummaryByDay">[[SummaryByDay]]</span></h3>
|
||
<p>
|
||
While the <em>Seasons</em> skin does not make use of it, there is also a <span
|
||
class="code">SummaryByDay</span> capability. As the name suggests, this results in one file per day. The
|
||
name of the template file should contain a <a
|
||
href="https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior"> strftime()</a> code for
|
||
the year, month and day; these will be replaced with the year, month, and day of the data in the file.
|
||
</p>
|
||
<pre class="tty">
|
||
[CheetahGenerator]
|
||
[[SummaryByDay]]
|
||
# Reports that summarize "by day"
|
||
[[[NOAA_day]]]
|
||
encoding = strict_ascii
|
||
template = NOAA/NOAA-%Y-%m-%d.txt.tmpl
|
||
</pre>
|
||
|
||
<p>
|
||
The template <span class="code">NOAA/NOAA-%Y-%m-%d.txt.tmpl</span> might look something like this:
|
||
</p>
|
||
<pre class="tty">
|
||
SUMMARY FOR DAY $day.dateTime
|
||
|
||
HOURLY TEMPERATURES AND HUMIDITIES:
|
||
#for $record in $day.records
|
||
$record.dateTime $record.outTemp $record.outHumidity
|
||
#end for
|
||
</pre>
|
||
<p class="note">
|
||
<strong>Note</strong><br/> This can create a <em>lot</em> of files — one per day. If you have 3 years
|
||
of records, this would be more than 1,000 files!
|
||
</p>
|
||
|
||
<h2>Tags</h2>
|
||
|
||
<p>
|
||
If you look inside a template, you will see it makes heavy use of <em>tags</em>. As the Cheetah generator
|
||
processes the template, it replaces each tag with an appropriate value and, sometimes, a label. This section
|
||
discusses the details of how that happens.
|
||
</p>
|
||
|
||
<p class="note">
|
||
If there is a tag 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.
|
||
Unfortunately, in other cases, the error message can be very cryptic and not very useful. So make small
|
||
changes and test often. Use the utility <a href="#wee_reports"><span class="code">wee_reports</span></a> to
|
||
speed up the process.
|
||
</p>
|
||
<p>Here are some examples of tags:</p>
|
||
<pre class="tty">$current.outTemp
|
||
$month.outTemp.max
|
||
$month.outTemp.maxtime</pre>
|
||
<p>
|
||
These code the current outside temperature, the maximum outside temperature for the month, and the time that
|
||
maximum occurred, 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 tags 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, tags will "do the right thing" and are all you will need. However, WeeWX offers extensive
|
||
customization of the generated output for specialized applications such as XML RSS feeds, or rigidly
|
||
formatted reports (such as the NOAA reports). This section specifies the various tag options available.
|
||
</p>
|
||
|
||
<p>There are two different versions of the tags, 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>
|
||
Formally, WeeWX first looks for the observation type in the record emitted by the <span class="code">NEW_ARCHIVE_RECORD</span>
|
||
event. This is generally the data emitted by the station console, augmented by any derived variables (<i>e.g.</i>
|
||
wind chill) that you might have specified. If the observation type cannot be found there, the most recent
|
||
record in the database will be searched.
|
||
</p>
|
||
<p>The most general tag for a "current" observation looks like:</p>
|
||
<pre class="tty">$current($timestamp=<em>some_time</em>, $max_delta=<em>delta_t</em>,$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">some_time</span> is a timestamp that you want to display. It is optional, The default is
|
||
to display the value for the current time.
|
||
</p>
|
||
|
||
<p class="indent">
|
||
<span class="code">delta_t</span> is the largest time difference (in seconds) between the time specified and
|
||
a timestamp of a record in the database that will be returned. By default, it is zero, which means there
|
||
must be an exact match with a specified time for a record to be retrieved.
|
||
</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 a set of optional formatting tags, which control how the
|
||
value will appear. See the section <em><a href="#formatting_options">Formatting Options</a></em> below.
|
||
</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>Aggregation periods is the other kind of tag. For example,</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 tag for an aggregation over time looks like:</p>
|
||
<pre
|
||
class="tty">$<em>period</em>($data_binding=<em>binding_name</em>, <em>$optional_ago</em>=<em>delta</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"><em>optional_ago</em></span> is a keyword that depends on the aggregation period. For
|
||
example, for <span class="code">week</span>, it would be <span class="code">weeks_ago</span>, for <span
|
||
class="code">day</span>, it would be <span class="code">days_ago</span>, <i>etc.</i>
|
||
</p>
|
||
|
||
<p class="indent">
|
||
<span class="code">delta</span> is an integer indicating which aggregation period is desired. For example
|
||
<span class="code">$week($weeks_ago=1)</span> indicates last week, <span
|
||
class="code">$day($days_ago=2)</span> would be the day-before-yesterday, <i>etc</i>. The default is zero:
|
||
that is, this aggregation period.
|
||
</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 a set of optional formatting tags, which control how the
|
||
value will appear. See the section <em><a href="#formatting_options">Formatting Options</a></em> below.
|
||
</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>Aggregation period</td>
|
||
<td>Meaning</td>
|
||
<td>Example</td>
|
||
<td>Meaning of example</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$hour</td>
|
||
<td>This hour.</td>
|
||
<td class="code">$hour.outTemp.maxtime</td>
|
||
<td>The time of the max temperature this hour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day</td>
|
||
<td>Today (since midnight).</td>
|
||
<td class="code">$day.outTemp.max</td>
|
||
<td>The max temperature since midnight</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$yesterday</td>
|
||
<td>Yesterday. Synonym for <span class="code">$day($days_ago=1)</span>.
|
||
</td>
|
||
<td class="code">$yesterday.outTemp.maxtime</td>
|
||
<td>The time of the max temperature yesterday.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$week</td>
|
||
<td>This week. The start of the week is set by option <a href="usersguide.htm#week_start"><span
|
||
class="code">week_start</span></a>.
|
||
</td>
|
||
<td class="code">$week.outTemp.max</td>
|
||
<td>The max temperature this week.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$month</td>
|
||
<td>This month.</td>
|
||
<td class="code">$month.outTemp.min</td>
|
||
<td>The minimum temperature this month.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$year</td>
|
||
<td>This 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>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>
|
||
<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>
|
||
|
||
<p>
|
||
The <em>$optional_ago</em> parameters can be useful for statistics farther in the past. Here are some
|
||
examples:
|
||
</p>
|
||
|
||
<table class="indent" style="width: 80%">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Aggregation period</td>
|
||
<td>Example</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$hour($hours_ago=<em>h</em>)
|
||
</td>
|
||
<td class="code">$hour($hours_ago=1).outTemp.avg</td>
|
||
<td>The average temperature last hour (1 hour ago).</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day($days_ago=<em>d</em>)
|
||
</td>
|
||
<td class="code">$day($days_ago=2).outTemp.avg</td>
|
||
<td>The average temperature day before yesterday (2 days ago).
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$week($weeks_ago=<em>d</em>)
|
||
</td>
|
||
<td class="code">$week($weeks_ago=1).outTemp.max</td>
|
||
<td>The maximum temperature last week.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$month($months_ago=<em>m</em>)
|
||
</td>
|
||
<td class="code">$month($months_ago=1).outTemp.max</td>
|
||
<td>The maximum temperature last month.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$year($years_ago=<em>m</em>)
|
||
</td>
|
||
<td class="code">$year($years_ago=1).outTemp.max</td>
|
||
<td>The maximum temperature last year.</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>Illegal conversions</h4>
|
||
|
||
<p>
|
||
If an inappropriate or nonsense conversion is asked for, <i>e.g.</i>,
|
||
</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>
|
||
A variety of tags and arguments are available to you to customize the formatting of the final observation
|
||
value. This table lists the tags:
|
||
</p>
|
||
<table class="indent">
|
||
<caption>Optional formatting tag</caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Optional formatting tag</td>
|
||
<td>Comment</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">.format(<em>args</em>)</td>
|
||
<td>Format the string according to a set of optional <em>args</em> (see below).</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">.ordinal_compass</td>
|
||
<td>Output compass ordinals for wind direction (<i>e.g.</i>"SW"). The ordinal abbreviations are set by
|
||
option <span class="code">directions</span> in the skin configuration file <span class="code">skin.conf</span>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">.raw</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 potential <span class="code">None</span> value.
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>The first of these tags has the formal structure:</p>
|
||
<pre class="tty">.format(format_string=None, None_string=None, add_label=True, localize=True)</pre>
|
||
|
||
<p>Here is the meaning of each of the optional arguments:</p>
|
||
|
||
<table class="indent">
|
||
<caption>Optional arguments for <span class="code">.format()</span></caption>
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Optional argument</td>
|
||
<td>Comment</td>
|
||
</tr>
|
||
<tr>
|
||
<td class='code text_highlight'>format_string</td>
|
||
<td>Use the optional string to format the value. If set to <span class="code">None</span>, then an
|
||
appropriate string format from <span class="code">skin.conf</span> will be used.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">None_string</td>
|
||
<td>Should the observation value be <span class="code">NONE</span>, then use the supplied string
|
||
(typically, something like "N/A"). If <span class="code">None_string</span> is set to <span
|
||
class="code">None</span>, then the value for <span class="code">NONE</span> in <span
|
||
class="code"> <a href="#Units_StringFormats">[Units][[StringFormats]]</a>
|
||
</span> will be used.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">add_label</td>
|
||
<td>If set to <span class="code">True</span> (the default), then a unit label (<i>e.g.</i>, °F) from
|
||
<span class="code">skin.conf</span> will be attached to the end. Otherwise, it will be left out.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code text_highlight">localize</td>
|
||
<td>If set to <span class="code">True</span> (the default), then localize the results. Otherwise, do
|
||
not.
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>If you're willing to honor the ordering of the arguments, the argument name can be omitted.</p>
|
||
|
||
<h3>Formatting examples</h3>
|
||
|
||
<p>This section gives a number of example tags, and their expected output. The following values are assumed:</p>
|
||
|
||
<table class="indent" style="width:50%">
|
||
<caption>Values used in the examples below</caption>
|
||
<tr class="first_row">
|
||
<td>Observation</td>
|
||
<td>Value</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">
|
||
outTemp
|
||
</td>
|
||
<td>45.2°F</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">
|
||
UV
|
||
</td>
|
||
<td>
|
||
<span class="code">None</span>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">
|
||
windDir
|
||
</td>
|
||
<td>138°</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">
|
||
dateTime
|
||
</td>
|
||
<td>1270250700</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>Here are the examples:</p>
|
||
<table class="indent">
|
||
<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 from <span class="code"><a
|
||
href="#Units_StringFormats">[Units][[StringFormats]]</a></span>. Label from <span class="code"><a
|
||
href="#Units_Labels">[Units][[Labels]]</a></span>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.format</td>
|
||
<td class="code">45.2°F</td>
|
||
<td>Same as the <span class="code">$current.outTemp</span>.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.format()</td>
|
||
<td class="code">45.2°F</td>
|
||
<td>Same as the <span class="code">$current.outTemp</span>.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.format(format_string="%.3f")</td>
|
||
<td class="code">45.200°F</td>
|
||
<td>Specified string format used; label from <span class="code"><a href="#Units_Labels">[Units][[Labels]]</a></span>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.format("%.3f")</td>
|
||
<td class="code">45.200°F</td>
|
||
<td>As above, except a positional argument, instead of the named argument, is being used.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.format(add_label=False)</td>
|
||
<td class="code">45.2</td>
|
||
<td>No label. The string formatting is from <span class="code"><a href="#Units_StringFormats">[Units][[StringFormats]]</a></span>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.UV</td>
|
||
<td class="code">N/A</td>
|
||
<td>The string specified by option <span class="code">NONE</span> in <span class="code"> <a
|
||
href="#Units_StringFormats">[Units][[StringFormats]]</a></span>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.UV.format(None_string="No UV")</td>
|
||
<td class="code">No UV</td>
|
||
<td>Specified <span class="code">None_string</span> is used.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.windDir</td>
|
||
<td class="code">138°</td>
|
||
<td>Formatting is from option <span class="code">degree_compass</span> in <span class="code"> <a
|
||
href="#Units_StringFormats">[Units][[StringFormats]]</a></span>.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.windDir.ordinal_compass</td>
|
||
<td class="code">SW</td>
|
||
<td>Ordinal direction from section <span class="code"><a
|
||
href="#Units_Ordinates">[Units][[Ordinates]]</a></span> is being substituted.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.dateTime</td>
|
||
<td class="code">02-Apr-2010 16:25</td>
|
||
<td>Time formatting from <span class="code"><a
|
||
href="#Units_TimeFormats">[Units][[TimeFormats]]</a></span> is being used.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.dateTime.format(format_string="%H:%M")</td>
|
||
<td class="code">16:25</td>
|
||
<td>Specified time format used.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.dateTime.format("%H:%M")</td>
|
||
<td class="code">16:25</td>
|
||
<td>As above, except a positional argument, instead of the named argument, is being used.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.dateTime.raw</td>
|
||
<td class="code">1270250700</td>
|
||
<td>Raw Unix epoch time (which is converted to a string by the template engine).
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$current.outTemp.raw</td>
|
||
<td class="code">45.2</td>
|
||
<td>Raw float value (which is converted to a string by the template engine).
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>Note that the same formatting conventions can be used for aggregation periods, such as <span class="code">$month</span>,
|
||
as well as <span class="code">$current</span>.
|
||
</p>
|
||
|
||
<h3>
|
||
Start, end, and <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
|
||
</p>
|
||
<pre class="tty">$current.dateTime</pre>
|
||
<p>
|
||
represents the <em>current time</em> (more properly, the time as of the end of the last archive interval)
|
||
and would produce something like
|
||
</p>
|
||
<pre class="example_output">01/09/2010 12:30:00</pre>
|
||
<p>
|
||
Like true observation types, explicit formats can be specified, except that they require a <a
|
||
href="https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior"> strftime() <em>time
|
||
format</em> </a>, rather than a <em>string format</em>.
|
||
</p>
|
||
|
||
<p>For example, adding a format descriptor like this:</p>
|
||
<pre class="tty">$current.dateTime.format("%d-%b-%Y %H:%M")</pre>
|
||
<p>produces</p>
|
||
|
||
<p class="example_output">09-Jan-2010 12:30</p>
|
||
|
||
<p>
|
||
For <em>aggregation periods</em>, such as <span class="code">$month</span>, you can request the
|
||
<em>start</em> or <em>end</em> of the period, by using suffixes <span class="code">.start</span> or <span
|
||
class="code">.end</span>, respectively. For example,
|
||
</p>
|
||
<pre class="tty">The current month runs from $month.start to $month.end.</pre>
|
||
<p>results in</p>
|
||
<pre class="example_output">The current month runs from 01/01/2010 12:00:00 AM to 02/01/2017 12:00:00 AM.</pre>
|
||
|
||
<p>
|
||
In addition to the suffixes <span class="code">.start</span> and <span class="code">.end</span>, the suffix
|
||
<span class="code">.dateTime</span> is provided for backwards compatibility. Like <span
|
||
class="code">.start</span>, it refers to the start of the interval.
|
||
</p>
|
||
|
||
<p>
|
||
The returned string values will always be in <em>local time</em>. However, if you ask for the raw value
|
||
</p>
|
||
<pre class="tty">$current.dateTime.raw</pre>
|
||
|
||
<p>
|
||
the returned value will be in 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. 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 changes in barometric
|
||
pressure. Here are some examples:
|
||
</p>
|
||
<table class="indent" style="width: 50%">
|
||
<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>
|
||
Note how you can explicitly specify a value in the tag itself (2nd row in the table 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 row in the table).
|
||
</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">$span</span>
|
||
</h3>
|
||
|
||
<p>
|
||
The tag <span class="code">$span</span> allows aggregation over a user defined period up to and including
|
||
the current time. Its most general form looks like:
|
||
</p>
|
||
|
||
<pre class="tty">$<em>span</em>([$data_binding=<em>binding_name</em>][,<em>$optional_delta</em>=<em>delta</em>]).<em>obstype</em>.<em>aggregation</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"><em>$optional_delta</em>=<em>delta</em></span> is one or more comma separated delta
|
||
settings from the table below. If more than one delta setting is included then the period used for the
|
||
aggregate is the sum of the individual delta settings. If no delta setting is included, or all included
|
||
delta settings are zero, the returned aggregate is based on the current <span class="code">obstype</span>
|
||
only.
|
||
</p>
|
||
|
||
<p class="indent">
|
||
<span class="code">obstype</span> is a observation type, such as <span class="code">outTemp</span>, that is
|
||
supported by the <span class="code">$current</span> tag. See <em><a href="#archive_types">Appendix: Archive
|
||
Types</a></em> for a table of observation types supported by the <span class="code">$current</span> tag.
|
||
</p>
|
||
|
||
<p class="indent">
|
||
<span class="code">aggregation</span> is an <em>aggregation type</em>. 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. 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 delta settings that can be used:</p>
|
||
<table class="indent">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Delta Setting</td>
|
||
<td>Example</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$time_delta=<em>seconds</em></td>
|
||
<td class="code">$span($time_delta=1800).outTemp.avg</td>
|
||
<td>The average temperature over the last immediate 30 minutes (1800 seconds).
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$hour_delta=<em>hours</em></td>
|
||
<td class="code">$span($hour_delta=6).outTemp.avg</td>
|
||
<td>The average temperature over the last immediate 6 hours.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day_delta=<em>days</em></td>
|
||
<td class="code">$span($day_delta=1).rain.sum</td>
|
||
<td>The total rainfall over the last immediate 24 hours.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$week_delta=<em>weeks</em></td>
|
||
<td class="code">$span($week_delta=2).barometer.max</td>
|
||
<td>The maximum barometric pressure over the last immediate 2 weeks.
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>For example, the template expressions</p>
|
||
<pre class="tty">The total rainfall over the last 30 hours is $span($hour_delta=30).rain.sum</pre>
|
||
<p>and</p>
|
||
<pre class="tty">The total rainfall over the last 30 hours is $span($hour_delta=6, $day_delta=1).rain.sum</pre>
|
||
<p>would both result in</p>
|
||
|
||
<p class="example_output">The total rainfall over the last 30 hours is 1.24 in</p>
|
||
|
||
<h3>
|
||
Tag <span class="code">$unit</span>
|
||
</h3>
|
||
|
||
<p>The type, label, and string formats for all units are also available, allowing you to do highly customized
|
||
labels:
|
||
</p>
|
||
<table class="indent" style="width: 50%">
|
||
<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.format(add_label=False)$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>
|
||
Tag <span class="code">$obs</span>
|
||
</h3>
|
||
|
||
<p>
|
||
The labels used for the various observation types are available using tag <span class="code">$obs</span>.
|
||
These are basically the values given in the skin dictionary, section <a href="#Labels_Generic"><span
|
||
class="code">[Labels][[Generic]]</span></a>.
|
||
</p>
|
||
<table class="indent" style="width: 50%">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag</td>
|
||
<td>Results</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$obs.label.outTemp</td>
|
||
<td class="code">Outside Temperature</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">$obs.label.UV</td>
|
||
<td class="code">UV Index</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
|
||
<h3>Iteration</h3>
|
||
|
||
<p>It is possible to iterate over the following:</p>
|
||
|
||
<table class="indent" style="Width: 50%">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag suffix</td>
|
||
<td>Results</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.records</td>
|
||
<td>Iterate over every record</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.hours</td>
|
||
<td>Iterate by hours</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.days</td>
|
||
<td>Iterate by days</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.months</td>
|
||
<td>Iterate by months</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.years</td>
|
||
<td>Iterate by years</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code first_col">.spans(interval=<em>seconds</em>)
|
||
</td>
|
||
<td>Iterate by custom length spans. The default interval is 10800 seconds (3 hours). The spans will
|
||
align to local time boundaries.
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>
|
||
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>
|
||
The following template again uses a Cheetah <span class="code">for</span> loop, this time to iterate over
|
||
3-hour spans over the last 24 hours, displaying the averages in each span. The iteration loop is <span
|
||
class="highlight"> highlighted </span>.
|
||
</p>
|
||
<pre class="tty"><p>3 hour averages over the last 24 hours</p>
|
||
<table>
|
||
<tr>
|
||
<td>Date/time</td><td>outTemp</td><td>outHumidity</td>
|
||
</tr>
|
||
<span class="highlight">#for $_span in $span($day_delta=1).spans(interval=10800)</span>
|
||
<tr>
|
||
<td>$_span.start.format("%d/%m %H:%M")</td><td>$_span.outTemp.avg</td><td>$_span.outHumidity.avg</td>
|
||
</tr>
|
||
<span class="highlight">#end for</span>
|
||
</table>
|
||
</pre>
|
||
<p>The result is:</p>
|
||
|
||
<div class="example_output">
|
||
<p>3 hour averages over the last 24 hours</p>
|
||
<table>
|
||
<tr>
|
||
<td>Date/time</td>
|
||
<td>outTemp</td>
|
||
<td>outHumidity</td>
|
||
</tr>
|
||
<tr>
|
||
<td>21/01 18:50</td>
|
||
<td>33.4°F</td>
|
||
<td>95%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>21/01 21:50</td>
|
||
<td>32.8°F</td>
|
||
<td>96%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>22/01 00:50</td>
|
||
<td>33.2°F</td>
|
||
<td>96%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>22/01 03:50</td>
|
||
<td>33.2°F</td>
|
||
<td>96%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>22/01 06:50</td>
|
||
<td>33.8°F</td>
|
||
<td>96%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>22/01 09:50</td>
|
||
<td>36.8°F</td>
|
||
<td>95%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>22/01 12:50</td>
|
||
<td>39.4°F</td>
|
||
<td>91%</td>
|
||
</tr>
|
||
<tr>
|
||
<td>22/01 15:50</td>
|
||
<td>35.4°F</td>
|
||
<td>93%</td>
|
||
</tr>
|
||
</table>
|
||
|
||
</div>
|
||
|
||
<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 other examples using iteration, as well as explicit formatting.
|
||
</p>
|
||
|
||
<h3>Comprehensive example</h3>
|
||
<p>
|
||
This example is designed to put together a lot of the elements described above, including iteration,
|
||
aggregation period starts and ends, formatting, and overriding units.
|
||
</p>
|
||
|
||
<pre class="tty">
|
||
<html>
|
||
<head>
|
||
<style>
|
||
td { border: 1px solid #cccccc; padding: 5px; }
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<table border=1 style="border-collapse:collapse;">
|
||
<tr style="font-weight:bold">
|
||
<td>Time interval</td>
|
||
<td>Max temperature</td>
|
||
<td>Time</td>
|
||
</tr>
|
||
#for $hour in $day($days_ago=1).hours
|
||
<tr>
|
||
<td>$hour.start.format("%H:%M")-$hour.end.format("%H:%M")</td>
|
||
<td>$hour.outTemp.max ($hour.outTemp.max.degree_C)</td>
|
||
<td>$hour.outTemp.maxtime.format("%H:%M")</td>
|
||
</tr>
|
||
#end for
|
||
<caption>
|
||
<p>
|
||
Hourly max temperatures yesterday<br/>
|
||
$day($days_ago=1).start.format("%d-%b-%Y")
|
||
</p>
|
||
</caption>
|
||
</table>
|
||
</body>
|
||
</html>
|
||
</pre>
|
||
<p><a href="examples/tag.htm">Click here</a> for the results.</p>
|
||
|
||
<h2>Almanac</h2>
|
||
|
||
<p>
|
||
If module <a href="http://rhodesmill.org/pyephem">pyephem</a> has been installed, then WeeWX 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>
|
||
|
||
<pre 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</pre>
|
||
|
||
<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 into three categories:</p>
|
||
<ul>
|
||
<li>Calendar events</li>
|
||
<li>Heavenly bodies</li>
|
||
<li>Functions</li>
|
||
</ul>
|
||
<p>We will cover each of these separately.</p>
|
||
<h3>Calendar events</h3>
|
||
|
||
<p>
|
||
"Calendar events" do not require a heavenly body. They cover things such as <span
|
||
class="code">next_solstice</span>, <span class="code">next_first_quarter_moon</span> or <span class="code">sidereal_time</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>or</p>
|
||
<pre class="tty">$almanac.sidereal_time</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>
|
||
<tr>
|
||
<td>sidereal_time</td>
|
||
<td></td>
|
||
<td></td>
|
||
<td></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p class="note" style="display: inline-block">
|
||
<strong>Note</strong><br/>The tag <span class="code">$almanac.sidereal_time</span> returns a value in
|
||
decimal degrees rather than a customary value from 0 to 24 hours.
|
||
</p>
|
||
|
||
<h3>Heavenly bodies</h3>
|
||
|
||
<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, WeeWX 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
|
||
WeeWX 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(almanac_time=<em>time</em>, ## Unix epoch time
|
||
lat=<em>latitude</em>, lon=<em>longitude</em>, ## degrees
|
||
altitude=<em>altitude</em>, ## meters
|
||
pressure=<em>pressure</em>, ## mbars
|
||
horizon=<em>horizon</em>, ## degrees
|
||
temperature=<em>temperature_C</em> ## degrees C
|
||
).<em>heavenly_body</em>(use_center=[01]).<em>attribute</em>
|
||
</pre>
|
||
<p>
|
||
As you can see, many other properties can be overridden besides pressure and the horizon angle.
|
||
</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>
|
||
|
||
<p class="note" style="display: inline-block">
|
||
<strong>Note</strong><br/>The tags <span class="code">ra</span>, <span class="code">a_ra</span> and <span
|
||
class="code">g_ra</span> return values in decimal degrees rather than customary values from 0 to 24 hours.
|
||
</p>
|
||
|
||
<h3>Functions</h3>
|
||
<p>There is actually one one function in this category: <span class="code">separation</span>. It returns the
|
||
angular separation between two heavenly bodies. For example, to calculate the angular separation between
|
||
Venus and Mars you would use:
|
||
</p>
|
||
<pre class="tty">
|
||
<p>The separation between Venus and Mars is
|
||
$almanac.separation(($almanac.venus.alt,$almanac.venus.az), ($almanac.mars.alt,$almanac.mars.az))</p>
|
||
</pre>
|
||
<p>This would result in:</p>
|
||
<p class="example_output">The separation between Venus and Mars is 55:55:31.8</p>
|
||
|
||
<h3>Adding new bodies to the almanac</h3>
|
||
<p>
|
||
It is possible to extend the WeeWX almanac, adding new bodies that it was not previously aware of. For
|
||
example, say we wanted to add <a href="https://en.wikipedia.org/wiki/433_Eros"><em>433 Eros</em></a>, the
|
||
first asteroid visited by a spacecraft. Here is the process:
|
||
</p>
|
||
<ol>
|
||
|
||
<li>
|
||
Put the following in the file <span class="code">user/extensions.py</span>:
|
||
<pre class="tty">import ephem
|
||
eros = ephem.readdb("433 Eros,e,10.8276,304.3222,178.8165,1.457940,0.5598795,0.22258902,71.2803,09/04.0/2017,2000,H11.16,0.46")
|
||
ephem.Eros = eros</pre>
|
||
This does two things: it adds orbital information about <em>433 Eros</em> to the internal pyephem
|
||
database, and it makes that data available under the name <span class="code">Eros</span> (note the
|
||
capital letter).
|
||
</li>
|
||
|
||
<li>
|
||
You can then use <em>433 Eros</em> like any other body in your templates. For example, to display when
|
||
it will rise above the horizon:
|
||
|
||
<pre class="tty">$almanac.eros.rise</pre>
|
||
|
||
</li>
|
||
</ol>
|
||
|
||
<h2>Wind</h2>
|
||
|
||
<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>Archive type</td>
|
||
<td>Meaning</td>
|
||
<td>Valid contexts</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windSpeed</td>
|
||
<td>The average wind speed seen during the archive period.
|
||
</td>
|
||
<td rowspan='4' class='code'>
|
||
$current, $latest, $day, $week, $month, $year, $rainyear
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windDir</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 code">windGust</td>
|
||
<td>The maximum (gust) wind speed seen during the archive period.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">windGustDir</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>Daily summary type</td>
|
||
<td>Meaning</td>
|
||
<td>Valid contexts</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">wind</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 class='code'>$day, $week, $month, $year, $rainyear</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="note" style="display: inline-block">
|
||
<strong>Note</strong><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: 90%;">
|
||
<tbody>
|
||
<tr class="first_row">
|
||
<td>Tag</td>
|
||
<td>Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$current.windSpeed</td>
|
||
<td>The average wind speed over the most recent archive interval.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$current.windDir</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 code">$current.windGust</td>
|
||
<td>The maximum wind speed (gust) over the most recent archive interval.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$current.windGustDir</td>
|
||
<td>The direction of the gust.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day.wind.avg</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 code">$day.wind.vecavg</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 code">$day.wind.vecdir</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>
|
||
<tr>
|
||
<td class="first_col code">$day.wind.max</td>
|
||
<td>The maximum wind gust since midnight.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day.wind.gustdir</td>
|
||
<td>The direction of the maximum wind gust.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day.wind.maxtime</td>
|
||
<td>The time of the maximum wind gust.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day.windSpeed.max</td>
|
||
<td>The max average wind speed. The wind is averaged over each of the archive intervals. Then the
|
||
maximum of these values is taken. Note that this is <em>not</em> the same as the maximum wind gust.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">$day.windDir.avg</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>
|
||
</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"><em>obj</em>.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"><em>obj</em>[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 WeeWX 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, WeeWX 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">$station.altitude</span>, is a <em>string</em>. In order to convert the <span class="code">ValueHelper</span>
|
||
it has in hand 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 conceivable
|
||
different observation types would be impossible!). Instead, class <span class="code">TimespanBinder</span>
|
||
defines the Python special method <span class="code"> <a style="text-decoration: none"
|
||
href="https://docs.python.org/2/reference/datamodel.html#object.__getattr__">__getattr__</a></span>.
|
||
If Python cannot find a hard coded version of an attribute, and the method <span
|
||
class="code">__getattr__</span> exists, it will try it. The definition provided by <span class="code">TimespanBinder</span>
|
||
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, WeeWX 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 WeeWX 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 WeeWX offers the tag <span class="code">$week</span>, this is statistics
|
||
<em>since Sunday at midnight</em>. We would like to have statistics for a full week, that is since
|
||
midnight seven days ago.
|
||
</li>
|
||
</ul>
|
||
<p>
|
||
This example is included in the distribution as <span class="code">examples/stats.py</span>. If you wish to
|
||
use or modify it, first copy it over to <span class="code">user/stats.py</span> then modify it there.
|
||
</p>
|
||
<pre class="tty">import datetime
|
||
import time
|
||
|
||
from weewx.cheetahgenerator import SearchList
|
||
from weewx.tags import TimespanBinder
|
||
from weeutil.weeutil import TimeSpan
|
||
|
||
class MyStats(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,
|
||
skin_dict=self.generator.skin_dict) # 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,
|
||
skin_dict=self.generator.skin_dict) # 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">MyStats</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 5
|
||
parameters.
|
||
<ul>
|
||
<li>The first, <span class='code'>timespan</span>, 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, <span class='code'>db_lookup</span>, is the database lookup function to be used. We
|
||
simply pass in <span class="code">db_lookup</span>.
|
||
</li>
|
||
<li>The third, <span class="code">formatter</span>, 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, <span class="code">converter</span>, should be an instance of <span class="code">weewx.units.Converter</span>,
|
||
which contains information about the target units (<i>e.g.</i>, <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>
|
||
<li>The fifth, <span class="code">skin_dict</span>, is an instance of <span class="code">configobj.ConfigObj</span>,
|
||
and contains the contents of the skin configuration file. We pass it on in order to allow
|
||
aggregations that need information from the file, such as heating and cooling degree-days.
|
||
</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 = user.stats.MyStats</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>
|
||
We put our addition in the file <span class="code">user/stats.py</span>, which means it will be in the
|
||
directory hierarchy where <span class="code">weewxd</span> resides. Python will search this hierarchy by
|
||
default, so it will find our addition. However, if you put it somewhere else, may will have to specify its
|
||
location with the environment variable <a
|
||
href="https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH"><span
|
||
class="code">PYTHONPATH</span></a> when you start WeeWX:
|
||
</p>
|
||
<pre class="tty">export PYTHONPATH=/home/me/secret_location</pre>
|
||
|
||
|
||
<h1 id="image_generator">The Image generator</h1>
|
||
|
||
<p class="note">
|
||
This section gives an overview of the Image generator. For details about each of its various options, see
|
||
the section <a href="#ImageGenerator"><em>[ImageGenerator]</em></a> in the <a href="#report_options"><em>Reference:
|
||
report options</em></a>.
|
||
</p>
|
||
|
||
<p>
|
||
The installed version of WeeWX 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 <a href="#ImageGenerator"><span
|
||
class="code">[ImageGenerator]</span></a> 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 = 500
|
||
image_height = 180
|
||
image_background_color = #f5f5f5
|
||
|
||
chart_background_color = #d8d8d8
|
||
chart_gridline_color = #a0a0a0
|
||
...</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 500
|
||
pixels in width, 180 pixels in height, and will have an RGB background color of #f5f5f5, a very light gray
|
||
(HTML color "WhiteSmoke"). The chart itself will have a background color of #d8d8d8 (a little darker gray),
|
||
and the gridlines will be #a0a0a0 (still darker). The other options farther down (not shown) will also apply
|
||
to all plots.
|
||
</p>
|
||
|
||
<h2>Time periods</h2>
|
||
|
||
<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="https://docs.python.org/3/library/datetime.html#strftime-strptime-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>
|
||
|
||
<h2>Image files</h2>
|
||
|
||
<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 WeeWX 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
|
||
database column name 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>
|
||
|
||
<h2>Including more than one type in a plot</h2>
|
||
|
||
<p>More than one observation 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>
|
||
<p>
|
||
<img src="images/sample_monthtempdew.png" alt="Monthly temperature and dewpoint"/>
|
||
</p>
|
||
|
||
<h2 id="including_same_sql_type_2x">Including a type more than once in a plot</h2>
|
||
|
||
<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 observation 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 database column. So, our
|
||
example would look like this:
|
||
</p>
|
||
<pre class="tty">[[[daytemp_with_avg]]]
|
||
[[[[avgTemp]]]]
|
||
data_type = outTemp
|
||
aggregate_type = avg
|
||
aggregate_interval = 3600
|
||
label = Avg. Temp.
|
||
[[[[outTemp]]]]</pre>
|
||
<p>
|
||
Here, the first plot line has been given the name <span class="code">avgTemp</span> to distinguish it from
|
||
the second line <span class="code">outTemp</span>. Any name will do — it just has to be different. 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 one 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 style="width:300px; height:180px" alt="Daily highs and lows" src="images/yearhilow.png"/>
|
||
</p>
|
||
|
||
<h2 id="line_gaps">Line gaps</h2>
|
||
|
||
<p id="line_gap_fraction">
|
||
If there is a time gap in the data, the option <span class="code">line_gap_fraction</span> controls how line
|
||
plots will be drawn. Here's what a plot looks like without and with this option being specified:
|
||
</p>
|
||
|
||
<div class="center" style="margin: 0;">
|
||
<div style="float: left">
|
||
<img src="images/day-gap-not-shown.png" alt="Gap not shown"/>
|
||
|
||
<div class="image_caption">
|
||
No <span class="code">line_gap_fraction</span> specified
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<img src="images/day-gap-showing.png" alt="Gap showing"/>
|
||
|
||
<div class="image_caption">
|
||
With <span class="code">line_gap_fraction=0.01</span>. Note how each line has been split into two
|
||
lines.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="clear: both"></div>
|
||
|
||
<h2>Progressive vector plots</h2>
|
||
|
||
<p>
|
||
WeeWX 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 database, WeeWX 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 WeeWX 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>
|
||
|
||
<h2>Overriding values</h2>
|
||
|
||
<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>
|
||
|
||
|
||
<h1 id="Using_multiple_bindings">Using multiple bindings</h1>
|
||
|
||
<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 WeeWX. 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.DaySummaryManager
|
||
# 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.DaySummaryManager
|
||
# 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]]
|
||
database_type = SQLite
|
||
database_name = weewx.sdb
|
||
|
||
<span class="highlight"> [[rpi_mysql]]
|
||
database_type = MySQL
|
||
database_name = weewx
|
||
host = rpi-bug</span>
|
||
|
||
[DatabaseTypes]
|
||
# This section defines defaults for the different types of databases.
|
||
|
||
[[SQLite]]
|
||
driver = weedb.sqlite
|
||
# Directory in which the database files are located
|
||
SQLITE_ROOT = %(WEEWX_ROOT)s/archive
|
||
|
||
[[MySQL]]
|
||
driver = weedb.mysql
|
||
# The host where the database is located
|
||
host = localhost
|
||
# The user name for logging in to the host
|
||
user = weewx
|
||
# The password for the user name
|
||
password = weewx
|
||
</pre>
|
||
|
||
<p>
|
||
The two additions have been <span class="highlight">highlighted</span>. The first, <span class="code">[[wmr100_binding]]</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>. It also
|
||
defines some characteristics of the binding, such as which manager is to be used and what its schema looks
|
||
like.
|
||
</p>
|
||
|
||
<p>
|
||
The second addition, <span class="code">[[rpi-mysql]]</span> defines the new database. Option <span
|
||
class="code">database_type</span> is set to <span class="code">MySQL</span>, indicating that it is a MySQL
|
||
database. Defaults for MySQL databases are defined in the section <span class="code">[[MySQL]]</span>. The
|
||
new database accepts all of them, except for <span class="code">host</span>, which as been set to the remote
|
||
host <span class="code">rpi-bug</span>, the name of my Raspberry Pi.
|
||
</p>
|
||
|
||
<h2>Explicit binding in tags</h2>
|
||
|
||
<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>
|
||
|
||
<h2>Explicit binding in images</h2>
|
||
|
||
<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 a 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' alt="Comparing temperatures"/>
|
||
|
||
<h2 id="stupid_detail">Stupid detail</h2>
|
||
|
||
<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. That's why the example above uses <span
|
||
class="code">$latest</span> instead of <span class="code">$current</span>.
|
||
</p>
|
||
|
||
|
||
<h1 id="localization">Localization</h1>
|
||
|
||
<p>
|
||
This section is provides suggestions for localization, including translation to different languages and
|
||
display of data in formats specific to a locale.
|
||
</p>
|
||
|
||
<h2>How to localize a single report</h2>
|
||
|
||
<p>
|
||
What happens when you come accross a report that you like, but it is written in another language, or uses
|
||
time formats that are foreign to your customs? This section explains how to convert the report to local
|
||
formats and language.
|
||
</p>
|
||
|
||
<h3>Translate the templates</h3>
|
||
|
||
<p>
|
||
Translate the text in each template file to the target language. Any strings that are not specified using
|
||
tags will need to be translated.
|
||
</p>
|
||
<p>
|
||
In every HTML template (these typically have a file suffix of <span class="code">.html.tmpl</span>) change
|
||
the HTML "lang" attribute to the target language. For example, for Spanish use <span class="code">es</span>:
|
||
</p>
|
||
<pre class="tty">
|
||
<!DOCTYPE html>
|
||
<html lang="<span class="highlight">es</span>">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
...
|
||
</pre>
|
||
<p>
|
||
The <span class="code">lang</span> can be language-only, e.g., <span class="code">en</span>, or it can be a
|
||
full language-country code, e.g., <span class="code">en-US</span>.
|
||
</p>
|
||
|
||
<p>
|
||
<a href="https://www.w3schools.com/tags/ref_language_codes.asp">language codes</a><br/> <a
|
||
href="https://www.w3schools.com/tags/ref_country_codes.asp">country codes</a><br/>
|
||
</p>
|
||
|
||
<h3>Translate labels and modify local options</h3>
|
||
|
||
<p>
|
||
Go through the report options that are used by the skin, translating labels and modifying formats to follow
|
||
local conventions. You can easily localize all of your reports by doing this in the section <span
|
||
class="code">[StdReport] / [[Defaults]]</span> in the WeeWX configuration file <span
|
||
class="code">weewx.conf</span>.
|
||
</p>
|
||
<p>
|
||
The default time formats should use whatever locale is defined on the computer running WeeWX. For example,
|
||
the format for current time, <span class="code">current = %x %X</span>, results in <span class="code">01/13/19 10:01:01</span>
|
||
when the locale is United States english (<span class="code">en_US</span>), but results in <span
|
||
class="code">13.01.2019 10:01:01</span> when the locale is German (<span class="code">de_DE</span>).
|
||
</p>
|
||
<p>
|
||
First try the generic date (<span class="code">%x</span>), time (<span class="code">%X</span>), and day
|
||
(<span class="code">%A</span>) formats — these will use the locale of your computer. If you still find
|
||
those foreign, you can customize using the <a
|
||
href="https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">specific
|
||
directives</a>.
|
||
</p>
|
||
<p>
|
||
Here is a list of the options in <span class="code">[StdReport] / [[Defaults]]</span>, with the options you
|
||
may need to change <span class="highlight">highlighted.</span>:
|
||
</p>
|
||
<pre class="tty">
|
||
[StdReport]
|
||
[[Defaults]]
|
||
[[[Units]]]
|
||
...
|
||
[[[[Labels]]]]
|
||
...
|
||
day = <span class="highlight">" day", " days"</span>
|
||
hour = <span class="highlight">" hour", " hours"</span>
|
||
minute = <span class="highlight">" minute", " minutes"</span>
|
||
second = <span class="highlight">" second", " seconds"</span>
|
||
|
||
[[[[TimeFormats]]]]
|
||
day = <span class="highlight">%X</span>
|
||
week = <span class="highlight">%X (%A)</span>
|
||
month = <span class="highlight">%x %X</span>
|
||
year = <span class="highlight">%x %X</span>
|
||
rainyear = <span class="highlight">%x %X</span>
|
||
current = <span class="highlight">%x %X</span>
|
||
ephem_day = <span class="highlight">%X</span>
|
||
ephem_year = <span class="highlight">%x %X</span>
|
||
|
||
[[[[Ordinates]]]]
|
||
directions = <span class="highlight">N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW, N/A</span>
|
||
|
||
[[[Labels]]]
|
||
hemispheres = <span class="highlight">N, S, E, W</span>
|
||
latlon_formats = "%02d", "%03d", "%05.2f"
|
||
[[[[Generic]]]]
|
||
barometer = <span class="highlight">Barometer</span>
|
||
dewpoint = <span class="highlight">Dew Point</span>
|
||
ET = <span class="highlight">ET</span>
|
||
heatindex = <span class="highlight">Heat Index</span>
|
||
inHumidity = <span class="highlight">Inside Humidity</span>
|
||
inTemp = <span class="highlight">Inside Temperature</span>
|
||
outHumidity = <span class="highlight">Humidity</span>
|
||
outTemp = <span class="highlight">Temperature</span>
|
||
radiation = <span class="highlight">Radiation</span>
|
||
rain = <span class="highlight">Rain</span>
|
||
rainRate = <span class="highlight">Rain Rate</span>
|
||
UV = <span class="highlight">UV Index</span>
|
||
windDir = <span class="highlight">Wind Direction</span>
|
||
windGust = <span class="highlight">Gust Speed</span>
|
||
windGustDir = <span class="highlight">Gust Direction</span>
|
||
windSpeed = <span class="highlight">Wind Speed</span>
|
||
windchill = <span class="highlight">Wind Chill</span>
|
||
windgustvec = <span class="highlight">Gust Vector</span>
|
||
windvec = <span class="highlight">Wind Vector</span>
|
||
extraTemp1 = <span class="highlight">Temperature1</span>
|
||
extraTemp2 = <span class="highlight">Temperature2</span>
|
||
extraTemp3 = <span class="highlight">Temperature3</span>
|
||
|
||
# Sensor status indicators
|
||
|
||
rxCheckPercent = <span class="highlight">Signal Quality</span>
|
||
txBatteryStatus = <span class="highlight">Transmitter Battery</span>
|
||
windBatteryStatus = <span class="highlight">Wind Battery</span>
|
||
rainBatteryStatus = <span class="highlight">Rain Battery</span>
|
||
outTempBatteryStatus = <span class="highlight">Outside Temperature Battery</span>
|
||
inTempBatteryStatus = <span class="highlight">Inside Temperature Battery</span>
|
||
consBatteryVoltage = <span class="highlight">Console Battery</span>
|
||
heatingVoltage = <span class="highlight">Heating Voltage</span>
|
||
supplyVoltage = <span class="highlight">Supply Voltage</span>
|
||
referenceVoltage = <span class="highlight">Reference Voltage</span>
|
||
|
||
[[[Almanac]]]
|
||
moon_phases = <span class="highlight">New, Waxing crescent, First quarter, Waxing gibbous, Full, Waning gibbous, Last quarter, Waning crescent</span>
|
||
</pre>
|
||
|
||
<h3 id="environment_variable_LANG">
|
||
Set the environment variable <span class="code">LANG</span>
|
||
</h3>
|
||
|
||
<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 WeeWX, 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>
|
||
|
||
<h2>How to create a skin for multiple locales</h2>
|
||
|
||
<p>
|
||
Let's say that you have created a new skin. How do you package that skin for use in other languages and
|
||
locales? This example shows how to translate the <em>Seasons</em> skin for multiple languages.
|
||
</p>
|
||
<p>
|
||
Create a directory for each language. Each directory contains template files and a skin configuration file.
|
||
Any text in each template file should be in the target language. Ensure that each HTML template file has the
|
||
<span class="code">lang</span> set properly.
|
||
</p>
|
||
<p>
|
||
Translate observation names and other labels, and put them into the skin configuration files. There should
|
||
be one configuration file for each language.
|
||
</p>
|
||
<p>
|
||
Ensure that any locale-specific formatting is specified properly. For example, consider the <span
|
||
class="code">current</span> time, which is parameterized in <span class="code">[Units][[TimeFormats]]</span>.
|
||
Users in a locale that uses 24-hour time expect the format <span class="code">%H:%M</span> whereas users in
|
||
a locale that uses 12-hour time expect <span class="code">%I:%M %p</span>. To make each translation
|
||
independent of the computer on which the reports will be generated, you must use the specific localization;
|
||
if you specify the generic format <span class="code">%X</span>, that will result in the format used by
|
||
whatever locale is set in the environment in which WeeWX is running.
|
||
</p>
|
||
<p>
|
||
The result will be a directory of templates and configurations, with one directory for each
|
||
language/localization.
|
||
</p>
|
||
<pre class="tty">
|
||
skins/Seasons/
|
||
skins/Seasons/en/skin.conf
|
||
skins/Seasons/en/index.html.tmpl
|
||
skins/Seasons/es/skin.conf
|
||
skins/Seasons/es/index.html.tmpl
|
||
skins/Seasons/de/skin.conf
|
||
skins/Seasons/de/index.html.tmpl
|
||
skins/Seasons/fr/skin.conf
|
||
skins/Seasons/fr/index.html.tmpl</pre>
|
||
|
||
<p>
|
||
Users will then create each report in the WeeWX configuration file.
|
||
</p>
|
||
<pre class="tty">
|
||
[StdReport]
|
||
[[Seasons_en]]
|
||
skin = Seasons/en
|
||
HTML_ROOT = public_html/en
|
||
[[Seasons_es]]
|
||
skin = Seasons/es
|
||
HTML_ROOT = public_html/es
|
||
[[Seasons_de]]
|
||
skin = Seasons/de
|
||
HTML_ROOT = public_html/de
|
||
[[Seasons_fr]]
|
||
skin = Seasons/fr
|
||
HTML_ROOT = public_html/fr</pre>
|
||
<p>
|
||
The result is multiple reports, each in a different language and localization, independent of the locale of
|
||
the computer on which they were generated.
|
||
</p>
|
||
|
||
|
||
<h1 id="service_engine">Customizing the WeeWX service engine </h1>
|
||
|
||
<p>This is an advanced topic intended for those who wish to try their hand at extending the internal engine in
|
||
WeeWX. Before attempting these examples, you should be reasonably proficient with Python.
|
||
</p>
|
||
|
||
<p class="warning">Please note that the API to the service engine may change in future versions!</p>
|
||
|
||
<p>
|
||
At a high level, WeeWX 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>
|
||
The services are specified in lists in the <a href="usersguide.htm#engine_services"><span class="code">[Engine][[Services]]</span></a>
|
||
stanza of the configuration file. The <span class="code">[[Services]]</span> section lists all the services
|
||
to be run, broken up into different <em>service lists</em>.
|
||
</p>
|
||
|
||
<p>
|
||
These lists are designed to orchestrate the data as it flows through the WeeWX engine. For example, you want
|
||
to make sure data has been processed by, for example, running it through the quality control service, <span
|
||
class="code">StdQC</span>, before putting them in the database. Similarly, the reporting system must come
|
||
<em>after</em> the archiving service. These groups insure that things happen in the proper sequence.
|
||
</p>
|
||
<p>
|
||
See the table <a href="#default_services">Default services</a> for a list of the services that are normally
|
||
run.
|
||
</p>
|
||
|
||
<h2 id="Customizing_a_service">Modifying an existing 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="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 id="Adding_a_service">Creating a new 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>.
|
||
</p>
|
||
|
||
<p>
|
||
This example is included in the standard distribution as <span class="code">examples/alarm.py:</span>
|
||
</p>
|
||
|
||
<pre class="tty">
|
||
import smtplib
|
||
import socket
|
||
import syslog
|
||
import threading
|
||
import time
|
||
from email.mime.text import MIMEText
|
||
|
||
import weewx
|
||
from weeutil.weeutil import timestamp_to_string, option_as_list
|
||
from weewx.engine import StdService
|
||
|
||
|
||
# Inherit from the base class StdService:
|
||
class MyAlarm(StdService):
|
||
"""Service that sends email 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.timeout = int(config_dict['Alarm'].get('timeout', 10))
|
||
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@example.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.new_archive_record) # NOTE 1
|
||
except KeyError as e:
|
||
syslog.syslog(syslog.LOG_INFO, "alarm: No alarm set. Missing parameter: %s" % e)
|
||
|
||
def new_archive_record(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
|
||
|
||
# Be prepared to catch an exception in the case that the expression contains
|
||
# a variable that is not in the record:
|
||
try: # NOTE 2
|
||
# 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 3
|
||
# Sound the alarm!
|
||
# Launch in a separate thread so it doesn't block the main LOOP thread:
|
||
t = threading.Thread(target=MyAlarm.sound_the_alarm, args=(self, record))
|
||
t.start()
|
||
# Record when the message went out:
|
||
self.last_msg_ts = time.time()
|
||
except NameError as e:
|
||
# The record was missing a named variable. Log it.
|
||
syslog.syslog(syslog.LOG_DEBUG, "alarm: %s" % e)
|
||
|
||
def sound_the_alarm(self, rec):
|
||
"""Sound the alarm in a 'try' block"""
|
||
|
||
# Wrap the attempt in a 'try' block so we can log a failure.
|
||
try:
|
||
self.do_alarm(rec)
|
||
except socket.gaierror:
|
||
# A gaierror exception is usually caused by an unknown host
|
||
syslog.syslog(syslog.LOG_CRIT, "alarm: unknown host %s" % self.smtp_host)
|
||
# Reraise the exception. This will cause the thread to exit.
|
||
raise
|
||
except Exception as e:
|
||
syslog.syslog(syslog.LOG_CRIT, "alarm: unable to sound alarm. Reason: %s" % e)
|
||
# Reraise the exception. This will cause the thread to exit.
|
||
raise
|
||
|
||
def do_alarm(self, rec):
|
||
"""Send an email out"""
|
||
|
||
# Get the time and convert to a string:
|
||
t_str = timestamp_to_string(rec['dateTime'])
|
||
|
||
# Log the alarm
|
||
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)
|
||
|
||
try:
|
||
# First try end-to-end encryption
|
||
s = smtplib.SMTP_SSL(self.smtp_host, timeout=self.timeout)
|
||
syslog.syslog(syslog.LOG_DEBUG, "alarm: using SMTP_SSL")
|
||
except (AttributeError, socket.timeout, socket.error):
|
||
syslog.syslog(syslog.LOG_DEBUG, "alarm: unable to use SMTP_SSL connection.")
|
||
# If that doesn't work, try creating an insecure host, then upgrading
|
||
s = smtplib.SMTP(self.smtp_host, timeout=self.timeout)
|
||
try:
|
||
# Be prepared to catch an exception if the server
|
||
# does not support encrypted transport.
|
||
s.ehlo()
|
||
s.starttls()
|
||
s.ehlo()
|
||
syslog.syslog(syslog.LOG_DEBUG,
|
||
"alarm: using SMTP encrypted transport")
|
||
except smtplib.SMTPException:
|
||
syslog.syslog(syslog.LOG_DEBUG,
|
||
"alarm: using SMTP 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, "alarm: 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 as 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, "alarm: 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.example.com
|
||
smtp_user = myusername
|
||
smtp_password = mypassword
|
||
mailto = auser@example.com, anotheruser@example.com
|
||
from = me@example.com
|
||
subject = "Alarm message from WeeWX!"</pre>
|
||
<p>
|
||
There are three 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.new_archive_record</span>. When the
|
||
event <span class='code'>NEW_ARCHIVE_RECORD</span> occurs, the function <span class="code">self.new_archive_record</span>
|
||
will be called. There are many other events that can be intercepted. Look in the file <span
|
||
class="code">weewx/__init__.py</span>.
|
||
</li>
|
||
<li>Some hardware does not emit all possible observation types in every record. So, it's possible that a
|
||
record may be missing some types that are used in the expression. This try block will catch the <span
|
||
class="code">NameError</span> exception that would be raised should this occur.
|
||
</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, WeeWX will supply something sensible. Note, however, that some mailers require a valid "from"
|
||
email address and the one WeeWX supplies may not satisfy its requirements.
|
||
</p>
|
||
|
||
<p>
|
||
To make this all work, you must first copy the <span class="code">alarm.py</span> file to the <span
|
||
class="code">user</span> directory. Then tell the engine to load this new service by adding the 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">, user.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 this example, 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>
|
||
|
||
|
||
<h2 id="Adding_2nd_source">Adding a second data source</h2>
|
||
|
||
<p>A very common problem is wanting to augment the data from your weather station with data from some other
|
||
device. Generally, you have two approaches for how to handle this:
|
||
</p>
|
||
<ul>
|
||
<li>Run two instances of WeeWX, each using its own database and <span class='code'>weewx.conf</span>
|
||
configuration file. The results are then combined in a final report, using WeeWX's ability <a
|
||
href="#Using_multiple_bindings">to use more than one database</a>. See the Wiki entry <a
|
||
href="https://github.com/weewx/weewx/wiki/weewx-multi"> <em>How to run multiple instances of
|
||
WeeWX</em></a> for details on how to do this.
|
||
</li>
|
||
<li>Run one instance, but use a custom WeeWX service to augment the records coming from your weather station
|
||
with data from the other device.
|
||
</li>
|
||
</ul>
|
||
|
||
<p>This section covers the latter approach.</p>
|
||
|
||
<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 total
|
||
power consumed. At the end of every archive interval you want to calculate the amount of power consumed
|
||
during the interval, then add the results to the record coming off your weather station. How would you do
|
||
this?
|
||
</p>
|
||
|
||
<p>Here is the outline of a service that retrieves the electrical consumption data and adds it to the archive
|
||
record. It assumes that you already have a function <span class='code'>download_total_power()</span> that,
|
||
somehow, downloads the amount of power consumed since time zero.
|
||
</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_record)
|
||
|
||
self.last_total = None
|
||
|
||
def new_archive_record(self, event):
|
||
|
||
total_power = download_total_power()
|
||
|
||
if self.last_total:
|
||
net_consumed = total_power - self.last_total
|
||
event.record['electricity'] = net_consumed
|
||
|
||
self.last_total = total_power</pre>
|
||
<p>
|
||
This adds a new key <span class="code">electricity</span> to the record dictionary and sets it equal to the
|
||
difference between the amount of power currently consumed and the amount consumed at the last archive
|
||
record. Hence, it will be the amount of power consumed over the archive interval. The unit should be
|
||
Watt-hours.
|
||
</p>
|
||
|
||
<p>
|
||
As an aside, it is important that the function <span class='code'>download_total_power()</span> does not
|
||
delay very long because it will sit right in the main loop of the WeeWX engine. 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 <span class="code">weewx.conf</span>,
|
||
section <span class="code">[Engine]</span>, subsection <span class="code">[[Services]]</span>.
|
||
</p>
|
||
|
||
<p>
|
||
In our case, the obvious place for our new service is in <span class="code">data_services</span>. When
|
||
you're done, your section <span class="code">[Engine]</span> will look something like this:
|
||
</p>
|
||
<pre class="tty">
|
||
# This section configures the internal WeeWX engine.
|
||
|
||
[Engine]
|
||
|
||
[[Services]]
|
||
# This section specifies the services that should be run. They are
|
||
# grouped by type, and the order of services within each group
|
||
# determines the order in which the services will be run.
|
||
prep_services = weewx.engine.StdTimeSynch
|
||
data_services = <span class="highlight">user.electricity.AddElectricity</span>
|
||
process_services = weewx.engine.StdConvert, weewx.engine.StdCalibrate, weewx.engine.StdQC, weewx.wxservices.StdWXCalculate
|
||
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>
|
||
|
||
<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 new SQL type to your
|
||
database, or change its unit system. This section shows you how to do this.
|
||
</p>
|
||
|
||
<h2 id="add_archive_type">Adding a new type to the database</h2>
|
||
|
||
<p>
|
||
It is not unusual to have observation types that exist in the loop packets and/or archive records, but are
|
||
not in the database schema. An example is the new observation type <span class="code">electricity</span>,
|
||
from the example, <a href="#Adding_2nd_source"><em>Adding a second data source</em></a>. If a type is not in
|
||
the database schema, then it will be a second class citizen in WeeWX's world: it cannot be used in a plot,
|
||
nor for most statistics. So how would you add such a type to the database schema?
|
||
</p>
|
||
|
||
<p>
|
||
The utility <a href="utilities.htm#wee_database_utility"><span class="code">wee_database</span></a> can do
|
||
this. It will create a new database that is similar to the old database, except it will have the new type in
|
||
its schema.
|
||
</p>
|
||
|
||
<p class="note" style="display: inline-block; width: 70%">
|
||
<strong>Note</strong><br/>It is possible to observe all of the observation types included in the loop
|
||
packets and archive records, whether or not they are stored in the database, by <a
|
||
href="usersguide.htm#Running_directly">running WeeWX directly</a>.
|
||
</p>
|
||
|
||
<p>Here's our general strategy:</p>
|
||
<ol>
|
||
<li>Extend the existing schema with the new type.
|
||
</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_database</span> to create the new database and populate it with
|
||
data from the old database.
|
||
</li>
|
||
<li>Shuffle databases around so WeeWX will use the new database.
|
||
</li>
|
||
</ol>
|
||
<p>Here is the recipe that follows that strategy:</p>
|
||
<ol>
|
||
<li>
|
||
<p>
|
||
<strong>Extend the existing schema with the new type.</strong> The schema that comes with WeeWX 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. Besides, our changes would get lost at the next upgrade.
|
||
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, then just add on our new
|
||
type.
|
||
</p>
|
||
<p>
|
||
For this example, we are going to add a few lines of code to the bottom of the file <span
|
||
class="code">user/electricity.py</span>:
|
||
</p>
|
||
<pre class="tty">import schemas.wview
|
||
schema_with_electricity = schemas.wview.schema + [('electricity', 'REAL')]
|
||
</pre>
|
||
<p>
|
||
This creates a new schema with the name
|
||
<span class="code">user.electricity.schema_with_electricity</span>,
|
||
which is just like the old one, except it has a new type, <span class="code">electricity</span>,
|
||
tacked on to the end.
|
||
</p>
|
||
<li>
|
||
<p>
|
||
<strong>Modify <span class="code">wx_binding</span>.</strong> When it creates the new, modified
|
||
database, <span class="code">wee_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>.
|
||
</p>
|
||
<p>
|
||
The <span class="code">[DataBindings]</span> section now looks like this:
|
||
</p>
|
||
|
||
<pre class="tty">[DataBindings]
|
||
[[wx_binding]]
|
||
database = archive_sqlite
|
||
table_name = archive
|
||
manager = weewx.wxmanager.DaySummaryManager
|
||
<span class="highlight">schema = user.electricity.electricity_schema</span></pre>
|
||
</li>
|
||
|
||
<li>
|
||
<p>
|
||
<strong>Check permissions.</strong> <span class="code">wee_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> <span class="cmd">GRANT select, update, create, delete, insert ON weewx_new.* TO weewx@localhost;</span></pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<strong>Create and populate the new database.</strong> Now run the utility <span class="code">wee_database</span>
|
||
with the <span class="code">--reconfigure</span> option and the path to the configuration file:
|
||
</p>
|
||
|
||
<p class="tty cmd">wee_database weewx.conf --reconfigure</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 WeeWX 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 cmd">cd <span class="symcode">SQLITE_ROOT</span>
|
||
mv weewx.sdb_new weewx.sdb</pre>
|
||
<p>For MySQL:</p>
|
||
<pre class="tty"><span class="cmd">mysql -u <username> --password=<mypassword></span>
|
||
mysql><span class="cmd"> DROP DATABASE weewx;</span> # Delete the old database
|
||
mysql><span class="cmd"> CREATE DATABASE weewx;</span> # Create a new one with the same name
|
||
mysql><span class="cmd"> RENAME TABLE weewx_new.archive TO weewx.archive;</span> # Rename to the nominal name</pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
It's worth noting that there's actually a hidden, last step: rebuilding the daily summaries inside
|
||
the new database. This will be done automatically by WeeWX at the next startup. Alternatively, it
|
||
can be done manually using the <a href="utilities.htm#wee_database_utility"><span class="code">wee_database</span></a>
|
||
utility and the <span class="code">--rebuild-daily</span> option:
|
||
</p>
|
||
<pre class="tty cmd">wee_database weewx.conf --rebuild-daily</pre>
|
||
</li>
|
||
</ol>
|
||
|
||
|
||
<h2 id="Changing_the_unit_system">Changing the database 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 set of units you want. The section <a
|
||
href="#how_to_change_units"><em>How to change units</em></a> 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 database from another piece of software that expects metric units.
|
||
</p>
|
||
|
||
<p>
|
||
You should not change the database unit system midstream. That is, do not 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 <a href="utilities.htm#wee_database_utility"><span class="code">wee_database</span></a>
|
||
to create the new database and populate it with data from the old database.
|
||
</li>
|
||
<li>Shuffle databases around so WeeWX 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_database</span>
|
||
with the <span class="code">--reconfigure</span> option:
|
||
</p>
|
||
<pre class="tty cmd">wee_database weewx.conf --reconfigure</pre>
|
||
<p>
|
||
This will create a new database (nominally, <span class="code">weewx.sdb_new</span> if you are using
|
||
SQLite, <span class="code">weewx_new</span> if you are using MySQL), using the schema found in <span
|
||
class="code">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 WeeWX 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 cmd">cd <span class="symcode">SQLITE_ROOT</span>
|
||
mv weewx.sdb_new weewx.sdb</pre>
|
||
<p>For MySQL:</p>
|
||
<pre class="tty"><span class="cmd">mysql -u <username> --password=<mypassword></span>
|
||
mysql><span class="cmd"> DROP DATABASE weewx;</span> # Delete the old database
|
||
mysql><span class="cmd"> CREATE DATABASE weewx;</span> # Create a new one with the same name
|
||
mysql><span class="cmd"> RENAME TABLE weewx_new.archive TO weewx.archive;</span> # Rename to the nominal name</pre>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
It's worth noting that there's actually a hidden, last step: rebuilding the daily summaries inside
|
||
the new database. This will be done automatically by WeeWX at the next startup. Alternatively, it
|
||
can be done manually using the <a href="utilities.htm#wee_database_utility"><span class="code">wee_database</span></a>
|
||
utility and the <span class="code">--rebuild-daily</span> option:
|
||
</p>
|
||
<pre class="tty cmd">wee_database weewx.conf --rebuild-daily</pre>
|
||
</li>
|
||
</ol>
|
||
|
||
<h2>Rebuilding the daily summaries</h2>
|
||
|
||
<p>
|
||
The <span class="code">wee_database</span> utility can also be used to rebuild the daily summaries:
|
||
</p>
|
||
|
||
<pre class="tty cmd">wee_database weewx.conf --rebuild-daily</pre>
|
||
|
||
<p>In most cases this will be sufficient; however, if anomalies remain in the daily summaries the daily summary
|
||
tables may be dropped first before rebuilding:
|
||
</p>
|
||
|
||
<pre class="tty cmd">wee_database weewx.conf --drop-daily</pre>
|
||
|
||
<p>
|
||
The summaries will automatically be rebuilt the next time WeeWX starts, or they can be rebuilt with the
|
||
utility:
|
||
</p>
|
||
|
||
<pre class="tty cmd">wee_database weewx.conf --rebuild-daily</pre>
|
||
|
||
|
||
<h1 id="customizing_units">Customizing units and unit groups</h1>
|
||
|
||
<p class="warning">
|
||
<strong>Warning!</strong><br/> This is an area that is rapidly changing in WeeWX. Presently, new units and
|
||
unit groups are added by manipulating the internal dictionaries in WeeWX (as described below). In the
|
||
future, they may be specified in <span class='code'>weewx.conf</span>.
|
||
</p>
|
||
|
||
<h2>Assigning a unit group</h2>
|
||
<p>
|
||
In the examples above, we created a new observation type, <span class='code'>electricity</span>, and added
|
||
it to the database schema. Now we would like to recognize that it is a member of the unit group <span
|
||
class='code'>group_energy</span> (which already exists), so it can enjoy the labels and formats already
|
||
provided for this group. This is done by extending the dictionary <span class='code'>weewx.units.obs_group_dict</span>.
|
||
</p>
|
||
|
||
<p>Add the following to our new services file <span class='code'>user/electricity.py</span>, just after the last
|
||
import statement:
|
||
</p>
|
||
<pre class="tty">import weewx
|
||
from weewx.engine import StdService
|
||
<span class="highlight">
|
||
import weewx.units
|
||
weewx.units.obs_group_dict['electricity'] = 'group_energy'</span>
|
||
|
||
class AddElectricity(StdService):
|
||
|
||
# [...]</pre>
|
||
|
||
<p>When our new service gets loaded by the WeeWX engine, these few lines will get run. They tell WeeWX that our
|
||
new observation type, <span class='code'>electricity</span>, is part of the unit group <span class='code'>group_energy</span>.
|
||
Once the observation has been associated with a unit group, the unit labels and other tag syntax will work
|
||
for that observation. So, now a tag like:
|
||
</p>
|
||
<pre class='tty'>$month.electricity.sum</pre>
|
||
<p>will return the total amount of electricity consumed for the month, in Watt-hours.</p>
|
||
|
||
<h2>Creating a new unit group</h2>
|
||
<p>
|
||
That was an easy one, because there was already an existing group, <span class='code'>group_energy</span>,
|
||
that covered our new observation type. But, what if we are measuring something entirely new, like force with
|
||
time? There is nothing in the existing system of units that covers things like newtons or pounds. We will
|
||
have to define these new units, as well as the unit group they can belong to.
|
||
</p>
|
||
<p>
|
||
We assume we have a new observation type, <span class='code'>force</span>, that we are measuring over time,
|
||
for a service named <span class="code">Rocket</span>, located in <span class='code'>
|
||
user/rocket.py</span>. We will create a new unit group, <span class='code'>group_force</span>, and new units,
|
||
<span class='code'>newton</span> and <span class='code'>pound</span>. Our new observation, <span
|
||
class='code'>force</span>, will belong to <span class='code'>group_force</span>, and will be measured in
|
||
units of <span class='code'>newton</span> or <span class='code'>pound</span>.
|
||
</p>
|
||
<p>
|
||
To make this work, we need to add the following to <span class="code">user/rocket.py</span>.
|
||
</p>
|
||
<ol>
|
||
<li>As before, we start by specifying what group our new observation type belongs to:
|
||
<pre class='tty'>
|
||
import weewx.units
|
||
weewx.units.obs_group_dict['force'] = 'group_force'</pre>
|
||
</li>
|
||
<li>Next, we specify what unit is used to measure force in the three standard unit systems used by weewx.
|
||
<pre class='tty'>
|
||
weewx.units.USUnits['group_force'] = 'pound'
|
||
weewx.units.MetricUnits['group_force'] = 'newton'
|
||
weewx.units.MetricWXUnits['group_force'] = 'newton'</pre>
|
||
</li>
|
||
<li>Then we specify what formats and labels to use for <span class='code'>newton</span> and <span
|
||
class='code'>pound</span>:
|
||
<pre class='tty'>
|
||
weewx.units.default_unit_format_dict['newton'] = '%.1f'
|
||
weewx.units.default_unit_format_dict['pound'] = '%.1f'
|
||
|
||
weewx.units.default_unit_label_dict['newton'] = ' newton'
|
||
weewx.units.default_unit_label_dict['pound'] = ' pound'</pre>
|
||
</li>
|
||
<li>Finally, we specify how to convert between them:
|
||
<pre class='tty'>
|
||
weewx.units.conversionDict['newton'] = {'pound': lambda x : x * 0.224809}
|
||
weewx.units.conversionDict['pound'] = {'newton': lambda x : x * 4.44822}
|
||
</pre>
|
||
|
||
</li>
|
||
</ol>
|
||
<p>
|
||
Now, when the service <span class="code">Rocket</span> gets loaded, these lines of code will get executed,
|
||
adding the necessary unit extensions to WeeWX.
|
||
</p>
|
||
|
||
<h2>Using the new units</h2>
|
||
|
||
<p>Now you've added a new type of units. How do you use it?</p>
|
||
|
||
<p>
|
||
Pretty much like any other units. 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(5000.0)</td>
|
||
<td>The number of days of the year where more than 5.0 kWh of energy was consumed.
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
|
||
<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>
|
||
A <em>driver</em> communicates with hardware. Each driver is a single python file that contains the code
|
||
that is the interface between a device and WeeWX. A driver may communicate directly with hardware using a
|
||
MODBus, USB, serial, or other physical interface. Or it may communicate over a network to a physical device
|
||
or a web service.
|
||
</p>
|
||
|
||
<h2>General guidelines</h2>
|
||
|
||
<ul>
|
||
<li>The driver should emit data as it receives it from the hardware (no caching).
|
||
</li>
|
||
<li>The driver should emit only data it receives from the hardware (no "filling in the gaps").
|
||
</li>
|
||
<li>The driver should not modify the data unless the modification is directly related to the hardware (<i>e.g.</i>,
|
||
decoding a hardware-specific sensor value).
|
||
</li>
|
||
<li>If the hardware flags "bad data", then the driver should emit a null value for that datum (Python <span
|
||
class="code">None</span>).
|
||
</li>
|
||
<li>The driver should not calculate any derived variables (such as dewpoint). The service <span
|
||
class="code">StdWXService</span> will do that.
|
||
</li>
|
||
<li>However, if the hardware emits a derived variable, then the driver should emit it.
|
||
</li>
|
||
</ul>
|
||
|
||
<h2>Implement the driver</h2>
|
||
|
||
<p>
|
||
Create a file in the user directory, say <span class="code">mydriver.py</span>. This file will contain the
|
||
driver class as well as any hardware-specific code. Do not put it in the <span
|
||
class="code">weewx/drivers</span> directory or it will be deleted when you upgrade WeeWX.
|
||
</p>
|
||
|
||
<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 Python <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 is capable of measuing an observation type but, for whatever
|
||
reason, its value is bad (maybe a bad checksum?), then set its value to <span class="code">None</span>. If
|
||
your hardware is incapable of measuring an observation type, then leave it out of the dictionary.
|
||
</p>
|
||
|
||
<p>
|
||
A couple of observation types are tricky. In particular, <span class="code">rain</span>. Generally, WeeWX
|
||
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 WeeWX. 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 WeeWX 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>, 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. WeeWX 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>
|
||
The <span class='code'>fileparse</span> driver is perhaps the simplest example of a WeeWX driver. It reads
|
||
name-value pairs from a file and uses the values as sensor 'readings'. The code is actually packaged as an
|
||
extension, located in <span class="code">examples/fileparse</span>, making it a good example of not only
|
||
writing a device driver, but also of how to package an extension. The actual driver itself is in <span
|
||
class="code">examples/fileparse/bin/user/fileparse.py</span>.
|
||
</p>
|
||
|
||
<p>
|
||
Another good example is the simulator code located in <span class='code'>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 Ultimeter (<span class="code">ultimeter.py</span>) and WMR100 (<span class="code">wmr100.py</span>)
|
||
drivers illustrate how to communicate with serial and USB hardware, respectively. They also show different
|
||
approaches for decoding data. Nevertheless, they are pretty 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 have been glossed over in this high-level description. If you
|
||
run into trouble, look for help in the <a href="https://groups.google.com/forum/#!forum/weewx-development">
|
||
<span class="code">weewx-development</span> forum</a>.
|
||
</p>
|
||
|
||
<h1 id="extensions">Extensions</h1>
|
||
|
||
<p>
|
||
A key feature of WeeWX is its ability to be extended by installing 3rd party <em>extensions</em>. Extensions
|
||
are a way to package one or more customizations so they can be installed and distributed as a functional
|
||
group.
|
||
</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>
|
||
Take a look at the <a href="https://github.com/weewx/weewx/wiki"> WeeWX wiki </a> for a sampling of some of
|
||
the extensions that are available.
|
||
</p>
|
||
|
||
|
||
<!-- Utility wee_extension moved to utilities.htm -->
|
||
|
||
|
||
<h2>Creating an extension</h2>
|
||
|
||
<p>
|
||
Now that you have made some customizations, you might want to share those changes with other WeeWX users.
|
||
Put your customizations into an extension to make installation, removal, and distribution easier.
|
||
</p>
|
||
|
||
<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>
|
||
|
||
<p>
|
||
Although one extension might use another extension, take care to write the dependent extension so that it
|
||
fails gracefully. For example, a skin might use data the forecast extension, but what happens if the
|
||
forecast extension is not installed? Make the skin display a message about "forecast not installed" but
|
||
otherwise continue to function.
|
||
</p>
|
||
|
||
<h2>Packaging an extension</h2>
|
||
|
||
<p>
|
||
The structure of an extension mirrors that of WeeWX 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 WeeWX ExtensionInstaller
|
||
</li>
|
||
</ul>
|
||
<p>
|
||
For example, here is the structure of a skin called <span class='code'>basic</span>:
|
||
</p>
|
||
|
||
<pre 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</pre>
|
||
|
||
<p>
|
||
Here is the structure of a search list extension called <span class='code'>xstats</span>:
|
||
</p>
|
||
|
||
<pre class='tty'>xstats/
|
||
xstats/changelog
|
||
xstats/install.py
|
||
xstats/readme.txt
|
||
xstats/bin/
|
||
xstats/bin/user/
|
||
xstats/bin/user/xstats.py</pre>
|
||
|
||
<p>
|
||
See the <span class='code'>extensions</span> directory of the WeeWX 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 cmd'>tar cvfz basic.tar.gz basic</p>
|
||
|
||
<p>Once an extension has been packaged, it can be installed using the <a
|
||
href="utilities.htm#wee_extension_utility">wee_extension</a> utility.
|
||
</p>
|
||
|
||
<h2>Default values</h2>
|
||
|
||
<p>
|
||
Whenever possible, an extension should <em>just work</em>, with a minimum of input from the user. At the
|
||
same time, parameters for the most frequently requested options should be easily accessible and easy to
|
||
modify. For skins, this might mean parameterizing strings into <span class="code">[Labels]</span> for easier
|
||
customization. Or it might mean providing parameters in <span class="code">[Extras]</span> to control skin
|
||
behavior or to parameterize links.
|
||
</p>
|
||
<p>
|
||
Some parameters <em>must</em> be specified, and no default value would be appropriate. For example, an
|
||
uploader may require a username and password, or a driver might require a serial number or IP address. In
|
||
these cases, use a default value in the configuration that will obviously require modification. The <em>username</em>
|
||
might default to <em>REPLACE_ME</em>. Also be sure to add a log entry that indicates the feature is disabled
|
||
until the value has been specified.
|
||
</p>
|
||
<p>
|
||
In the case of drivers, use the configuration editor to prompt for this type of required value.
|
||
</p>
|
||
|
||
|
||
<h1 id="report_options">Reference: report options</h1>
|
||
|
||
<p>
|
||
This section contains the options available in the skin configuration file, <span
|
||
class="code">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>
|
||
|
||
<p>
|
||
As an example, the <span class="code">skin.conf</span> file for the <em>Seasons</em> skin includes three
|
||
options:
|
||
</p>
|
||
<table class="indent" style="width: 50%">
|
||
<tr class="first_row">
|
||
<td>Skin option</td>
|
||
<td>Template tag</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">radar_img</td>
|
||
<td class="code">$Extras.radar_img</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">radar_url</td>
|
||
<td class="code">$Extras.radar_url</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="code">googleAnalyticsId</td>
|
||
<td class="code">$Extras.googleAnalyticsId</td>
|
||
</tr>
|
||
</table>
|
||
<p>
|
||
If you take a look at the template <span class="code">radar.inc</span> you will see examples of testing for
|
||
these tags.
|
||
</p>
|
||
|
||
<p class="config_option">radar_img</p>
|
||
|
||
<p>Set to an URL to show a local radar image for your region.</p>
|
||
|
||
<p class="config_option">radar_url</p>
|
||
|
||
<p>If the 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 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">[Labels]</h2>
|
||
|
||
<p>This section defines various labels.</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" id="Labels_Generic">[[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
|
||
UV = UV Index</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
|
||
(<i>e.g.</i>, <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">[Units]</h2>
|
||
|
||
<p>This section controls how units are managed and displayed.</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 WeeWX (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. WeeWX 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_distance</p>
|
||
|
||
<p>
|
||
Which measurement unit to be used for distance (such as for wind run). Possible options are <span
|
||
class="code">mile</span> or <span class="code">km</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) 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>
|
||
|
||
<h3 class="config_section" id="Units_TimeFormats">[[TimeFormats]]</h3>
|
||
|
||
<p>
|
||
This sub-section is used for time labels. It uses <a
|
||
href="https://docs.python.org/3/library/datetime.html#strftime-strptime-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 Customization 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" id="Units_Ordinates">[[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 <br/> growing_base
|
||
</p>
|
||
|
||
<p>Set to the base temperature for calculating heating, cooling, and growing 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
|
||
growing_base = 50.0, degree_F</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 id="CheetahGenerator">[CheetahGenerator]</h2>
|
||
|
||
<p>This section contains the options for the Cheetah generator.</p>
|
||
|
||
<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://pythonhosted.org/Cheetah/users_guide">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 = user.stats.MyStats, user.forecast.ForecastVariables</pre>
|
||
<p class="config_option" id='option_encoding'>encoding</p>
|
||
|
||
<p>
|
||
As Cheetah goes through the template, it substitutes strings for all tag values. This option controls which
|
||
encoding to use for the new strings. The encoding can be chosen on a per file basis. 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 (<i>e.g.</i>, 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" id="option_template">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>, <span
|
||
class="code">MM</span>, <span class="code">WW</span> or <span class="code">DD</span> in its name, these will
|
||
be substituted for the year, month, week and day of 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" id="stale_age">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="note" style="display: inline-block; width: 70%">
|
||
<strong>Note</strong><br/>Precise control over when a <em><a href="usersguide.htm#Reports">report</a></em>
|
||
is run is available through use of the <span class="code">report_timing</span> option in <span class="code">weewx.conf</span>.
|
||
The <span class="code">report_timing</span> option uses a CRON-like setting to control precisely when a
|
||
report is run. See the <em><a href="#customizing_gen_time">Scheduling reports</a></em> section for details
|
||
on the <span class="code">report_timing</span> option.
|
||
</p>
|
||
|
||
<p class="config_option">[[SummaryByDay]]</p>
|
||
|
||
<p>
|
||
The <span class="code">SummaryByDay</span> section defines some special behavior. Each template in this
|
||
section will be used multiple times, each time with a different per-day timespan. Be sure to include <span
|
||
class="code">YYYY</span>, <span class="code">MM</span>, and <span class="code">DD</span> in the filename of
|
||
any template in this section.
|
||
</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>
|
||
|
||
<h2 class="config_section" id="ImageGenerator">[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'>#f5f5f5</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'>#d8d8d8</span>.
|
||
</p>
|
||
|
||
<p class="config_option">chart_gridline_color</p>
|
||
|
||
<p>
|
||
The color of the chart grid lines. Optional. Default is <span class='code'>#a0a0a0</span>
|
||
</p>
|
||
|
||
<div class="image image-right" style="clear: right">
|
||
<div class="image">
|
||
<img src="images/antialias.gif" alt="Effect of anti_alias option"/>
|
||
|
||
<div class="image_caption">
|
||
A GIF showing the same image with <span class="code">anti_alias=1</span>, <span
|
||
class="code">2</span>, and <span class="code">4</span>.
|
||
</div>
|
||
</div>
|
||
<div class="image">
|
||
<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>
|
||
</div>
|
||
<p class="config_option">anti_alias</p>
|
||
|
||
<p>
|
||
Setting to 2 or more might give a sharper image, with fewer jagged edges. Experimentation is in order.
|
||
Default is <span class="code">1</span>.
|
||
</p>
|
||
|
||
<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">#ffffff</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">#f0f0f0</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">#efefef</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 WeeWX 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 WeeWX 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 WeeWX 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="https://docs.python.org/3/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">bottom_label_offset</p>
|
||
|
||
<p>The margin of the bottom label from the bottom of the plot. Default is 3.</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 WeeWX 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="https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior"> strftime format</a>.
|
||
Optional. If not given, a sensible format will be chosen automatically.
|
||
</p>
|
||
|
||
<p class="config_option">x_interval</p>
|
||
|
||
<p>
|
||
The time interval in seconds between x-axis tick marks. Optional. If not given, a suitable default will be
|
||
chosen.
|
||
</p>
|
||
|
||
<p class="config_option">x_label_spacing</p>
|
||
|
||
<p>
|
||
Specifies the ordinal increment between labels on the x-axis: For example, 3 means a label every 3rd tick
|
||
mark. Optional. The default is <span class='code'>2</span>.
|
||
</p>
|
||
|
||
<p class="config_option">y_label_spacing</p>
|
||
|
||
<p>
|
||
Specifies the ordinal increment between labels on the y-axis: For example, 3 means a label every 3rd tick
|
||
mark. Optional. The default is <span class='code'>2</span>.
|
||
</p>
|
||
|
||
<p class="config_option">y_nticks</p>
|
||
|
||
<p>
|
||
The nominal number of ticks along the y-axis. The default is <span class='code'>10</span>.
|
||
</p>
|
||
|
||
<p class="config_option">stale_age</p>
|
||
|
||
<p>
|
||
Image file staleness age, in seconds. If the image file is older than this age it will be generated. If no
|
||
<span class="code">stale_age</span> is specified, then the image file will be generated every time the
|
||
generator runs.
|
||
</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 WeeWX 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. Optional. In the
|
||
case of bar charts, this is the color of the outline of the bar. Default is <span class="code">#0000ff, #00ff00, #ff0000</span>.
|
||
<br/> <br/> Individual line color can be overridden by using option <span class="code">color</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>).
|
||
</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.
|
||
Optional. Default is <span class="code">1, 1, 1</span>. <br/> <br/> Individual line widths can be overridden
|
||
by using option <span class="code">width</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">count</span>, <span
|
||
class="code">cumulative</span>, <span class="code">diff</span>, <span class="code">last</span>, <span
|
||
class="code">max</span>, <span class="code">min</span>, <span class="code">sum</span>, and <span
|
||
class="code">tderiv</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">fill_color</p>
|
||
|
||
<p>
|
||
This option is to override the fill color for a bar chart. Optional. Default is to use the color in <span
|
||
class="code">chart_fill_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 mark 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">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 a 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="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.
|
||
</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">leafTemp1</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">leafWet1</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">soilMoist3</td>
|
||
<td>X</td>
|
||
<td>X</td>
|
||
<td>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">count</td>
|
||
<td>The number of non-null values in the aggregation period.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">diff</td>
|
||
<td>The difference between the last and first value in the aggregation period.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">exists</td>
|
||
<td>Returns <span class="code">True</span> if the observation type exists in the database.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">first</td>
|
||
<td>The first value in the aggregation period.</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">firsttime</td>
|
||
<td>The time of the first value in the aggregation period.
|
||
</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">has_data</td>
|
||
<td>Returns <span class="code">True</span> if the observation type exists in the database and is
|
||
non-null.
|
||
</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</td>
|
||
<td>The maximum value in the aggregation period.</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">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">maxtime</td>
|
||
<td>The time of the maximum value.</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">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">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">min</td>
|
||
<td>The minimum value in the aggregation period.</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">minsum</td>
|
||
<td>The minimum daily sum in the aggregation period. Aggregation period must be one day or longer.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">minsumtime</td>
|
||
<td>The time of the minimum daily sum.</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">min_ge(val)</td>
|
||
<td>The number of days where the minimum 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">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">rms</td>
|
||
<td>The root mean square 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">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">sum_le(val)</td>
|
||
<td>The number of days where the sum of 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">tderiv</td>
|
||
<td>
|
||
The time derivative between the last and first value in the aggregation period. This is the
|
||
difference in value divided by the difference in time.
|
||
</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 code">US</td>
|
||
<td>0x01</td>
|
||
<td>U.S. Customary</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col code">METRICWX</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 code">METRIC</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<br/> cloudbase
|
||
</td>
|
||
<td>foot <br/> meter
|
||
</td>
|
||
<td>foot</td>
|
||
<td>meter</td>
|
||
<td>meter</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_amp</td>
|
||
<td></td>
|
||
<td>amp</td>
|
||
<td>amp</td>
|
||
<td>amp</td>
|
||
<td>amp</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_concentration</td>
|
||
<td>AqPM2_5<br/>AqPM10</td>
|
||
<td>microgram_per_meter_cubed</td>
|
||
<td>microgram_per_meter_cubed</td>
|
||
<td>microgram_per_meter_cubed</td>
|
||
<td>microgram_per_meter_cubed</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_data</td>
|
||
<td></td>
|
||
<td>byte<br/> bit</td>
|
||
<td>byte</td>
|
||
<td>byte</td>
|
||
<td>byte</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_degree_day</td>
|
||
<td>cooldeg<br/> heatdeg<br/> growdeg
|
||
</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_distance</td>
|
||
<td>windrun</td>
|
||
<td>mile<br/>km</td>
|
||
<td>mile</td>
|
||
<td>km</td>
|
||
<td>km</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_energy</td>
|
||
<td></td>
|
||
<td>kilowatt_hour<br/>watt_hour<br/>watt_second</td>
|
||
<td>watt_hour</td>
|
||
<td>watt_hour</td>
|
||
<td>watt_hour</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="first_col">group_energy2</td>
|
||
<td></td>
|
||
<td>kilowatt_hour<br/>watt_hour<br/>watt_second</td>
|
||
<td>watt_second</td>
|
||
<td>watt_second</td>
|
||
<td>watt_second</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_length</td>
|
||
<td></td>
|
||
<td>inch<br/> cm
|
||
</td>
|
||
<td>inch</td>
|
||
<td>cm</td>
|
||
<td>cm</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_power</td>
|
||
<td></td>
|
||
<td>kilowatt<br/>watt</td>
|
||
<td>watt</td>
|
||
<td>watt</td>
|
||
<td>watt</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>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>appTemp <br/> dewpoint <br/> extraTemp1 <br/> extraTemp2 <br/> extraTemp3 <br/> heatindex <br/>
|
||
heatingTemp <br/> humidex <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_volume</td>
|
||
<td></td>
|
||
<td>cubic_foot<br/> gallon<br/> litre
|
||
</td>
|
||
<td>gallon</td>
|
||
<td>litre</td>
|
||
<td>litre</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>
|
||
|
||
</div>
|
||
<!-- end id technical_content -->
|
||
|
||
<div class="footer">
|
||
<p class="copyright">
|
||
© <a href="copyright.htm">Copyright</a> Tom Keffer
|
||
</p>
|
||
</div>
|
||
|
||
</div>
|
||
<!-- end class main -->
|
||
|
||
</body>
|
||
</html>
|