OC
OceanRemote
Low-code IoT platform
← Back to Course

Weather Station Dashboard and Alerts

Weather Station Dashboard and Alerts

šŸ“Š Weather Station Dashboard and Alerts - Real-Time Weather Monitoring

šŸ“Š What You'll Learn:

  • šŸŒ”ļø Set up critical weather alerts for temperature, humidity, wind, and rain
  • 🚨 Receive instant notifications when thresholds are crossed
  • šŸŒ§ļø Take protective action before weather damages your crops
  • šŸ“Š Configure a complete weather dashboard with real-time data

A weather station is only useful if you act on the data. Setting up automated alerts ensures you never miss a critical weather event - heat waves, frost, heavy rain, or high winds. This lesson teaches you the essential alert thresholds for farm protection.

šŸ“‹ Recommended Weather Alert Thresholds

Condition Threshold Urgency Action Required
šŸŒ”ļø High Temperature > 35°C šŸ”“ HIGH Increase irrigation by 50%, provide shade cloth
ā„ļø Low Temperature (Frost Risk) < 5°C šŸ”“ HIGH Cover crops, irrigate before dawn, move potted plants indoors
šŸ’§ High Humidity > 80% 🟔 MEDIUM Check for fungal disease, increase ventilation, apply fungicide
šŸ’Ø High Wind > 30 km/h 🟔 MEDIUM Stop pesticide spraying, secure structures, stake tall crops
šŸŒ§ļø Heavy Rain > 10 mm/hour 🟔 MEDIUM Skip irrigation, check drainage systems, cover vulnerable plants
šŸ“‰ Rapid Pressure Drop > 2 hPa/hour šŸ”“ HIGH āš ļø Storm approaching within 12-24 hours! Secure equipment
šŸŒž Extreme Heat > 40°C 🚨 CRITICAL Emergency irrigation, evacuate livestock, stop field work
ā„ļø Freezing < 0°C 🚨 CRITICAL Harvest sensitive crops, irrigate continuously, use row covers
šŸŒ§ļø Extreme Rain > 25 mm/hour 🚨 CRITICAL 🚨 Flooding risk! Evacuate low areas
šŸ’” Alert Priority Levels:
  • 🚨 CRITICAL (Red): Immediate action required within minutes - life or crop-threatening
  • šŸ”“ HIGH (Orange): Action required within hours - significant risk to crops
  • 🟔 MEDIUM (Yellow): Action within 24-48 hours - monitor closely
  • šŸ”µ LOW (Blue): Informational only - no immediate action needed

šŸ“‹ Complete Weather Alert Code

/*
 * Complete Weather Station Dashboard with Alerts
 * Sends SMS/Email/Push notifications when thresholds are crossed
 */

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// ========== WIFI CONFIGURATION ==========
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";

// ========== ALERT CONFIGURATION ==========
const float HIGH_TEMP_THRESHOLD = 35.0;      // °C
const float EXTREME_TEMP_THRESHOLD = 40.0;    // °C
const float LOW_TEMP_THRESHOLD = 5.0;         // °C
const float FREEZE_THRESHOLD = 0.0;           // °C
const float HIGH_HUMIDITY_THRESHOLD = 80.0;    // %
const float HIGH_WIND_THRESHOLD = 30.0;       // km/h
const float HEAVY_RAIN_THRESHOLD = 10.0;      // mm/hour
const float PRESSURE_DROP_THRESHOLD = 2.0;    // hPa/hour

// ========== SENSOR DATA ==========
float currentTemp = 0;
float currentHumidity = 0;
float currentPressure = 0;
float windSpeed = 0;
float rainRate = 0;
bool isRaining = false;

// ========== PRESSURE TRACKING ==========
float pressureHistory[24];
int pressureIndex = 0;
int pressureCount = 0;

// ========== ALERT FUNCTIONS ==========
void sendSMS(String message) {
    // Integrate with SMS gateway (Twilio, Africa's Talking, etc.)
    Serial.println("šŸ“± SMS Alert: " + message);
}

void sendEmail(String message) {
    // Integrate with email service
    Serial.println("šŸ“§ Email Alert: " + message);
}

void sendPushNotification(String message) {
    // Integrate with OceanRemote push notifications
    Serial.println("šŸ“± Push Alert: " + message);
}

// ========== CHECK TEMPERATURE ALERTS ==========
void checkTemperatureAlerts(float temp) {
    if (temp >= EXTREME_TEMP_THRESHOLD) {
        sendPushNotification("🚨 CRITICAL: Extreme heat " + String(temp) + "°C! Emergency irrigation needed!");
        sendSMS("šŸ”„ Heat emergency: " + String(temp) + "°C");
    } 
    else if (temp >= HIGH_TEMP_THRESHOLD) {
        sendPushNotification("āš ļø High temperature alert: " + String(temp) + "°C. Increase irrigation.");
    }
    else if (temp <= FREEZE_THRESHOLD) {
        sendPushNotification("🚨 CRITICAL: Freezing " + String(temp) + "°C! Protect crops immediately!");
        sendSMS("ā„ļø Freeze warning: " + String(temp) + "°C");
    }
    else if (temp <= LOW_TEMP_THRESHOLD) {
        sendPushNotification("āš ļø Frost risk: " + String(temp) + "°C. Cover sensitive crops.");
    }
}

// ========== CHECK HUMIDITY ALERTS ==========
void checkHumidityAlerts(float humidity) {
    if (humidity > HIGH_HUMIDITY_THRESHOLD) {
        sendPushNotification("šŸ’§ High humidity: " + String(humidity) + "%. Fungus risk - increase ventilation.");
    }
}

// ========== CHECK WIND ALERTS ==========
void checkWindAlerts(float wind) {
    if (wind > HIGH_WIND_THRESHOLD) {
        sendPushNotification("šŸ’Ø High wind: " + String(wind) + " km/h. Stop spraying, secure structures.");
    }
}

// ========== CHECK RAIN ALERTS ==========
void checkRainAlerts(float rain, bool raining) {
    if (raining) {
        sendPushNotification("šŸŒ§ļø Rain detected! Skipping irrigation.");
    }
    if (rain > HEAVY_RAIN_THRESHOLD) {
        sendPushNotification("āš ļø Heavy rain: " + String(rain) + " mm/hour. Check drainage.");
    }
    if (rain > 25) {
        sendSMS("🚨 Extreme rain: " + String(rain) + " mm/hour. Flooding risk!");
    }
}

// ========== CHECK PRESSURE TREND ==========
void addPressureReading(float pressure) {
    pressureHistory[pressureIndex] = pressure;
    pressureIndex = (pressureIndex + 1) % 24;
    if (pressureCount < 24) pressureCount++;
}

float getPressureTrend() {
    if (pressureCount < 3) return 0;
    
    int current = (pressureIndex - 1 + 24) % 24;
    int past = (pressureIndex - 4 + 24) % 24;  // 3 hours ago
    
    return (pressureHistory[current] - pressureHistory[past]) / 3;
}

void checkPressureAlerts(float trend) {
    if (trend < -PRESSURE_DROP_THRESHOLD) {
        sendPushNotification("āš ļø Rapid pressure drop: " + String(trend) + " hPa/hour. Storm approaching!");
        sendSMS("šŸŒ©ļø Storm warning: Pressure dropping rapidly");
    }
}

// ========== DISPLAY DASHBOARD ==========
void displayDashboard() {
    Serial.println("\n╔══════════════════════════════════════════════════════════════╗");
    Serial.println("ā•‘                    šŸŒ¤ļø WEATHER DASHBOARD                       ā•‘");
    Serial.println("ā•‘                    " + String(__TIME__) + "                                  ā•‘");
    Serial.println("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•");
    
    Serial.println("\nšŸŒ”ļø TEMPERATURE:");
    if (currentTemp > HIGH_TEMP_THRESHOLD) {
        Serial.printf("   šŸ”“ %.1f°C (HIGH - Action needed)\n", currentTemp);
    } else if (currentTemp < LOW_TEMP_THRESHOLD) {
        Serial.printf("   šŸ”µ %.1f°C (LOW - Frost risk)\n", currentTemp);
    } else {
        Serial.printf("   🟢 %.1f°C (Normal)\n", currentTemp);
    }
    
    Serial.println("\nšŸ’§ HUMIDITY:");
    if (currentHumidity > HIGH_HUMIDITY_THRESHOLD) {
        Serial.printf("   🟔 %.1f%% (HIGH - Disease risk)\n", currentHumidity);
    } else {
        Serial.printf("   🟢 %.1f%% (Normal)\n", currentHumidity);
    }
    
    Serial.println("\nšŸ’Ø WIND:");
    if (windSpeed > HIGH_WIND_THRESHOLD) {
        Serial.printf("   🟔 %.1f km/h (HIGH - Caution)\n", windSpeed);
    } else {
        Serial.printf("   🟢 %.1f km/h (Normal)\n", windSpeed);
    }
    
    Serial.println("\nšŸŒ§ļø RAIN:");
    Serial.printf("   Raining: %s\n", isRaining ? "YES" : "NO");
    Serial.printf("   Rate: %.1f mm/hour\n", rainRate);
    
    float trend = getPressureTrend();
    Serial.println("\nšŸ“Š PRESSURE TREND:");
    if (trend < -PRESSURE_DROP_THRESHOLD) {
        Serial.printf("   šŸ”“ %.1f hPa/hour (RAPID DROP - Storm risk)\n", trend);
    } else {
        Serial.printf("   🟢 %.1f hPa/hour (Stable)\n", trend);
    }
    
    Serial.println("\n══════════════════════════════════════════════════════════════\n");
}

// ========== SEND TO OCEANREMOTE ==========
void sendToOceanRemote() {
    if (WiFi.status() != WL_CONNECTED) return;
    
    HTTPClient http;
    http.begin("https://api.oceanremote.net/device/state");
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    String data = "token=YOUR_TOKEN";
    data += "&temperature=" + String(currentTemp);
    data += "&humidity=" + String(currentHumidity);
    data += "&pressure=" + String(currentPressure);
    data += "&wind_speed=" + String(windSpeed);
    data += "&rain_rate=" + String(rainRate);
    data += "&raining=" + String(isRaining ? "YES" : "NO");
    
    http.POST(data);
    http.end();
}

// ========== READ SENSORS (Placeholder) ==========
void readSensors() {
    // Replace with actual sensor readings
    // currentTemp = dht.readTemperature();
    // currentHumidity = dht.readHumidity();
    // currentPressure = bmp.readPressure() / 100.0F;
    // windSpeed = readWindSpeed();
    // rainRate = readRainRate();
    // isRaining = (digitalRead(RAIN_PIN) == LOW);
    
    // Test values - replace with actual!
    currentTemp = 36.5;
    currentHumidity = 85.0;
    currentPressure = 1008.0;
    windSpeed = 25.0;
    rainRate = 12.0;
    isRaining = true;
}

// ========== SETUP ==========
void setup() {
    Serial.begin(115200);
    
    // Connect to WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) delay(500);
    Serial.println("āœ… WiFi connected!");
    
    Serial.println("========================================");
    Serial.println("šŸŒ¤ļø WEATHER STATION DASHBOARD v2.0");
    Serial.println("   Real-time alerts + monitoring");
    Serial.println("========================================\n");
}

// ========== LOOP ==========
void loop() {
    readSensors();
    
    // Add pressure to history
    addPressureReading(currentPressure);
    
    // Check all alerts
    checkTemperatureAlerts(currentTemp);
    checkHumidityAlerts(currentHumidity);
    checkWindAlerts(windSpeed);
    checkRainAlerts(rainRate, isRaining);
    checkPressureAlerts(getPressureTrend());
    
    // Display dashboard
    displayDashboard();
    
    // Send to cloud
    sendToOceanRemote();
    
    delay(600000);  // Check every 10 minutes
}
    
šŸ“– Case Study - Frost Alert Saves Citrus Crop:

A citrus farmer in South Africa set up low-temperature alerts:

  • ā„ļø 2 AM alert: Temperature dropped to 3°C (frost risk)
  • šŸ“± Push notification: Farmer woke up and checked dashboard
  • šŸ’§ Action: Started irrigation before dawn (water releases heat when freezing)
  • šŸŒ”ļø Result: Temperature dropped to -1°C but crops survived
  • šŸ’° Savings: Prevented $10,000 in crop loss

"The frost alert woke me at 2 AM. Without it, I would have lost my entire harvest." - Citrus Farmer, South Africa

šŸ’” Dashboard Best Practices:
  • šŸ“± Mobile-first design: Most farmers check on phones - ensure dashboard is responsive
  • šŸŽØ Color code everything: Red = critical, Yellow = warning, Green = normal
  • 🚨 Multiple alert methods: Push notification + SMS (for when internet is down)
  • ā° Avoid alert fatigue: Use cooldown periods (don't alert every minute)
  • šŸ“Š Historical trends: Show 24-hour graphs to visualize patterns
šŸŽÆ Key Takeaways:
  • āœ… High temp (>35°C): Increase irrigation, provide shade
  • āœ… Low temp (<5°C): Frost risk - cover crops, irrigate before dawn
  • āœ… High humidity (>80%): Fungus risk - increase ventilation
  • āœ… High wind (>30 km/h): Stop spraying, secure structures
  • āœ… Heavy rain (>10 mm/h): Skip irrigation, check drainage
  • āœ… Rapid pressure drop (>2 hPa/h): Storm approaching in 12-24 hours

Next lesson: Calibration and Maintenance of Weather Station

šŸ’” 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.