Introduction: Arduino Wireless Weather Station & Web Server
Replace my PC (which has been on 24-7 for 6 years) and weather station software with an Arduino – Lower power consumption, less maintenance and smaller physical footprint. Minimum PC functionality requiring duplication:
• Logging of weather data (wind speed, wind direction, outdoor humidity, outdoor temperature, rain, UV, cloud height, wind chill, pressure, forecast, indoor temperature/humidity (x3 channels) every hour
• House power usage (logged every hour)
• Web page update showing current data and 24/48 hour trends for all elements above
• Email alerts of extremes
Hardware to be monitored
• Oregon Scientific WMR628 wireless weather station
• OWL power monitor
Following some extensive research on the web, I established that there was nothing that quite met my objectives so if I wanted to do this, I had to do it myself! Before we get into the design/code, I need to stress that I am an engineer, and as my IT group tell me on regular occasions, engineers don’t make good software developers. This will become apparent as we go through this process – however what I’ve built works, meets my needs and I’m quite pleased with the overall outcome. That’s not to say that I am not open to feedback (constructive of course!). As I lead you through the development, if there is anything that I could do more efficiently or just better, please let me know as it’s the only way I can learn!
Note in order to view the web pages from the weather station external to your local network, you will need to open a port on your router. This is not covered here.
Step 1: Decode the Wireless Signals
This was the biggest hurdle and I have to pass all the credit for this phase to Dominique Pierre at JeeLabs whose code I have used (with support from Dominique) to decode all my sensors. Hardware for testing is simple (and explained on the JeeLabs website). A point to note here is that initially I used an Arduino UNO, but (as will be explained later) I moved to a MEGA. For testing and decoding purposes, either will work and I strongly recommend this step before anything else so that you can identify and verify that the received signals are from the sensors and that you can interpret them. I used a simple Excel spreadsheet to manually verify the decoded signals and work out the check sums before any weather station coding started.
Step 2: Hardware
In addition to the RF radio receiver, I used an RTC – You could use the Ethernet shield and an NTP, but I felt the key focus should be the logging rather than the internet/server side, and this could be done ‘offline’ should the network be down when using an RTC. I have built a variant of this project for a friend too who had limited sensors, so included an ‘on board’ pressure and temperature sensor. What you use is up to you, and I have included example code for all elements later. The schematic provides an overview of the hardware that has been used. Built in Fritzing, I have also created a ‘mini Shield’ that slots onto the ‘end’ of the MEGA where the Ethernet shield finishes (shown in white in the photo). This ‘shield’ incorporates foot prints for the optional items and some break-out pins for future options. Combinations that have been tried/tested include:
• RF receiver for Oregon Scientific sensors and RTC
• RF receiver for Cresta sensors, RTC and BMP085 barometric/temperature sensor
• External LM35 temperature sensor (waterproofed and measure the temperature of the stream in our garden) and external stream depth monitor (not detailed here, but uses an I2C ultrasonic distance meter mounted on a bridge to assess height of stream – interestingly, the depth can vary from 30cm to 150cm during heavy rain!).
However any combination should work and code can be modified to log/web serve as appropriate.
Schematic shows the components on the shield, as I indicate above, not all need to be used, but options are there if wanted. Not shown is the Ethernet shield too that simply plugs into the MEGA.
Components you’ll need:
1. Arduino MEGA 2560
2. Ethernet shield (with micro SD card)
3. RF 433MHz receiver (Aurel RX-4M50RR30SF used and functions well from here)
5. DS3234 RTC breakout module
6. LM35 temperature sensor (up to 2, optional)
7. BMP085 pressure sensor (optional)
In order to mount the Arduino and ‘shield’ into a standard Arduino enclosure, I had to remove two of the locating pins, but these are easily snapped off and do not impact the secure mounting of the hardware. Note that on the PCB, the receiver module is located on the underside of the PCB (plenty of room) so that the memory card can still be ejected without interference.
I used a 433MHz whip aerial to make the device look neater (not connected in the photo, but shown mounted on the box in the 2nd picture) – not sure it responds any better than my test aerial – a piece of wire; but looks a lot neater and more professional!
Step 3: Code for Logging Data
This is an extension of step 1, taking the received signals and interpreting the signals to get ‘real’ values. These are stored in global variables as the data is used in multiple places (i.e. the logging phase, and the web page serving page, Step 4). I have typically used integers to save memory where possible and speed up processing, dividing by 10 to get one decimal place when logging or ‘serving’ the values to the web. I also have included triggers for maximum and minimum values (that are stored in EEPROM at midnight in case of power loss at some point during the year). For certain parameters, there are also triggers to send an email (Step 5).
I have added a checksum to those elements that required validation as occasionally, erroneous data would be processed and skew the maximum/minimum data. Decoding of the Oregon Scientific signals was based on info found on the internet here and for the Cresta devices here. Note that the RF decoding code is different for each the Oregon Scientific and the Cresta devices. Examples of both are included in the example sketch file.
Step 4: Code for Web Serving
There are two key elements to this. One is to serve a page directly from the Arduino that is fixed format and essentially a list of sensor readings, battery status, Arduino status etc. This is useful for ‘debugging’ both the software, but also verifies that the hardware is working as expected – for example if a sensor is not being decoded as it’s out of range or suffers interference, it can be monitored on the ‘last updated’ details. The second element is to serve more complex pages. The solution coded is (I think) quite powerful, as it will load a template file (in text form) from the root of the SD card and where it finds a ‘variable’ (indicated with an opening and closing ~~), it replaces this with the value before serving to the web page. This means that quite complicated web pages can be created without re-coding the Arduino and without hogging memory/resources, including references to external files such as .css files, images etc. which can be stored on your own website rather than on and served by the Arduino (which it isn’t designed to do it).
Originally, the code was intended to work on an UNO, but I needed to store large arrays of data (48 values x 13 groups) for the trend graphs (see example web page) and although the compile size came in under the 32k mark, the Arduino failed due to memory ‘overload’… Going to the MEGA also allowed additional functionality to be added (such as emails, sunrise etc.) without issue. Feel free to optimise the code and squeeze it onto the UNO…
The example file (graphs.htm) creates the web page below and makes use of the Google Charts api to render the charts with simple hyperlink calls. Note that the code only works with 8.3 named files (due to the use of SDFat), hence the use of .htm named files. To view the processed page, simply type the Arduino IP code:Port followed by /graphs.htm.
The code also includes maths for calculating some derived parameters, such as cloud base height and wind chill. Two other actions are available via URL in addition to the normal page delivery:
• YourIP:Port/EEPROM – Forces the current maximum and minimum (and rain count) to be logged in EEPROM. Useful to do before powering down for any reason to ensure that the yearly data is maintained. Note: the EEPROM is only written too once per day, at midnight. This extends the life of the Arduino EEPROM and as this device is intended to be powered indefinitely I figured daily was sufficient.
• YourIP:Port /TIME&year&mo&day&hr&mi – although an RTC has been used, it seems to lose time over a period. This function allows the user to reset the RTC (via the web) to the ‘correct time’ and to update for summer time changes.
The basic logging and Server code is based on the tutorial here and modified to suit both my needs and changes to Arduino 1.0 compiler.
• TimeLord Library
• EEPROMWriteAnything Library
• RTCLib Library
• SDFat Library (and Ethernet/SD card tutorial)
Step 5: Code for Email
Using a simple web page client, I call a URL to a php script located on my web page to email a set email distribution list. Again, as this is hosted off the Arduino, I can change the distribution and content of the email at any time.
Weather Station Alert email php script:
// The following lines read the parameters from the URL
$TO = 'email address 1';
$TO .= ', email address 2';
$FROM = 'your email address';
$SUBJECT = 'Weather Station Update';
$TIME = $_REQUEST["TIME"];
$TEMPNOW = $_REQUEST["TEMPNOW"];
$WSNOW = $_REQUEST["WSNOW"];
$WDNOW = $_REQUEST["WDNOW"];
$RAIN = $_REQUEST["RAIN"];
$TEMPMAX = $_REQUEST["TEMPMAX"];
$TEMPMIN = $_REQUEST["TEMPMIN"];
$WSMAX = $_REQUEST["WSMAX"];
$TRIGGER = $_REQUEST["TRIGGER"];
$MESSAGE = 'Message from Weather Station
Timed at ' .$TIME. '
- Temperature now is' .$TEMPNOW. 'C
- Wind Speed now is ' .$WSNOW. 'mph at deg
- Rain Today ' .$RAIN. 'mm
- Max Temperature Today is ' .$TEMPMAX. 'C
- Min Temperature Today is ' .$TEMPMIN. 'C
- Max Wind Speed Today is ' .$WSMAX. 'mph
Email sent due to ' .$TRIGGER. ';
// This sends the message
mail($TO, $SUBJECT, $MESSAGE, "From: ".$FROM);
There is also an email issued if there is power loss and the system is rebooted.
Step 6: Known Limitations and Areas for Improvement
1. The biggest issue I have come across is that whilst checking for any web page request, the Arduino is missing decoding the RF signals. This was made worse by the change to Arduino 1.0 (which seems to take an age to check for any server requests). To overcome this, I only check for internet activity when there is an RF signal received and has been decoded (which works well for me as I have lots of sensors and there is a signal received every few seconds) , or every 5 seconds by means of a check on mills(). This works in practice (with a maximum delay in receipt of the web page by the user of around 5 seconds and without obvious loss of readings), but I am sure there are better ways of doing this, such as software interrupts maybe?
2. Some of the coding is poor (I could make better use of functions/procedures and possibly even some library work (which is beyond me)) and I am sure there are more efficient ways of achieving the same ends. The code works and it does what I want it to do reliably (been running several months with no issues), but any improvements/recommendation welcome.
Hope this information is useful.