#include #include #include "secrets.h" #define ADC_PIN A0 #define RELAY_PIN 13 #define RELAY_OFF LOW #define RELAY_ON HIGH #define NUM_SAMPLES 20 #define SAMPLE_TIME 100 #define WATER_THRESHOLD 750 #define MESSAGE_INTERVAL 1000 * 60 * 60 // one hour WiFiClient wifiClient; MqttClient mqttClient(wifiClient); const char broker[] = BROKER; int port = 1883; const char topic[] = "iot/water"; String macAddress = String(ESP.getChipId(), HEX); String shortName = macAddress.substring(0, 4); String deviceName = "ws_" + shortName; void relayOn() { Serial.println("Setting relay ON"); digitalWrite(RELAY_PIN, RELAY_ON); } void relayOff() { Serial.println("Setting relay OFF"); digitalWrite(RELAY_PIN, RELAY_OFF); } bool sampleWater() { bool waterDetected = true; Serial.print("Samples: "); for (int i = 0; i < NUM_SAMPLES; i++) { int sample = analogRead(ADC_PIN); Serial.print(sample); Serial.print(",\t"); if (sample < WATER_THRESHOLD) { waterDetected = false; } delay(SAMPLE_TIME); } Serial.println(waterDetected ? "POS" : "NEG"); return waterDetected; } void sendWaterLeakTrue() { mqttClient.beginMessage(topic); mqttClient.print("{\"id\": \""); mqttClient.print(deviceName); mqttClient.print("\", \"water_leak\": true}"); mqttClient.endMessage(); } void sendWaterLeakFalse() { mqttClient.beginMessage(topic); mqttClient.print("{\"id\": \""); mqttClient.print(deviceName); mqttClient.print("\", \"water_leak\": false}"); mqttClient.endMessage(); } void setup() { pinMode(RELAY_PIN, OUTPUT); Serial.begin(115200); delay(1000); Serial.println(); Serial.println(); Serial.println(); Serial.println("===== BOOT UP ====="); WiFi.mode(WIFI_STA); WiFi.begin(SECRET_SSID, SECRET_PASS); Serial.print("[WIFI] Attempting to connect to wifi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("[WIFI] Connected to the network"); Serial.println(); mqttClient.setId(deviceName); Serial.print("[MQTT] Attempting to connect to the MQTT broker: "); Serial.println(broker); while (!mqttClient.connect(broker, port)) { Serial.print("MQTT connection failed! Error code = "); Serial.println(mqttClient.connectError()); delay(5000); } Serial.println("[MQTT] Connected to the MQTT broker."); Serial.println("Turning relay on."); relayOn(); } void loop() { static unsigned long last_pos_message = 0; static unsigned long last_neg_message = 0; bool leakDetected = sampleWater(); if (leakDetected) { relayOff(); Serial.println("Leak detected"); } mqttClient.poll(); if (WiFi.status() != WL_CONNECTED) { Serial.println("[WIFI] Lost connection. Reconnecting..."); WiFi.begin(SECRET_SSID, SECRET_PASS); return; } else if (!mqttClient.connected()) { Serial.print("[MQTT] Not connected! Error code = "); Serial.println(mqttClient.connectError()); Serial.println("[MQTT] Reconnecting..."); mqttClient.connect(broker, port); return; } // TODO: replace this spaghetti with a state machine if (leakDetected) { if (!last_pos_message || millis() - last_pos_message > MESSAGE_INTERVAL) { last_pos_message = millis(); last_neg_message = 0; sendWaterLeakTrue(); } } else { if (!last_neg_message || millis() - last_neg_message > MESSAGE_INTERVAL) { last_pos_message = 0; last_neg_message = millis(); sendWaterLeakFalse(); } } }