Introduction: Personal Weather Station Using Raspberry Pi With BME280 in Java

About: We are a group of makers. We work in IoT, IOS app, android app, embedded design, sensor design, raspberry pi, arduino, beaglebone, particle electron, particle photon, Bluetooth.

Bad weather always looks worse through a window.

We’ve always been interested in monitoring our local weather and what we see out the window. We also wanted better control over our heating and A/C system. Building a Personal Weather Station is a great learning experience. When you finish building this project you will have a better understanding of how wireless communications work, how sensors work, and how powerful the Raspberry Pi platform can be. With this project as a base and the experience gained, you will be able to easily build more complex projects in the future.

Step 1: Bill of Essential Equipment

1. A Raspberry Pi

The first step is to get your hands on a Raspberry Pi board. Raspberry Pi is a Linux powered single board computer. Its goal is to improve programming skills and hardware understanding. It was quickly adopted by hobbyists and electronics enthusiasts for innovative projects.

2. I²C Shield for Raspberry Pi

The INPI2(I2C adapter) provides the Raspberry Pi 2/3 an I²C port for use with multiple of I²C devices. It's available on Dcube Store

3. Digital Humidity, Pressure and Temperature Sensor, BME280

The BME280 is a humidity, pressure and temperature sensor that has fast response time and high overall accuracy. We purchased this sensor from Dcube Store

4. I²C Connecting Cable

We had the I²C connecting cable available at Dcube Store

5. Micro USB cable

The micro USB cable Power supply is an ideal choice for powering the Raspberry Pi.

6. Interpret Internet Access via EthernetCable/WiFi Adapter

One of the first things that you will want to do is to get your Raspberry Pi connected up to the Internet. We can connect using an Ethernet cable. Another possibility is that you can connect to a wireless network using a USB wireless Adapter.

7. HDMI Cable(Display & connectivity cable)

Any HDMI/DVI monitor and any TV should work as a display for the Pi. But it's optional. Remote access(like-SSH) possibility can’t be ruled out also. You can also get access with PUTTY software.

Step 2: Hardware Connections for Setup

Make the circuit as per the schematic shown.

While learning, we got thoroughly with the basics of electronics regarding hardware and software knowledge. We wanted to draw up a simple electronics schematic for this project. Electronic schematics are like a blueprint for electronics. Draw up a blueprint and follow the design carefully. We have applied some basics of electronics here. Logic gets you from A to B, Imagination will take you everywhere !

Connection of the Raspberry Pi and I²C Shield

First of all take the Raspberry Pi and place the I²C Shield(with Inward Facing I²C Port) on it. Press the Shield gently over the GPIO pins of Pi and we are done with this step as easy as pie(see the pic).

Connection of the Sensor and Raspberry Pi

Take the sensor and Connect the I²C cable with it. Make sure that I²C Output ALWAYS connects to the I²C Input. The same has to be followed for the Raspberry Pi with the I²C shield mounted over it the GPIO pins.
We have the I²C Shield and the connecting cables on our side as a very big relief and a very big advantage as we are left only with the plug and play option. No more pins and wiring issue and hence, confusion is gone. Just imagine yourself in the web of wires and getting into that. A relief from that. This makes things uncomplicated.

Note : The brown wire should always follow the Ground (GND) connection between the output of one device and the input of another device.

Internet Connectivity is a Need

You have a choice here actually. You can connect Raspberry Pi with the LAN cable or the wireless Nano USB Adapter for WIFI Connectivity. Either way, the manifest is to connect to the internet which is accomplished.

Powering of the Circuit

Plug in the Micro USB cable into the power jack of Raspberry Pi. Punch up and voila! Everything's good to go and we will start immediately.

Connection to Display

We can either have the HDMI cable connected to a monitor or a TV. We can access a Raspberry Pi without connecting it to a monitor using -SSH(Access the command line of the Pi from another computer). You can also use the PUTTY software for that. This option is for advanced users so we won't be covering it in detail here.

I’ve heard there’s going to be a recession, I’ve decided not to participate.

Step 3: Raspberry Pi Programming in Java

The Java Code for the Raspberry Pi and BME280 Sensor. It's available in ourGithub repository.

Before going on to the code, make sure you read the instructions given in the Readme file and Setup your Raspberry Pi according to it. It will take just take a moment to do so.
A personal weather station is a set of weather-measuring instruments operated by a private individual, club, association, or even business. Personal weather stations may be operated solely for the enjoyment and education of the owner, but many personal weather station operators also share their data with others, either by manually compiling data and distributing it, or through the use of the internet or amateur radio.

The code is in it’s simplest form you can imagine and you should have no issue with it but ask if you have. Even if you know a thousand things, still ask someone who knows.

You can copy the working java code for this sensor from here as well.

<p>// Distributed with a free-will license.<br>// Use it any way you want, profit or free, provided it fits in the licenses of its associated works.
// BME280
// This code is designed to work with the BME280_I2CS I2C Mini Module available from ControlEverything.com.
// https://www.controleverything.com/content/Humidity?sku=BME280_I2CS#tabs-0-product_tabset-2</p><p>import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;
import java.io.IOException;</p><p>public class BME280
{
    public static void main(String args[]) throws Exception
    {
        // Create I2C bus
        I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1);
        // Get I2C device, BME280 I2C address is 0x76(108)
        I2CDevice device = bus.getDevice(0x76);
        
        // Read 24 bytes of data from address 0x88(136)
        byte[] b1 = new byte[24];
        device.read(0x88, b1, 0, 24);
        
        // Convert the data
        // temp coefficients
        int dig_T1 = (b1[0] & 0xFF) + ((b1[1] & 0xFF) * 256);
        int dig_T2 = (b1[2] & 0xFF) + ((b1[3] & 0xFF) * 256);
        if(dig_T2 > 32767)
        {
            dig_T2 -= 65536;
        }
        int dig_T3 = (b1[4] & 0xFF) + ((b1[5] & 0xFF) * 256);
        if(dig_T3 > 32767)
        {
            dig_T3 -= 65536;
        }
        
        // pressure coefficients
        int dig_P1 = (b1[6] & 0xFF) + ((b1[7] & 0xFF) * 256);
        int dig_P2 = (b1[8] & 0xFF) + ((b1[9] & 0xFF) * 256);
        if(dig_P2 > 32767)
        {
            dig_P2 -= 65536;
        }
        int dig_P3 = (b1[10] & 0xFF) + ((b1[11] & 0xFF) * 256);
        if(dig_P3 > 32767)
        {
            dig_P3 -= 65536;
        }
        int dig_P4 = (b1[12] & 0xFF) + ((b1[13] & 0xFF) * 256);
        if(dig_P4 > 32767)
        {
            dig_P4 -= 65536;
        }
        int dig_P5 = (b1[14] & 0xFF) + ((b1[15] & 0xFF) * 256);
        if(dig_P5 > 32767)
        {
            dig_P5 -= 65536;
        }
        int dig_P6 = (b1[16] & 0xFF) + ((b1[17] & 0xFF) * 256);
        if(dig_P6 > 32767)
        {
            dig_P6 -= 65536;
        }
        int dig_P7 = (b1[18] & 0xFF) + ((b1[19] & 0xFF) * 256);
        if(dig_P7 > 32767)
        {
            dig_P7 -= 65536;
        }
        int dig_P8 = (b1[20] & 0xFF) + ((b1[21] & 0xFF) * 256);
        if(dig_P8 > 32767)
        {
            dig_P8 -= 65536;
        }
        int dig_P9 = (b1[22] & 0xFF) + ((b1[23] & 0xFF) * 256);
        if(dig_P9 > 32767)
        {
            dig_P9 -= 65536;
        }
        
        // Read 1 byte of data from address 0xA1(161)
        int dig_H1 = ((byte)device.read(0xA1) & 0xFF);
        
        // Read 7 bytes of data from address 0xE1(225)
        device.read(0xE1, b1, 0, 7);
        
        // Convert the data
        // humidity coefficients
        int dig_H2 = (b1[0] & 0xFF) + (b1[1] * 256);
        if(dig_H2 > 32767)
        {
            dig_H2 -= 65536;
        }
        int dig_H3 = b1[2] & 0xFF ;
        int dig_H4 = ((b1[3] & 0xFF) * 16) + (b1[4] & 0xF);
        if(dig_H4 > 32767)
        {
            dig_H4 -= 65536;
        }
        int dig_H5 = ((b1[4] & 0xFF) / 16) + ((b1[5] & 0xFF) * 16);
        if(dig_H5 > 32767)
        {
            dig_H5 -= 65536;
        }
        int dig_H6 = b1[6] & 0xFF;
        if(dig_H6 > 127)
        {
            dig_H6 -= 256;
        }
        
        // Select control humidity register
        // Humidity over sampling rate = 1
        device.write(0xF2 , (byte)0x01);
        // Select control measurement register
        // Normal mode, temp and pressure over sampling rate = 1
        device.write(0xF4 , (byte)0x27);
        // Select config register
        // Stand_by time = 1000 ms
        device.write(0xF5 , (byte)0xA0);
        
        // Read 8 bytes of data from address 0xF7(247)
        // pressure msb1, pressure msb, pressure lsb, temp msb1, temp msb, temp lsb, humidity lsb, humidity msb
        byte[] data = new byte[8];
        device.read(0xF7, data, 0, 8);
        
        // Convert pressure and temperature data to 19-bits
        long adc_p = (((long)(data[0] & 0xFF) * 65536) + ((long)(data[1] & 0xFF) * 256) + (long)(data[2] & 0xF0)) / 16;
        long adc_t = (((long)(data[3] & 0xFF) * 65536) + ((long)(data[4] & 0xFF) * 256) + (long)(data[5] & 0xF0)) / 16;
        // Convert the humidity data
        long adc_h = ((long)(data[6] & 0xFF) * 256 + (long)(data[7] & 0xFF));
        
        // Temperature offset calculations
        double var1 = (((double)adc_t) / 16384.0 - ((double)dig_T1) / 1024.0) * ((double)dig_T2);
        double var2 = ((((double)adc_t) / 131072.0 - ((double)dig_T1) / 8192.0) *
                       (((double)adc_t)/131072.0 - ((double)dig_T1)/8192.0)) * ((double)dig_T3);
        double t_fine = (long)(var1 + var2);
        double cTemp = (var1 + var2) / 5120.0;
        double fTemp = cTemp * 1.8 + 32;
        
        // Pressure offset calculations
        var1 = ((double)t_fine / 2.0) - 64000.0;
        var2 = var1 * var1 * ((double)dig_P6) / 32768.0;
        var2 = var2 + var1 * ((double)dig_P5) * 2.0;
        var2 = (var2 / 4.0) + (((double)dig_P4) * 65536.0);
        var1 = (((double) dig_P3) * var1 * var1 / 524288.0 + ((double) dig_P2) * var1) / 524288.0;
        var1 = (1.0 + var1 / 32768.0) * ((double)dig_P1);
        double p = 1048576.0 - (double)adc_p;
        p = (p - (var2 / 4096.0)) * 6250.0 / var1;
        var1 = ((double) dig_P9) * p * p / 2147483648.0;
        var2 = p * ((double) dig_P8) / 32768.0;
        double pressure = (p + (var1 + var2 + ((double)dig_P7)) / 16.0) / 100;
        
        // Humidity offset calculations
        double var_H = (((double)t_fine) - 76800.0);
        var_H = (adc_h - (dig_H4 * 64.0 + dig_H5 / 16384.0 * var_H)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * var_H * (1.0 + dig_H3 / 67108864.0 * var_H)));
        double humidity = var_H * (1.0 -  dig_H1 * var_H / 524288.0);
        if(humidity > 100.0)
        {
            humidity = 100.0;
        }else
            if(humidity < 0.0) 
            {
                humidity = 0.0;
            }
        
        // Output data to screen
        System.out.printf("Temperature in Celsius : %.2f C %n", cTemp);
        System.out.printf("Temperature in Fahrenheit : %.2f F %n", fTemp);
        System.out.printf("Pressure : %.2f hPa %n", pressure);
        System.out.printf("Relative Humidity : %.2f %% RH %n", humidity);
    }
}</p>

Step 4: The Code Practicality

Now, download (or git pull) the code and open it in the Raspberry Pi.

Run the commands to Compile and Upload the code on the terminal and see the output on Monitor. After few moments, it will screen all the parameters. Making ensure that you have a smooth code transition and a calm(ish) result, you think of more ideas to make further amendments(Every Project starts with a Story).

Step 5: Utilization in Constructive World

The BME280 achieves high performance in all applications requiring humidity and pressure measurement. These emerging applications are Context Awareness, e.g. Skin Detection, Room Change Detection, Fitness Monitoring / Well-Being, Warning Regarding Dryness or High Temperatures, Measurement of Volume and Air Flow, Home Automation Control, Control Heating, Ventilation, Air Conditioning (HVAC), Internet of Things(IoT), GPS Enhancement (e.g. Time-to-First-Fix Improvement, Dead Reckoning, Slope Detection), Indoor Navigation (Change of Floor Detection, Elevator Detection), Outdoor Navigation, Leisure & Sports Applications, Weather Forecast And Vertical Velocity Indication (Rise/Sink Speed).

Step 6: Conclusion

As you can see, this project is a great demonstration of what hardware and software are capable of. In a little amount of time, one can build such an impressive project! Of course, this is a just the beginning. Making a more sophisticated Personal Weather Station like Automated Airport Personal Weather Stations can involve some more sensors like Anemometer(wind speed), Transmissometer(visibility), Pyranometer(solar radiation) etc. We have a video tutorial on Youtube having the basic functioning of the I²C sensor with Rasp Pi. It’s really amazing to see the results and working of the I²C communications. Check it as well. Have fun building and learning! Please let us know what you think of this instructable. We would love to make some improvements if necessary.

Once we accept our limits, we go beyond them.