// -------- LIBRARIES -------- #include #include #include #include // -------- PIN DEFINITIONS (WEMOS D1 MINI) -------- #define DHTPIN D4 #define DHTTYPE DHT11 #define LDR_PIN D3 // digital pin #define RAIN_PIN A0 // analog pin (only analog input) #define LED_PIN D5 // I2C Pins #define I2C_SDA D1 #define I2C_SCL D2 // -------- OBJECTS -------- DHT dht(DHTPIN, DHTTYPE); SFE_BMP180 bmp; WiFiClient espClient; PubSubClient client(espClient); // -------- WIFI & MQTT CREDENTIALS -------- const char* ssid = "YOUR_WIFI_SSID"; const char* password = "YOUR_WIFI_PASSWORD"; const char* mqtt_server = "YOUR_MQTT_BROKER"; const int mqtt_port = 1883; const char* mqtt_topic = "weather/station"; // -------- VARIABLES -------- double T, P; unsigned long lastSensorRead = 0; const long sensorInterval = 2000; // Read sensors every 2 seconds unsigned long lastMQTTSend = 0; const long mqttInterval = 30000; // Send data every 30 seconds // Wemos D1 Mini specific int ldrThreshold = 500; // Digital LDR threshold // Battery monitoring #define BATTERY_PIN A0 #define BATTERY_VOLTAGE_DIVIDER 2.0 #define RAIN_DIGITAL_PIN D6 // Digital rain sensor pin unsigned long lastBatteryCheck = 0; const long batteryCheckInterval = 60000; // Check battery every minute int batteryLevel = 100; float batteryVoltage = 0.0; struct WeatherData { float temperature; float humidity; float pressure; int rainLevel; bool lightDetected; bool valid; }; struct BatteryData { float voltage; int percentage; bool charging; bool lowBattery; }; BatteryData batteryData; WeatherData currentData; // -------- FUNCTIONS -------- // DHT SENSOR void readDHT() { float h = dht.readHumidity(); float t = dht.readTemperature(); if (isnan(h) || isnan(t)) { Serial.println("DHT Error!"); currentData.valid = false; return; } currentData.temperature = t; currentData.humidity = h; } // RAIN SENSOR (Digital for Wemos D1 Mini) void readRain() { // Use digital rain sensor to free A0 for battery monitoring int value = digitalRead(RAIN_DIGITAL_PIN); // Convert digital to percentage (simplified) if (value == HIGH) { currentData.rainLevel = 0; // No rain (digital HIGH) } else { currentData.rainLevel = 80; // Rain detected (digital LOW) } } // PRESSURE SENSOR void readPressure() { if (bmp.startTemperature()) { delay(100); if (bmp.getTemperature(T)) { if (bmp.startPressure(3)) { delay(100); if (bmp.getPressure(P, T)) { currentData.pressure = P; } } } } else { Serial.println("BMP180 Error"); currentData.valid = false; } } // LDR SENSOR (Digital for Wemos D1 Mini) void readLDR() { // For Wemos D1 Mini, we'll use digital reading with threshold // You could also use analog reading on A0, but it's used by rain sensor int value = digitalRead(LDR_PIN); currentData.lightDetected = (value == HIGH); digitalWrite(LED_PIN, currentData.lightDetected ? HIGH : LOW); } // BATTERY MONITORING void readBattery() { // Read battery voltage through voltage divider int adcValue = analogRead(BATTERY_PIN); batteryVoltage = adcValue * (3.3 / 1023.0) * BATTERY_VOLTAGE_DIVIDER; // Calculate battery percentage (3.0V = 0%, 4.2V = 100%) batteryLevel = map(batteryVoltage * 100, 300, 420, 0, 100); batteryLevel = constrain(batteryLevel, 0, 100); // Update battery data structure batteryData.voltage = batteryVoltage; batteryData.percentage = batteryLevel; batteryData.lowBattery = (batteryLevel < 20); // Detect charging (voltage > 4.0V indicates charging) batteryData.charging = (batteryVoltage > 4.0); Serial.print("Battery: "); Serial.print(batteryVoltage, 2); Serial.print("V ("); Serial.print(batteryLevel); Serial.print("%) "); if (batteryData.charging) Serial.print("Charging"); if (batteryData.lowBattery) Serial.print(" LOW BATTERY!"); Serial.println(); } // READ ALL SENSORS void readSensors() { currentData.valid = true; readDHT(); readRain(); readPressure(); readLDR(); if (currentData.valid) { Serial.print("Temp: "); Serial.print(currentData.temperature); Serial.print("°C, Humidity: "); Serial.print(currentData.humidity); Serial.print("%, Rain: "); Serial.print(currentData.rainLevel); Serial.print("%, Pressure: "); Serial.print(currentData.pressure); Serial.print(" hPa, Light: "); Serial.println(currentData.lightDetected ? "YES" : "NO"); } } // STATUS INDICATION void updateStatus() { if (!currentData.valid) { // Blink LED rapidly for sensor error digitalWrite(LED_PIN, HIGH); delay(100); digitalWrite(LED_PIN, LOW); delay(100); digitalWrite(LED_PIN, HIGH); delay(100); digitalWrite(LED_PIN, LOW); } else if (batteryData.lowBattery) { // Blink LED slowly for low battery warning digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); delay(500); } else { // LED indicates light detection status digitalWrite(LED_PIN, currentData.lightDetected ? HIGH : LOW); } } // POWER MANAGEMENT void managePower() { if (batteryData.lowBattery) { Serial.println("WARNING: Low battery - consider deep sleep"); // Optional: Enter deep sleep to conserve power // Uncomment below lines for automatic deep sleep on low battery /* Serial.println("Entering deep sleep due to low battery"); ESP.deepSleep(300000000); // 5 minutes */ } if (batteryData.charging) { Serial.println("Battery charging - solar power active"); } } // SETUP WIFI void setupWiFi() { Serial.println("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("\nWiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } else { Serial.println("Failed to connect to WiFi"); } delay(2000); } // RECONNECT MQTT void reconnectMQTT() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); String clientId = "ESP32WeatherStation-"; clientId += String(random(0xffff), HEX); if (client.connect(clientId.c_str())) { Serial.println("connected"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } // SEND MQTT DATA void sendMQTTData() { if (!currentData.valid || !client.connected()) { return; } String payload = "{"; payload += "\"temperature\":" + String(currentData.temperature, 2) + ","; payload += "\"humidity\":" + String(currentData.humidity, 2) + ","; payload += "\"pressure\":" + String(currentData.pressure, 2) + ","; payload += "\"rainLevel\":" + String(currentData.rainLevel) + ","; payload += "\"lightDetected\":" + String(currentData.lightDetected ? "true" : "false") + ","; payload += "\"battery\":" + String(batteryData.percentage) + ","; payload += "\"batteryVoltage\":" + String(batteryData.voltage, 2) + ","; payload += "\"charging\":" + String(batteryData.charging ? "true" : "false"); payload += "}"; if (client.publish(mqtt_topic, payload.c_str())) { Serial.println("MQTT data sent successfully"); } else { Serial.println("Failed to send MQTT data"); } // Also send battery status separately String batteryPayload = "{"; batteryPayload += "\"percentage\":" + String(batteryData.percentage) + ","; batteryPayload += "\"voltage\":" + String(batteryData.voltage, 2) + ","; batteryPayload += "\"charging\":" + String(batteryData.charging ? "true" : "false") + ","; batteryPayload += "\"lowBattery\":" + String(batteryData.lowBattery ? "true" : "false"); batteryPayload += "}"; client.publish("weather/battery", batteryPayload.c_str()); } // -------- SETUP -------- void setup() { Serial.begin(115200); // Initialize pins pinMode(LDR_PIN, INPUT); pinMode(RAIN_DIGITAL_PIN, INPUT); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); // Initialize I2C and sensors (Wemos D1 Mini pins) Wire.begin(I2C_SDA, I2C_SCL); // D1, D2 dht.begin(); if (!bmp.begin()) { Serial.println("BMP180 not detected!"); } // Initialize WiFi setupWiFi(); // Initialize MQTT client.setServer(mqtt_server, mqtt_port); // Initial sensor reading readSensors(); readBattery(); updateStatus(); managePower(); Serial.println("Weather Station Ready (Wemos D1 Mini + Solar + Battery)"); } // -------- LOOP -------- void loop() { unsigned long currentMillis = millis(); // Reconnect MQTT if needed if (!client.connected()) { reconnectMQTT(); } client.loop(); // Read sensors at regular interval if (currentMillis - lastSensorRead >= sensorInterval) { lastSensorRead = currentMillis; readSensors(); updateStatus(); } // Check battery status every minute if (currentMillis - lastBatteryCheck >= batteryCheckInterval) { lastBatteryCheck = currentMillis; readBattery(); managePower(); } // Send MQTT data at regular interval if (currentMillis - lastMQTTSend >= mqttInterval) { lastMQTTSend = currentMillis; sendMQTTData(); } delay(100); }