#include #include #include const char* ssid = "hidan"; const char* password = "poiuytrewq"; const char* mqtt_server = "192.168.237.151"; const int mqtt_port = 1883; const int pump1Pin = 33; // Pompa TDS const int pump2Pin = 25; // Pompa Nutrisi A const int pump3Pin = 26; // Pompa Nutrisi B const int tdsPin = 32; // Pin sensor TDS const int trigPin = 19; // Pin trigger ultrasonik const int echoPin = 18; // Pin echo ultrasonik const int flowSensorPin1 = 17; // Pin sensor aliran air 1 (WaterFlow1) const int flowSensorPin2 = 15; // Pin sensor aliran air 2 (WaterFlow2) WiFiClient espClient; PubSubClient client(espClient); volatile int pulseCount1 = 0; volatile int pulseCount2 = 0; float totalFlow1 = 0.0; float totalFlow2 = 0.0; unsigned long lastFlowTime1 = 0; unsigned long lastFlowTime2 = 0; unsigned long lastMsgTime1 = 0; unsigned long lastMsgTime2 = 0; const unsigned long interval = 100; // Interval untuk mengirim pesan MQTT (dalam milidetik) bool pump1Active = true; bool pump2Active = true; bool pump3Active = true; bool waterflow1Active = true; bool waterflow2Active = true; bool ultrasonicActive = true; void IRAM_ATTR pulseCounter1() { pulseCount1++; } void IRAM_ATTR pulseCounter2() { pulseCount2++; } void setup_wifi() { delay(10); Serial.begin(115200); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.print("IP Address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); // Copy payload to a string String message; for (int i = 0; i < length; i++) { message += (char)payload[i]; } Serial.println(message); // Process the message based on the topic if (String(topic) == "control") { if (message == "on1") { digitalWrite(pump1Pin, LOW); pump1Active = true; } else if (message == "off1") { digitalWrite(pump1Pin, HIGH); pump1Active = false; } else if (message == "on2") { digitalWrite(pump2Pin, LOW); pump2Active = true; waterflow1Active = true; // Aktifkan waterflow 1 saat pompa 2 menyala } else if (message == "off2") { digitalWrite(pump2Pin, HIGH); pump2Active = false; waterflow1Active = false; // Nonaktifkan waterflow 1 saat pompa 2 mati } else if (message == "on3") { digitalWrite(pump3Pin, LOW); pump3Active = true; waterflow2Active = true; // Aktifkan waterflow 2 saat pompa 3 menyala } else if (message == "off3") { digitalWrite(pump3Pin, HIGH); pump3Active = false; waterflow2Active = false; // Nonaktifkan waterflow 2 saat pompa 3 mati } else if (message == "on4") { ultrasonicActive = true; } else if (message == "off4") { ultrasonicActive = false; } } } void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); if (client.connect("ESP32Client")) { Serial.println("connected"); client.subscribe("control"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } float readTemperature() { // Dummy function for temperature. Replace with actual sensor reading if available return 27.0; // Using 27°C for calibration } float readCalibratedTDS() { const float VREF = 3.3; // Reference voltage at ADC const int ADC_RESOLUTION = 4095; // ADC 12-bit const float TEMP_COEFFICIENT = 0.02; // Temperature compensation coefficient const float TDS_FACTOR = 0.95; // TDS conversion factor const int numSamples = 10; // Number of samples for averaging float averageVoltage = 0.0; for (int i = 0; i < numSamples; i++) { int sensorValue = analogRead(tdsPin); float voltage = sensorValue * (VREF / ADC_RESOLUTION); // Convert ADC value to voltage averageVoltage += voltage; delay(50); // Small delay between samples } averageVoltage /= numSamples; float temperature = readTemperature(); float compensationCoefficient = 1.5 + TEMP_COEFFICIENT * (temperature - 27.0); // Temperature compensation float compensationVoltage = averageVoltage / compensationCoefficient; float tdsValue = (133.42 * pow(compensationVoltage, 3) - 255.86 * pow(compensationVoltage, 2) + 857.39 * compensationVoltage) * TDS_FACTOR; return tdsValue; } void publishTDS() { if (client.connected() && pump1Active) { // Publish only if pump 1 is active float tdsValue = readCalibratedTDS(); String tdsValueStr = String(tdsValue); // Convert float to String client.publish("tds_topic", tdsValueStr.c_str()); } } void publishWaterflow1() { unsigned long currentMillis = millis(); if (pump2Active && waterflow1Active) { unsigned long flowTime = currentMillis - lastFlowTime1; if (flowTime > 0) { // Avoid division by zero // Calculate flow rate in mL/s float flowRate1 = (pulseCount1 / 7.5) / (flowTime / 1000.0); // Calibration factor: 7.5 pulses per mL // Calculate total flow totalFlow1 += (pulseCount1 / 7.5); // Add volume to total Serial.print("pulseCount1: "); Serial.println(pulseCount1); Serial.print("flowRate1: "); Serial.println(flowRate1); Serial.print("totalFlow1: "); Serial.println(totalFlow1); if (currentMillis - lastMsgTime1 >= interval) { DynamicJsonDocument doc1(200); doc1["speed_waterflow"] = flowRate1; doc1["total_cairan"] = totalFlow1; String jsonString1; serializeJson(doc1, jsonString1); client.publish("waterflow1_topic", jsonString1.c_str()); lastMsgTime1 = currentMillis; } // Reset pulseCount and update lastFlowTime pulseCount1 = 0; lastFlowTime1 = currentMillis; } } else { // Reset pulseCount if pump is inactive pulseCount1 = 0; lastFlowTime1 = currentMillis; } } void publishWaterflow2() { // Similar function to publishWaterflow1 for the second flow sensor unsigned long currentMillis = millis(); if (pump3Active && waterflow2Active) { unsigned long flowTime = currentMillis - lastFlowTime2; if (flowTime > 0) { // Avoid division by zero // Calculate flow rate in mL/s float flowRate2 = (pulseCount2 / 7.5) / (flowTime / 1000.0); // Calibration factor: 7.5 pulses per mL // Calculate total flow totalFlow2 += (pulseCount2 / 7.5); // Add volume to total Serial.print("pulseCount2: "); Serial.println(pulseCount2); Serial.print("flowRate2: "); Serial.println(flowRate2); Serial.print("totalFlow2: "); Serial.println(totalFlow2); if (currentMillis - lastMsgTime2 >= interval) { DynamicJsonDocument doc2(200); doc2["speed_waterflow"] = flowRate2; doc2["total_cairan"] = totalFlow2; String jsonString2; serializeJson(doc2, jsonString2); client.publish("waterflow2_topic", jsonString2.c_str()); lastMsgTime2 = currentMillis; } // Reset pulseCount and update lastFlowTime pulseCount2 = 0; lastFlowTime2 = currentMillis; } } else { // Reset pulseCount if pump is inactive pulseCount2 = 0; lastFlowTime2 = currentMillis; } } float measureDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH); float distance = (duration * 0.034) / 2; return distance; } void publishUltrasonic() { if (ultrasonicActive) { // Publish only if any pump is active float distance = measureDistance(); String distanceStr = String(distance); // Convert float to String client.publish("ultrasonic_topic", distanceStr.c_str()); } } void setup() { pinMode(pump1Pin, OUTPUT); pinMode(pump2Pin, OUTPUT); pinMode(pump3Pin, OUTPUT); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(flowSensorPin1, INPUT_PULLUP); pinMode(flowSensorPin2, INPUT_PULLUP); digitalWrite(pump1Pin, LOW); // Aktifkan pompa 1 secara default digitalWrite(pump2Pin, LOW); // Aktifkan pompa 2 secara default digitalWrite(pump3Pin, LOW); // Aktifkan pompa 3 secara default digitalWrite(trigPin, LOW); // Pastikan pin trigger ultrasonik low attachInterrupt(digitalPinToInterrupt(flowSensorPin1), pulseCounter1, FALLING); attachInterrupt(digitalPinToInterrupt(flowSensorPin2), pulseCounter2, FALLING); setup_wifi(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); // Publish semua data meskipun tidak ada perubahan status pompa atau sensor publishTDS(); publishWaterflow1(); publishWaterflow2(); publishUltrasonic(); }