157 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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();
 | |
| 		}
 | |
| 	}
 | |
| }
 |