weatherstation.ino 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // -------- LIBRARIES --------
  2. #include <WiFi.h>
  3. #include <PubSubClient.h>
  4. #include <DHT.h>
  5. #include <SFE_BMP180.h>
  6. // -------- PIN DEFINITIONS (WEMOS D1 MINI) --------
  7. #define DHTPIN D4
  8. #define DHTTYPE DHT11
  9. #define LDR_PIN D3 // digital pin
  10. #define RAIN_PIN A0 // analog pin (only analog input)
  11. #define LED_PIN D5
  12. // I2C Pins
  13. #define I2C_SDA D1
  14. #define I2C_SCL D2
  15. // -------- OBJECTS --------
  16. DHT dht(DHTPIN, DHTTYPE);
  17. SFE_BMP180 bmp;
  18. WiFiClient espClient;
  19. PubSubClient client(espClient);
  20. // -------- WIFI & MQTT CREDENTIALS --------
  21. const char* ssid = "YOUR_WIFI_SSID";
  22. const char* password = "YOUR_WIFI_PASSWORD";
  23. const char* mqtt_server = "YOUR_MQTT_BROKER";
  24. const int mqtt_port = 1883;
  25. const char* mqtt_topic = "weather/station";
  26. // -------- VARIABLES --------
  27. double T, P;
  28. unsigned long lastSensorRead = 0;
  29. const long sensorInterval = 2000; // Read sensors every 2 seconds
  30. unsigned long lastMQTTSend = 0;
  31. const long mqttInterval = 30000; // Send data every 30 seconds
  32. // Wemos D1 Mini specific
  33. int ldrThreshold = 500; // Digital LDR threshold
  34. // Battery monitoring
  35. #define BATTERY_PIN A0
  36. #define BATTERY_VOLTAGE_DIVIDER 2.0
  37. #define RAIN_DIGITAL_PIN D6 // Digital rain sensor pin
  38. unsigned long lastBatteryCheck = 0;
  39. const long batteryCheckInterval = 60000; // Check battery every minute
  40. int batteryLevel = 100;
  41. float batteryVoltage = 0.0;
  42. struct WeatherData {
  43. float temperature;
  44. float humidity;
  45. float pressure;
  46. int rainLevel;
  47. bool lightDetected;
  48. bool valid;
  49. };
  50. struct BatteryData {
  51. float voltage;
  52. int percentage;
  53. bool charging;
  54. bool lowBattery;
  55. };
  56. BatteryData batteryData;
  57. WeatherData currentData;
  58. // -------- FUNCTIONS --------
  59. // DHT SENSOR
  60. void readDHT() {
  61. float h = dht.readHumidity();
  62. float t = dht.readTemperature();
  63. if (isnan(h) || isnan(t)) {
  64. Serial.println("DHT Error!");
  65. currentData.valid = false;
  66. return;
  67. }
  68. currentData.temperature = t;
  69. currentData.humidity = h;
  70. }
  71. // RAIN SENSOR (Digital for Wemos D1 Mini)
  72. void readRain() {
  73. // Use digital rain sensor to free A0 for battery monitoring
  74. int value = digitalRead(RAIN_DIGITAL_PIN);
  75. // Convert digital to percentage (simplified)
  76. if (value == HIGH) {
  77. currentData.rainLevel = 0; // No rain (digital HIGH)
  78. } else {
  79. currentData.rainLevel = 80; // Rain detected (digital LOW)
  80. }
  81. }
  82. // PRESSURE SENSOR
  83. void readPressure() {
  84. if (bmp.startTemperature()) {
  85. delay(100);
  86. if (bmp.getTemperature(T)) {
  87. if (bmp.startPressure(3)) {
  88. delay(100);
  89. if (bmp.getPressure(P, T)) {
  90. currentData.pressure = P;
  91. }
  92. }
  93. }
  94. } else {
  95. Serial.println("BMP180 Error");
  96. currentData.valid = false;
  97. }
  98. }
  99. // LDR SENSOR (Digital for Wemos D1 Mini)
  100. void readLDR() {
  101. // For Wemos D1 Mini, we'll use digital reading with threshold
  102. // You could also use analog reading on A0, but it's used by rain sensor
  103. int value = digitalRead(LDR_PIN);
  104. currentData.lightDetected = (value == HIGH);
  105. digitalWrite(LED_PIN, currentData.lightDetected ? HIGH : LOW);
  106. }
  107. // BATTERY MONITORING
  108. void readBattery() {
  109. // Read battery voltage through voltage divider
  110. int adcValue = analogRead(BATTERY_PIN);
  111. batteryVoltage = adcValue * (3.3 / 1023.0) * BATTERY_VOLTAGE_DIVIDER;
  112. // Calculate battery percentage (3.0V = 0%, 4.2V = 100%)
  113. batteryLevel = map(batteryVoltage * 100, 300, 420, 0, 100);
  114. batteryLevel = constrain(batteryLevel, 0, 100);
  115. // Update battery data structure
  116. batteryData.voltage = batteryVoltage;
  117. batteryData.percentage = batteryLevel;
  118. batteryData.lowBattery = (batteryLevel < 20);
  119. // Detect charging (voltage > 4.0V indicates charging)
  120. batteryData.charging = (batteryVoltage > 4.0);
  121. Serial.print("Battery: ");
  122. Serial.print(batteryVoltage, 2);
  123. Serial.print("V (");
  124. Serial.print(batteryLevel);
  125. Serial.print("%) ");
  126. if (batteryData.charging) Serial.print("Charging");
  127. if (batteryData.lowBattery) Serial.print(" LOW BATTERY!");
  128. Serial.println();
  129. }
  130. // READ ALL SENSORS
  131. void readSensors() {
  132. currentData.valid = true;
  133. readDHT();
  134. readRain();
  135. readPressure();
  136. readLDR();
  137. if (currentData.valid) {
  138. Serial.print("Temp: ");
  139. Serial.print(currentData.temperature);
  140. Serial.print("°C, Humidity: ");
  141. Serial.print(currentData.humidity);
  142. Serial.print("%, Rain: ");
  143. Serial.print(currentData.rainLevel);
  144. Serial.print("%, Pressure: ");
  145. Serial.print(currentData.pressure);
  146. Serial.print(" hPa, Light: ");
  147. Serial.println(currentData.lightDetected ? "YES" : "NO");
  148. }
  149. }
  150. // STATUS INDICATION
  151. void updateStatus() {
  152. if (!currentData.valid) {
  153. // Blink LED rapidly for sensor error
  154. digitalWrite(LED_PIN, HIGH);
  155. delay(100);
  156. digitalWrite(LED_PIN, LOW);
  157. delay(100);
  158. digitalWrite(LED_PIN, HIGH);
  159. delay(100);
  160. digitalWrite(LED_PIN, LOW);
  161. } else if (batteryData.lowBattery) {
  162. // Blink LED slowly for low battery warning
  163. digitalWrite(LED_PIN, HIGH);
  164. delay(500);
  165. digitalWrite(LED_PIN, LOW);
  166. delay(500);
  167. } else {
  168. // LED indicates light detection status
  169. digitalWrite(LED_PIN, currentData.lightDetected ? HIGH : LOW);
  170. }
  171. }
  172. // POWER MANAGEMENT
  173. void managePower() {
  174. if (batteryData.lowBattery) {
  175. Serial.println("WARNING: Low battery - consider deep sleep");
  176. // Optional: Enter deep sleep to conserve power
  177. // Uncomment below lines for automatic deep sleep on low battery
  178. /*
  179. Serial.println("Entering deep sleep due to low battery");
  180. ESP.deepSleep(300000000); // 5 minutes
  181. */
  182. }
  183. if (batteryData.charging) {
  184. Serial.println("Battery charging - solar power active");
  185. }
  186. }
  187. // SETUP WIFI
  188. void setupWiFi() {
  189. Serial.println("Connecting to WiFi...");
  190. WiFi.begin(ssid, password);
  191. int attempts = 0;
  192. while (WiFi.status() != WL_CONNECTED && attempts < 20) {
  193. delay(500);
  194. Serial.print(".");
  195. attempts++;
  196. }
  197. if (WiFi.status() == WL_CONNECTED) {
  198. Serial.println("\nWiFi connected");
  199. Serial.println("IP address: ");
  200. Serial.println(WiFi.localIP());
  201. } else {
  202. Serial.println("Failed to connect to WiFi");
  203. }
  204. delay(2000);
  205. }
  206. // RECONNECT MQTT
  207. void reconnectMQTT() {
  208. while (!client.connected()) {
  209. Serial.print("Attempting MQTT connection...");
  210. String clientId = "ESP32WeatherStation-";
  211. clientId += String(random(0xffff), HEX);
  212. if (client.connect(clientId.c_str())) {
  213. Serial.println("connected");
  214. } else {
  215. Serial.print("failed, rc=");
  216. Serial.print(client.state());
  217. Serial.println(" try again in 5 seconds");
  218. delay(5000);
  219. }
  220. }
  221. }
  222. // SEND MQTT DATA
  223. void sendMQTTData() {
  224. if (!currentData.valid || !client.connected()) {
  225. return;
  226. }
  227. String payload = "{";
  228. payload += "\"temperature\":" + String(currentData.temperature, 2) + ",";
  229. payload += "\"humidity\":" + String(currentData.humidity, 2) + ",";
  230. payload += "\"pressure\":" + String(currentData.pressure, 2) + ",";
  231. payload += "\"rainLevel\":" + String(currentData.rainLevel) + ",";
  232. payload += "\"lightDetected\":" + String(currentData.lightDetected ? "true" : "false") + ",";
  233. payload += "\"battery\":" + String(batteryData.percentage) + ",";
  234. payload += "\"batteryVoltage\":" + String(batteryData.voltage, 2) + ",";
  235. payload += "\"charging\":" + String(batteryData.charging ? "true" : "false");
  236. payload += "}";
  237. if (client.publish(mqtt_topic, payload.c_str())) {
  238. Serial.println("MQTT data sent successfully");
  239. } else {
  240. Serial.println("Failed to send MQTT data");
  241. }
  242. // Also send battery status separately
  243. String batteryPayload = "{";
  244. batteryPayload += "\"percentage\":" + String(batteryData.percentage) + ",";
  245. batteryPayload += "\"voltage\":" + String(batteryData.voltage, 2) + ",";
  246. batteryPayload += "\"charging\":" + String(batteryData.charging ? "true" : "false") + ",";
  247. batteryPayload += "\"lowBattery\":" + String(batteryData.lowBattery ? "true" : "false");
  248. batteryPayload += "}";
  249. client.publish("weather/battery", batteryPayload.c_str());
  250. }
  251. // -------- SETUP --------
  252. void setup() {
  253. Serial.begin(115200);
  254. // Initialize pins
  255. pinMode(LDR_PIN, INPUT);
  256. pinMode(RAIN_DIGITAL_PIN, INPUT);
  257. pinMode(LED_PIN, OUTPUT);
  258. digitalWrite(LED_PIN, LOW);
  259. // Initialize I2C and sensors (Wemos D1 Mini pins)
  260. Wire.begin(I2C_SDA, I2C_SCL); // D1, D2
  261. dht.begin();
  262. if (!bmp.begin()) {
  263. Serial.println("BMP180 not detected!");
  264. }
  265. // Initialize WiFi
  266. setupWiFi();
  267. // Initialize MQTT
  268. client.setServer(mqtt_server, mqtt_port);
  269. // Initial sensor reading
  270. readSensors();
  271. readBattery();
  272. updateStatus();
  273. managePower();
  274. Serial.println("Weather Station Ready (Wemos D1 Mini + Solar + Battery)");
  275. }
  276. // -------- LOOP --------
  277. void loop() {
  278. unsigned long currentMillis = millis();
  279. // Reconnect MQTT if needed
  280. if (!client.connected()) {
  281. reconnectMQTT();
  282. }
  283. client.loop();
  284. // Read sensors at regular interval
  285. if (currentMillis - lastSensorRead >= sensorInterval) {
  286. lastSensorRead = currentMillis;
  287. readSensors();
  288. updateStatus();
  289. }
  290. // Check battery status every minute
  291. if (currentMillis - lastBatteryCheck >= batteryCheckInterval) {
  292. lastBatteryCheck = currentMillis;
  293. readBattery();
  294. managePower();
  295. }
  296. // Send MQTT data at regular interval
  297. if (currentMillis - lastMQTTSend >= mqttInterval) {
  298. lastMQTTSend = currentMillis;
  299. sendMQTTData();
  300. }
  301. delay(100);
  302. }