Arduino Weatherstation

At University, Alexander Zenger and I decided to realise a weatherstation with an Arduino Microcontroller. We wanted to measure temperatur, pressure and humidity. It should be also possible to get every 5 min a value update on an external server.

Our basic idea was to develope a weatherstation which is easy to use with different technologies (Smartphone, Internet, Microcontroller, …). It should also be possible to add new sensors quite easy and adapt the station to your own needs. Therefore we developed a weatherstation and a smartphone application to use with the weatherstation.

[TOC]

Requirements

A short overview of my requirements:

  • measure temperature
  • measure pressure
  • measure humidity
  • 5 min interval for weather values
  • send data to extern server
  • generate graphic of values

Arduino

I use a Arduino Uno. The Arduino Uno is a microcontroller board based on the ATmega328.

arduino uno

Summary

MicrocontrollerATmega328
Operating Voltage5V
Input Voltage (recommended)7-12V
Input Voltage (limits)6-20V
Digital I/O Pins14 (of which 6 provide PWM output)
Analog Input Pins6
DC Current per I/O Pin40 mA
DC Current for 3.3V Pin50 mA
Flash Memory32 KB of which 0.5 KB used by bootloader
SRAM2 KB
EEPROM1 KB
Clock Speed16 MHz

Used Sensors

I use five sensors to measure the required values. My experience with the soldering iron is not bad, but not the best, so I use for temperature, humidity and pressure sensors on simple breakout boards.

To pressure, temperature and humidity sensors and to minimize code in the main arduino file (weatherstation.ino) I extracted the code into own cpp classes.

To measure windspeed, winddirection and precipitation I use the following sensor:

Wind/Precipitation

It is available at watterott.

bmp085

bmp085

This is a simple breakout board for the BMP085 high-precision, low-power barometric pressure sensor. The BMP085 offers a measuring range of 300 to 1100 hPa with an absolute accuracy of down to 0.03 hPa. It’s based on piezo-resistive technology for EMC robustness, high accuracy and linearity as well as long term stability. This sensor supports a voltage supply between 1.8 and 3.6VDC. It is designed to be connected directly to a micro-controller via the I2C bus

get data on arduino

I catch the values of the bmp085 through the I2C-Bus. It was a long and hard work, and I don’t really want to explain the whole source file.

You can download it at GitHub.

hih4030

hih4030

This is a breakout board for Honeywell’s HIH-4030 humidity sensor. The HIH-4030 measures relative humidity (%RH) and delivers it as an analog output voltage. You can connect the output of the sensor directly to an ADC on a microcontroller; and, thanks to the sensor’s near linear voltage output, the data is very easy to process.

Voltage applied to the supply pins should be within 4-5.8VDC, and optimally at 5V. The sensor will typically only consume about 200μA.

get data on arduino

To get data is quite easy. The hih4030 sensor can be handled with analog input signals on the arduino.

To receive just the sensor signal we can use something like:

pinMode(HIH4030_PIN, INPUT);
    hih4030_value = analogRead(HIH4030_PIN);

Here you get just the plain value of the sensor. This has to be calculated to get the real humidity. Everything we need for this calculation can be found in the data sheet.

First the analog input has to be calculated to the right voltage according to the Arduino Page.

voltage = hih4030_value / 1023.0 * SUPPLYVOLTAGE;
    sensorRH = voltage - ZERO_OFFSET / SLOPE;
    trueRH = sensorRH / (1.0546 - 0.00216 * temp);

wind speed

The wind speed sensor (anemometer) is provided with a reed switch (NO = normally open). With each revolution, the contact closes. A recolution (pulse) corresponds to a wind speed of 2.4 km/h.

get data on arduino

To get data is quite easy. The wind speed sensor can be handled with digital input signals on the arduino.

To receive just the sensor signal we can use something like:

pinMode(WIND_SPEED_PIN, INPUT);
    digitalWrite(WIND_SPEED_PIN, HIGH);
    ....
    windSpeedValue = digitalRead(WIND_SPEED_PIN);

wind direction

The unit for displaying the wind direction sensor is the most complicated of the wind and rain unit. Here the schematic diagram:

windrichtung

There are eight magnetic switches, each connected to a different restistance. The magnet can connect two switches simultaneously, so that we can recognize a total of 16 states/positions.

I use an external resistor of 10K as a voltage divider and measure the output voltage with an AC converter (analog pin 2).

This table (from datasheet) shows the various states and the resultant values:

windrichtung

More detailed information are available at the datasheed.

get data on arduino

To get sensor values of the wind direction sensor, we can use analog input signals on the arduino.

To receive a signal, do something like:

sensorValue = analogRead(WIND_DIRECTION_PIN);

After we received a value, we have to map the incoming scale (0-1024) to volts (0-5). This can be done with a function called map:

sensorVolt = map(sensorValue, 1, 1024, 1, 5000);

rain

The rain sensor triggers after filling (0.2794 mm) one pulse, the open contact is closed and the sensor emptied himself (by the way: 1 mm corresponds to one liter of rain per square meter).

We can not query this sensor at predictable intervals. A meaningful measurement of wind speed should last about 10 minutes. During this time, our program would therefore measure the wind speed and can answer no pulses of precipitation sensor.

So we need a way that allows us to capture and process each pulse of the precipitation sensor while we just measure the wind speed. To this end, we use the interrupts of our Arduino microprocessor. The standard Arduino provide us 2, the Arduino Mega 6 interrupts. Each of the interrupt is tied to a particular pin. The pins used are therefore NOT optional. The Interrupt 0 is digital pin 2, pin 3 to 1, the interrupt digitally.

These interrupts can be addressed by the attachInterrupt function.

The syntax is:

attachInterrupt (interrupt, function, mode)

To receive interrupts, we can do something like:

attachInterrupt(0, countRain, CHANGE);

    void countRain(){
        rainCounter = rainCounter++;
    }

To calculate how much rain falls down, we use this form:

rain = ((rainCounter * 0.28) + 0.5; // 1 pulse = 0.2794 mm

Schematic

bmp085 and hih4030

verkabelung

Short description for bmp085:

blue:SCL -> AI5
yellow:SDA -> AI4

Wind/Precipitation

verkabelung

perl script

I use a short perl cgi-bin script on my external debian server to catch the sensor values and to draw the graphics. Here I explain some parts of my script.

get data

my $Daten = "";

    if($ENV{'REQUEST_METHOD'} eq 'POST') {
        $Daten = $ENV{'QUERY_STRING'};
        my @ValueField = split(/&/, $Daten);
        foreach my $Field (@ValueField) {
            (my $name,my $value) = split(/=/, $Field);
            if ($name eq "P" ){  # pressure
                    $pressure = $value / 100.0; # get pressure in hPa and not in Pa
                print LOG "++ got pressure value from arduino: $value\n";
            }elsif ( $name eq "T" ){ # Temperature
                $temperature = $value;
                print LOG "++ got temperature value from arduino: $value\n";
            }elsif ( $name eq "H" ){ # Humidity
                $humidity = $value;
                print LOG "++ got humidity value from arduino: $value\n";
            }
        }
    }
    else {
        read(STDIN, $Daten, $ENV{'CONTENT_LENGTH'});
    }

database

To store the weather values, I use RRDtool of Tobi Oetiker. In this tool, the data are stored in a circular buffer. To minimize the configuration part of rrdtool, I use rrdSimple (use RRD::Simple ();). It is quite easy to use because the main configurations are already done. You will see later on, how easy it is to use.

open database

$rrdSimple = RRD::Simple->new( file => $dbSimple );
    if(! -f $dbSimple){
        $rrdSimple->create(
            temperature => "GAUGE",
            pressure => "GAUGE",
            humidity => "GAUGE"
        );
    }

update values

$rrdSimple->update(
        temperature => $temperature,
        pressure => $pressure,
        humidity => $humidity
        );

draw graphics

%rtn = $rrdSimple->graph(
        destination => "$home/temp",
        title => "Wetterstation",
        width => "500",
        height => "200",
        vertical_label => "Temperatur/Druck/Humidity",
        interlaced => ""
        );

screenshots

Here you can see the graphics drawn by the rrd tool:

Annual rrd-annual

Monthly rrd-monthly

Weekly rrd-weekly

Daily rrd-daily

Smartphone Application

Widget view

rrd-daily

Widget Graph view

rrd-daily

Widget settings

rrd-daily

Sources

All sources to use with the arduino weatherstation are available on GitHub.

Also the sources of the android widget are available on GitHub.

If you want to run a “external server” you can get the debian package containing all necessary settings.

get debian package

UPDATE
The settings to handle wind speed, wind direction and rain are coming soon. I just have to cleanup my sources.

First of all you have to add the pool to your sources list:

sudo echo "deb http://pool.maxoberberger.net/ squeeze main" >> /etc/apt/sources.list

You also need the pool-key:

wget -O - http://pool.maxoberberger.net/max@maxoberberger.net.gpg.key | sudo apt-key add -

Now you are ready to get the configuration package:

apt-get update
    apt-get install arduino-configuration

Demo

A live demo can be seen at my weatherpage

If you want to use my weatherstation (be aware that it can be down sometimes for testing/development) here are the values you need:

IP: oberbergers.de
HTTP Call: /cgi-bin/arduino.pl
Available Sensors (json Filter):

  • temperature (temperature)
  • air pressure (pressure)
  • humidity (himidity)
  • windspeed (windspeed) - unit: knots
  • winddirection (winddirection) - unit: degree
comments powered by Disqus