#include #include #include #include #include #include #include // ================= LCD ================= LiquidCrystal_I2C lcd(0x27, 16, 2); // ================= MQTT ================= const char* mqtt_server = "broker.emqx.io"; const int mqtt_port = 1883; WiFiClient espClient; PubSubClient client(espClient); // ================= PIN ================= #define TURBIDITY_PIN 34 #define TRIG_PIN 5 #define ECHO_PIN 18 #define RELAY_MASUK 26 #define RELAY_KELUAR 27 // ================= SENSOR ================= long duration; float distance; int turbidityValue; // ================= FILTER ================= float filteredDistance = 0; float alphaDistance = 0.1; // ================= STATUS RELAY ================= bool relayMasuk = false; bool relayKeluar = false; // ===================================================== // WIFI MANAGER // ===================================================== void setup_wifi() { Serial.println("Memulai WiFiManager..."); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Connecting WiFi"); lcd.setCursor(0, 1); lcd.print("Please wait..."); WiFiManager wm; bool res; res = wm.autoConnect("AutoConnectAP", "password"); if (!res) { Serial.println("Gagal connect WiFi"); lcd.clear(); lcd.setCursor(0, 0); lcd.print("WiFi Failed"); delay(800); ESP.restart(); } else { Serial.println("WiFi Connected!"); Serial.print("IP Address: "); Serial.println(WiFi.localIP()); lcd.clear(); lcd.setCursor(0, 0); lcd.print("WiFi Connected"); lcd.setCursor(0, 1); lcd.print(WiFi.localIP()); delay(800); } } void WiFiEvent(WiFiEvent_t event) { switch(event) { case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: Serial.println("WiFi Lost"); WiFi.reconnect(); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: Serial.print("IP : "); Serial.println(WiFi.localIP()); break; default: break; } } // ===================================================== // PUBLISH STATUS RELAY // ===================================================== void publishRelayStatus() { StaticJsonDocument<200> doc; doc["pompa_masuk"] = relayMasuk ? 1 : 0; doc["pompa_keluar"] = relayKeluar ? 1 : 0; char buffer[200]; serializeJson(doc, buffer); client.publish("aquamonn/relay_status", buffer); } // ===================================================== // CONTROL RELAY MASUK // ===================================================== void setRelayMasuk(bool state) { relayMasuk = state; // RELAY ACTIVE LOW digitalWrite(RELAY_MASUK, state ? LOW : HIGH); } // ===================================================== // CONTROL RELAY KELUAR // ===================================================== void setRelayKeluar(bool state) { relayKeluar = state; // RELAY ACTIVE LOW digitalWrite(RELAY_KELUAR, state ? LOW : HIGH); } // ===================================================== // MQTT CALLBACK // ===================================================== void callback(char* topic, byte* payload, unsigned int length) { Serial.println(); Serial.println("========== MQTT CALLBACK =========="); Serial.print("Waktu (ms): "); Serial.println(millis()); Serial.print("Topic : "); Serial.println(topic); String message = ""; for (unsigned int i = 0; i < length; i++) { message += (char)payload[i]; } Serial.print("Payload : "); Serial.println(message); StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, message); if (error) { Serial.print("JSON Error : "); Serial.println(error.c_str()); return; } if (String(topic) == "aquamonn/relay1") { if (doc.containsKey("pompa_masuk")) { bool state = doc["pompa_masuk"] == 1; Serial.print("Pompa Masuk : "); Serial.println(state ? "ON" : "OFF"); setRelayMasuk(state); } if (doc.containsKey("pompa_keluar")) { bool state = doc["pompa_keluar"] == 1; Serial.print("Pompa Keluar : "); Serial.println(state ? "ON" : "OFF"); setRelayKeluar(state); } publishRelayStatus(); } Serial.println("=================================="); Serial.println(); } // ===================================================== // MQTT RECONNECT // ===================================================== void reconnect() { if (client.connected()) return; if (WiFi.status() != WL_CONNECTED) return; Serial.println("Connecting MQTT..."); String clientId = "ESP32-" + String(random(0xffff), HEX); if (client.connect(clientId.c_str())) { Serial.println("MQTT Connected"); client.subscribe("aquamonn/relay1"); } else { Serial.print("MQTT Failed rc="); Serial.println(client.state()); } } // ===================================================== // ULTRASONIC STABLE // ===================================================== float readUltrasonicStable() { const int samples = 5; float data[samples]; for (int i = 0; i < samples; i++) { digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2); digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW); long duration = pulseIn(ECHO_PIN, HIGH, 30000); if (duration == 0) { data[i] = 0; } else { data[i] = duration * 0.034 / 2; } delay(20); } // Sorting for (int i = 0; i < samples - 1; i++) { for (int j = i + 1; j < samples; j++) { if (data[j] < data[i]) { float temp = data[i]; data[i] = data[j]; data[j] = temp; } } } // Ambil rata-rata data tengah float avg = 0; for (int i = 1; i < 4; i++) { avg += data[i]; } return avg / 3.0; } // ===================================================== // SETUP // ===================================================== void setup() { Serial.begin(115200); analogReadResolution(12); analogSetAttenuation(ADC_11db); randomSeed(micros()); // ================= PIN ================= pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT); pinMode(RELAY_MASUK, OUTPUT); pinMode(RELAY_KELUAR, OUTPUT); // RELAY OFF digitalWrite(RELAY_MASUK, HIGH); digitalWrite(RELAY_KELUAR, HIGH); // ================= I2C ================= Wire.begin(21, 22); // ================= LCD ================= lcd.begin(); lcd.backlight(); lcd.setCursor(0, 0); lcd.print("System Ready"); delay(2000); lcd.clear(); // ================= WIFI ================= setup_wifi(); WiFi.onEvent(WiFiEvent); // Sinkronisasi waktu dari internet (WIB) configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov"); Serial.print("Mengambil waktu"); struct tm timeinfo; while (!getLocalTime(&timeinfo)) { Serial.print("."); delay(500); } Serial.println("\nWaktu berhasil disinkronkan"); // ================= MQTT ================= client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); client.setBufferSize(512); filteredDistance = readUltrasonicStable(); } // ===================================================== // LOOP // ===================================================== void loop() { // ================= WIFI RECONNECT ================= if (WiFi.status() != WL_CONNECTED) { Serial.println("WiFi Disconnect... reconnect"); WiFi.reconnect(); unsigned long start = millis(); while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) { delay(500); Serial.print("."); } if (WiFi.status() == WL_CONNECTED) { Serial.println("\nWiFi Connected"); } else { Serial.println("\nReconnect WiFi Failed"); } return; // jangan lanjut MQTT } // ================= MQTT ================= if (!client.connected()) { reconnect(); } Serial.print("client.loop() : "); Serial.println(millis()); client.loop(); // ================= ULTRASONIC ================= float rawDistance = readUltrasonicStable(); filteredDistance = (alphaDistance * rawDistance) + ((1.0 - alphaDistance) * filteredDistance); distance = filteredDistance; // ================= TURBIDITY ================= turbidityValue = analogRead(TURBIDITY_PIN); // Hitung tegangan sensor float voltage = turbidityValue * (3.3 / 4095.0); // Persamaan hasil kalibrasi float turbidityNTU = -0.8261 * turbidityValue + 1633.94; // Batasi nilai turbidityNTU = constrain(turbidityNTU, 10.0, 400.0); // ================= JSON MQTT ================= StaticJsonDocument<200> doc; doc["adc"] = turbidityValue; doc["turbidity"] = turbidityNTU; doc["distance"] = distance; doc["pompa_masuk"] = relayMasuk ? 1 : 0; doc["pompa_keluar"] = relayKeluar ? 1 : 0; char buffer[200]; serializeJson(doc, buffer); // ================= PUBLISH ================= client.publish( "aquamonn/kekeruhan", buffer ); // ================= SERIAL ================= struct tm timeinfo; if (getLocalTime(&timeinfo)) { char waktu[25]; strftime(waktu, sizeof(waktu), "%d-%m-%Y %H:%M:%S", &timeinfo); Serial.print("Tanggal: "); Serial.print(waktu); Serial.print(" | ADC: "); Serial.print(turbidityValue); Serial.print(" | NTU: "); Serial.print(turbidityNTU); Serial.print(" | Tegangan: "); Serial.print(voltage, 3); Serial.print(" V"); Serial.print(" | Distance: "); Serial.print(distance); Serial.print(" | Pompa Masuk: "); Serial.print(relayMasuk ? "ON" : "OFF"); Serial.print(" | Pompa Keluar: "); Serial.println(relayKeluar ? "ON" : "OFF"); } // ================= LCD ================= lcd.clear(); lcd.setCursor(0, 0); lcd.print("NTU:"); lcd.print(turbidityNTU, 1); lcd.setCursor(0, 1); lcd.print("M:"); lcd.print(relayMasuk ? "ON" : "OFF"); lcd.print(" K:"); lcd.print(relayKeluar ? "ON" : "OFF"); delay(800); }