|
|
@@ -1,18 +1,18 @@
|
|
|
// -------- LIBRARIES --------
|
|
|
-#include <Wire.h>
|
|
|
-#include <LiquidCrystal_I2C.h>
|
|
|
#include <WiFi.h>
|
|
|
#include <PubSubClient.h>
|
|
|
#include <DHT.h>
|
|
|
#include <SFE_BMP180.h>
|
|
|
-// -------- PIN DEFINITIONS --------
|
|
|
-#define DHTPIN 4
|
|
|
+// -------- PIN DEFINITIONS (WEMOS D1 MINI) --------
|
|
|
+#define DHTPIN D4
|
|
|
#define DHTTYPE DHT11
|
|
|
-#define LDR_PIN 35 // input only pin (good choice)
|
|
|
-#define RAIN_PIN 34 // analog pin
|
|
|
-#define LED_PIN 2
|
|
|
+#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 --------
|
|
|
-LiquidCrystal_I2C lcd(0x27, 16, 2);
|
|
|
DHT dht(DHTPIN, DHTTYPE);
|
|
|
SFE_BMP180 bmp;
|
|
|
WiFiClient espClient;
|
|
|
@@ -29,6 +29,16 @@ 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;
|
|
|
@@ -39,6 +49,15 @@ struct WeatherData {
|
|
|
bool valid;
|
|
|
};
|
|
|
|
|
|
+struct BatteryData {
|
|
|
+ float voltage;
|
|
|
+ int percentage;
|
|
|
+ bool charging;
|
|
|
+ bool lowBattery;
|
|
|
+};
|
|
|
+
|
|
|
+BatteryData batteryData;
|
|
|
+
|
|
|
WeatherData currentData;
|
|
|
// -------- FUNCTIONS --------
|
|
|
// DHT SENSOR
|
|
|
@@ -53,12 +72,16 @@ void readDHT() {
|
|
|
currentData.temperature = t;
|
|
|
currentData.humidity = h;
|
|
|
}
|
|
|
-// RAIN SENSOR
|
|
|
+// RAIN SENSOR (Digital for Wemos D1 Mini)
|
|
|
void readRain() {
|
|
|
- int value = analogRead(RAIN_PIN);
|
|
|
- value = map(value, 0, 4095, 0, 100);
|
|
|
- value = 100 - value;
|
|
|
- currentData.rainLevel = value;
|
|
|
+ // 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() {
|
|
|
@@ -77,12 +100,42 @@ void readPressure() {
|
|
|
currentData.valid = false;
|
|
|
}
|
|
|
}
|
|
|
-// LDR SENSOR
|
|
|
+// 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;
|
|
|
@@ -104,37 +157,49 @@ void readSensors() {
|
|
|
Serial.println(currentData.lightDetected ? "YES" : "NO");
|
|
|
}
|
|
|
}
|
|
|
-// UPDATE LCD DISPLAY
|
|
|
-void updateDisplay() {
|
|
|
+// STATUS INDICATION
|
|
|
+void updateStatus() {
|
|
|
if (!currentData.valid) {
|
|
|
- lcd.setCursor(0, 0);
|
|
|
- lcd.print("Sensor Error! ");
|
|
|
- lcd.setCursor(0, 1);
|
|
|
- lcd.print("Check wiring ");
|
|
|
- return;
|
|
|
+ // 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
|
|
|
+ */
|
|
|
}
|
|
|
|
|
|
- // Display temperature and humidity on first line
|
|
|
- lcd.setCursor(0, 0);
|
|
|
- lcd.print("T:");
|
|
|
- lcd.print(currentData.temperature, 1);
|
|
|
- lcd.print("C H:");
|
|
|
- lcd.print(currentData.humidity, 0);
|
|
|
- lcd.print("%");
|
|
|
-
|
|
|
- // Display rain and pressure on second line
|
|
|
- lcd.setCursor(0, 1);
|
|
|
- lcd.print("R:");
|
|
|
- lcd.print(currentData.rainLevel);
|
|
|
- lcd.print("% P:");
|
|
|
- lcd.print(currentData.pressure, 0);
|
|
|
- lcd.print(" ");
|
|
|
+ if (batteryData.charging) {
|
|
|
+ Serial.println("Battery charging - solar power active");
|
|
|
+ }
|
|
|
}
|
|
|
// SETUP WIFI
|
|
|
void setupWiFi() {
|
|
|
Serial.println("Connecting to WiFi...");
|
|
|
- lcd.setCursor(0, 0);
|
|
|
- lcd.print("WiFi connecting");
|
|
|
|
|
|
WiFi.begin(ssid, password);
|
|
|
|
|
|
@@ -149,12 +214,8 @@ void setupWiFi() {
|
|
|
Serial.println("\nWiFi connected");
|
|
|
Serial.println("IP address: ");
|
|
|
Serial.println(WiFi.localIP());
|
|
|
- lcd.setCursor(0, 0);
|
|
|
- lcd.print("WiFi connected ");
|
|
|
} else {
|
|
|
Serial.println("Failed to connect to WiFi");
|
|
|
- lcd.setCursor(0, 0);
|
|
|
- lcd.print("WiFi failed! ");
|
|
|
}
|
|
|
|
|
|
delay(2000);
|
|
|
@@ -188,7 +249,10 @@ void sendMQTTData() {
|
|
|
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 += "\"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())) {
|
|
|
@@ -196,6 +260,16 @@ void sendMQTTData() {
|
|
|
} 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() {
|
|
|
@@ -203,14 +277,12 @@ void setup() {
|
|
|
|
|
|
// Initialize pins
|
|
|
pinMode(LDR_PIN, INPUT);
|
|
|
- pinMode(RAIN_PIN, INPUT);
|
|
|
+ pinMode(RAIN_DIGITAL_PIN, INPUT);
|
|
|
pinMode(LED_PIN, OUTPUT);
|
|
|
digitalWrite(LED_PIN, LOW);
|
|
|
|
|
|
- // Initialize I2C and sensors
|
|
|
- Wire.begin(21, 22); // SDA, SCL
|
|
|
- lcd.init();
|
|
|
- lcd.backlight();
|
|
|
+ // Initialize I2C and sensors (Wemos D1 Mini pins)
|
|
|
+ Wire.begin(I2C_SDA, I2C_SCL); // D1, D2
|
|
|
dht.begin();
|
|
|
|
|
|
if (!bmp.begin()) {
|
|
|
@@ -225,12 +297,11 @@ void setup() {
|
|
|
|
|
|
// Initial sensor reading
|
|
|
readSensors();
|
|
|
- updateDisplay();
|
|
|
+ readBattery();
|
|
|
+ updateStatus();
|
|
|
+ managePower();
|
|
|
|
|
|
- lcd.setCursor(0, 0);
|
|
|
- lcd.print("System Ready");
|
|
|
- delay(2000);
|
|
|
- lcd.clear();
|
|
|
+ Serial.println("Weather Station Ready (Wemos D1 Mini + Solar + Battery)");
|
|
|
}
|
|
|
// -------- LOOP --------
|
|
|
void loop() {
|
|
|
@@ -246,7 +317,14 @@ void loop() {
|
|
|
if (currentMillis - lastSensorRead >= sensorInterval) {
|
|
|
lastSensorRead = currentMillis;
|
|
|
readSensors();
|
|
|
- updateDisplay();
|
|
|
+ updateStatus();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check battery status every minute
|
|
|
+ if (currentMillis - lastBatteryCheck >= batteryCheckInterval) {
|
|
|
+ lastBatteryCheck = currentMillis;
|
|
|
+ readBattery();
|
|
|
+ managePower();
|
|
|
}
|
|
|
|
|
|
// Send MQTT data at regular interval
|