Weather Station using Raspberry Pi & Arduino

Introduction

This post will be extensive so will be separated into 3 parts to make it easier to write and read. I have spent the last couple of months developing a weather station; both for the fun of it and to improve my understanding of the C programming language. The weather station will perform quite a few tasks. It comes in 3 separate bits; several remote sensors that transmit their temperature, location and battery status over an RF link, a receiver module that receives the data over the RF link and the raspberry pi main station which talks over I2C to the receiver unit to get the data. The raspberry pi then processes this information to display on an LCD screen. It has five buttons; one switches between all remote sensors and it’s self, 2nd switches between the data&time, IP address and WiFi signal strength, 3rd switches between Celsius and Fahrenheit, 4th turns the display backlight on/off and 5th safely turns the raspberry pi off. All of the code is written in C, both the raspberry pi and arduino.

Please note this does not explain the code line by line and assumes you have an understanding of the “C” programming language. I give solutions to problems I came across and a overall explanation of the code. Hopefully you will find this useful but please comment if you have any queries.

Part One: Arduino Based Remote Sensors

The remote sensor has several parts. A 7 segment display, a button to switch between display on/off, Celsius, Fahrenheit and battery, power module, radio transmitter, two LEDs and the Atmega 328p (Arduino microcontroller, Arduino is used as a programmer only). I bought most of the parts from banggood.com as I found them cheaper, free delivery from China can take a while but they have a few of their things in Europe which arrives quicker.

Parts:

Amount Part Type URL
1 Banggood 4 Digit Display http://www.banggood.com/2Pcs-4-Bits-Digital-Tube-LED-Display-Module-Board-With-Clock-p-944244.html
1 DS18B20 1-Wire Temperature Sensor http://www.banggood.com/DS18B20-Waterproof-Digital-Temperature-Temp-Sensor-Probe-1M-2M-3M-5M-10M-15M-p-983801.html
1 Green LED http://www.banggood.com/200Pcs-3MM-LED-Light-Assorted-Kit-Red-Green-Blue-Yellow-White-DIY-LEDs-Set-p-1018612.html
1 Red LED http://www.banggood.com/200Pcs-3MM-LED-Light-Assorted-Kit-Red-Green-Blue-Yellow-White-DIY-LEDs-Set-p-1018612.html
2 470Ω Resistor http://www.banggood.com/750Pcs-30-Values-1-14W-Five-Color-Ring-Metal-Film-Resistor-Kit-p-961336.html
2 10kΩ Resistor http://www.banggood.com/750Pcs-30-Values-1-14W-Five-Color-Ring-Metal-Film-Resistor-Kit-p-961336.html
1 Pushbutton http://www.banggood.com/50Pcs-Tactile-Push-Button-Switch-Momentary-Tact-Cap-Assorted-Kit-12x12x7_3mm-KeyCaps-p-1007178.html
1 atmega328 http://www.banggood.com/5Pcs-DIP28-ATmega328P-PU-MCU-IC-Chip-With-Arduino-UNO-Bootloader-p-953574.html
1 FS1000A – 433Mhz RF Transmitter http://www.banggood.com/5Pcs-433Mhz-RF-Transmitter-With-Receiver-Kit-For-Arduino-MCU-Wireless-p-951033.html
1 Breadboard http://eu.banggood.com/Wholesale-Warehouse-MB102-830-Tie-Points-Solderless-PCB-Breadboard-65-Pcs-Jumper-Cables-wp-Eu-920099.html
1 Chip Holder http://www.banggood.com/20Pcs-28-Pins-IC-DIP-2_54mm-Wide-Integrated-Circuit-Sockets-Adaptor-p-944247.html
1 Power Module http://www.banggood.com/2Pcs-2-Way-5V-3_3V-Breadboard-Power-Module-For-Arduino-p-950153.html

Fritzing Diagram

TransmitterTo program the chip externally using an Arduino please see here

The Code

Please note: The 7 Segment display driver used I have written so is available on a previous post or via the Arduino community website.

So what does the code do?

Setup:

This sets up the button, threading stuff (not true threads, an implementation to run code blocks at specified times), pins and the RF transmitter. There are three threads, one for transmitting the data over RF, second for gathering the battery information and third for checking the temperature. Pay particular attention to the timings; the transmitting thread runs at a random time so it minimises the chance of a collision with another probe, the battery runs every 2 minutes to save battery life and it is not necessary to run any more. The most important thread is “tempCheck”, this is because this action takes 2ms to complete (Reduced from default 750ms) and the 7 segment display needs a value to be constantly written to it otherwise it would go off. This makes the display sensitive to timings, if there is a delay in the code then the display will go off and a small delay like 50ms will make the display flicker. I experimented for a while but found the optimal solution for me. If the code didn’t check the temperature at all then the display would be full brightness without any flicker at all, but this would be pointless. If I made the temperature check only happen every 10 seconds then it would be too slow to react and you would see a noticeable flick. I chose to check every 8ms because the display is constant with no visible flicker although it is not quite full brightness and it reacts instantly to temperature change. If you run the chip at 16mhz instead of 8 then the timings would be different. The rest of the setup code should pretty much explain itself.

Loop:

The lines 144 – 170 make the push button a switch so it switches the display between 4 modes and controls the timing of the threads. The button increments a displayValToShow value when pushed and further down in the loop a series of “ifs” checks the value to determine what to send to the display function. I noticed that using a switch statement here makes the code neater but performs noticeably slower as the display flickers. It is possible the compiler is not optimising the switch correctly. The code then calls a function to convert the float values to a char array so they can be displayed by the 7 segment display as the function takes a char array. After the if statements have been called then a function call prints the char array on the display. Please note “////” is sent to the display as this turns the display “off”.

Checking Temp Quickly:

This was an issue when using a 7 segment display as noted above. The display needs to be constantly updated fast enough that the human eye can’t see any flicker. The display is not constantly on like an LCD but a series of pulses. For more information see my previous post here. The DS18B20 temperature probe takes 750ms to read a value in it’s full accuracy mode and 93ms in its least accurate. Both of these times are slow enough to visibly pause the display but I found a way of asynchronously getting the reading which reduces the time to 2ms with any level of accuracy. I was able to tweak how often to fetch the temperature to every 8ms which meant the display did not flicker.

Sending the Temp etc over RF:

I wanted to send several bits of data over the RF radios, including temperature, battery status and sensor ID. The easiest and neatest way of doing this was sending a structure, but the excellent Virtual Wire library function “vw_send” requires bytes to be sent. To send a structure the structure needs to be cast into a “uint8_t *” which would send it over as bytes. I also blink a green LED to show transmission.

To prevent multiple sensors transmitting at the same time then I have made them choose a random time upon power on using the analogue pin of the atmega as a seed. I decided to choose between 1-2mins however the code above is development code and is between 10 and 20 seconds. This is located on lines 107 & 129.

Device Prototype

I built this using a breadboard and then built another sensor using a perf board. The next step would be a printed circuit board as this would be more professional, reliable and quicker to build. Here are some pictures.

Arduino based remote sensor for weather station
Remote sensor for weather station

To Do:

There are a few things I still need to implement.

  1. Tidy up the code to production
  2. Optimise for battery use
  3. Add diode to finished circuit so I can use a battery or mains
  4. Possibly add a voltage regulator to keep it at 5v when running off a battery
  5. Possibly add a voltage step-up device for the transmitter so it can operate at 12v to improve its range
  6. Get printed PCB
  7. Build a case

Part Two: Arduino Based Receive Sensor module for Raspberry Pi

This module is designed to receive the RF transmissions and store them in a temporary structure. The raspberry pi will ask the module to send the data over a i2c connection when asked.

Fritzing Diagram:

Arduino Based Receiver Module

The module has five buttons; from left to right: Switch Sensor, (Switch between Date&Time, IP, WiFi Signal), Switch between Celsius & Fahrenheit, Turn Display LED off and Safely Shutdown. As you can see from the diagram above the buttons are attached to the raspberry pi directly as well as the LCD screen (Please note the LCD is not attached on the diagram as mine is soldered to the i2c chip already so I am just showing the connections from the i2c chip). These will be explained in the next section but I mention them here because I soldered together a module which plugs directly onto the raspberry pi as one unit.

The Atmega 328p chip runs a loop checking  to see if the receiver module has received a valid signal and if it has then it copies it into the sensor structure. The code checks the temperature and humidity of the DHT22 sensor every 2 seconds and copies into the correct structure. The code only performs something else when the raspberry pi sends a request via the i2c interface; either a 1 or 0. Depending on the number then the chip will send back the local data or remote sensor data. A union is used so the structure can be sent as a char array; a uint16_t should be used here for consistency and not just an int as the raspberry pi needs to use a uint16_t to rebuild the structure correctly. This is because the Atmega 328p stores an int as 2 bytes while the raspberry pi stores an int as 4 bytes.

The Code:

Photos:

Receive Module
Receive Module
Receive Module
Receive Module
Receive Module
Receive Module
Receive Module
Receive Module

As you can see I decided to build it as a two tier board with small nuts holding them apart. This was easier to build and mount the LCD. I will move the DHT22 module to the top board as it gets affected by the raspberry pi’s heat and the second board is cooler, I will also extend the LED’s if I put it in a case.

Part Three: Raspberry Pi C code for the central weather station

This is where all the intelligence happens. The code has a view bugs in it still however they do not effect the usage of the weather station itself. As the explained earlier the buttons perform the following functions: from left to right: Switch Sensor, (Switch between Date&Time, IP, WiFi Signal), Switch between Celsius & Fahrenheit, Turn Display LED off and Safely Shutdown. The code is quite large and has many threads to enable all the buttons and sensor functions to work simultaneously. There are three “c” files and one header file. The code does use the wiringPi library and therefore requires root to run. I’ll start with the smallest file first; the header file.

Header File:

This is pretty small and simple to understand. The code should explain itself, the functions will be explained later on.

i2c.c Code:

This code opens the i2c device and stores the int used to access it in a global variable. There are functions here to get the data from the chip, either remote sensor information or the local temp probe. The piLock is set to number 2 which is the same as the lock used in another file accessing the i2c device. This means corruption of the i2c devices won’t occur.

mlcd.c File:

This file writes information to the 16×2 LCD display. The code was originally quickly written by a colleague of mine (without the device) and I modified it to into more of a library. The code was ported from a Python script I had found. The code is commented and is only basic in terms of functionality. There is no function to move the cursor around or clear only a section of the display for example. I could not find anything written in C for the raspberry Pi so had to quickly make one (with some help).

weatherStation.c Code:

This file is far too large to go through the code line by line but I have commented every function with an explanation. Please comment if there is anything you don’t understand or think could be improved. The code initualises the button struct’s and starts all the threads. Every 5 seconds the value from the Atmega chip is retrieved and processed into the correct struct. The display displays the date/time by default but any press of the button changes that. The sensor values are written to a RAM disk so they can be monitored by Zabbix.

To compile the files then run this command:

To run in the background then add an & at the end of the last command.

Zabbix Monitoring Integration:

Zabbix Temp Values
Zabbix Temp Values

 

QT Mobile/Desktop Application:

To Do. I would like to learn QT so I will write a application to control the station. Add sensors etc.

Video:

Weather Station Preview

References:

https://www.arduino.cc/en/Tutorial/ArduinoToBreadboardhttps://www.arduino.cc/en/Main/Standalone
http://www.gammon.com.au/forum/?id=11637
https://github.com/ivanseidel/ArduinoThread
http://www.homautomation.org/2014/03/06/running-atmega328-in-a-standalone-mode-without-arduino-shield/
https://monotok.org/arduino-using-c-to-write-7-segment-4-bit-display-driver/
https://www.arduino.cc/en/Hacking/PinMapping168
http://computers.tutsplus.com/tutorials/building-a-wireless-sensor-network-in-your-home–cms-19745
https://tushev.org/articles/arduino/10/how-it-works-ds18b20-and-arduino
http://www.homautomation.org/2015/11/17/ds18b20-how-to-change-resolution-9101112-bits/
https://arduino-info.wikispaces.com/Brick-Temperature-DS18B20
https://www.arduino.cc/en/Reference/BitwiseAnd
https://github.com/milesburton/Arduino-Temperature-Control-Library/blob/master/examples/WaitForConversion/WaitForConversion.pde
http://www.hobbytronics.co.uk/arduino-float-vars
http://www.asciitable.com/
https://www.arduino.cc/en/tutorial/switch
https://forum.mysensors.org/topic/186/new-library-to-read-arduino-vcc-supply-level-without-resistors-for-battery-powered-sensor-nodes-that-do-not-use-a-voltage-regulator-but-connect-directly-to-the-batteries/2
https://forum.arduino.cc/index.php?topic=341819.0

Please share 🙂