Learn how to build a real IoT weather station using the Arduino UNO R4 WiFi and BME280 sensor, sending live temperature, humidity, and pressure data to Arduino IoT Cloud — with full code, wiring diagrams, and dashboard.
What We're Building
In this project, you'll build a cloud-connected weather station that measures:
- Temperature (°C / °F)
- Humidity (%)
- Atmospheric Pressure (hPa)
All three readings will be streamed live to the Arduino IoT Cloud, where you can monitor them from anywhere in the world via a browser or the free Arduino IoT Remote app on your phone.
Components Required
| Component | Qty | Notes |
|---|---|---|
| Arduino UNO R4 WiFi | 1 | Built-in ESP32-S3 WiFi module |
| BME280 Sensor Module | 1 | Measures temp + humidity + pressure via I²C |
| Breadboard | 1 | Full or half size |
| Jumper Wires (M-M) | 4 | For I²C connections |
| USB-A to USB-C Cable | 1 | For power & programming |
Why BME280 over DHT22?
The BME280 gives you three measurements (including barometric pressure) over a single I²C bus using just 2 wires, making it more capable and cleaner to wire. The DHT22 only gives temperature and humidity.
Wiring the BME280 to Arduino UNO R4 WiFi
The BME280 uses the I²C protocol, so it only needs 4 wires:
BME280 Pin → Arduino UNO R4 WiFi Pin
──────────────────────────────────────
VCC → 3.3V
GND → GND
SDA → A4 (I²C Data)
SCL → A5 (I²C Clock)
Important: The BME280 runs on 3.3V, not 5V. Connecting it to the 5V pin can damage the sensor permanently.
Here's the schematic overview:
┌────────────────────────────┐
│ Arduino UNO R4 WiFi │
│ │
│ 3.3V ──────────────► VCC │
│ GND ──────────────► GND │ ← BME280
│ A4 ──────────────► SDA │
│ A5 ──────────────► SCL │
└────────────────────────────┘
☁️ Step 1 — Set Up Arduino IoT Cloud
Before writing any code, you need to configure the Arduino IoT Cloud. It's free for up to 2 devices.
1.1 Create a Free Account
Go to cloud.arduino.cc and sign up or log in.
1.2 Create a New "Thing"
- Click Things in the left sidebar
- Click + Create Thing
- Name it
WeatherStation
1.3 Add Your Device
- Click Select Device → Set up a new device
- Choose Arduino board and wait for it to detect your UNO R4 WiFi (connected via USB)
- Give your device a name (e.g.,
MyWeatherStation) - Save the Secret Key — you'll need this later! It's shown only once.
1.4 Add Cloud Variables
Click + Add Variable and create the following three variables:
| Variable Name | Type | Permission | Update Policy |
|---|---|---|---|
temperature |
float |
Read Only | On Change |
humidity |
float |
Read Only | On Change |
pressure |
float |
Read Only | On Change |
1.5 Configure WiFi Credentials
In the Network section of your Thing, enter:
- Your WiFi SSID
- Your WiFi Password
- The Secret Key you saved earlier
Step 2 — Install Required Libraries
Open Arduino IDE 2.x and install these libraries via Tools → Manage Libraries:
| Library | Author | Purpose |
|---|---|---|
Adafruit BME280 Library |
Adafruit | BME280 sensor driver |
Adafruit Unified Sensor |
Adafruit | Dependency for BME280 |
ArduinoIoTCloud |
Arduino | Cloud sync (auto-installed by Cloud Editor) |
Arduino_ConnectionHandler |
Arduino | WiFi connection management |
Tip: If you use the Arduino Cloud Web Editor, the
ArduinoIoTCloudlibrary is automatically included. You only need to install the Adafruit libraries manually.
Step 3 — Full Project Code
The Arduino IoT Cloud auto-generates a thingProperties.h file that handles all cloud variable declarations and WiFi/authentication. You write the main .ino sketch file.
WeatherStation.ino
// ============================================================
// Cloud-Connected Weather Station
// Arduino UNO R4 WiFi + BME280 + Arduino IoT Cloud
// Series: IoT Projects #7
// ============================================================
#include "thingProperties.h" // Auto-generated by Arduino IoT Cloud
#include <Wire.h> // I²C communication
#include <Adafruit_Sensor.h> // Unified sensor abstraction
#include <Adafruit_BME280.h> // BME280 sensor driver
// ── Sensor configuration ──────────────────────────────────
#define SEA_LEVEL_PRESSURE_HPA (1013.25) // Standard sea-level pressure
Adafruit_BME280 bme; // BME280 instance using default I²C address (0x76)
// ── Read interval ─────────────────────────────────────────
unsigned long lastReadTime = 0;
const unsigned long READ_INTERVAL = 10000; // Read every 10 seconds
// =============================================================
void setup() {
Serial.begin(9600);
delay(1500); // Wait for Serial Monitor to open
Serial.println("=================================");
Serial.println(" Cloud Weather Station — Boot ");
Serial.println("=================================");
// Initialize BME280 sensor
if (!bme.begin(0x76)) {
// Try alternate I²C address (some modules use 0x77)
if (!bme.begin(0x77)) {
Serial.println(" BME280 not found! Check wiring.");
Serial.println(" Expected addresses: 0x76 or 0x77");
while (1) delay(10); // Halt — no sensor, no point continuing
}
}
Serial.println(" BME280 sensor initialized");
// Set BME280 sampling settings for weather monitoring
// (lower oversampling = faster reads, less power)
bme.setSampling(
Adafruit_BME280::MODE_NORMAL, // Continuous measurement
Adafruit_BME280::SAMPLING_X2, // Temp oversampling x2
Adafruit_BME280::SAMPLING_X2, // Pressure oversampling x2
Adafruit_BME280::SAMPLING_X1, // Humidity oversampling x1
Adafruit_BME280::FILTER_X16, // IIR filter for stability
Adafruit_BME280::STANDBY_MS_500 // Standby 500ms between reads
);
// ── Arduino IoT Cloud init ───────────────────────────────
initProperties(); // Defined in thingProperties.h
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
// Debug level: 2 = moderate verbosity
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
Serial.println(" Connecting to WiFi and Arduino IoT Cloud...");
}
// =============================================================
void loop() {
// Keep cloud connection alive — MUST be called every loop
ArduinoCloud.update();
unsigned long now = millis();
// Only read sensors every READ_INTERVAL milliseconds
if (now - lastReadTime >= READ_INTERVAL) {
lastReadTime = now;
readAndPublishSensorData();
}
}
// =============================================================
// Reads BME280 data, validates it, and pushes to IoT Cloud
// =============================================================
void readAndPublishSensorData() {
float temp = bme.readTemperature(); // °C
float hum = bme.readHumidity(); // %
float pres = bme.readPressure() / 100.0F; // Pa → hPa
// ── Validate readings ─────────────────────────────────────
if (isnan(temp) || isnan(hum) || isnan(pres)) {
Serial.println(" Invalid sensor reading — skipping update");
return;
}
// ── Sanity range checks ───────────────────────────────────
if (temp < -40.0 || temp > 85.0) {
Serial.println(" Temperature out of sensor range!");
return;
}
if (hum < 0.0 || hum > 100.0) {
Serial.println(" Humidity out of range!");
return;
}
// ── Update Cloud variables ────────────────────────────────
// These names MUST match what you created in IoT Cloud
temperature = temp;
humidity = hum;
pressure = pres;
// ── Debug output ──────────────────────────────────────────
Serial.println("─────────────────────────────────");
Serial.print(" Temperature : ");
Serial.print(temp, 1);
Serial.println(" °C");
Serial.print(" Humidity : ");
Serial.print(hum, 1);
Serial.println(" %");
Serial.print(" Pressure : ");
Serial.print(pres, 2);
Serial.println(" hPa");
// Derived: estimated altitude above sea level
float altitude = bme.readAltitude(SEA_LEVEL_PRESSURE_HPA);
Serial.print(" Altitude : ");
Serial.print(altitude, 1);
Serial.println(" m (estimated)");
Serial.println("─────────────────────────────────");
}
Understanding thingProperties.h
The Cloud Editor auto-generates this file. Here's what it looks like — you do not edit this manually:
// AUTO-GENERATED by Arduino IoT Cloud — do not edit
#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>
const char THING_ID[] = "your-thing-id-here";
const char DEVICE_KEY[] = "your-secret-key-here"; // From Cloud setup
// Cloud variables — must match what you defined in the dashboard
float temperature;
float humidity;
float pressure;
void initProperties() {
ArduinoCloud.setThingId(THING_ID);
ArduinoCloud.addProperty(temperature, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(humidity, READ, ON_CHANGE, NULL);
ArduinoCloud.addProperty(pressure, READ, ON_CHANGE, NULL);
}
WiFiConnectionHandler ArduinoIoTPreferredConnection("YOUR_SSID", "YOUR_PASS");
Step 4 — Build the Cloud Dashboard
Once your board is online and publishing data:
- Go to your Thing → click Dashboard tab
- Click + Add Widget and add:
| Widget | Cloud Variable | Notes |
|---|---|---|
| Gauge | temperature |
Set range: −10 to 50 °C |
| Gauge | humidity |
Set range: 0–100 % |
| Gauge | pressure |
Set range: 950–1050 hPa |
| Chart | temperature |
Shows trend over time |
| Chart | humidity |
Shows trend over time |
- Arrange and resize widgets to your liking
- Click Share Dashboard (top right) to get a public URL
Mobile App: Download Arduino IoT Remote (Android / iOS) to monitor from your phone!
Step 5 — Serial Monitor Output
When everything is working, your Serial Monitor (9600 baud) will show:
=================================
Cloud Weather Station — Boot
=================================
BME280 sensor initialized
Connecting to WiFi and Arduino IoT Cloud...
─────────────────────────────────
Temperature: 27.4 °C
Humidity: 61.2 %
Pressure: 1009.87 hPa
Altitude: 28.4 m (estimated)
─────────────────────────────────
Troubleshooting
BME280 Not Detected
Most BME280 modules ship with I²C address 0x76, but some use 0x77. The code already tries both. You can confirm the address with an I²C scanner sketch:
// I²C Scanner — paste into a new sketch and upload
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Scanning I²C bus...");
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.print("Found device at 0x");
Serial.println(addr, HEX);
}
}
Serial.println("Scan complete.");
}
void loop() {}
WiFi Not Connecting
- Double-check SSID and password (case-sensitive)
- The UNO R4 WiFi supports 2.4 GHz only — ensure your router isn't on 5 GHz
- Verify the Device Secret Key matches what you saved during setup
Cloud Variables Not Updating
- Make sure
ArduinoCloud.update()is called every loop iteration - Variables should be declared in
thingProperties.h, not in your main sketch - Check that variable names in your code exactly match the names in the Cloud dashboard
Pressure Readings Look Wrong
Local atmospheric pressure varies with altitude. If your readings seem off, look up your city's actual pressure from a weather service and adjust SEA_LEVEL_PRESSURE_HPA accordingly.
Taking It Further
Here are some ways to extend this project:
Add a Local OLED Display
Show data locally even when WiFi is unavailable using a 0.96" SSD1306 OLED (I²C):
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// In setup():
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
// In your read function:
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Temp: "); display.print(temp); display.println(" C");
display.print("Hum: "); display.print(hum); display.println(" %");
display.print("Pres: "); display.print(pres); display.println(" hPa");
display.display();
Add IoT Cloud Alerts
In the Arduino IoT Cloud dashboard, use Triggers to:
- Send an email notification when temperature exceeds 35°C
- Send a push notification when humidity drops below 20%
Log to Google Sheets
Use IFTTT or Zapier with a webhook trigger connected to your Arduino IoT Cloud Thing to log every reading to a Google Sheet automatically.
Add a Rain Sensor
Wire an FC-37 rain sensor to analog pin A0 and add a bool isRaining variable to detect precipitation:
#define RAIN_PIN A0
#define RAIN_THRESHOLD 500 // Adjust based on your sensor
bool detectRain() {
int rawValue = analogRead(RAIN_PIN);
return (rawValue < RAIN_THRESHOLD); // Lower value = wetter
}
Full Bill of Materials with Links
| Component | Where to Buy (India) |
|---|---|
| Arduino UNO R4 WiFi | Robocraze · |
| BME280 Sensor Module | Robocraze · Amazon.in |
| 0.96" OLED Display (optional) | Robocraze · Probots.co.in |
| Breadboard + Jumper Kit | Local electronics store / online |
Resources & Further Reading
- Arduino UNO R4 WiFi Official Docs
- Arduino IoT Cloud Getting Started
- Adafruit BME280 Library Guide
- Arduino IoT Remote App
- Original YouTube Tutorial
Summary
In this project you:
- Wired a BME280 sensor to the Arduino UNO R4 WiFi over I²C
- Created a Thing on Arduino IoT Cloud with 3 cloud variables
- Wrote clean, production-ready Arduino code that syncs sensor data to the cloud every 10 seconds
- Built a live dashboard with gauges and trend charts
- Learned to debug common wiring and connectivity issues
The Arduino UNO R4 WiFi's built-in WiFi and native Arduino IoT Cloud support makes it one of the easiest boards to get started with IoT — no external ESP modules or complex networking libraries needed.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.