#include #include #include #include #include #include #include #include // WiFi Credentials const char* ssid = "IANION"; const char* password = "ianryanian"; // Thinger.io Credentials #define USERNAME "iannion" #define DEVICE_ID "yono3" #define DEVICE_CREDENTIAL "H3GFa2M7cN&wYxbk" RTC_DS3231 rtc; LiquidCrystal_I2C lcd(0x27, 20, 4); volatile int flow_frequency = 0; float vol = 0.0, l_minute; const unsigned char flowsensor = 13; const unsigned char buttonPin1 = 14; const unsigned char buttonPin2 = 12; const unsigned char buttonPin3 = 2; const unsigned char buttonPin4 = 16; unsigned long currentTime; unsigned long cloopTime; float volume_per_pulse = 0.004; float cost_per_liter = 5.07; float total_cost = 0.0; Servo servo; const int servoPin = 3; const int posisiBuka = 0; const int posisiTutup = 180; const unsigned long delayBuka = 1000; const unsigned long delayTutup = 2000; int limitSet2Counter = 0; int limitSet3Counter = 0; bool kranDitutup = true; ThingerESP8266 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL); WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200, 60000); unsigned long lastThingerUpdateTime = 0; const unsigned long thingerUpdateInterval = 60000; // Update every 60 seconds void IRAM_ATTR flow() { static unsigned long last_interrupt_time = 0; unsigned long interrupt_time = millis(); if (interrupt_time - last_interrupt_time > 10) { flow_frequency++; } last_interrupt_time = interrupt_time; } void setup() { Serial.begin(115200); lcd.init(); lcd.backlight(); pinMode(flowsensor, INPUT); digitalWrite(flowsensor, HIGH); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); servo.attach(servoPin); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); timeClient.begin(); timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); if (!rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); } if (rtc.lostPower()) { Serial.println("RTC lost power, set time..."); rtc.adjust(DateTime(epochTime)); } attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING); currentTime = millis(); cloopTime = currentTime; thing.add_wifi(ssid, password); thing["meyala"] >> [] (pson & out) { out["flow_rate"] = String(l_minute); out["volume"] = String(vol); out["total_cost"] = String(total_cost); }; thing["current_time"] >> [](pson& out) { DateTime now = rtc.now(); char buffer[30]; snprintf(buffer, sizeof(buffer), "%02d/%02d/%d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute()); out = String(buffer); }; } void tutupKatup() { if (!kranDitutup) { Serial.println("Menutup katup..."); servo.write(posisiTutup); delay(delayTutup); // Delay untuk memastikan servo memiliki waktu untuk bergerak kranDitutup = true; } } void bukaKatup() { if (kranDitutup) { Serial.println("Membuka katup..."); servo.write(posisiBuka); delay(delayBuka); // Delay untuk memastikan servo memiliki waktu untuk bergerak kranDitutup = false; } } bool kirimDataKeThinger() { pson data; data["flow_rate"] = l_minute; data["volume"] = vol; data["total_cost"] = total_cost; bool success = thing.write_bucket("meyala", data); if (!success) { Serial.println("Gagal mengirim data ke Thinger.io"); } return success; } void resetData() { vol = 0; total_cost = 0.0; limitSet2Counter = 0; limitSet3Counter = 0; Serial.println("Semua pembacaan sensor direset"); // Update Thinger.io dengan nilai reset kirimDataKeThinger(); // Perbarui tampilan LCD lcd.setCursor(0, 1); lcd.print("Flow :0 L/M "); lcd.setCursor(0, 2); lcd.print("Volume :0 mL "); lcd.setCursor(0, 3); lcd.print("Cost :Rp 0.00 "); } void loop() { DateTime now = rtc.now(); timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); rtc.adjust(DateTime(epochTime)); lcd.setCursor(0, 0); if (now.day() < 10) lcd.print('0'); lcd.print(now.day()); lcd.print('/'); if (now.month() < 10) lcd.print('0'); lcd.print(now.month()); lcd.print('/'); lcd.print(now.year()); lcd.print(' '); if (now.hour() < 10) lcd.print('0'); lcd.print(now.hour()); lcd.print(':'); if (now.minute() < 10) lcd.print('0'); lcd.print(now.minute()); currentTime = millis(); if (currentTime >= (cloopTime + 1000)) { cloopTime = currentTime; if (flow_frequency != 0) { l_minute = (flow_frequency * volume_per_pulse * 60); Serial.print("Flow: "); Serial.print(l_minute); Serial.println(" L/M"); lcd.setCursor(0, 1); lcd.print("Flow :"); lcd.print(l_minute); lcd.print(" L/M "); vol += l_minute / 60; total_cost += (l_minute / 60) * cost_per_liter; Serial.print("Volume: "); Serial.print(vol); Serial.println(" L"); Serial.print("Volume: "); Serial.print(vol * 1000); Serial.println(" mL"); lcd.setCursor(0, 2); lcd.print("Volume :"); lcd.print(int(vol * 1000)); lcd.print(" mL "); Serial.print("Cost: Rp "); Serial.print(total_cost, 2); Serial.println(); lcd.setCursor(0, 3); lcd.print("Cost :Rp "); lcd.print(total_cost, 2); lcd.print(" "); if (limitSet2Counter > 0 && vol >= (2.0 * limitSet2Counter)) { // Batasan kelipatan 2 liter Serial.println("Batas aliran tercapai: " + String(2.0 * limitSet2Counter) + " liter!"); thing.call_endpoint("Notifikasi_Harian"); // kirim notifikasi dengan endpoint tutupKatup(); } if (limitSet3Counter > 0 && vol >= (3.0 * limitSet3Counter)) { // Batasan kelipatan 3 liter Serial.println("Batas aliran tercapai: " + String(3.0 * limitSet3Counter) + " liter!"); thing.call_endpoint("Notifikasi_Harian3"); // kirim notifikasi dengan endpoint tutupKatup(); } flow_frequency = 0; } else { Serial.println("Flow: 0 L/M"); lcd.setCursor(0, 1); lcd.print("Flow :0 L/M "); } } if (digitalRead(buttonPin1) == LOW) { limitSet2Counter++; limitSet3Counter = 0; // Reset counter untuk batasan 3 liter Serial.println("Batas aliran ditetapkan untuk 2 liter kelipatan " + String(limitSet2Counter)); lcd.setCursor(0, 3); lcd.print("Limit :2 L "); delay(500); bukaKatup(); } if (digitalRead(buttonPin2) == LOW) { limitSet3Counter++; limitSet2Counter = 0; // Reset counter untuk batasan 2 liter Serial.println("Batas aliran ditetapkan untuk 3 liter kelipatan " + String(limitSet3Counter)); lcd.setCursor(0, 3); lcd.print("Limit :3 L "); delay(500); bukaKatup(); } if (digitalRead(buttonPin3) == LOW) { resetData(); delay(500); } if (digitalRead(buttonPin4) == LOW) { if (kranDitutup) { bukaKatup(); } } if (currentTime - lastThingerUpdateTime >= thingerUpdateInterval) { lastThingerUpdateTime = currentTime; kirimDataKeThinger(); } thing.handle(); delay(10); }