DEV Community

Danieldsouza
Danieldsouza

Posted on

Build a Cloud-Connected Weather Station with Arduino UNO R4 WiFi

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)
Enter fullscreen mode Exit fullscreen mode

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  │
└────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

☁️ 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"

  1. Click Things in the left sidebar
  2. Click + Create Thing
  3. Name it WeatherStation

1.3 Add Your Device

  1. Click Select DeviceSet up a new device
  2. Choose Arduino board and wait for it to detect your UNO R4 WiFi (connected via USB)
  3. Give your device a name (e.g., MyWeatherStation)
  4. 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 ArduinoIoTCloud library 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("─────────────────────────────────");
}
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

Step 4 — Build the Cloud Dashboard

Once your board is online and publishing data:

  1. Go to your Thing → click Dashboard tab
  2. 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
  1. Arrange and resize widgets to your liking
  2. 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)
─────────────────────────────────
Enter fullscreen mode Exit fullscreen mode

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() {}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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


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.