You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.4 KiB
156 lines
3.4 KiB
#include <ArduinoMqttClient.h> |
|
#include <ESP8266WiFi.h> |
|
|
|
#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(); |
|
} |
|
} |
|
}
|
|
|