Building a Web Weather Station
Last fall, my family and I moved from central Iowa to the little mountain resort town of Estes Park, Colorado. Estes Park is a beautiful town at the east entrance of Rocky Mountain National Park. More than three million tourists visit the park each summer.
When we moved here, I brought along my fledgling consulting business, Daylight Software, and set up web pages to drum up a little work. In a flash of inspiration, I decided I would either buy or build weather station equipment and offer weather data on the Web. Visitors from around the nation—and the globe—would see my web pages, and Daylight Software would be established as a Linux consulting powerhouse. Well, maybe it wouldn't lead to global domination, but it would surely be a good thing. I saw it as a community service, since no public weather reporting service was available, other than the time and temperature sign on one of the local banks.
After some investigation, I decided that my hardware development skills were not sufficient to design and build weather sensors. I shopped around and eventually purchased a Texas Weather Instruments “Weather Report” WRL-25 system from American Weather Enterprises of Media, PA (http://www.americanweather.com/).
The WRL-25 is like many weather stations in that it includes an RS-232 connection and comes with DOS/Windows software for downloading and viewing the gathered data. It has sensors for wind speed, wind direction, temperature, humidity, atmospheric pressure and rainfall. Using a regular television antenna mast and fittings, I mounted the weather station sensors on the roof of my house, snaking the sensor cables through the attic space and down to my office in the basement. I mounted the handsome display unit on a shelf in the office.
Across the room from the weather display is my array of computers, including my Linux workstation. I am running the Red Hat 4.0 Colgate release, 2.0.18 kernel, on my AMD 486DX-4 120MHz ISA server. I built a cable and attached the weather display to the Boca AT-66 serial card in the server. I then wrote some Perl scripts to build HTML and GIF files and upload them to my ISP, and to manage the data readings put out by the weather station.
The sensors are mounted on two ten-foot sections of steel TV antenna mast, available in the U.S. from stores such as Radio Shack. Approximately four feet are buried in the ground, and the rest of the mast is vertical at the gable end of our single-story house. The mast is attached with a TV mast bracket at the roof line of the house. About six feet of mast projects above the roof line.
The sensors came supplied with clamps and hardware to attach them to the mast. (See Figure 1.) I followed the installation instructions and mounted the wind direction/speed sensor module pointed north at the top of the mast. The temperature and humidity sensors are in a “pagoda” enclosure to protect them from direct sunlight, and the pagoda is mounted about three feet above the roof line. The rain collector is mounted at the roof line; I used a carpenter's level to mount it properly.
Multi-wire cables from the sensor modules go into the bottom of the junction box, where they are plugged into matching connectors from 100-foot cables which run to the weather display unit. (See Figure 2.) All excess cable is coiled up and attached securely under the eave. Cables going into the junction box were left drooping slightly, to encourage rain to drip off instead of flowing into the junction box.
The 100-foot cables run through the attic and out through a hole at the peak of the eave. The hole was later filled with caulking to discourage squirrels and other pests from getting in. From the attic, I drilled a hole in the top plate of an interior wall and snaked the cables down to the basement. A fancy wooden switchplate made for cable TV installations serves to mask the hole where the cables come through the wall into my office/computer area. The cables connect to the back of the WRL-25 display unit.
I ended up crawling through the blown-in fiberglass insulation in the attic more times than I care to remember. If you do this, be careful—wear a dust mask or respirator and long sleeves and trousers. The attic was hot. I considered this to be the most difficult part of the installation.
I had to set the current time on the display unit and change some of the option settings. Other than that, the sensors and other features of the WRL-25 were all calibrated and ready to run.
On the back of the display unit is a 9-pin serial pigtail. The WRL-25 came with a mix-and-match 4-ended 25 and 9 pin serial cable for adapting to whatever connectors are available. I did not use that particular cable. My Boca Io-AT-66 six-port serial card uses RJ-45 sockets for its connections. So, I made a cable from a ten-foot scrap of eight-wire twisted pair that already had an RJ-45 connector crimped on one end. Pin assignments and wiring information were included in the Io-AT-66 documentation.
The WRL-25 can be programmed to periodically send a status report over the serial line. This can be used to print directly on a serial printer. I programmed my unit to send a reading every 5 minutes. I also changed an optional setting to allow the rainfall rate report and to print a daily Max/Min report at the end of each day. I set the serial line data rate to 9600bps.
The unit can also be directed using single-character commands through the serial connection. I rarely use this feature. The PC software that came with the unit can be used to set various options and settings, as can the buttons on the display panel. So, more sophisticated programming could be used to query the unit on demand or change various features. I elected to use the simple logging feature to gather my data.
I was able to run a quick test on my setup by using the following command:
cat < /dev/ttyS19
This command takes any input appearing on the /dev/ttyS19 serial line and echoes it to the screen. Pushing the manual report button on the WRL-25 produced a one-line report on the screen. I was a happy camper!
Reports that come down the serial line look like this:
17:05 08/09/97 WSW 00MPH 460F 069F 057F 085% 23.42F 00.00"D 01.39"M 00.00"R
The first two fields are time and date. The current time and date are maintained on the WRL-25 display unit. I have not noticed any great drift in the time setting.
The second two fields are wind direction (WSW—West by South West) and speed (00 MPH—miles per hour).
Fields 5 through 7 are temperature readings in degrees Fahrenheit. Field 5 is not connected to any sensor, so it should be ignored. Field 6 is indoor temperature and field 7 is outdoor temperature.
Field 8 is relative humidity, which in this example is 85%. Field 9 is atmospheric pressure in inches of mercury accompanied by a single character for falling (F), rising (R) or steady (S).
The last three fields are daily rainfall and monthly rainfall, both in inches, and rainfall rate in inches per hour.
At the end of each day, two lines of daily minimum and maximum readings are reported:
Max 08/08/97 WSW 24MPH 460F 074F 081F 100% 23.42" 00.00"D 01.39"M 00.00"R Min 08/08/97 SW 00MPH 460F 068F 044F 021% 23.28" 00.00"D 01.39"M 00.00"R
These lines are in the same format as the other reports, except for the first field which marks these records as Max/Min reports. The readings for daily min/max are independent. In the above example, the high temperature for the day was 81 degrees F and the highest humidity reading was 100%. These readings did not occur at the same time and are unrelated, except that both are the maximum for that particular statistic.
My first pass at a data collection script was a simple cat command:
cat /dev/ttyS19 >> data1
It worked—mainly by accident. The next time my machine was rebooted, it didn't work at all. When I fired it up, the weather station console started spitting out all sorts of long reports. After a little head scratching, it became obvious that regular character echoing was feeding back command characters—not at all what I had in mind.
My current script is called weatherd.pl and is shown in Listing 1 with blank lines removed. Line 8 sets the variable $TTY to be the first command-line argument. Line 10 resets the terminal to the appropriate speed, parity and non-echoing. I used the stty command to get the terminal settings the way I wanted them, then saved the setup to a file. This stty command reads from that file and sets the terminal to the saved configuration.
Data is kept in a file, with the name of the file being the current date. Each day's data goes into one file (lines 14-16). The print statement on line 16 helps me feel confident things are working right. Beginning with line 27, for each data line that comes in from the tty, we check to see if it is a minimum or maximum and that it is still today's data. Minimum and maximum data go into separate files.
To start weatherd.pl, I added the following single line to my /etc/inittab file:
This line starts up weatherd.pl and respawns it if it should die for any reason.
Now I had the data coming in from the weather station, getting picked up by weatherd.pl and thrown into a file using the date as its name.
The next step was to format the data into an HTML file for display over the Web. I wrote a Perl script (Listing 2) that takes the last line from the current data file, in combination with a template HTML file, and fills in the weather information. It also calculates the corrected atmospheric pressure and the dew point. (The dew point calculation was given to me by John Kleist, Colorado Climate Center, email@example.com.) Last of all, it looks in yesterday's Max/Min files and puts those values in the output HTML.
I also wrote a script, plotdays.pl (Listing 3), that plots some of the interesting statistics for the last few days.
Finally, I have a master program called loop.pl, which I wrote to reliably connect to my ISP, set up my PPP connection, transfer e-mail, set the system time and upload the weather data.
First, we have to look at how to automate an FTP connection. FTP is usually used for interactive network file transfer. To use regular FTP, you need to have an account on the remote machine. In this case, I use my ISP shell account with Front Range Internet (frii.net). A user can set up an automated FTP session by using a file called .netrc in their $HOME directory. I added to my system a user called “weather” dedicated to owning the weather data files and scripts. In the /home/weather/.netrc file, I have the following lines:
machine ftp.frii.net login: password: macdef init cd public_html put /home/weather/WWW/wscurrent.html wscurrent.html put /home/weather/WWW/wsplot.html wsplot.html put /home/weather/WWW/temp.gif temp.gif put /home/weather/WWW/pressure.gif pressure.gif put /home/weather/WWW/raind.gif raind.gif put /home/weather/WWW/winds.gif winds.gif quit
The statements in this file define and execute a macro called init. All I have to do is start FTP and this script attempts to run the macro, uploading my HTML and GIF files to the appropriate place on my ISP account.
Both Listing 1 and Listing 3 are called from a short script called doup, Listing 4, which also does the actual FTP call.
Last but not least, loop.pl (Listing 5), is executed continuously by the root user. The only tricky part of loop.pl is the necessity to recover if a command gets stuck due to a loss of connection with the ISP. I wrote a replacement for the regular Perl “system” function which allows me to specify a timeout for each command. If that command exceeds the time alloted, it and all of its children are killed. Loop.pl also has other jobs to do, like downloading and uploading my e-mail and setting the system time using ntpdate. While those jobs are happening, I have a child process simultaneously running the doup script. If the ancillary jobs finish first, they give doup a little more time to complete. With a good connection, there is no problem getting everything done in less than one minute.
I have two different dial-up scripts, because there are two possible telephone numbers for the computer to try when dialing my ISP. If the primary number fails, it tries the second number. If both fail, it sleeps for 60 seconds and tries again. The goal of the sleep statements in loop.pl is to have the connection occur approximately every 15 minutes. Otherwise, the comments in the code pretty much cover all of the details.
One of my main concerns is lightning. Fortunately, our site is in a wooded area that is somewhat protected from direct lightning strikes. Still, I would feel even better if the remote weather sensors were electrically isolated from the display unit and my Linux machine. Some sort of optical isolation would probably work.
Also, I may have to develop an automated way to set the clock on the weather display unit.
Otherwise, the system seems to be working pretty well. With weatherd.pl running from the inittab, and with loop.pl in my startup rc files, the weather station monitoring continues after a reboot without manual intervention. Power loss or server failure will interrupt the service, but neither of those are common occurrences.
My weather station web page (see Figure 3) can be found at http://www.frii.net/~daylight/wscurrent.html. Please stop by and check it out. If you have the opportunity, come to Estes Park and see what a beautiful place it is.
All listings referred to in this article are available by anonymous download in the file ftp.linuxjournal.com/pub/lj/listings/issue56/2538.tgz.