Advanced Weather Station v2.0: Real‑Time Temperature, Pressure, Humidity & Altitude Monitoring
Build a compact weather station that accurately measures temperature, pressure, humidity, and altitude right in your living space.
Story
Using the Adafruit Starter Pack for Windows 10 IoT Core on a Raspberry Pi 2, this project demonstrates how to interface a BME280 sensor (or BMP280) to read environmental data and publish it to a cloud service.
If you own a BMP280, follow the Weather Station v1 guide instead: Weather Station v1.
Hardware
Connect the Raspberry Pi 2 to a breadboard and wire the BME280 sensor according to the Fritzing diagram in the “Schematics” section below.
Software
Download the starter code from GitHub – ms‑iot/adafruitsample. We’ll walk you through adding the necessary code to communicate with the sensor and publish your readings.
Open Lesson_203v2\StartSolution\lesson_203v2.sln and edit mainpage.xaml.cs.
A fully completed version is available at Lesson_203v2\FullSolution\lesson_203v2.sln.
MainPage.xaml.cs
Add a reference to the BME280 class:
public sealed partial class MainPage : Page
{
// Create a new object for our sensor class
BME280 BME280;
Initialize the sensor in OnNavigatedTo:
// Create a new object for our sensor class BME280 = new BME280Sensor(); // Initialize the sensor await BME280.Initialize();
Next, add code to gather and log data:
- Create variables for temperature, pressure, humidity and altitude, initialized to 0.
- Set a sea‑level pressure constant (default 1013.25 hPa).
- Read the four measurements ten times and output them to the debug console.
//Initialize them to 0.
float temp = 0;
float pressure = 0;
float altitude = 0;
float humidity = 0;
//Create a constant for pressure at sea level.
const float seaLevelPressure = 1022.00f;
//Read 10 samples of the data
for (int i = 0; i < 10; i++){
temp = await BME280.ReadTemperature();
pressure = await BME280.ReadPreasure();
altitude = await BME280.ReadAltitude(seaLevelPressure);
humidity = await BME280.ReadHumidity();
//Write the values to your debug console
Debug.WriteLine("Temperature: " + temp.ToString() + " deg C");
Debug.WriteLine("Humidity: " + humidity.ToString() + " %");
Debug.WriteLine("Pressure: " + pressure.ToString() + " Pa");
Debug.WriteLine("Altitude: " + altitude.ToString() + " m");
Debug.WriteLine("\n");
}
BME280.cs
Open BME280.cs and add the following after the register‑address enum:
//String for the friendly name of the I2C bus const string I2CControllerName = "I2C1"; //Create an I2C device private I2cDevice bme280 = null; //Create new calibration data for the sensor BME280_CalibrationData CalibrationData; //Variable to check if device is initialized bool init = false;
Enhance the Initialize method to set up the I2C connection:
public async Task Initialize()
{
Debug.WriteLine("BME280::Initialize");
try
{
I2cConnectionSettings settings = new I2cConnectionSettings(BME280_Address);
settings.BusSpeed = I2cBusSpeed.FastMode;
string aqs = I2cDevice.GetDeviceSelector(I2CControllerName);
DeviceInformationCollection dis = await DeviceInformation.FindAllAsync(aqs);
bme280 = await I2cDevice.FromIdAsync(dis[0].Id, settings);
if (bme280 == null)
{
Debug.WriteLine("Device not found");
}
}
catch (Exception e)
{
Debug.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);
throw;
}
}
Add the Begin routine to verify the sensor signature and load calibration data:
private async Task Begin()
{
Debug.WriteLine("BME280::Begin");
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CHIPID };
byte[] ReadBuffer = new byte[] { 0xFF };
bmp280.WriteRead(WriteBuffer, ReadBuffer);
Debug.WriteLine("BME280 Signature: " + ReadBuffer[0].ToString());
if (ReadBuffer[0] != BMP280_Signature)
{
Debug.WriteLine("BMP280::Begin Signature Mismatch.");
return;
}
init = true;
CalibrationData = await ReadCoefficeints();
await WriteControlRegister();
await WriteControlRegisterHumidity();
}
Control‑register helpers:
private async Task WriteControlRegisterHumidity()
{
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROLHUMID, 0x03 };
bmp280.Write(WriteBuffer);
await Task.Delay(1);
}
private async Task WriteControlRegister()
{
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROL, 0x3F };
bmp280.Write(WriteBuffer);
await Task.Delay(1);
}
Utility functions to read register data:
private UInt16 ReadUInt16_LittleEndian(byte register)
{
UInt16 value = 0;
byte[] writeBuffer = new byte[] { 0x00 };
byte[] readBuffer = new byte[] { 0x00, 0x00 };
writeBuffer[0] = register;
bmp280.WriteRead(writeBuffer, readBuffer);
int h = readBuffer[1] << 8;
int l = readBuffer[0];
value = (UInt16)(h + l);
return value;
}
private byte ReadByte(byte register)
{
byte value = 0;
byte[] writeBuffer = new byte[] { 0x00 };
byte[] readBuffer = new byte[] { 0x00 };
writeBuffer[0] = register;
bmp280.WriteRead(writeBuffer, readBuffer);
value = readBuffer[0];
return value;
}
Calibration and compensation functions are derived directly from the BMP280 datasheet and are already provided.
Implement ReadTemperature to return the sensor’s temperature in degrees Celsius:
public async Task<float> ReadTemperature()
{
if (!init) await Begin();
byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_MSB);
byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_LSB);
byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_XLSB);
Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
double temp = BMP280_compensate_T_double(t);
return (float)temp;
}
Complete ReadPreasure (note the original typo; we retain it for compatibility):
public async Task<float> ReadPreasure()
{
if (!init) await Begin();
if (t_fine == Int32.MinValue) await ReadTemperature();
byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_MSB);
byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_LSB);
byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_XLSB);
Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
Int64 pres = BMP280_compensate_P_Int64(t);
return ((float)pres) / 256;
}
Finally, implement ReadAltitude to calculate altitude using the barometric formula:
public async Task<float> ReadAltitude(float seaLevel)
{
if (!init) await Begin();
float pressure = await ReadPreasure();
pressure /= 100;
return 44330.0f * (1.0f - (float)Math.Pow((pressure / seaLevel), 0.1903f));
}
Your project is now ready to deploy!
Expected Output
Temperature: 24.46189 deg C
Humidity: 54.372 %
Pressure: 99738.73 Pa
Altitude: 205.1726 m
Source: Weather Station V 2.0
Manufacturing process
- DIY Solar‑Powered Weather Station with Raspberry Pi
- Building an Outdoor Weather Station with Raspberry Pi 2 and ADS‑WS1
- Build a Raspberry Pi Weather Station that Emails Daily Weather Data
- Real‑Time Weather Monitoring with Arduino & ThingSpeak IoT
- Arduino Nano Weather Station: Sensor Kit & OLED Display
- Build a Reliable Arduino Weather Station with DHT Sensors
- Portable IoT Weather Station with Arduino Nano 33 IoT
- Build a Smart Weather Station with Arduino UNO and AWS Integration
- Build a Simple Weather Station with Arduino UNO, BMP280 Sensor & LCD
- Arduino Wireless Weather Station: DIY Portable Weather Monitoring Kit