mirror of
https://github.com/weewx/weewx.git
synced 2026-06-09 09:35:19 -04:00
1023 lines
56 KiB
HTML
1023 lines
56 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
<!-- $Revision$ -->
|
|
<!-- $Author$ -->
|
|
<!-- $Date$ -->
|
|
<head>
|
|
<meta http-equiv="Content-Language" content="en-us" />
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>Customizing weewx</title>
|
|
<style type="text/css">
|
|
body {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
p {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
ol {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
ul {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
li {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
dl {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
dt {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
dd {
|
|
font: 11pt Verdana,arial,sans-serif;
|
|
color: black;
|
|
}
|
|
h1 {
|
|
font: normal normal bold xx-large Verdana, arial, sans-serif;
|
|
color: #FFFFFF;
|
|
border: 1px solid black;
|
|
border-bottom: 2px solid black;
|
|
border-right: 2px solid black;
|
|
background-color: #008080;
|
|
padding-left: .5em;
|
|
padding-right: .5em;
|
|
margin-top: 60pt;
|
|
border-right-width: medium;
|
|
border-bottom-width: medium;
|
|
}
|
|
h2 {
|
|
font: x-large Verdana, arial, sans-serif;
|
|
color: teal;
|
|
border: 1px solid black;
|
|
background-color: #e8e8e8;
|
|
padding-left: .5em;
|
|
padding-right: .5em;
|
|
margin-top: 30pt;
|
|
}
|
|
h3 {
|
|
font: medium Verdana, arial, sans-serif;
|
|
color: teal;
|
|
border: 1px solid black;
|
|
background-color: #e8e8e8;
|
|
padding-left: .5em;
|
|
padding-right: .5em;
|
|
}
|
|
h4 {
|
|
font: medium Verdana, arial, sans-serif;
|
|
color: black;
|
|
font-weight: bold;
|
|
}
|
|
.code {
|
|
font-family: "Courier New", Courier, monospace;
|
|
}
|
|
table {
|
|
border-style: solid;
|
|
border-width: 1px;
|
|
border-collapse: collapse;
|
|
}
|
|
td {
|
|
border-style: solid;
|
|
border-width: 1px;
|
|
}
|
|
.indent {
|
|
margin-left: 40px;
|
|
}
|
|
.tty {
|
|
font-family: "Courier New", Courier, monospace;
|
|
margin-left: 40px;
|
|
margin-top: 0px;
|
|
margin-bottom: 0px;
|
|
background-color: #FFFFCC;
|
|
}
|
|
.title {
|
|
text-align: center;
|
|
margin-top: 0px;
|
|
}
|
|
.config_option {
|
|
font-family: "Courier New", Courier, monospace;
|
|
font-weight: normal;
|
|
}
|
|
.config_section {
|
|
font-family: "Courier New", Courier, monospace;
|
|
}
|
|
.config_important {
|
|
font-family: "Courier New", Courier, monospace;
|
|
font-weight: bold;
|
|
color: #0000FF;
|
|
}
|
|
.bold_n_blue {
|
|
color: #0000FF;
|
|
}
|
|
.xxsmall {
|
|
font-size: xx-small;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1 class="title">Customizing weewx v1.6</h1>
|
|
<h1>Table of Contents</h1>
|
|
<ol>
|
|
<li>Overview</li>
|
|
</ol>
|
|
<h1>Introduction</h1>
|
|
<p>This document covers the customization of weewx. </p>
|
|
<p>For users who are only interested in customizing the generated reports,
|
|
modifying the options in the Standard skin configuration file skin.conf will give you all
|
|
the flexibility you need. You can easily add new plot images, change the titles
|
|
of images, change the units used in the reports, and so on, just by changing
|
|
options in this file. If this is your goal, skip the sections on the run-time
|
|
internals and just peruse the section on skin.conf.</p>
|
|
<p>However, if your goal is a specialized application such as adding alarms, RSS
|
|
feeds, etc., then it would be worth your while to read about the internal
|
|
architecture and how to customize it. </p>
|
|
<h2>Overview of the weewx architecture</h2>
|
|
<p>At a high-level, <span class="code">weewx</span> consists of an engine class called
|
|
<span class="code">StdEngine</span>. It is
|
|
responsible for loading any "<em>services</em>" that are to be run and arranging for them
|
|
to be called when key events occur, such as the arrival of LOOP data. The default install of <span class="code">weewx</span> includes the following services:</p>
|
|
<table style="width: 60%" align="center">
|
|
<tr>
|
|
<td><strong>Service</strong></td>
|
|
<td><strong>Function</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdWunderground</span></td>
|
|
<td>Starts thread to manage WU connection; adds new data to a Queue to
|
|
be posted to the WU by the thread.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdCatchUp</span></td>
|
|
<td>Any data found on the weather station memory but not yet in the
|
|
archive, is retrieved and put in the archive.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdTimeSynch</span></td>
|
|
<td>Arranges to have the clock on the station synchronized at regular
|
|
intervals.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdPrint</span></td>
|
|
<td>Prints out new LOOP and archive packets on the console.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdProcess</span></td>
|
|
<td>Launches a new thread to do processing after a new archive record
|
|
arrives. The thread loads zero or more reports and processes them in
|
|
order. Reports do things such as generate HTML files, generate images,
|
|
or FTP files to a web server. New reports can be added easily by the
|
|
user.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>It is easy to extend old services or to add new ones. The source distribution includes an example
|
|
new service called "<span class="code">MyAlarm</span>," which sends an email
|
|
when an arbitrary expression evaluates <span class="code">True</span>. It is
|
|
also possible to extend the internal engine. These advanced topics are covered
|
|
later in section XX.</p>
|
|
<h3>Reports</h3>
|
|
<p>For the moment, we focus on the last service, <span class="code">weewx.wxengine.StdProcess</span>, the
|
|
standard service for creating reports. This will be what most users want to
|
|
customize even if it means just changing a few options.</p>
|
|
<p>This service runs zero or more <em>
|
|
Reports</em>, each using one or more <em>Generators</em>. A generator does
|
|
things such as generate HTML from a template, create plot images from the data
|
|
file, or upload data to a webserver via FTP. The default install of weewx
|
|
includes the following generators:</p>
|
|
<table style="width: 60%" align="center" >
|
|
<tr>
|
|
<td>Generator</td>
|
|
<td><strong>Function</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="code">weewx.reportengine.FileGenerator</td>
|
|
<td>Generates HTML files from templates. </td>
|
|
</tr>
|
|
<tr>
|
|
<td class="code">weewx.reportengine.ImageGenerator</td>
|
|
<td>Generates image plots</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.reportengine.Ftp</span></td>
|
|
<td>FTP uploads data</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.reportengine.Copy</span></td>
|
|
<td>Copies files locally.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>A 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>, skin.conf. 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 customizing or
|
|
overriding the skin configuration file skin.conf.
|
|
</p>
|
|
<p>Note that the Ftp and Copy "Reports" are a kind of funny report in that they
|
|
don't actually generate anything to do with the presentation layer. Instead,
|
|
they make use of the same reporting machinery, but use it to move files around.
|
|
They fit nicely into the report architecture, insuring that they can be well
|
|
integrated with the generation of the actual presentation.
|
|
</p>
|
|
<p>The out-of-the-box weewx configuration file weewx.conf has been set up to run
|
|
two reports, the first called StandardReport, and the second called FTP.
|
|
StandardReport runs against a skin called Standard, which is included in the
|
|
distribution. FTP runs against a "skin" (note the quotes) called Ftp, also
|
|
included. Each has its own configuration file, skin.conf. While it is unlikely
|
|
you will need to change the Ftp skin configuration file, you very much will want
|
|
to look at modifying the Standard skin configuration file.</p>
|
|
<h1>The Standard skin configuration file</h1>
|
|
<p>This section is a reference to the options appearing in the Standard skin configuration file, found in <span class="code"><em>$WEEWX_ROOT</em>/skins/Standard/skin.conf</span>.</p>
|
|
<p>It is worth noting that, like the main configuration file <span class="code">
|
|
weewx.conf</span>, UTF-8 is used throughout.</p>
|
|
<h3>Root options</h3>
|
|
<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 order.</p>
|
|
<p class="config_option">singleton_list</p>
|
|
<p>Similar to generator_list, except the generators in this list get run only
|
|
once, the first time the report engine service is started. It is useful for
|
|
doing one-time chores, such as copying files to the destination directory or
|
|
initializing some service.<br />
|
|
</p>
|
|
<h2 class="config_section">[Units]</h2>
|
|
<p>This section deals with Units and their formatting. </p>
|
|
<h3 class="config_section">[[Groups]]</h3>
|
|
<p>This subsection lists all the <em>Unit Groups</em> and specifies which unit
|
|
system is to be used for each one of them. </p>
|
|
<p>As there are many different observational measurement types (such as '<span class="code">outTemp</span>',
|
|
'<span class="code">barometer</span>', etc.) used in <span class="code">weewx</span>
|
|
(more than 50 at last count), it would be tedious, not to say possibly
|
|
inconsistent, to specify a different measurement system for each one of them. At
|
|
the other extreme, requiring all of them to be "U.S. Customary" or "Metric" seems
|
|
overly restrictive. <span class="code">Weewx</span> has taken a middle route and
|
|
divided all the different observation types into 12 different "unit groups." 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">degrees_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">foot</span>" or "<span class="code">inch_per_hour</span>",
|
|
not "<span class="code">feet</span>" or "<span class="code">inches_per_hour</span>." See section <a href="#Units">Units</a> for more information, including a concise
|
|
summary of the groups, their members, and which options can be used for each
|
|
group.</p>
|
|
<h4 class="config_important"><a name="group_altitude">group_altitude</a></h4>
|
|
<p>Which measurement unit to be used for altitude. Possible options
|
|
are '<span class="code">foot</span>' or
|
|
'<span class="code">meter</span>'.</p>
|
|
<h4 class="config_option">group_direction</h4>
|
|
<p>Which measurement unit to be used for direction. The only option is
|
|
"<span class="code">degree_compass</span>".</p>
|
|
<h4 class="config_option">group_moisture</h4>
|
|
<p>The measurement unit to be used for soil moisture. The only option
|
|
is "<span class="code">centibar</span>."</p>
|
|
<h4 class="config_option">group_percent</h4>
|
|
<p>The measurement unit to be used for percentages. The only option is
|
|
"<span class="code">percent</span>".</p>
|
|
<h4 class="config_important">group_pressure</h4>
|
|
<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>
|
|
<h4 class="config_option">group_radiation</h4>
|
|
<p>The measurement unit to be used for radiation. The only option is
|
|
"<span class="code">watt_per_meter_squared</span>."</p>
|
|
<h4 class="config_important">group_rain</h4>
|
|
<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>
|
|
|
|
<h4 class="config_important">group_rainrate</h4>
|
|
<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>
|
|
|
|
<h4 class="config_important">group_speed</h4>
|
|
<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>
|
|
<h4 class="config_important">group_speed2</h4>
|
|
<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 of "<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>
|
|
<h4 class="config_important"><a name="group_temperature">group_temperature</a></h4>
|
|
<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>
|
|
<h4 class="config_option">group_volt</h4>
|
|
<p>The measurement unit to be used for voltages. The only option is "<span class="code">volt</span>."</p>
|
|
<h3 class="config_section"><a name="Units_StringFormats">[[StringFormats]]</a></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>
|
|
<p class="tty">degree_C = %.1f</p>
|
|
<p class="tty">inch = %.2f</p>
|
|
<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>
|
|
<h3 class="config_section">[[Labels]]</h3>
|
|
<p>This subsection specifies what label is to be used for each measurement unit
|
|
type. For example, the options</p>
|
|
<p class="tty">degree_F = °F</p>
|
|
<p class="tty">inch = ' in'</p>
|
|
<p>would cause all temperatures to have unit labels '<span class="code">°F</span>'
|
|
and all precipitation to have labels '<span class="code"> in</span>'. If any
|
|
special symbols are to be used (such as the degree sign above) they should be
|
|
encoded in UTF-8. (This is generally what most text editors use if you
|
|
cut-and-paste from a character map.)</p>
|
|
<h2 class="config_section">[Files]</h2>
|
|
<p>This section controls text generation from templates, specifically which
|
|
files are to be produced from which template.</p>
|
|
<h3>Overview of file generation</h3>
|
|
<p>Customization of file generation consists of playing with the various options offered below and,
|
|
failing that, modifying the template files that come with the distribution.</p>
|
|
<p>Each template file is named something like <span class="code"><em>D/F.E.tmpl</em></span>,
|
|
where <span class="code">D</span> is the subdirectory the template sits in
|
|
and will also be the subdirectory the results will be put in, and
|
|
<span class="code">F.E</span> is the generated file name. So, given a template
|
|
file with name <span class="code">Acme/index.html.tmpl</span>, the results will
|
|
be put in <span class="code"><em>$HTML_ROOT</em>/Acme/index.html</span>.</p>
|
|
<p>The skin that comes with the standard distribution of <span class="code">weewx</span> contains three
|
|
different kinds of generated output:</p>
|
|
<ol>
|
|
<li>Summary by month. In addition to the naming rules above, if the template
|
|
file has the letters <span class="code">YYYY</span> and <span class="code">
|
|
MM</span> in its name, these will be substituted for the year and month,
|
|
respectively. The default distribution has been set up to produce NOAA
|
|
monthly summaries, one for each month, as a simple text file (no HTML). </li>
|
|
<li>Summary by year. In addition to the naming rules above, if the
|
|
template file has the letters <span class="code">YYYY</span> in its name,
|
|
the year will be substituted. The default distribution has been set up to
|
|
produce NOAA yearly summaries, one for each year, as a simple text file (no
|
|
HTML). </li>
|
|
<li>Summary "To Date". The default distribution has been set up to produce reports for the day,
|
|
week, month, and year-to-date observations. These four files are all HTML
|
|
files. The first, the daily summary (output file index.html), includes a
|
|
drop-down list that allows the NOAA month and yearly summaries to be
|
|
displayed.</li>
|
|
</ol>
|
|
<h3>Root options</h3>
|
|
<h4 class="config_option">encoding</h4>
|
|
<p>This option controls which encoding is to be used for the generated output.
|
|
There are 3 possible choices:</p>
|
|
<table style="width: 60%" align="center" >
|
|
<tr>
|
|
<td><strong>Encoding</strong></td>
|
|
<td><strong>Comments</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="code">html_entities</td>
|
|
<td>Non 7-bit characters will be represented as HTML entities (<em>e.g.</em>
|
|
the degree sign will be represented as <span class="code">&#176;</span>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="code">utf8</td>
|
|
<td>Non 7-bit characters will be represented in UTF-8.</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="code">strict_ascii</td>
|
|
<td>Non 7-bit characters will be ignored</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>By default, the encoding <span class="code">html_entities</span> is used for
|
|
HTML files, <span class="code">strict_ascii</span> for the NOAA template files.
|
|
</p>
|
|
<h3>[[SummaryByMonth]]</h3>
|
|
<p>This section controls how summaries-by-month are generated. The default
|
|
configuration generates NOAA-by-month summaries. </p>
|
|
<h3>[[SummaryByYear]]</h3>
|
|
<p>This section controls how summaries-by-year are generated. The default
|
|
configuration generates NOAA-by-year summaries. </p>
|
|
<h3>[[ToDate]]</h3>
|
|
<p>This section controls how observations-to-date are generated. The default
|
|
configuration generates four files, one for day, week, month, and year-to-date.</p>
|
|
<h3>[[Copy]]</h3>
|
|
<p>This section controls which files are to be copied over from the skin
|
|
subdirectory 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>
|
|
<h2 class="config_section">[Images]</h2>
|
|
<p>This section, which controls which images (plots) get generated and with which
|
|
options, is by far the most complicated. However, it is extremely flexible and powerful.</p>
|
|
<h3>Time periods</h3>
|
|
<p>The section consists of one or more sub-sections, one for each time period (day, week,
|
|
month, and year). These sub-sections define the nature of aggregation and plot types
|
|
for the time period. For example, here's a typical set of options for sub-section
|
|
<span class="code">[[month_images]]</span>, controlling how images that cover a
|
|
month period are generated:</p>
|
|
<p class="tty">[[month_images]]</p>
|
|
<p class="tty"> x_label_format = %d</p>
|
|
<p class="tty"> bottom_label_format = %m/%d/%y %H:%M</p>
|
|
<p class="tty"> time_length = 2592000 # == 30 days</p>
|
|
<p class="tty"> aggregate_type = avg</p>
|
|
<p class="tty"> aggregate_interval = 10800 # == 3 hours</p>
|
|
<p>The option <span class="code">x_label_format</span> gives a
|
|
<a href="http://docs.python.org/library/datetime.html#strftime-behavior">strftime()</a>
|
|
type format for the x-axis. In this example, it will only show days (format option
|
|
"<span class="code">%d</span>"). The <span class="code">bottom_label_format</span>
|
|
is the format used to time stamp the image at the bottom. In this example, it will
|
|
show the time as <span class="code">10/25/09 15:35</span>. A plot will cover a nominal
|
|
30 days, and all items included in it will use an aggregate type of averaging over
|
|
3 hours. </p>
|
|
<h3>Image files</h3>
|
|
<p>Within each sub-section is another nesting, one for each image to be generated.
|
|
The title of each sub-sub-section is the filename to be used for the image.
|
|
Finally, at one additional nesting level (!) are the logical names of all the
|
|
line types to be drawn in the image. Values specified in the
|
|
level above can be overridden. For example, here's a typical set of options for
|
|
sub-sub-section <span class="code">[[[monthrain]]]</span>: </p>
|
|
<p class="tty">[[[monthrain]]]</p>
|
|
<p class="tty"> plot_type = bar</p>
|
|
<p class="tty"> yscale = None, None, 0.02</p>
|
|
<p class="tty"> [[[[rain]]]]</p>
|
|
<p class="tty"> aggregate_type = sum</p>
|
|
<p class="tty"> aggregate_interval = 86400</p>
|
|
<p class="tty"> label = Rain (daily avg)</p>
|
|
<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. It 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">ymin</span> and <span class="code">ymax</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, we are letting
|
|
<span class="code">weewx</span> pick sensible y minimum and maximum values, but
|
|
we are requiring 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 haven't said
|
|
otherwise, the SQL data type to be used for this line will be the same as its
|
|
logical name, that is, <span class="code">rain</span>, but this can be
|
|
overridden (see below). The aggregation type will be summing (overriding
|
|
the averaging specified in sub-section <span class="code">[[month_images]]</span>),
|
|
so you get the total rain over the aggregate period (rather than the average) over
|
|
an aggregation interval of 86,400 seconds (one day). The plot line will be titled
|
|
with the indicated label ('<span class="code">Rain (daily avg)</span>')</p>
|
|
<h3>Including more than one SQL type in a plot</h3>
|
|
<p>More than one SQL type can be included in a plot. For example, here's how to
|
|
generate a plot with the week's outside temperature as well as dewpoint:</p>
|
|
<p class="tty">[[[monthtempdew]]]</p>
|
|
<p class="tty"> [[[[outTemp]]]]</p>
|
|
<p class="tty"> [[[[dewpoint]]]]</p>
|
|
<p>This would create an image in file <span class="code">monthtempdew.png</span>
|
|
that includes a line plot of both outside temperature and dewpoint.</p>
|
|
<h3>Including the same SQL type more than once in a plot</h3>
|
|
<p>Another example. Say you want a plot of the day'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>
|
|
<p class="tty">## WRONG ##</p>
|
|
<p class="tty">[[[daytemp_with_avg]]]</p>
|
|
<p class="tty"> [[[[outTemp]]]]</p>
|
|
<p class="tty"> aggregate_type = avg</p>
|
|
<p class="tty"> aggregate_interval = 3600</p>
|
|
<p class="tty"> [[[[outTemp]]]] # OOPS! The same section name appears more than
|
|
once!</p>
|
|
<p>The option parser does not allow the same section name ('<span class="code">outTemp</span>'
|
|
in this case) to appear more than once at a given level in the configuration
|
|
file, so an error will be declared (technical reason: formally, the sections are
|
|
an unordered dictionary). If you wish for the same SQL type to appear more than
|
|
once in a plot then there is a trick you must know: use option
|
|
<span class="code">data_type</span>. This will override the default action that
|
|
the logical line name is used for the SQL type. So, our example would look like
|
|
this:</p>
|
|
<p class="tty">[[[daytemp_with_avg]]]</p>
|
|
<p class="tty"> [[[[a_logical_name]]]]</p>
|
|
<p class="tty"> data_type = outTemp</p>
|
|
<p class="tty"> aggregate_type = avg</p>
|
|
<p class="tty"> aggregate_interval = 3600</p>
|
|
<p class="tty"> [[[[outTemp]]]]</p>
|
|
<p>Here, the first logical line has been given the name "<span class="code">a_logical_name</span>"
|
|
to distinguish it from the second line "<span class="code">outTemp</span>". We
|
|
have specified that the first line will use data type <span class="code">outTemp</span>
|
|
and that it will use averaging over a one hour period. The second also uses
|
|
<span class="code">outTemp</span>, but will not use averaging.</p>
|
|
<p>The result is a nice plot of the day's temperature, overlaid with a 3-hour
|
|
smoothed average.</p>
|
|
<h3>Progressive vector plots</h3>
|
|
<p><span class="code">Weewx</span> can produce progressive vector plots as well as the more conventional
|
|
x-y plots. To produce these, use plot type '<span class="code">vector</span>'.
|
|
You need a vector type to produce this kind of plot. There are two: '<span class="code">windvec</span>',
|
|
and '<span class="code">windgustvec</span>'. While they don't actually appear in
|
|
the SQL database, <span class="code">weewx</span> understands that they represent special vector-types.
|
|
The first, '<span class="code">windvec</span>', represents the average wind in
|
|
an archive period, the second, '<span class="code">windgustvec</span>' the max
|
|
wind in an archive period. Here's how to produce a progressive vector plot of
|
|
the year's biggest daily wind gusts, along with daily averages:</p>
|
|
<p class="tty">[[[yeargustoverlay]]]</p>
|
|
<p class="tty"> aggregate_interval = 86400</p>
|
|
<p class="tty"> [[[[windvec]]]]</p>
|
|
<p class="tty"> plot_type = vector</p>
|
|
<p class="tty"> aggregate_type = avg</p>
|
|
<p class="tty"> [[[[windgustvec]]]]</p>
|
|
<p class="tty"> plot_type = vector</p>
|
|
<p class="tty"> aggregate_type = max</p>
|
|
<p>This will produce an image file with name <span class="code">
|
|
yeargustoverlay.png</span>. It will consist of two progressive vector plots,
|
|
both using daily aggregation (86,400 seconds). For the first set of vectors, the daily
|
|
average will be used. In the second, the max of the gusts will be used.</p>
|
|
<p>By default, the sticks in the progressive wind plots point towards the wind
|
|
source. That is, the stick for a wind from the west will point left. If you have
|
|
a chronic wind direction (as I do), you may want to rotate the default direction
|
|
so that all the vectors don't line up over the x-axis, overlaying each other. Do
|
|
this by using option <span class="code">vector_rotate</span>. For example, with
|
|
my chronic westerlies, I set <span class="code">vector_rotate</span> to 90.0, so
|
|
winds out of the west point straight up. </p>
|
|
<p>If you use this kind of plot (the out-of-the-box version of
|
|
<span class="code">weewx</span> includes daily, weekly, monthly, and yearly
|
|
progressive wind plots), a small compass rose will be put in the lower-left
|
|
corner of the image to show the orientation of North.</p>
|
|
<h3>Overriding values</h3>
|
|
<p>Remember that values at any level can override values specified at a higher
|
|
level. For example, say you want to generate the standard plots, but for a few
|
|
key observation types such as barometer, you want to also generate some
|
|
oversized plots to give you extra detail, perhaps for an HTML popup. The
|
|
standard <span class="code">weewx.conf</span> file specifies plot size of
|
|
300x180 pixels, which will be used for all plots unless overridden:</p>
|
|
<p class="tty">[Images]</p>
|
|
<p class="tty"> ...</p>
|
|
<p class="tty"> image_width=300</p>
|
|
<p class="tty"> image_height = 180</p>
|
|
<p>The standard plot of barometric pressure will appear in <span class="code">
|
|
daybarometer.png</span>:</p>
|
|
<p class="tty"> [[[daybarometer]]]</p>
|
|
<p class="tty"> [[[[barometer]]]] </p>
|
|
<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>
|
|
<p class="tty"> [[[daybarometer_big]]]</p>
|
|
<p class="tty"> image_width = 600</p>
|
|
<p class="tty"> image_height = 360</p>
|
|
<p class="tty"> [[[[barometer]]]]</p>
|
|
<h3>Summary</h3>
|
|
<p>Studying this section in the shipped version of <span class="code">weewx.conf</span>
|
|
will give you ideas about the many different image plot configurations that are
|
|
possible without hacking the code. </p>
|
|
<h2>[Labels]</h2>
|
|
<p>This section controls what label to use for each type of measurement unit. It is generally
|
|
used in plot generation, although there are a few other areas where it is used. It consists of
|
|
two sub-sections:</p>
|
|
<h4 class="config_option">[[Generic]]</h4>
|
|
<p>This sub-sections specifies default labels to be used for each SQL type. For
|
|
example, options</p>
|
|
<p class="tty">inTemp = Inside Temperature</p>
|
|
<p class="tty">outTemp = Outside Temperature</p>
|
|
<p>would cause the given labels to be used for plots involving SQL types
|
|
<span class="code">inTemp </span>and <span class="code">outTemp</span>..</p>
|
|
<h4 class="config_option">[[<a name="Units_StringFormats1">UnitLabels]]</a></h4>
|
|
<p>This sub-section specifies what label to be used for each measurement unit
|
|
type. For example, the options</p>
|
|
<p class="tty">degree_F = \xb0F</p>
|
|
<p class="tty">inch = ' in'</p>
|
|
<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>'. (NB: the code
|
|
<span class="code">\xb0</span> is the hexadecimal value <span class="code">b0</span>,
|
|
which in many encodings encodes the degree sign.)</p>
|
|
<h3 class="config_section">[HTML]</h3>
|
|
<p>Section [HTML] has two options and two sub-sections. For additional information
|
|
on HTML generation <a href="#HTML_Generation">see the section below</a>.</p>
|
|
<h4 class="config_option">template_root</h4>
|
|
<p>This option specifies the directory, relative to <span class="code"><em>WEEWX_ROOT</em></span>,
|
|
where the HTML templates can be found. Required. No default.</p>
|
|
<h4 class="config_option">html_root</h4>
|
|
<p>This option specifies the directory, relative to <span class="code"><em>WEEWX_ROOT</em></span>,
|
|
where the generated HTML files should be put. Required. No default.</p>
|
|
<h4 class="config_option"><a name="HTML_UnitLabels">[[UnitLabels]]</a></h4>
|
|
<p>This subsection is similar to its eponymous counterpart in section
|
|
<span class="code">[Labels]</span> above, except it is used for HTML generation.
|
|
It is useful to have a separate section because HTML uses special 'entity' codes
|
|
to code special characters, such as the degree sign. For example, the options</p>
|
|
<p class="tty">degree_F = &deg;F</p>
|
|
<p class="tty">inch = ' in'</p>
|
|
<p>would cause outside temperature and rain to have unit labels '<span class="code">°F</span>'
|
|
and '<span class="code"> in</span>', respectively.</p>
|
|
<h4 class="config_option"><a name="HTML_Time">[[Time]]</a></h4>
|
|
<p>This subsection is used for time labels in HTML generation. It uses
|
|
<a href="http://docs.python.org/library/datetime.html#strftime-behavior">strftime()</a>
|
|
formats. For example</p>
|
|
<p class="tty">week = %H:%M on %A</p>
|
|
<p class="tty">month = %d-%b-%Y %H:%M</p>
|
|
<p>would specify that week data should use a format such as "<span class="code">15:20
|
|
on Sunday</span>", while month data should look like "<span class="code">06-Oct-2009
|
|
15:20</span>"</p>
|
|
<p> </p>
|
|
<h1>Customizing the weewx service engine</h1>
|
|
<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 with a
|
|
set of member functions. The engine arranges to have appropriate member
|
|
functions called when specific events happen. For example, when a new LOOP
|
|
packet arrives, member function <span class="code">processLoopPacket()</span> of
|
|
all services is called.</p>
|
|
<p>To customize, you can</p>
|
|
<ul>
|
|
<li>Customize a service</li>
|
|
<li>Add a service</li>
|
|
<li>Customize the engine</li>
|
|
</ul>
|
|
<p>This document describes how to do all three.</p>
|
|
<p>The default install of <span class="code">weewx</span> includes the following services:</p>
|
|
<table style="width: 100%">
|
|
<tr>
|
|
<td><strong>Service</strong></td>
|
|
<td><strong>Function</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdWunderground</span></td>
|
|
<td>Starts thread to manage WU connection; adds new data to a Queue to
|
|
be posted to the WU by the thread.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdCatchUp</span></td>
|
|
<td>Any data found on the weather station memory but not yet in the
|
|
archive, is retrieved and put in the archive.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdTimeSynch</span></td>
|
|
<td>Arranges to have the clock on the station synchronized at regular
|
|
intervals.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdPrint</span></td>
|
|
<td>Prints out new LOOP and archive packets on the console.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="code">weewx.wxengine.StdProcess</span></td>
|
|
<td>Launches a new thread to do processing after a new archive record
|
|
arrives. The thread loads zero or more reports and processes them in
|
|
order. Reports do things such as generate HTML files, generate images,
|
|
or FTP files to a web server. New reports can be added easily by the
|
|
user.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h2>Customizing a Service</h2>
|
|
<p>The service <span class="code">weewx.wxengine.StdPrint</span> prints out new LOOP and archive packets
|
|
to the console when they arrive. By default, it prints out time, barometer,
|
|
outside temperature, wind speed, and wind direction. Suppose you don't like
|
|
this, and want to print out humidity as well when a new LOOP packet arrives, but
|
|
leave the printing of archive packets alone. This could be done by subclassing the default
|
|
print service <span class="code">StdPrint</span> and overriding member function <span class="code">
|
|
processLoopPacket()</span>. </p>
|
|
<p>In file <span class="code">myprint.py</span>:</p>
|
|
<p class="tty">from weewx.wxengine import StdPrint<br />
|
|
from weeutil.weeutil import timestamp_to_string<br />
|
|
<br />
|
|
class MyPrint(StdPrint):<br />
|
|
<br />
|
|
# Override the default processLoopPacket:<br />
|
|
def processLoopPacket(self, physicalPacket):<br />
|
|
print "LOOP: ", timestamp_to_string(physicalPacket['dateTime']),\<br />
|
|
|
|
physicalPacket['barometer'],\<br />
|
|
|
|
physicalPacket['outTemp'],\<br />
|
|
|
|
physicalPacket['outHumidity'],\<br />
|
|
|
|
physicalPacket['windSpeed'],\<br />
|
|
|
|
physicalPacket['windDir']</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 the standard print service name in the
|
|
option <span class="code">service_list</span>, located in <span class="code">
|
|
[Engines][[WxEngine]]</span>:</p>
|
|
<p class="tty">[Engines]<br />
|
|
[[WxEngine]]<br />
|
|
|
|
service_list = weewx.wxengine.StdWunderground, weewx.wxengine.StdCatchUp,<br />
|
|
weewx.wxengine.StdTimeSynch, myprint.MyPrint,<br />
|
|
weewx.wxengine.StdProcess</p>
|
|
<p>(Note that this list is shown on several lines for clarity, but in actuality
|
|
it 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>
|
|
<h2>Adding a Service</h2>
|
|
<p>Suppose there is no service that can easily be 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's an example that implements an alarm that sends off an email
|
|
when an arbitrary expression evaluates True. This example is included in the standard
|
|
distribution in subdirectory '<span class="code">examples</span>.'</p>
|
|
<p>File <span class="code">examples/alarm.py</span>:</p>
|
|
<p class="tty">import time<br />
|
|
import smtplib<br />
|
|
from email.mime.text import MIMEText<br />
|
|
import threading<br />
|
|
import syslog<br />
|
|
<br />
|
|
from weewx.wxengine import StdService<br />
|
|
from weeutil.weeutil import timestamp_to_string<br />
|
|
<br />
|
|
# Inherit from the base class StdService:<br />
|
|
class MyAlarm(StdService):<br />
|
|
"""Custom service that sounds an alarm if an expression
|
|
evaluates true"""<br />
|
|
<br />
|
|
def __init__(self, engine):<br />
|
|
# Pass the initialization information
|
|
on to my superclass:<br />
|
|
StdService.__init__(self, engine)<br />
|
|
<br />
|
|
# This will hold the time when the
|
|
last alarm message went out:<br />
|
|
self.last_msg = None<br />
|
|
self.expression = None<br />
|
|
<br />
|
|
def setup(self):<br />
|
|
try:<br />
|
|
# Dig the
|
|
needed options out of the configuration dictionary.<br />
|
|
# If a
|
|
critical option is missing, an exception will be thrown and<br />
|
|
# the alarm
|
|
will not be set.<br />
|
|
|
|
self.expression = self.engine.config_dict['Alarm']['expression']<br />
|
|
|
|
self.time_wait = int(self.engine.config_dict['Alarm'].get('time_wait', '3600'))<br />
|
|
|
|
self.smtp_host = self.engine.config_dict['Alarm']['smtp_host']<br />
|
|
|
|
self.smtp_user = self.engine.config_dict['Alarm'].get('smtp_user')<br />
|
|
|
|
self.smtp_password = self.engine.config_dict['Alarm'].get('smtp_password')<br />
|
|
self.TO =
|
|
self.engine.config_dict['Alarm']['mailto']<br />
|
|
syslog.syslog(syslog.LOG_INFO,
|
|
"alarm: Alarm set for expression %s" % self.expression)<br />
|
|
except:<br />
|
|
|
|
self.expression = None<br />
|
|
|
|
self.time_wait = None<br />
|
|
<br />
|
|
def postArchiveData(self, rec):<br />
|
|
# Let the super class see the record
|
|
first:<br />
|
|
StdService.postArchiveData(self, rec)<br />
|
|
<br />
|
|
# See if the alarm has been set:<br />
|
|
if self.expression:<br />
|
|
# To avoid a
|
|
flood of nearly identical emails, this will do<br />
|
|
# the check
|
|
only if we have never sent an email, or if we haven't<br />
|
|
# sent one in
|
|
the last self.time_wait seconds:<br />
|
|
if not
|
|
self.last_msg or abs(time.time() - self.last_msg) >= self.time_wait :<br />
|
|
<br />
|
|
|
|
# Evaluate the expression in the context of 'rec'.<br />
|
|
|
|
# Sound the alarm if it evaluates true:<br />
|
|
|
|
if eval(self.expression, None, rec): #
|
|
NOTE 1<br />
|
|
|
|
# Sound the alarm!<br />
|
|
|
|
# Launch in a separate thread so it doesn't block the main LOOP thread:<br />
|
|
|
|
t = threading.Thread(target = MyAlarm.soundTheAlarm, args=(self, rec))<br />
|
|
|
|
t.start()<br />
|
|
<br />
|
|
def soundTheAlarm(self, rec):<br />
|
|
"""This function is called when the
|
|
given expression evaluates True."""<br />
|
|
<br />
|
|
# Get the time and convert to a
|
|
string:<br />
|
|
t_str = timestamp_to_string(rec['dateTime'])<br />
|
|
# Form the message text:<br />
|
|
msg_text = "Alarm expression %s
|
|
evaluated True at %s\nRecord:\n%s" % (self.expression, t_str, str(rec))<br />
|
|
# Convert to MIME:<br />
|
|
msg = MIMEText(msg_text)<br />
|
|
<br />
|
|
# Fill in MIME headers:<br />
|
|
msg['Subject'] = "Alarm message from
|
|
weewx"<br />
|
|
msg['From'] = "weewx"<br />
|
|
msg['To'] = self.TO<br />
|
|
<br />
|
|
# Create an instance of class SMTP
|
|
for the given SMTP host:<br />
|
|
s = smtplib.SMTP(self.smtp_host)<br />
|
|
# If a username has been given,
|
|
assume that login is required for this host:<br />
|
|
if self.smtp_user:<br />
|
|
s.login(self.smtp_user,
|
|
self.smtp_password)<br />
|
|
# Send the email:<br />
|
|
s.sendmail(msg['From'], [self.TO],
|
|
msg.as_string())<br />
|
|
# Log out of the server:<br />
|
|
s.quit()<br />
|
|
# Record when the message went out:<br />
|
|
self.last_msg = time.time()<br />
|
|
# Log it in the system log:<br />
|
|
syslog.syslog(syslog.LOG_INFO,
|
|
"alarm: Alarm sounded for expression %s" % self.expression)<br />
|
|
syslog.syslog(syslog.LOG_INFO, " ***
|
|
email sent to: %s" % self.TO)</p>
|
|
<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>
|
|
<p class="tty">[Alarm]<br />
|
|
expression = "outTemp < 40.0"<br />
|
|
time_wait = 1800<br />
|
|
smtp_host = smtp.mymailserver.com<br />
|
|
smtp_user = myusername<br />
|
|
smtp_password = mypassword<br />
|
|
mailto = auser@adomain.com</p>
|
|
<p>These options specify that the alarm is to be sounded when "<span class="code">outTemp
|
|
< 40.0</span>" evaluates True, 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. (The place in the
|
|
code where the expression is evaluated is marked with "<span class="code">Note 1</span>".)</p>
|
|
<p>Another example expression could be:</p>
|
|
<p class="tty"> expression = "outTemp < 32.0 and windSpeed >
|
|
10.0"</p>
|
|
<p>In this case, the alarm is sounded if the outside temperature drops below
|
|
freezing and the wind speed is greater than 10.0. </p>
|
|
<p>Option <span class="code">time_wait</span> is used to avoid a flood of nearly
|
|
identical emails. The new service will wait this long before sending another
|
|
email out.</p>
|
|
<p>Email will be sent through the SMTP host specified by option
|
|
<span class="code">smtp_host</span>. The recipient is specified in 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>To make this all work, you must tell the engine to load this new service.
|
|
This is done by adding your service name to the list <span class="code">
|
|
service_list</span>, located in <span class="code">[Engines][[WxEngine]]</span>:</p>
|
|
<p class="tty">[Engines]<br />
|
|
[[WxEngine]]<br />
|
|
|
|
service_list = weewx.wxengine.StdWunderground, weewx.wxengine.StdCatchUp,<br />
|
|
weewx.wxengine.StdTimeSynch, weewx.wxengine.StdPrint,<br />
|
|
weewx.wxengine.StdProcess, examples.alarm.MyAlarm</p>
|
|
<p>(Again, note that this list is shown on several lines for clarity, but in
|
|
actuality it must be all on one line.)</p>
|
|
<h2>Customizing the Engine</h2>
|
|
<p>In this section, we look at how to install a custom Engine. In general, this
|
|
is the least desirable way to proceed, but in some cases it may be the only way
|
|
to get what you want.</p>
|
|
<p>For example, suppose you want to define a new event for when the first
|
|
archive of a day arrives. This can be done by extending the the standard engine. </p>
|
|
<p>This example is in file <span class="code">example/daily.py</span>:</p>
|
|
<p class="tty">from weewx.wxengine import StdEngine, StdService<br />
|
|
from weeutil.weeutil import startOfArchiveDay<br />
|
|
<br />
|
|
class MyEngine(StdEngine):<br />
|
|
"""A customized weewx engine."""<br />
|
|
<br />
|
|
def __init__(self, *args, **vargs):<br />
|
|
# Pass on the initialization data to
|
|
my superclass:<br />
|
|
StdEngine.__init__(self, *args, **vargs)<br />
|
|
<br />
|
|
# This will record the timestamp of
|
|
the old day<br />
|
|
self.old_day = None<br />
|
|
<br />
|
|
def postArchiveData(self, rec):<br />
|
|
# First let my superclass process it:<br />
|
|
StdEngine.postArchiveData(self, rec)<br />
|
|
<br />
|
|
# Get the timestamp of the start of
|
|
the day using<br />
|
|
# the utility function
|
|
startOfArchiveDay <br />
|
|
dayStart_ts = startOfArchiveDay(rec['dateTime'])<br />
|
|
<br />
|
|
# Call the function firstArchiveOfDay
|
|
if either this is<br />
|
|
# the first archive since startup, or
|
|
if a new day has started<br />
|
|
if not self.old_day or self.old_day
|
|
!= dayStart_ts:<br />
|
|
self.old_day
|
|
= dayStart_ts<br />
|
|
|
|
self.newDay(rec)
|
|
# Note 1<br />
|
|
<br />
|
|
def newDay(self, rec):<br />
|
|
"""Called when the first archive
|
|
record of a day arrives."""<br />
|
|
<br />
|
|
# Go through the list of service
|
|
objects. This<br />
|
|
# list is actually in my superclass
|
|
StdEngine.<br />
|
|
for svc_obj in self.service_obj:<br />
|
|
# Because
|
|
this is a new event, not all services will<br />
|
|
# be prepared
|
|
to accept it. Check first to see if the<br />
|
|
# service has
|
|
a member function "firstArchiveOfDay"<br />
|
|
# before
|
|
calling it:<br />
|
|
if hasattr(svc_obj,
|
|
"firstArchiveOfDay"): # Note 2<br />
|
|
|
|
# The object does have the member function. Call it:<br />
|
|
|
|
svc_obj.firstArchiveOfDay(rec)</p>
|
|
<p>This customized engine works by monitoring the arrival of archive records,
|
|
and checking their time stamp (<span class="code">rec['dateTime']</span>. It
|
|
calculates the time stamp for the start of the day, and if it changes, calls
|
|
member function <span class="code">newDay()</span> (Note 1). </p>
|
|
<p>The member function <span class="code">newDay()</span> then goes through the
|
|
list of services (attribute <span class="code">self.service_obj</span>). Because
|
|
this engine is defining a new event (first archive of the day), the existing
|
|
services may not be prepared to accept it. So, the engine checks each one to
|
|
make sure it has a function <span class="code">firstArchiveOfDay</span> before
|
|
calling it (Note 2)</p>
|
|
<p>To use this engine, go into file <span class="code">weewxd.py</span> and change the line</p>
|
|
<p class="tty">weewx.wxengine.main()</p>
|
|
<p>so that it uses your new engine:</p>
|
|
<p class="tty">from examples.daily import MyEngine<br />
|
|
<br />
|
|
# Specify that my specialized engine should be used instead<br />
|
|
# of the default:<br />
|
|
weewx.wxengine.main(EngineClass = MyEngine)</p>
|
|
<p>We now have a new engine that defines a new event ("<span class="code">firstArchiveOfDay</span>"),
|
|
but there is no service to take advantage of it. We define a new service:</p>
|
|
<p class="tty"># Define a new service to take advantage of the new event<br />
|
|
class DailyService(StdService):<br />
|
|
"""This service can do something when the first archive
|
|
record of<br />
|
|
a day arrives."""<br />
|
|
<br />
|
|
def firstArchiveOfDay(self, rec):<br />
|
|
"""Called when the first archive
|
|
record of a day arrives."""<br />
|
|
<br />
|
|
print "The first archive of the day
|
|
has arrived!"<br />
|
|
print rec<br />
|
|
<br />
|
|
# You might want to do something here
|
|
like run a cron job</p>
|
|
<p>This service will simply print out a notice and then print out the new
|
|
record. However, if there is some daily processing you want to do, perhaps a
|
|
backup, or running utility <a href="http://www.weewx.com/wunderfixer">
|
|
wunderfixer</a>, this would be the place to do it.</p>
|
|
<p>The final step is to go into your configuration file and specify that this
|
|
new service be loaded, by adding its class name to option <span class="code">
|
|
service_list</span>:</p>
|
|
<p class="tty">[Engines]<br />
|
|
<br />
|
|
[[WxEngine]]<br />
|
|
# The list of services the main weewx engine should run:<br />
|
|
service_list = weewx.wxengine.StdWunderground,
|
|
weewx.wxengine.StdCatchUp,<br />
|
|
|
|
weewx.wxengine.StdTimeSynch, weewx.wxengine.StdPrint,<br />
|
|
|
|
weewx.wxengine.StdProcess, examples.daily.DailyService</p>
|
|
<p>(Again, note that this list is shown on several lines for clarity, but in
|
|
actuality it must be all on one line.)</p>
|
|
|
|
</body>
|
|
|
|
</html>
|