Weather Monitor




Introduction: Weather Monitor

It is convenient to read simple weather data such as temperature, pressure and humidity from display of the weather station. In this instruction is shown how to build own weather monitor system based on arduino microcontroller. You can buy excellent weather station from Oregon or other vendor, but what about fun to build your own device?

There are at least three interesting components in the project:

  • power-efficient arduino sensor that can run over a half-year on two AA batteries.
  • the software library that supports Oregon V2.1 protocol with advanced direct port manipulation functions.
  • two-variant of home monitoring module: rich one and chip one

I hope, you enjoy investigating these components or you can use the library.

Step 1: Wireless Couple

The wireless transmitter and receiver couple is the key component of the wireless weather monitoring system. The working distance of the monitoring system depends on the couple quality. There are a lot non-expensive of wireless modules on e-bay like this one. Unfortunately, the working range of the modules made in china is very low, about 10 cm.To get acceptable range of communication, you need to buy separate heterodyne receiver module, RXB6.

The second valuable component is antenna. The best one is a copper wire 34 or 17 cm length. But, it in not convenient to use long wire in the module. So, it is recommended to use compact helical antenna like shown on the picture.

Step 2: Wireless Sensor

I believe that it is better to follow the standards than create own proprietary protocol to send the data between the sensor and weather station. In this case you have a flexibility what sensor to use. You can buy a remote Oregon sensor THGN123N for about $20 or you can build your own temperature/humidity wireless sensor that implements Oregon protocol V2.1 for about $9 and have fun! In this project the library based on the software created by Domonique Pierre is used. His library successfully emulated Oregon V2.1 protocol for wireless sensors.

First of all, the pressure inside and outside is the same in normal conditions. So, we can place the pressure sensor inside the home module. In the outdoor module we need accurate temperature and humidity sensor to check the weather conditions. The sensor module si7021 has shown perfect results, so I recommend this sensor one more time: it has great accuracy, small form-factor and low power consumption.

Second, we need mobile platform with low power requirements that can run on the batteries for a long time. We can use atmega328p-pu chip, running at 1 MHz. The power consumption of this system is about 5 micro Amps!

There are several articles in the Internet about running Arduino controller on the batteries. For example, this article describes how to run the Arduino pro mini on batteries for long time. You need to cut-off the green power led that consumes about 10 mA. Unfortunately, you can destroy your Arduino board while trying to cut the desired wire, like I did. I believe it is better to build own Arduino from the scratch without any lLED at all. In this case, you can also decrease the power consumption by slowing down the CPU to 1 MHz. Please, read the very detailed tutorial about creating own Arduino board running at 1 MHz and consuming as low as 5 micro Amps.

At the beginning, I tried to use pure library written by Domonique Pierre. Unfortunately, the controller speed is not sufficient to send the data in the time limits required by the protocol. To make the library faster, direct port manipulation was implemented in the new version of the library.

There are two output ports in Atmega 328 controller, B and D. In the library you can see two different classes for each port, directPortB and directPortD. The constructor for OregonSensor class automatically selects appropriate port based on the transmission pin number. There are direct port manipulation functions to send "one" and "zero" signal according by the Oregon protocol that allows to speed-up the signal transmission.

The sketch can be download here (weather_Oregon_12864.ino)

As to a budget of the own-made sensor, you can evaluate the price of all components:

  • atmega328p-pu chip - $1,52 (if you buy one chip)
  • industrial si7021 sensor - $2,60
  • 433 MHz receiver/transmitter kit - $1
  • ams1117-adj voltage regulator - $0.10
  • 2xAA battery case - $1
  • all small components (capacitors/resistors) - $2

Total: $8.22.

Step 3: Full Version of Display Module

The display module draws the received data from the sensors on the graphical screen. The module requires external power supply because of high power consumption. The 3" black and white display based on st7920 chip is used to draw sensors parameters and some graphs. This display is big enough, well-readable and capable to draw the graphic information such as temperature or pressure change with time.

This version of display module is based on arduino mega 2560 because the reach functionality of sketch with the graphic library requires a lot of memory.

The module has the following features:

  • Display the indoor temperature and humidity; display the pressure
  • Supports up to 4 external sensors
  • Store the sensor data in the SD-card
  • Draws the graphs of temperature, pressure and humidity of all sensors per day and per week
  • Display sunrise and sunset times

Using rotary encoder you can select the information shown on the display. You can see the current weather conditions or history data from any sensor for a day or week period.The localization messages are combined in a single display class and can be easily translated to other language.

The external sensors has one byte ID. The Oregon sensor changes its ID each time you replaced the battery in the sensor. Arduino based sensors has unique ID, that you can change inside the sketch of the sensor. The display module stores the ID of 'main' external sensor in the EEPROM. The information of this sensor is displayed on the left side of the screen. On the right side of the screen you can see the other sensors data or analog clock.

The display module has menu subsystem to tune the parameters. To enter the menu, long press the rotary encoder button. In the menu you can make the following configurations:

  • Change the main external sensor ID
  • Set morning and evening time for display backlight
  • Set system clock

The information from the main external sensor is shown on the left side of the display in the main mode. You can manually setup (through menu) the ID of the main sensor or disable this setting by selecting '??' variant. In this case, the first external sensor will be selected as a main. When you setup the main sensor ID, the controller assumes variant of all available sensor ID it has beed received. So, first wait for all available sensors to be rigistered first. As i mention before, on the right side of the screen all external sensor data is displayed periodically with the sensor ID.

The module has photo resister to automatically adjust the intensity ob backlight of the screen. You can prevent the backlight at night period by setting the morning and evening times in the menu. Autmatic backlight adjustment is working during the day period.

The sketch is available here. Also, you need the library to calculate sunrises and sunsets.

There is weather forecast icon in the top-right corner of the screen. The weather forecast is based on pressure change. It is not very accurate but fun.

Step 4: Component List for the Full Version Monitor

The display monitor schematics is shown on the picture in this section. Here you can see arduino mega, sd-card reader, lcd display and other components. ne555 is ised to prevent controller hung-up. This watch-dog timer every 60-80 seconds resets the arduino in case there was no restart (through A2 pin).

To build full version of the monitor module you required these components:

  • Arduino mega2560
  • lcd 12864 screen basen on st7020 chip
  • dht22 temperature/humidity sensor
  • bmp180 sensor
  • RXB6 superheterodyne 433 MHz receiver module
  • Helical antenna for the wireless module
  • ds3132 clock module
  • SD-card (better microSD) reader module for arduino
  • rotary encoder with a push button
  • photo resistor (photo-diode on the schematics)
  • 3x 100nF ceramic capacitors
  • general purpose bipolar npn transistor, ksp10 or 2n2222
  • 10k Ohm potentiometer
  • 2x 10 kOhm resistors
  • ne555 ic

  • 220 uF capacitor 10v

  • 10 nF ceramic capacitor

  • 300 k resister

  • 3.3 k resister

  • 470 Ohm resister

  • 220 ohm resister

  • 1n4001 diode

  • 5 v regulated external power supply

Step 5: Lite Version of Display Module

This is the non-expensive variant of display module based on small arduino controller such as arduino nano or atmega328p-pu IC. The module only shows the sensor data. The main external sensor ID is built into the sketch constant and cannot be changed from the module. You need to download the sketch one more time. Lite version schematic is available in two variants: based on arduino nano or atmega328p-pu ic. The nano variant is much more easier to build.

The sketch can be download from here (weather_Oregon_12864_atmega328p.ino).

Unfortunately, the bmp180 sensor can hang the arduino controller. To prevent this situation, the ne555 ic is implemented in schematics. This is some sort of watch-dog timer for near 60 second. This timer is highlighted on the schematics and can be omitted.

In this version of display module, there is no menu, so the main sensor ID is hard-coded in the sketch. If you set 0 as the sensor ID, the data of the first external sensor will be choosed as the main sensor data. Or you can directly set your sensor ID. In this version of the display module on the right side of the screen all sensor data (including internal one) is shown. The internal sensor has ID equal to 0.

Required components for arduino nano variant:

  • arduino nano microcontroller
  • bmp280 pressure sensor
  • dht22 temperature/humidity sensor
  • RX6 433 MHz receiver
  • photo resistor
  • ne555 ic
  • general purpose npn bipolar transistor 2n2222 or ksp10
  • 220 uF capacitor 10v
  • 10 nF ceramic capacitor
  • 100 uF capacitor 10v
  • 10 uF capacitor 10v
  • 100 nF ceramic capacitor
  • 10 kOhm potentiometer
  • 4x 10 kOhm resisters
  • 300 k resister
  • 3.3 k resister
  • 470 Ohm resister
  • 220 ohm resister
  • 1n4001 diode
  • External power supply 7-9v

Required components for atmega328p-pu variant:

  • atmega328p-puIC
  • 16 MHz oscillator
  • 2x22pF capacitors
  • ams1117-3.3 voltage regulator
  • bmp280 pressure sensor
  • dht22 temperature/humidity sensor
  • RX6 433 MHz receiver
  • photo resistor
  • ne555 ic
  • general purpose npn bipolar transistor 2n2222 or ksp10
  • 220 uF capacitor 10v
  • 10 nF ceramic capacitor
  • 100 uF capacitor 10v
  • 10 uF capacitor 10v
  • 100 nF ceramic capacitor
  • 10 kOhm potentiometer
  • 4x 10 kOhm resisters
  • 300 k resister
  • 3.3 k resister
  • 470 Ohm resister
  • 220 ohm resister
  • 1n4001 diode
  • External regulated power supply 5v
Arduino Contest 2016

Participated in the
Arduino Contest 2016

Be the First to Share


    • Make it Glow Contest

      Make it Glow Contest
    • First Time Author Contest

      First Time Author Contest
    • PCB Challenge

      PCB Challenge

    4 Discussions


    Question 2 years ago on Step 5


    j'aimerai utiliser <sunMoon> avec un st7920 mais je n'arrive pas à avoir l'heure sunset,sunrise .

    pourriez vous m'aider ,d'avance merci

    #include "U8glib.h" // OLED
    #include "Wire.h" // I2C
    #include <Time.h>
    #include "TimeLib.h" // Time Manipulation
    #include <sunMoon.h>
    #include "DS1307RTC.h" // DS1307 RTC
    //int Sunrise, Sunset;
    char timebuf[20]; // Time
    char datebuf[20]; // Date
    char sRisebuf[20];// char sunrise
    char sSetbuf[20];// char sunset
    int year2digit; // 2 digit year
    int year4digit; // 4 digit year
    #define OUR_latitude 43.70 //27.0133 Moscow cordinates
    #define OUR_longtitude 7.25 //49.6641
    #define OUR_timezone 120//180 localtime with UTC difference in minutes
    sunMoon sm;

    //U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8); // D0=13, D1=11, CS=10, DC=9, Reset=8
    U8GLIB_ST7920_128X64 u8g(13, 11, 12, U8G_PIN_NONE);

    const uint8_t brainy_bitmap[] PROGMEM = {
    0x00, 0x00, 0x03, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x46,
    0x00, 0x00, 0x00, 0x00, 0xFC, 0x47, 0xC0, 0x00, 0x00, 0x01, 0xCE, 0x4C, 0x60, 0x00, 0x00, 0x03,
    0x02, 0x58, 0x30, 0x00, 0x00, 0x03, 0x02, 0x58, 0x10, 0x00, 0x00, 0x02, 0x02, 0x58, 0x18, 0x00,
    0x00, 0x03, 0x06, 0x4C, 0x18, 0x00, 0x00, 0x07, 0x04, 0x44, 0x18, 0x00, 0x00, 0x0D, 0x80, 0x40,
    0x3C, 0x00, 0x00, 0x09, 0xC0, 0x40, 0xE6, 0x00, 0x00, 0x18, 0x78, 0x47, 0xC2, 0x00, 0x00, 0x18,
    0x0C, 0x4E, 0x02, 0x00, 0x00, 0x1F, 0x86, 0x4C, 0x7E, 0x00, 0x00, 0x0E, 0xC6, 0xE8, 0xEE, 0x00,
    0x00, 0x18, 0x43, 0xF8, 0x82, 0x00, 0x00, 0x10, 0x06, 0x4C, 0x03, 0x00, 0x00, 0x30, 0x0C, 0x46,
    0x01, 0x00, 0x00, 0x30, 0x18, 0x46, 0x01, 0x00, 0x00, 0x10, 0x18, 0x43, 0x03, 0x00, 0x00, 0x18,
    0x10, 0x43, 0x03, 0x00, 0x00, 0x1C, 0x70, 0x41, 0x86, 0x00, 0x00, 0x0F, 0xE0, 0x40, 0xFE, 0x00,
    0x00, 0x09, 0x1E, 0x4F, 0x06, 0x00, 0x00, 0x08, 0x30, 0x43, 0x86, 0x00, 0x00, 0x0C, 0x20, 0x41,
    0x86, 0x00, 0x00, 0x06, 0x60, 0x40, 0x8C, 0x00, 0x00, 0x07, 0x60, 0x40, 0xB8, 0x00, 0x00, 0x01,
    0xE0, 0x41, 0xF0, 0x00, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xBE, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xCF, 0x82, 0x0C, 0x86, 0x46, 0x1F, 0xEF, 0xC3, 0x0C,
    0xC6, 0xEE, 0x1C, 0xEC, 0xC7, 0x0C, 0xE6, 0x7C, 0x1C, 0xED, 0x8D, 0x8C, 0xFE, 0x38, 0x1C, 0xED,
    0x8D, 0xCC, 0xDE, 0x38, 0x1D, 0xCD, 0xDF, 0xCC, 0xCE, 0x38, 0x1F, 0x8C, 0xF8, 0xEC, 0xC6, 0x38,
    0x1F, 0xEC, 0x08, 0x0C, 0xC2, 0x18, 0x1C, 0xEC, 0x00, 0xC0, 0x00, 0x00, 0x1C, 0xFD, 0xFB, 0xC0,
    0x00, 0x00, 0x1C, 0xFC, 0x63, 0x00, 0x00, 0x00, 0x1C, 0xEC, 0x63, 0xC0, 0x00, 0x00, 0x1F, 0xEC,
    0x60, 0xC0, 0x00, 0x00, 0x1F, 0xCC, 0x63, 0xC0, 0x00, 0x00, 0x1F, 0x0C, 0x63, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x2B, 0x4F, 0x67,
    0x42, 0x38, 0x7B, 0xEA, 0x86, 0xB2, 0x28, 0xC7,


    void draw(void) {
    u8g.drawBitmapP( 78, 5, 6, 50, brainy_bitmap); // put bitmap
    u8g.setFont(u8g_font_fur11); // select font
    u8g.setPrintPos(0, 12); // set position
    u8g.print(timebuf); // display time
    u8g.setPrintPos(0, 22); // set position
    u8g.print(datebuf); // display date

    void setup(void) {

    tmElements_t tm;
    sm.init(OUR_timezone, OUR_latitude, OUR_longtitude);
    time_t sRise = sm.sunRise();time_t sunrise
    time_t sSet = sm.sunSet();time_t sunset
    uint32_t jDay = sm.julianDay(); // Optional call
    byte mDay = sm.moonDay();
    time_t s_date = makeTime(tm);
    jDay = sm.julianDay(s_date);
    mDay = sm.moonDay(s_date);
    sRise = sm.sunRise(s_date);
    sSet = sm.sunSet(s_date);


    void loop(void) {

    tmElements_t tm;
    if ( {
    year2digit = tm.Year - 30; // 2 digit year variable
    // year4digit = tm.Year + 1970; // 4 digit year variable

    sprintf(timebuf, "%02d:%02d:%02d",tm.Hour, tm.Minute, tm.Second); // format time
    sprintf(datebuf, "%02d/%02d/%02d",tm.Day, tm.Month, year2digit); // format date
    sprintf(sRisebuf, "%02d:%02d:%02d",tm.Hour,tm.Minute,tm.Second); // sprintf(sunset, "%02d:%02d", hour(rise), minute(rise));
    sprintf(sSetbuf, "%02d:%02d:%02d",tm.Hour,tm.Minute,tm.Second); // sprintf(sunrise, "%02d:%02d", hour(rise), minute(rise));
    time_t sRise = sm.sunRise();
    time_t sSet = sm.sunSet();
    time_t sunRise(time_t date = 0);
    time_t sunSet(time_t date = 0);

    u8g.firstPage(); // Put information on OLED
    do {
    } while( u8g.nextPage() );


    delay(1000); // Delay of 1sec



    Reply 2 years ago

    Dear friend,

    Sorry, i can only use english or russian. Suppose, the english is more convenient for you.

    Here is an example of using the library ( This example is a part of the library.

    SunMon class methods use current time of the microcontroller if they are called without an argument. You must synchroze the system time with the RTC time to get current time and date. Or youcan call the methods with anargument - time of the day you want to see the sunrise or sunset. Please, investigate the example. In lines 46-50 you can see the today data, and in the lnes 22-28 and 56-63 you can see the data for specific day.


    4 years ago

    no script?


    Reply 4 years ago

    Do you mean the sketch, source sode? There are links to the github repository inside description.