markleyhut banner image

WunderGround Personal Weather Station (PWS) HOW-TO for the Davis Weather Wizard III on Linux


Background:

Years ago while living on a mountain top at 8850ft where the winds blow 9 months a year and are sustained 60mph I purchased a Davis Weather Wizard III.  Recently I purchased a WeatherLink module and had it connected to a Windows PC.  While this was interesting I did not what to run a PC full time just to update weather info.  Another project of mine utilized a Linksys NSLU2 NAS device with an Intel IXP425 processor.  This low power NAS device was a perfect fit for the task.  So I set off to find a way to get an unsupported weather station to run on a special purpose device.  This how-to details what was done as well as showcases the results.  You could easily run this on a PC or other dedicated device as well.

Disclaimer:

Use the information below AT YOUR OWN RISK!  I will not be held responsible if you destroy your system during any parts of this HOW-TO.

Hardware:

nslu2 pic

About the NSLU2:

A brief overview of the device can be found here.

More detailed information can be found here.


Hardware Requirements:


The NSLU2-Linux site also shows many modifications that can be done to the NSLU2.  I performed the one located here which doubles the processor speed.  My setup also uses an old Maxtor OneTouch hard drive.

Software Requirements:

# apt-get install mysql-server-5.0 libdbd-mysql-perl
# mysql -p
Enter password:
mysql> create database meteo;
Query OK, 1 row affected
mysql> exit
Bye

# apt-get build-dep debian-installer
# apt-get install libxml2 libxml2-dev libpng12-0 libpng12-dev libpng3 libgd2-xpm gettext gettext-base liblocate-gettext-perl
# cd your-source-dir
# tar xvf meteo-0.9.15-modified.tar
# cd meteo-0.9.15-modified
# ./configure
# make
# make install
<!--

meteo.xml ** graph configuration file (fixes colors and scales for the
meteo graphs) This version expresses the graphs we were used
to in previous release completely in the new XML syntax.

(c) 2001 Dr. Andreas Mueller, Beratung und Entwicklung

$Id: meteo.xml,v 1.32 2004/05/08 20:09:31 afm Exp $

-->
<meteo>
<!--
database configuration

each meteo instance has exactly one database, which may hold data
for several stations (as in the sample installation, where the
database holds data for the stations in Gurin and Altendorf)
-->
<database>
<hostname>localhost</hostname>
<dbname>meteo</dbname>
<user>meteo</user>
<password>public</password>
<writer>YOUR USER NAME</writer>
<writerpassword>YOUR USER PASSWORD</writerpassword>
<!-- the msgqueue tag is required if the meteodequeue process is used,
which is highly recommended. Make sure the file referenced here
exists, as it is needed by SysV IPC to generate a msgqueue id. -->
<msgqueue>/tmp/meteodb-queue.log</msgqueue>
<!-- the updatefile tag is only necessary if the database updates
cannot be sent to a database directly. Use the file generated
by this directive to update the database off line. -->
<!-- <updatefile>file:///home/jeff/weather/meteo-queue.log</updatefile. -->
<prefix>meteo</prefix>
</database>

<!--
station configuration

for each station, define the type, the connection method (using url and
possibly speed) und the sensors. Use the meteosensors program to find out
what sensors your particular station knows about. The sensor configuration
here only affects what meteopoll will read and store in the database.
You are still free to add other data manually and use the meteodraw program
to draw graphs of this data.

Fully qualified field names are formed by the name attributes of the
station and sensor tags and the contents of the field tags. The Altendorf
station below has the following fully qualified fields:
Altendorf.inside.temperature
Altendorf.inside.humidity
Altendorf.inside.barometer
Altendorf.outside.temperature
Altendorf.outside.humidity
Altendorf.outside.rain
Altendorf.outside.wind
-->
<station name="INSERT YOUR STATION ID HERE">
<url>file:///dev/ttyUSB0</url>
<type>Wizard</type>
<speed>2400</speed>
<sensors>
<!-- each sensor name must appear in the sensor table in the db-->
<!-- each field name must appear in the mfield table in the db -->
<sensor name="inside">
<field>temperature</field>
</sensor>
<sensor name="outside">
<field>temperature</field>
<field>rain</field>
<field>wind</field>
</sensor>
</sensors>
<averages>
<sensor name="inside">
<average name="temperature" base="temperature" operator="avg"/>
<average name="temperature_min" base="temperature" operator="min"/>
<average name="temperature_max" base="temperature" operator="max"/>
</sensor>
<sensor name="outside">
<average name="temperature" base="temperature" operator="avg"/>
<average name="temperature_min" base="temperature" operator="min"/>
<average name="temperature_max" base="temperature" operator="max"/>
</sensor>
<sensor name="outside">
<average name="wind" base="wind" operator="wind"/>
<average name="winddir" base="wind" operator="avg"/>
<average name="windgust" base="wind" operator="max"/>
</sensor>
<sensor name="outside">
<average name="rain" base="rain" operator="sum"/>
<average name="raintotal" base="rain" operator="sum"/>
</sensor>
</averages>
<sun method="compute"/>
</station>

<!--
Graph configurations

Each graph has a name by which it can be referenced. The meteodraw program
uses the name look up the XML specification of the graph. The name will
be used to form the file name for the produced graph (together with the
time label), so it should be a legal part of a filename, in particular it
should not contain /, and shell metacharacters will cause file names
that are clumsy to handle in shell scripts.
-->
<graphs lockfile="lockfile" running="3" queued="10">
<graph name="INSERT YOUR STATION ID HERE.temperature-new" offset="-10800"
height="300" width="600" bgcolor="#ffffff" fgcolor="#000000">
<!-- label and axis definitions -->
<leftlabel align="center">Temperatur grad F</leftlabel>
<rightlabel align="center">relative Humidity %</rightlabel>
<leftaxis type="dynamic" maxname="tt" minname="dd" min="-100" max="100"
origin="0" maxtickcount="20"
first="-100"
last="100" step="10" format="%.1f" ticks="yes" gridlines="yes"/>
<rightaxis min="0" max="100" first="0" last="100" step="20" format="%3.0f"
ticks="yes" gridlines="no"/>
<!-- the graphwindow tag defines the area inside the image where the
data will be plotted -->
<graphwindow llx="55" lly="19" urx="545" ury="293"/>

<!-- the channels contains the query definitions that tell meteodraw
how to retrieve the data from the database, and give it symbolic
names, and thq channel tags that describe how the data should
be plotted -->
<channels>
<!--
the query tag describes how data has to be retrived and modified
before graphing.
-->
<query>
<!-- give certain data sets in the DB a symbolic name -->
<select name="t">ENTER YOUR STATION ID HERE.temperature</select>
<select name="tmax">ENTER YOUR STATION ID HERE.temperature_max</select>
<select name="tmin">ENTER YOUR STATION ID HERE.temperature_min</select>
<!-- perform some arithmetic on the data sets, give the result
again a symbolic name -->
<data name="tt">
<function name="floor" limit="-50">
<function name="ceil" limit="50">
<value name="t"/>
</function>
</function>
</data>
</query>

<!-- draw graphs for the datasets as specified in the previous tags -->
<channel color="#aaaaff" type="range" scale="left"
namelower="dewpointmin" nameupper="dewpointmax"/>
<channel color="#0000ff" type="curve" scale="left" name="dewpoint"/>
<channel color="#ffaaaa" type="range" scale="left"
namelower="tmin" nameupper="tmax"/>
<channel color="#654321" type="curve" scale="left" name="tt"/>
<channel color="#dddddd" type="nodata" name="t"/>

</channels>
</graph>

<!-- Temperature graph -->
<graph name="ENTER YOUR STATION ID HERE.temperature_outside" offset="-25200"
height="288" width="600" bgcolor="#ffffff" fgcolor="#000000">
<leftlabel align="center">Temperature (deg F)</leftlabel>
<leftaxis type="static" min="-15" max="110"
first="-10" last="100" step="10" format="%.0f"
ticks="yes" gridlines="yes"/>
<graphwindow llx="55" lly="19" urx="556" ury="278"/>
<channels>
<query>
<select name="t">ENTER YOUR STATION ID HERE.outside.temperature</select>
<select name="tmin">ENTER YOUR STATION ID HERE.outside.temperature_min</select>
<select name="tmax">ENTER YOUR STATION ID HERE.outside.temperature_max</select>
</query>
<channel color="#ffb4b4" type="range" scale="left"
nameupper="tmax" namelower="tmin"/>
<channel color="#b40000" type="curve" scale="left" name="t"/>
<channel color="#e6e6e6" type="nodata" name="t"/>
</channels>
</graph>

<!-- inside Temperature graph -->
<graph name="ENTER YOUR STATION ID HERE.temperature_inside" offset="-25200"
height="288" width="600" bgcolor="#ffffff" fgcolor="#000000">
<leftlabel align="center">Temperature (deg F)</leftlabel>
<leftaxis type="static" min="40" max="100"
first="50" last="90" step="10" format="%.0f"
ticks="yes" gridlines="yes"/>
<graphwindow llx="55" lly="19" urx="556" ury="278"/>
<channels>
<query>
<select name="t">ENTER YOUR STATION ID HERE.inside.temperature</select>
<select name="tmin">ENTER YOUR STATION ID HERE.inside.temperature_min</select>
<select name="tmax">ENTER YOUR STATION ID HERE.inside.temperature_max</select>
</query>
<channel color="#ffb4b4" type="range" scale="left"
nameupper="tmax" namelower="tmin"/>
<channel color="#b40000" type="curve" scale="left" name="t"/>
<channel color="#e6e6e6" type="nodata" name="t"/>
</channels>
</graph>

<!-- Wind -->
<graph name="ENTER YOUR STATION ID HERE.wind" offset="-25200"
height="288" width="600" bgcolor="#ffffff" fgcolor="#000000">
<leftlabel align="center">Speed (mph)</leftlabel>
<rightlabel align="center">Azimut (deg) 360=N 270=W 180=S 90=E</rightlabel>
<leftaxis type="static" min="0" max="100"
first="0" last="50" step="5" format="%.0f"
ticks="yes" gridlines="yes"/>
<rightaxis type="static" min="-540" max="360"
first="0" last="360" step="180" format="%.0f"
ticks="yes" gridlines="yes"/>
<graphwindow llx="55" lly="19" urx="556" ury="278"/>
<channels>
<query>
<select name="azi">ENTER YOUR STATION ID HERE.outside.winddir</select>
<select name="v">ENTER YOUR STAATION ID HERE.outside.wind</select>
<select name="vmax">ENTER YOUR STATION ID HERE.outside.windgust</select>
</query>
<!-- note that there are some cultural differences with the wind
letters below. In Switzerland, Nordwind means wind _from_ the
north, which is wind with azimut 180deg. In other places, the
letters may be interpreted just the other way round, so you
will prefer to use letters="NESW" (pointed out by Mark Trettin)
-->
<channel type="windbackground" scale="right"
northcolor="#e0e0ff" southcolor="#ffe0e0"
westcolor="#e0ffe0" eastcolor="#ffffc8"
letters="SWNE" />
<channel color="#6464ff" type="curve" scale="right" name="azi"/>
<channel color="#006400" type="histogram" scale="left" name="vmax"/>
<channel color="#00ff00" type="histogram" scale="left" name="v"/>
<channel color="#ffffff" type="lowdata" name="vmax" limit="0.1"/>
<channel color="#e6e6e6" type="nodata" name="azi"/>
</channels>
</graph>

<!-- Rain -->
<graph name="ENTER YOUR STATION ID HERE.rain" offset="-25200"
height="288" width="600" bgcolor="#ffffff" fgcolor="#000000">
<leftlabel align="center">Precipitation (in)</leftlabel>
<rightlabel align="center">Total rain (in)</rightlabel>
<leftaxis interval="300" type="static" min="0" max="6"
first="0" last="6" step="1" format="%.0f"
ticks="yes" gridlines="yes"/>
<leftaxis interval="1800" type="static" min="0" max="10"
first="0" last="10" step="2" format="%.0f"
ticks="yes" gridlines="yes"/>
<leftaxis type="static" min="0" max="30"
first="0" last="30" step="10" format="%.0f"
ticks="yes" gridlines="yes"/>
<rightaxis type="dynamic" minname="totalrain" maxname="totalrain"
origin="0" maxtickcount="10" step="10" ticks="yes" gridlines="no"
format="%3.0f" />
<graphwindow llx="55" lly="19" urx="556" ury="278"/>
<channels>
<query>
<select name="rain">COSUPER9.outside.rain</select>
<data name="totalrain">
<function name="accumulate">
<value name="rain"/>
</function>
</data>
</query>
<channel color="#0000ff" type="histogram" scale="left" name="rain"/>
<channel color="#00ffff3f" type="curve" scale="right" name="totalrain"/>
<channel color="#f3f3f33f" type="nodata" name="rain"/>
</channels>
</graph>

<!-- observatory graphs -->
<graph name="OBS.outside"
height="144" width="500" bgcolor="#ffffff" fgcolor="#000000">
<leftlabel align="center">moisture</leftlabel>
<rightlabel align="center">clouds</rightlabel>
<leftaxis type="static" min="0" max="100" first="0" last="100"
step="10" format="%.0f" ticks="yes" gridlines="yes"/>
<rightaxis type="static" min="0" max="100" first="0" last="100"
step="10" format="%.0f" ticks="yes" gridlines="yes"/>
<graphwindow llx="55" lly="19" urx="455" ury="139"/>
<channels>
<query>
<select name="m">OBS.outside.moist</select>
<select name="c">OBS.outside.clouds</select>
</query>
<channel color="#00ff00" type="curve" scale="left" name="m"/>
<channel color="#ff0000" type="curve" scale="right" name="c"/>
</channels>
</graph>

</graphs>

</meteo>

# meteopoll -s YOUR_STATION_ID -f /usr/local/share/meteo/meteo.xml -l file:///var/log/meteo.log -b mysql -m /path/to/mapfile
Here the -m flag instructs Meteo to generate the mapfile which is an XML file created every minute.  The mapfile is used to determine some of the values to be uploaded to Wunderground. You will need to run Meteo with the mapfile for the upload program to work.  You should see two meteopoll process running.  This is normal.

# chmod +x meteo-wu-wizard.pl
# m h  dom mon dow   command
*/5 * * * * /usr/bin/perl /path/to/meteo-wu-wizard.pl > /dev/null 2&>1
Notes:

If you have trouble check the logs first!  Run meteopoll with the debug level turned up.  man meteopoll to find out how to do this.

Meteo is a very flexable program.  If you want to create your own .png images files you should see the meteoavg man page.  There are also other useful tools in the /usr/local/bin folder reated to the inner workings of Meteo.  Have a look if you are interested.

Also I am not a programmer.  I'm a hacker.  This is the method I used to get things working.  If you have a better one that's free let me know.  If you find errors in my code let me know and I'll update this HOW-TO. (jeff at markleyhut . com)



If you found this HOW-TO useful and are using the upload program please HELP A BROTHER OUT and donate!



Troubleshooting:

One area to check if things ar not working is to make sure the temperature unit values in the mfield table is set correctly.  Also check that the ID's for the other wind and rain values match what is in the meteo.xml file.  Mine are as follows:
mysql> select * from mfield;
+-----------------+-----+-------+-------------------+
| name | id | unit | class |
+-----------------+-----+-------+-------------------+
| temperature | 0 | F | TemperatureValue |
| temperature_min | 1 | F | TemperatureValue |
| temperature_max | 2 | F | TemperatureValue |
| humidity | 10 | % | HumidityValue |
| humidity_max | 11 | % | HumidityValue |
| humidity_min | 12 | % | HumidityValue |
| wetness | 20 | index | LeafwetnessValue |
| wetness_min | 21 | index | LeafwetnessValue |
| wetness_max | 22 | index | LeafwetnessValue |
| barometer | 30 | inHg | PressureValue |
| barometer_min | 31 | inHg | PressureValue |
| barometer_max | 32 | inHg | PressureValue |
| solar | 40 | W/m2 | SolarValue |
| uv | 41 | index | UVValue |
| rain | 50 | in | Rain |
| raintotal | 51 | in | Rain |
| rainrate | 52 | in/h | RainRate |
| wind | 60 | mph | Wind |
| winddir | 61 | deg | NULL |
| windgust | 62 | mph | WindSpeed |
| windx | 63 | mph | NULL |
| windy | 64 | mph | NULL |
| moisture | 70 | cb | MoistureValue |
| waterlevel | 71 | m | LevelValue |
| waterlevel_min | 72 | m | LevelValue |
| waterlevel_max | 73 | m | LevelValue |
| sunrise | 100 | unix | TimeValue |
| sunset | 101 | unix | TimeValue |
| battery | 110 | V | VoltageValue |
| transmitter | 111 | V | TransmitterStatus |
| duration | 120 | s | NULL |
| samples | 121 | | NULL |
+-----------------+-----+-------+-------------------+
My Station table looks like this:

mysql> select * from sensor;
+---------+----+-----------+
| name | id | stationid |
+---------+----+-----------+
| inside | 0 | 1 |
| outside | 1 | 1 |
| rain | 2 | 1 |
| wind | 3 | 1 |
| console | 4 | 2 |
| iss | 5 | 2 |
| soil1 | 6 | 2 |
| console | 7 | 3 |
+---------+----+-----------+
Copyright © 2012 Jeff Markley