OC
OceanRemote
Low-code IoT platform
← Back to Course

Pressure Sensor Code with Forecasting

Pressure Sensor Code with Forecasting

šŸ“Š Pressure Sensor Code with Weather Forecasting - Predict Rain 24 Hours in Advance

šŸ“Š What You'll Learn:

  • šŸŒ”ļø Measure barometric pressure using BMP280/BME280 sensor
  • šŸ“ˆ Calculate pressure trends to predict weather 12-48 hours in advance
  • šŸŒ§ļø Detect approaching storms from rapid pressure drops
  • ā˜€ļø Generate automatic weather forecasts from sensor data

Barometric pressure is the most reliable indicator of upcoming weather. A falling pressure means rain is coming. A rapid drop means a storm is approaching. This lesson teaches you to read pressure trends and generate your own forecasts - no internet required!

šŸ“Š Pressure Trend Interpretation Guide

3-Hour Trend (hPa) Meaning Weather Forecast Farm Action
> +3.0 hPaRapidly Risingā˜€ļø Clearing - high pressure moving inGood for harvesting, spraying
+1.0 to +3.0 hPaRisingšŸŒ¤ļø Improving - weather getting betterPlan outdoor work
-1.0 to +1.0 hPaStableā˜ļø No change - current conditions continueNormal operations
-3.0 to -1.0 hPaFallingšŸŒ§ļø Worsening - rain likely in 12-24 hoursReduce irrigation, prepare for rain
< -3.0 hPaRapidly Fallingā›ˆļø Storm approaching! Rain within 6-12 hours🚨 Emergency: Secure equipment, skip irrigation
šŸ’” The 1-Hour vs 3-Hour Rule:

Short-term fluctuations (1-hour trends) can be noisy. The 3-hour trend is more reliable for forecasting. A consistent drop over 3+ hours is a strong indicator of approaching bad weather. For storm warnings, also check the rate of drop - faster drop = more severe storm.

šŸ”Œ BMP280/BME280 Wiring

═══════════════════════════════════════════════════════════════════════════════
                    BMP280 / BME280 WIRING (I2C)
═══════════════════════════════════════════════════════════════════════════════

    BMP280/BME280 Sensor              ESP32 Dev Board
    ══════════════════════            ══════════════════
    
    VCC (3.3V/5V)        ──────────►  3.3V
    GND                  ──────────►  GND
    SDA                  ──────────►  GPIO21 (I2C SDA)
    SCL                  ──────────►  GPIO22 (I2C SCL)
    
    Address options:
    - Connect SDO to GND  → Address 0x76 (most common)
    - Connect SDO to 3.3V → Address 0x77
    
    āš ļø BME280 includes humidity sensor (BMP280 = pressure only)
    Both work with same code - BME280 gives extra humidity data

═══════════════════════════════════════════════════════════════════════════════

šŸ“– Complete Pressure Weather Station Code

/*
 * Complete Barometric Pressure Weather Station
 * Predicts weather using pressure trends
 * BMP280/BME280 sensor with 24-hour memory
 * 
 * Features:
 * - Real-time pressure readings
 * - 1h, 3h, 6h, 12h, 24h pressure trends
 * - Weather forecasting without internet
 * - Storm warnings and alerts
 */

#include <Wire.h>
#include <Adafruit_BMP280.h>
#include <WiFi.h>
#include <HTTPClient.h>

// ========== SENSOR CONFIGURATION ==========
#define I2C_SDA 21
#define I2C_SCL 22
#define BMP280_ADDRESS 0x76   // Or 0x77

Adafruit_BMP280 bmp;

// ========== DATA STORAGE ==========
const int MAX_READINGS = 48;        // 48 hours at 1 reading per hour
float pressureHistory[MAX_READINGS];
float temperatureHistory[MAX_READINGS];
float humidityHistory[MAX_READINGS];  // Only for BME280
int readingIndex = 0;
int readingCount = 0;

// ========== STATISTICS ==========
float pressureMin = 9999;
float pressureMax = 0;
float pressureAvg = 0;
float pressureTrend1h = 0;
float pressureTrend3h = 0;
float pressureTrend6h = 0;
float pressureTrend12h = 0;
float pressureTrend24h = 0;

unsigned long lastReading = 0;
const unsigned long READING_INTERVAL = 3600000;  // 1 hour

// ========== ALTITUDE CORRECTION ==========
float stationAltitude = 0;  // meters above sea level (0 for sea level)

// ========== WIFI (Optional) ==========
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";

// ========== ADD PRESSURE READING ==========
void addPressureReading(float pressure, float temp, float humidity) {
    pressureHistory[readingIndex] = pressure;
    temperatureHistory[readingIndex] = temp;
    if (humidity >= 0) humidityHistory[readingIndex] = humidity;
    
    readingIndex = (readingIndex + 1) % MAX_READINGS;
    if (readingCount < MAX_READINGS) readingCount++;
    
    // Update statistics
    if (pressure < pressureMin) pressureMin = pressure;
    if (pressure > pressureMax) pressureMax = pressure;
    
    // Calculate average
    pressureAvg = 0;
    for (int i = 0; i < readingCount; i++) {
        pressureAvg += pressureHistory[i];
    }
    pressureAvg = pressureAvg / readingCount;
}

// ========== CALCULATE PRESSURE TREND ==========
float calculateTrend(int hours) {
    if (readingCount < hours) return 0;
    
    int currentIdx = (readingIndex - 1 + MAX_READINGS) % MAX_READINGS;
    int pastIdx = (readingIndex - 1 - hours + MAX_READINGS) % MAX_READINGS;
    
    float currentPressure = pressureHistory[currentIdx];
    float pastPressure = pressureHistory[pastIdx];
    
    return (currentPressure - pastPressure) / hours;  // hPa per hour
}

// ========== UPDATE ALL TRENDS ==========
void updateTrends() {
    if (readingCount < 2) return;
    
    pressureTrend1h = calculateTrend(1);
    pressureTrend3h = calculateTrend(3);
    pressureTrend6h = calculateTrend(6);
    pressureTrend12h = calculateTrend(12);
    pressureTrend24h = calculateTrend(24);
}

// ========== WEATHER FORECAST GENERATOR ==========
String generateForecast() {
    float trend = pressureTrend3h;  // 3-hour trend is most reliable
    
    if (trend > 2.5) {
        return "ā˜€ļø Clearing rapidly - High pressure moving in. Great weather ahead!";
    } else if (trend > 1.0) {
        return "šŸŒ¤ļø Improving conditions - Becoming sunnier. Good for outdoor work.";
    } else if (trend > -1.0) {
        return "ā˜ļø Steady conditions - Current weather will continue.";
    } else if (trend > -2.5) {
        return "šŸŒ§ļø Deteriorating - Rain likely within 12-24 hours. Reduce irrigation.";
    } else {
        return "ā›ˆļø Storm approaching! Rapid pressure drop. Heavy rain likely within 6-12 hours. Take precautions!";
    }
}

// ========== CHECK FOR STORM WARNING ==========
int getStormWarning() {
    // Returns severity: 0=none, 1=watch, 2=warning, 3=emergency
    if (pressureTrend3h < -4.0) return 3;      // Emergency - severe storm
    if (pressureTrend3h < -3.0) return 2;      // Warning - storm approaching
    if (pressureTrend3h < -2.0 && pressureTrend24h < -5.0) return 1;  // Watch
    return 0;
}

// ========== FROST WARNING ==========
bool checkFrostRisk(float temperature) {
    if (temperature < 3.0 && pressureTrend3h > 1.0) {
        return true;  // Clear, cold night = frost risk
    }
    return false;
}

// ========== READ SENSORS ==========
void readSensors() {
    float pressure = bmp.readPressure() / 100.0F;  // Convert Pa to hPa
    float temperature = bmp.readTemperature();
    
    // Optional: BME280 humidity reading
    // float humidity = bme.readHumidity();
    float humidity = -1;  // Placeholder for BMP280
    
    // Altitude correction (if needed)
    if (stationAltitude > 0) {
        pressure = pressure + (stationAltitude / 8.4);
    }
    
    addPressureReading(pressure, temperature, humidity);
}

// ========== DISPLAY PRESSURE REPORT ==========
void displayReport() {
    Serial.println("\n╔══════════════════════════════════════════════════════════════╗");
    Serial.println("ā•‘                    šŸ“Š BAROMETRIC REPORT                       ā•‘");
    Serial.println("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•");
    
    Serial.printf("\nšŸ“Š CURRENT PRESSURE: %.1f hPa\n", pressureHistory[(readingIndex - 1 + MAX_READINGS) % MAX_READINGS]);
    Serial.printf("   šŸ“ˆ 3h Trend: %.1f hPa/hour\n", pressureTrend3h);
    
    Serial.println("\nšŸ“ˆ PRESSURE TRENDS:");
    Serial.printf("   1-hour:  %.1f hPa/hour\n", pressureTrend1h);
    Serial.printf("   3-hour:  %.1f hPa/hour %s\n", pressureTrend3h, 
                  pressureTrend3h < 0 ? "ā¬‡ļø Falling" : (pressureTrend3h > 0 ? "ā¬†ļø Rising" : "āž”ļø Stable"));
    Serial.printf("   6-hour:  %.1f hPa/hour\n", pressureTrend6h);
    Serial.printf("   12-hour: %.1f hPa/hour\n", pressureTrend12h);
    Serial.printf("   24-hour: %.1f hPa/hour\n", pressureTrend24h);
    
    Serial.println("\nšŸŒ¤ļø WEATHER FORECAST:");
    Serial.println("   " + generateForecast());
    
    int storm = getStormWarning();
    if (storm > 0) {
        Serial.println("\nāš ļø STORM ALERT:");
        if (storm == 3) Serial.println("   🚨 EMERGENCY: Severe storm approaching! Take cover immediately!");
        else if (storm == 2) Serial.println("   āš ļø WARNING: Storm approaching within 12 hours! Secure equipment.");
        else Serial.println("   ā„¹ļø WATCH: Pressure falling - monitor for worsening conditions.");
    }
    
    Serial.println("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
}

// ========== CONNECT TO WIFI (Optional) ==========
void connectWiFi() {
    Serial.print("šŸ“” Connecting to WiFi");
    WiFi.begin(ssid, password);
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 20) {
        delay(500);
        Serial.print(".");
        attempts++;
    }
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println("\nāœ… WiFi connected!");
    } else {
        Serial.println("\nāš ļø WiFi connection failed - running offline");
    }
}

// ========== SETUP ==========
void setup() {
    Serial.begin(115200);
    delay(1000);
    
    // Initialize I2C
    Wire.begin(I2C_SDA, I2C_SCL);
    
    // Initialize BMP280
    if (!bmp.begin(BMP280_ADDRESS)) {
        Serial.println("āŒ BMP280 not found! Check wiring and address.");
        while (1) delay(100);
    }
    
    // Configure BMP280 for weather monitoring (less noise)
    bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,      // Normal mode
                    Adafruit_BMP280::SAMPLING_X2,      // Temperature oversampling
                    Adafruit_BMP280::SAMPLING_X16,     // Pressure oversampling
                    Adafruit_BMP280::FILTER_X16,       // Filter for noise reduction
                    Adafruit_BMP280::STANDBY_MS_1000); // Standby time
    
    Serial.println("========================================");
    Serial.println("šŸ“Š BAROMETRIC WEATHER STATION v2.0");
    Serial.println("   Pressure-based weather forecasting");
    Serial.println("========================================\n");
    
    // Optional: Connect to WiFi
    // connectWiFi();
    
    Serial.println("āœ… Sensor ready! Collecting pressure data...\n");
    Serial.println("šŸ’” Tip: Need 24 hours of data for accurate trends\n");
    
    // Take initial readings to fill buffer
    for (int i = 0; i < 6; i++) {
        readSensors();
        updateTrends();
        delay(10000);
    }
}

// ========== LOOP ==========
void loop() {
    unsigned long now = millis();
    
    if (now - lastReading >= READING_INTERVAL) {
        readSensors();
        updateTrends();
        displayReport();
        
        // Optional: Send to OceanRemote
        // sendToOceanRemote();
        
        lastReading = now;
    }
    
    delay(1000);
}
    
šŸ“– Case Study - Pressure Forecasting Saves Harvest:

A wheat farmer in Ethiopia used pressure trend forecasting to predict a storm:

  • šŸ“‰ Pressure drop detected: -4.2 hPa in 3 hours at 8 AM
  • šŸŒ§ļø Forecast generated: "Storm approaching within 12 hours"
  • ā° Action taken: Harvested wheat 2 days early
  • šŸ’§ Result: Saved 80% of crop before hail destroyed remaining fields

"The pressure sensor warned us about the storm before local radio. We harvested early and saved our crop." - Wheat Farmer, Ethiopia

šŸ’” Pressure Forecasting Pro Tips:
  • šŸ“ Need 24 hours of data: Trends become accurate after a full day of readings
  • šŸ“ Watch the acceleration: Pressure drop speeding up? Storm severity increasing.
  • šŸ“ Combine with humidity: Falling pressure + rising humidity = rain confirmed
  • šŸ“ Altitude correction: For highland farms (1,500m+), correct pressure to sea level for standard references
  • šŸ“ Filter noise: Use oversampling (SAMPLING_X16) and filter (FILTER_X16) for stable readings
šŸŽÆ Key Takeaways:
  • āœ… Pressure falling (-1 to -3 hPa/3h): Rain likely in 12-24 hours → reduce irrigation
  • āœ… Pressure rapidly falling (< -3 hPa/3h): Storm approaching → emergency action
  • āœ… Pressure rising (+1 to +3 hPa/3h): Clearing weather → good for harvesting
  • āœ… Pressure stable (±1 hPa/3h): Current conditions continue → normal operations
  • āœ… BMP280/BME280 ($5-10): Affordable pressure sensor for farm forecasting
  • āœ… No internet needed: Forecast from local pressure readings
šŸ’” Key Takeaways:
  • Apply these concepts directly to your farm or project.
  • Take notes on important details for the quiz.
  • Use the button below to track your progress.