#include #include #include #include #include #include #include #include #include Preferences preferences; byte iup[] = {B00000, B00100, B01010, B10001, B00100, B01010, B10001, B00000}; byte idown[] = {B00000, B10001, B01010, B00100, B10001, B01010, B00100, B00000}; byte istop[] = {B00000, B11111, B11111, B11111, B11111, B11111, B00000, B00000}; byte ifeedStart[] = {B11111, B11111, B01110, B01110, B00000, B00100, B00000, B00100}; byte ifeedStop[] = {B11111, B10001, B01010, B01110, B00000, B00000, B00000, B00000}; byte ilimitUp[] = {B00100, B01110, B10101, B00100, B11111, B11111, B00000, B00000}; byte ilimitDown[] = {B00100, B00100, B00100, B00100, B00100, B00100, B11111, B11111}; byte isignalOn[] = {B00001, B00011, B00111, B01111, B11111, B11111, B00000, B00000}; byte isignalOff[] = {B10100, B01000, B10101, B00011, B00011, B00111, B01111, B11111}; // Inisialisasi LCD (alamat I2C, jumlah kolom, jumlah baris) const int lcdColumns = 16; const int lcdRows = 2; LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows); // Variabel untuk deteksi long press pada tombol stop unsigned long stopButtonPressStartTime = 0; bool isStopButtonLongPressed = false; const unsigned long LONG_PRESS_DURATION = 3000; // 3 detik // MQTT dan WiFi credentials const char* ssid = "IOT-EKASA"; const char* password = "iot-ekasa"; const char* mqtt_broker = "server.local"; const int mqtt_port = 1883; const char* mqttUser = ""; const char* mqttPassword = ""; // MQTT topic const char* mqttTopicSetOtomatis = "setOtomatis"; const char* mqttTopicKontrol = "kontrol"; // WiFi dan MQTT Client WiFiClient espClient; PubSubClient client(espClient); // Deklarasi Fungsi void wifi_connect(); void mqtt_connect(); void mqttCallback(char* topic, byte* payload, unsigned int length); void updateTimeLeft(); void checkButtons(); void stopAll(); void startProcess(const char *status, unsigned long duration); void setIconUp(); void setIconDown(); void setIconStop(); bool checkTimeElapsed(unsigned long duration); void checkLimitSwitch(); void checkConnections(); // Scheduler dan Tugas Scheduler runner; Task taskUpdateTime(500, TASK_FOREVER, &updateTimeLeft); Task taskCheckButtons(100, TASK_FOREVER, &checkButtons); Task taskCheckLimitSwitch(50, TASK_FOREVER, &checkLimitSwitch); Task taskCheckConnections(1000, TASK_FOREVER, &checkConnections); // Setiap 1000 ms (1 detik) // Variabel Servo myServo; int servoPin = 4; const int relay1 = 32; const int relay2 = 33; const int limitSwitchPin = 5; // Tambahkan variabel global untuk menyimpan status sebelumnya bool previousRemoteMode = false; bool standbyActive = false; unsigned long standbyStartTime = 0; const unsigned long standbyDuration = 5000; // 5 detik // Tombol dan LED const int selectorButtonPin = 25; // Selector mode (Manual / Otomatis) const int ledPin = 26; // LED untuk indikasi mode // Tombol menggunakan ezButton ezButton buttonCW(13); // Tombol UP ezButton buttonCCW(12); // Tombol DOWN ezButton buttonServo(27); ezButton btnEmergencyStop(14); unsigned long durasiServo = 5; unsigned long durasiTurun = 5; unsigned long durasiRendam = 1; // Dalam menit unsigned long startTime = 0; bool servoActive = false; bool turunActive = false; bool rendamActive = false; bool upActive = false; bool processActive = false; bool isManualMode = true; // Default: Mode Manual bool remoteMode = false; // Default: Remote mode = false (Manual Mode) // Variabel debounce untuk Selector Mode unsigned long lastDebounceTimeSelector = 0; const unsigned long debounceDelaySelector = 500; void setup() { Serial.begin(115200); lcd.init(); lcd.backlight(); lcd.createChar(0, ifeedStart); lcd.createChar(1, ifeedStop); lcd.createChar(2, iup); lcd.createChar(3, idown); lcd.createChar(4, istop); lcd.createChar(5, ilimitUp); lcd.createChar(6, ilimitDown); lcd.createChar(7, isignalOn); // Setup tombol dengan debounce buttonCW.setDebounceTime(50); buttonCCW.setDebounceTime(50); buttonServo.setDebounceTime(50); btnEmergencyStop.setDebounceTime(50); pinMode(limitSwitchPin, INPUT_PULLUP); pinMode(relay1, OUTPUT); pinMode(relay2, OUTPUT); pinMode(selectorButtonPin, INPUT_PULLUP); // Selector Mode pinMode(ledPin, OUTPUT); // LED Indikator digitalWrite(relay1, LOW); digitalWrite(relay2, LOW); myServo.attach(servoPin, 500, 2400); myServo.write(0); // Setup TaskScheduler runner.init(); runner.addTask(taskUpdateTime); runner.addTask(taskCheckButtons); runner.addTask(taskCheckLimitSwitch); runner.addTask(taskCheckConnections); taskUpdateTime.enable(); taskCheckButtons.enable(); taskCheckLimitSwitch.enable(); taskCheckConnections.enable(); setSignalOff(); // clearKeterangan(); // wifi_connect(); // mqtt_connect(); // Inisialisasi Preferences preferences.begin("config", false); // Namespace "config", read-write mode // Baca durasiServo, durasiTurun, durasiRendam dari Preferences durasiServo = preferences.getUInt("durasiServo", 5); // Default 5 detik durasiTurun = preferences.getUInt("durasiTurun", 5); // Default 5 detik durasiRendam = preferences.getUInt("durasiRendam", 1); // Default 1 menit Serial.println("Durasi Servo: " + String(durasiServo) + " detik"); Serial.println("Durasi Turun: " + String(durasiTurun) + " detik"); Serial.println("Durasi Rendam: " + String(durasiRendam) + " menit"); // Tampilkan informasi timer pertama kali displayInfoTimer(); if (digitalRead(limitSwitchPin) == LOW) { // lcd.clear(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Anco diatas"); lcd.setCursor(2, 1); lcd.print("Standby ..."); }else{ // lcd.clear(); clearKeterangan(); setLimitUp(); lcd.setCursor(2, 0); lcd.print("Set Posisi!"); lcd.setCursor(2, 1); lcd.print("Ready"); } delay(1000); // Pengecekan Selector Mode (Remote Mode) if (digitalRead(selectorButtonPin) == LOW) { remoteMode = true; // Aktifkan Remote Mode digitalWrite(ledPin, HIGH); // Nyalakan LED lcd.setCursor(14, 0); lcd.print("|R"); delay(500); // Debounce sederhana } else { remoteMode = false; // Nonaktifkan Remote Mode (Manual Mode) digitalWrite(ledPin, LOW); // Matikan LED lcd.setCursor(14, 0); lcd.print("|M"); } delay (1000); } void loop() { runner.execute(); // Jalankan scheduler client.loop(); // MQTT loop } // Fungsi untuk memperbarui waktu tersisa void updateTimeLeft() { if (processActive) { unsigned long elapsedTime = (millis() - startTime) / 1000; unsigned long timeLeft = 0; if (servoActive) { timeLeft = max(0UL, durasiServo - elapsedTime); } else if (turunActive) { timeLeft = max(0UL, durasiTurun - elapsedTime); } else if (rendamActive) { timeLeft = max(0UL, (durasiRendam * 60) - elapsedTime); } unsigned long hours = timeLeft / 3600; unsigned long minutes = (timeLeft % 3600) / 60; unsigned long seconds = timeLeft % 60; lcd.setCursor(2, 1); lcd.print("Time: "); if (hours < 10) lcd.print('0'); lcd.print(hours); lcd.print(':'); if (minutes < 10) lcd.print('0'); lcd.print(minutes); lcd.print(':'); if (seconds < 10) lcd.print('0'); lcd.print(seconds); } } //// Fungsi untuk memantau tombol //void checkButtons() { // buttonCW.loop(); // buttonCCW.loop(); // buttonServo.loop(); // btnEmergencyStop.loop(); // // // // Pengecekan Selector Mode (Remote Mode) // if (digitalRead(selectorButtonPin) == LOW) { // remoteMode = true; // Aktifkan Remote Mode // digitalWrite(ledPin, HIGH); // Nyalakan LED // lcd.setCursor(14, 0); // lcd.print("|R"); // delay(500); // Debounce sederhana // } else { // remoteMode = false; // Nonaktifkan Remote Mode (Manual Mode) // digitalWrite(ledPin, LOW); // Matikan LED // lcd.setCursor(14, 0); // lcd.print("|M"); // disconnectWiFi(); // } // // if (btnEmergencyStop.isPressed()) { // stopAll(); // } // // if (buttonServo.isPressed() && !processActive) { // processActive = true; // servoActive = true; // startProcess("Feeding", durasiServo); // setFeedStart(); // myServo.write(90); // } // // if (servoActive && checkTimeElapsed(durasiServo)) { // clearKeterangan(); // setFeedStop(); // myServo.write(0); // lcd.setCursor(2, 0); // lcd.print("Stop Feed"); // lcd.setCursor(2, 1); // lcd.print("Standby ...(5s)"); // delay(5000); // servoActive = false; // turunActive = true; //// lcd.clear(); // clearKeterangan(); // startProcess("Turun", durasiTurun); // setIconDown(); // digitalWrite(relay1, LOW); // digitalWrite(relay2, HIGH); // } // // if (turunActive && checkTimeElapsed(durasiTurun)) { // turunActive = false; // rendamActive = true; // // startProcess("Rendam", durasiRendam * 60); // setIconStop(); // digitalWrite(relay1, LOW); // digitalWrite(relay2, LOW); // } // // if (rendamActive && checkTimeElapsed(durasiRendam * 60)) { // rendamActive = false; // upActive = true; // setIconUp(); //// startProcess("Anco Naik", 0); // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Angkat Anco"); // lcd.setCursor(2, 1); // lcd.print("Motor Up"); // digitalWrite(relay1, HIGH); // digitalWrite(relay2, LOW); // } //if (!remoteMode) { // Kontrol Manual // if (buttonCW.isPressed()) { // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Anco Naik"); // setIconUp(); // upActive = true; // digitalWrite(relay1, HIGH); // digitalWrite(relay2, LOW); // } // // if (buttonCCW.isPressed()) { // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Anco Turun"); // setIconDown(); // digitalWrite(relay1, LOW); // digitalWrite(relay2, HIGH); // } // } //} //void checkButtons() { // buttonCW.loop(); // buttonCCW.loop(); // buttonServo.loop(); // btnEmergencyStop.loop(); // // unsigned long currentMillis = millis(); // // // Pengecekan Selector Mode (Remote Mode) dengan debounce non-blocking // bool currentSelectorState = (digitalRead(selectorButtonPin) == LOW); // if (currentSelectorState != previousRemoteMode) { // if (currentMillis - lastDebounceTimeSelector > debounceDelaySelector) { // if (currentSelectorState) { // // Mode berubah ke Remote Mode // remoteMode = true; // digitalWrite(ledPin, HIGH); // Nyalakan LED // lcd.setCursor(14, 0); // lcd.print("|R "); // setSignalOn(); // Update ikon koneksi // Serial.println("Mode: Remote"); // } else { // // Mode berubah ke Manual Mode // remoteMode = false; // digitalWrite(ledPin, LOW); // Matikan LED // lcd.setCursor(14, 0); // lcd.print("|M "); // disconnectWiFi(); // Putuskan koneksi WiFi dan MQTT // Serial.println("Mode: Manual"); // } // lastDebounceTimeSelector = currentMillis; // } // } // previousRemoteMode = currentSelectorState; // // // Pengecekan tombol Emergency Stop // if (btnEmergencyStop.isPressed()) { // stopAll(); // } // // // Pengecekan tombol Servo // if (buttonServo.isPressed() && !processActive && !remoteMode) { // processActive = true; // servoActive = true; // startProcess("Feeding", durasiServo); // setFeedStart(); // myServo.write(90); // Serial.println("Proses manual dimulai."); // } // // // Pengecekan durasi Servo // if (servoActive && checkTimeElapsed(durasiServo)) { // clearKeterangan(); // setFeedStop(); // myServo.write(0); // lcd.setCursor(2, 0); // lcd.print("Stop Feed"); // lcd.setCursor(2, 1); // lcd.print("Standby ...(5s)"); // // // Mulai Standby tanpa delay // standbyActive = true; // standbyStartTime = millis(); // servoActive = false; // } // // // Pengecekan Standby // if (standbyActive && (millis() - standbyStartTime >= standbyDuration)) { // standbyActive = false; // turunActive = true; // clearKeterangan(); // startProcess("Turun", durasiTurun); // setIconDown(); // digitalWrite(relay1, LOW); // digitalWrite(relay2, HIGH); // Serial.println("Proses turun dimulai setelah standby."); // } // // // Pengecekan durasi Turun // if (turunActive && checkTimeElapsed(durasiTurun)) { // turunActive = false; // rendamActive = true; // // startProcess("Rendam Anco", durasiRendam * 60); // setIconStop(); // digitalWrite(relay1, LOW); // digitalWrite(relay2, LOW); // Serial.println("Proses rendam dimulai."); // } // // // Pengecekan durasi Rendam // if (rendamActive && checkTimeElapsed(durasiRendam * 60)) { // rendamActive = false; // upActive = true; // setIconUp(); // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Angkat Anco"); // lcd.setCursor(2, 1); // lcd.print("Motor Up"); // digitalWrite(relay1, HIGH); // digitalWrite(relay2, LOW); // Serial.println("Proses angkat anco dimulai."); // } // // // Kontrol Manual // if (!remoteMode) { // Kontrol Manual // if (buttonCW.isPressed()) { // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Anco Naik"); // setIconUp(); // upActive = true; // digitalWrite(relay1, HIGH); // digitalWrite(relay2, LOW); // } // // if (buttonCCW.isPressed()) { // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Anco Turun"); // setIconDown(); // digitalWrite(relay1, LOW); // digitalWrite(relay2, HIGH); // } // } //} void checkButtons() { buttonCW.loop(); buttonCCW.loop(); buttonServo.loop(); btnEmergencyStop.loop(); unsigned long currentMillis = millis(); // Pengecekan Selector Mode (Remote Mode) dengan debounce non-blocking bool currentSelectorState = (digitalRead(selectorButtonPin) == LOW); if (currentSelectorState != previousRemoteMode) { if (currentMillis - lastDebounceTimeSelector > debounceDelaySelector) { if (currentSelectorState) { // Mode berubah ke Remote Mode remoteMode = true; digitalWrite(ledPin, HIGH); // Nyalakan LED lcd.setCursor(14, 0); lcd.print("|R "); setSignalOn(); // Update ikon koneksi Serial.println("Mode: Remote"); } else { // Mode berubah ke Manual Mode remoteMode = false; digitalWrite(ledPin, LOW); // Matikan LED lcd.setCursor(14, 0); lcd.print("|M "); disconnectWiFi(); // Putuskan koneksi WiFi dan MQTT Serial.println("Mode: Manual"); } lastDebounceTimeSelector = currentMillis; } } previousRemoteMode = currentSelectorState; // Pengecekan tombol Emergency Stop dengan deteksi long press if (btnEmergencyStop.isPressed()) { if (stopButtonPressStartTime == 0) { // Tombol baru saja ditekan stopButtonPressStartTime = currentMillis; isStopButtonLongPressed = false; Serial.println("Emergency Stop button pressed."); } else { // Tombol sedang ditekan if (!isStopButtonLongPressed && (currentMillis - stopButtonPressStartTime >= LONG_PRESS_DURATION)) { // Long press terdeteksi isStopButtonLongPressed = true; displayInfoTimer(); Serial.println("Emergency Stop button long pressed. Displaying Info Timer."); } } } else { if (stopButtonPressStartTime != 0) { // Tombol dilepas if (!isStopButtonLongPressed) { // Ini adalah short press stopAll(); Serial.println("Emergency Stop button short pressed. Stopping all processes."); } // Reset variabel deteksi stopButtonPressStartTime = 0; isStopButtonLongPressed = false; // Tampilkan informasi timer setelah tombol dilepas displayInfoTimer(); } } // Pengecekan tombol Servo if (buttonServo.isPressed() && !processActive && !remoteMode) { processActive = true; servoActive = true; startProcess("Feeding", durasiServo); setFeedStart(); myServo.write(90); Serial.println("Proses manual dimulai."); } // Pengecekan durasi Servo if (servoActive && checkTimeElapsed(durasiServo)) { clearKeterangan(); setFeedStop(); myServo.write(0); lcd.setCursor(2, 0); lcd.print("Stop Feed"); lcd.setCursor(2, 1); lcd.print("Standby ...(5s)"); // Mulai Standby tanpa delay standbyActive = true; standbyStartTime = millis(); servoActive = false; } // Pengecekan Standby if (standbyActive && (millis() - standbyStartTime >= standbyDuration)) { standbyActive = false; turunActive = true; clearKeterangan(); startProcess("Turun", durasiTurun); setIconDown(); digitalWrite(relay1, LOW); digitalWrite(relay2, HIGH); Serial.println("Proses turun dimulai setelah standby."); } // Pengecekan durasi Turun if (turunActive && checkTimeElapsed(durasiTurun)) { turunActive = false; rendamActive = true; startProcess("Rendam Anco", durasiRendam * 60); setIconStop(); digitalWrite(relay1, LOW); digitalWrite(relay2, LOW); Serial.println("Proses rendam dimulai."); } // Pengecekan durasi Rendam if (rendamActive && checkTimeElapsed(durasiRendam * 60)) { rendamActive = false; upActive = true; setIconUp(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Angkat Anco"); lcd.setCursor(2, 1); lcd.print("Motor Up"); digitalWrite(relay1, HIGH); digitalWrite(relay2, LOW); Serial.println("Proses angkat anco dimulai."); } // Kontrol Manual if (!remoteMode) { // Kontrol Manual if (buttonCW.isPressed()) { clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Instruksi:"); lcd.setCursor(2, 1); lcd.print("Anco Naik"); setIconUp(); upActive = true; digitalWrite(relay1, HIGH); digitalWrite(relay2, LOW); } if (buttonCCW.isPressed()) { clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Instruksi:"); lcd.setCursor(2, 1); lcd.print("Anco Turun"); setIconDown(); digitalWrite(relay1, LOW); digitalWrite(relay2, HIGH); } } } // Fungsi pengecekan limit switch saat UP void checkLimitSwitch() { if (upActive && digitalRead(limitSwitchPin) == LOW) { stopAll(); setLimitUp(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Anco di atas"); lcd.setCursor(2, 1); lcd.print("Standby ..."); } } // Fungsi untuk memulai proses void startProcess(const char *status, unsigned long duration) { // lcd.clear(); clearKeterangan(); startTime = millis(); lcd.setCursor(2, 0); lcd.print(status); } // Fungsi untuk menghentikan semua proses void stopAll() { digitalWrite(relay1, LOW); digitalWrite(relay2, LOW); myServo.write(0); servoActive = false; turunActive = false; rendamActive = false; upActive = false; processActive = false; // lcd.clear(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Instruksi:"); lcd.setCursor(2, 1); lcd.print("Motor Stop"); setIconStop(); } //// Fungsi untuk kontrol tampilan UP //void setUp() { // lcd.clear(); // lcd.setCursor(0, 0); // lcd.print("UP"); //} // //// Fungsi untuk kontrol tampilan DOWN //void setDown() { // lcd.clear(); // lcd.setCursor(0, 0); // lcd.print("DOWN"); //} // Fungsi untuk mengecek apakah waktu habis bool checkTimeElapsed(unsigned long duration) { return millis() - startTime >= duration * 1000; } // Fungsi koneksi WiFi void wifi_connect() { Serial.print("Connecting to WiFi..."); // lcd.clear(); setSignalOff(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("WiFi status:"); lcd.setCursor(2, 1); lcd.print("Connecting..."); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Connected to WiFi"); // lcd.clear(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Wifi Connected"); lcd.setCursor(2, 1); lcd.print(WiFi.localIP()); setSignalOn(); delay(1000); } // Fungsi koneksi MQTT void mqtt_connect() { client.setServer(mqtt_broker, mqtt_port); client.setCallback(mqttCallback); while (!client.connected()) { Serial.print("Connecting to MQTT..."); if (client.connect("ESP32Client", mqttUser, mqttPassword)) { Serial.println("connected"); // lcd.clear(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Server Con:"); lcd.setCursor(2, 1); lcd.print("Connected"); setSignalOn(); client.subscribe(mqttTopicSetOtomatis); client.subscribe(mqttTopicKontrol); } else { Serial.print("failed with state "); Serial.println(client.state()); // lcd.clear(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Net status:"); lcd.setCursor(2, 1); lcd.print("Disconected"); setSignalOff(); delay(2000); } } } //// Callback MQTT untuk menerima pesan //void mqttCallback(char* topic, byte* payload, unsigned int length) { // String message; // for (int i = 0; i < length; i++) { // message += (char)payload[i]; // } // // Serial.print("Message received: "); // Serial.println(message); // // Parsing JSON payload // DynamicJsonDocument doc(1024); // DeserializationError error = deserializeJson(doc, payload, length); // if (error) { // Serial.print("deserializeJson() failed: "); // Serial.println(error.f_str()); // return; // } // String instruksi = doc["instruksi"]; // durasiServo = doc["durasiServo"].as(); // durasiTurun = doc["durasiTurun"].as(); // durasiRendam = doc["durasiRendam"].as(); // // if (instruksi == "otomatis") { // if (!processActive) { // processActive = true; // servoActive = true; // startProcess("Feeding", durasiServo); // setFeedStart(); // myServo.write(90); // Serial.println("Proses otomatis dimulai."); // } // } // // if (String(topic) == mqttTopicKontrol) { // if (message == "naik") { // digitalWrite(relay1, HIGH); // digitalWrite(relay2, LOW); //// lcd.clear(); // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Anco Naik"); // setIconUp(); // } else if (message == "turun") { // digitalWrite(relay1, LOW); // digitalWrite(relay2, HIGH); //// lcd.clear(); // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Anco Turun"); // setIconUp(); // } else if (message == "stop") { // stopAll(); //// lcd.clear(); // clearKeterangan(); // lcd.setCursor(2, 0); // lcd.print("Instruksi:"); // lcd.setCursor(2, 1); // lcd.print("Motor Stop"); // setIconStop(); // } // } //} // Callback MQTT untuk menerima pesan void mqttCallback(char* topic, byte* payload, unsigned int length) { String message; for (int i = 0; i < length; i++) { message += (char)payload[i]; } Serial.print("Message received on topic ["); Serial.print(topic); Serial.print("]: "); Serial.println(message); // Penanganan untuk topik "setOtomatis" dengan format JSON if (String(topic) == mqttTopicSetOtomatis) { // Parsing JSON payload DynamicJsonDocument doc(1024); DeserializationError error = deserializeJson(doc, payload, length); if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.f_str()); return; } String instruksi = doc["instruksi"]; durasiServo = doc["durasiServo"].as(); durasiTurun = doc["durasiTurun"].as(); durasiRendam = doc["durasiRendam"].as(); // Simpan nilai baru ke Preferences preferences.putUInt("durasiServo", durasiServo); preferences.putUInt("durasiTurun", durasiTurun); preferences.putUInt("durasiRendam", durasiRendam); Serial.println("Durasi Servo diperbarui: " + String(durasiServo) + " detik"); Serial.println("Durasi Turun diperbarui: " + String(durasiTurun) + " detik"); Serial.println("Durasi Rendam diperbarui: " + String(durasiRendam) + " menit"); if (instruksi == "otomatis") { if (!processActive) { processActive = true; servoActive = true; startProcess("Feeding", durasiServo); setFeedStart(); myServo.write(90); Serial.println("Proses otomatis dimulai."); } } } // Penanganan untuk topik "kontrol" dengan perintah sederhana else if (String(topic) == mqttTopicKontrol) { if (message == "naik") { digitalWrite(relay1, HIGH); digitalWrite(relay2, LOW); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Instruksi:"); lcd.setCursor(2, 1); lcd.print("Anco Naik"); setIconUp(); Serial.println("Instruksi: Anco Naik"); } else if (message == "turun") { digitalWrite(relay1, LOW); digitalWrite(relay2, HIGH); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Instruksi:"); lcd.setCursor(2, 1); lcd.print("Anco Turun"); setIconDown(); // Perbaiki dari setIconUp() ke setIconDown() Serial.println("Instruksi: Anco Turun"); } else if (message == "stop") { stopAll(); clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Instruksi:"); lcd.setCursor(2, 1); lcd.print("Motor Stop"); setIconStop(); Serial.println("Instruksi: Motor Stop"); } } } void setFeedStart() { lcd.setCursor(0, 1); lcd.write(byte(0)); } void setFeedStop() { lcd.setCursor(0, 1); lcd.write(byte(1)); } void setIconUp() { lcd.setCursor(0, 1); lcd.write(byte(2)); // lcd.setCursor(2, 1); // lcd.print("Anco Naik"); } void setIconDown() { lcd.setCursor(0, 1); lcd.write(byte(3)); // lcd.setCursor(2, 1); // lcd.print("Anco Turun"); } void setIconStop() { lcd.setCursor(0, 1); lcd.write(byte(4)); } void setLimitUp() { lcd.setCursor(0, 1); lcd.write(byte(5)); } void setLimitDown() { lcd.setCursor(0, 1); lcd.write(byte(6)); } void setSignalOn() { // lcd.setCursor(0, 0); // lcd.write(byte(7)); lcd.createChar(7, isignalOn); // Kembalikan karakter asli ke slot 7 lcd.setCursor(0, 0); lcd.write(byte(7)); } void setSignalOff() { // lcd.setCursor(0, 0); // lcd.print("x"); lcd.createChar(7, isignalOff); // Kembalikan karakter asli ke slot 7 lcd.setCursor(0, 0); lcd.write(byte(7)); } // Fungsi untuk membersihkan area tertentu pada LCD void clearLCDArea(byte row, byte startCol, byte endCol) { // Pastikan baris dan kolom berada dalam rentang yang valid if (row >= lcdRows) return; if (startCol >= lcdColumns) return; if (endCol >= lcdColumns) endCol = lcdColumns - 1; // Set kursor ke posisi awal lcd.setCursor(startCol, row); // Hitung jumlah spasi yang perlu ditulis byte numSpaces = endCol - startCol + 1; // Tulis spasi sebanyak yang diperlukan for (byte i = 0; i < numSpaces; i++) { lcd.print(" "); } } void clearKeterangan(){ // Bersihkan kembali area tertentu clearLCDArea(0, 2, lcdColumns - 1); // Baris 0, kolom 2-15 clearLCDArea(1, 2, lcdColumns - 1); // Baris 1, kolom 2-15 } void checkConnections() { if (!remoteMode) { // Jika tidak dalam remoteMode, tidak perlu memeriksa koneksi return; } bool wifiConnected = (WiFi.status() == WL_CONNECTED); bool mqttConnected = client.connected(); // Jika WiFi terputus, coba reconnect if (!wifiConnected) { Serial.println("WiFi disconnected. Attempting to reconnect..."); setSignalOff(); // Update ikon LCD untuk menunjukkan status terputus wifi_connect(); // Coba reconnect WiFi } // Jika MQTT terputus, coba reconnect if (wifiConnected && !mqttConnected) { Serial.println("MQTT disconnected. Attempting to reconnect..."); setSignalOff(); // Update ikon LCD untuk menunjukkan status terputus mqtt_connect(); // Coba reconnect MQTT } // Jika kedua koneksi terhubung, update ikon LCD if (wifiConnected && mqttConnected) { setSignalOn(); } else { setSignalOff(); } } void disconnectWiFi() { if (WiFi.status() == WL_CONNECTED) { WiFi.disconnect(true); // Memutuskan koneksi dan menghapus SSID/password Serial.println("WiFi disconnected."); // Perbarui LCD jika perlu clearKeterangan(); lcd.setCursor(2, 0); lcd.print("Net status:"); lcd.setCursor(2, 1); lcd.print("Disconnected"); setSignalOff(); } } // Fungsi untuk menampilkan informasi timer pada LCD void displayInfoTimer() { clearKeterangan(); // Baris Pertama: "Motor Stop" // clearLCDArea(0, 0, lcdColumns - 1); // Bersihkan seluruh baris pertama lcd.setCursor(2, 0); lcd.print("Motor Stop"); // Baris Kedua: "F: 5s T:5s R:1m" // clearLCDArea(1, 0, lcdColumns - 1); // Bersihkan seluruh baris kedua lcd.setCursor(2, 1); lcd.print("F:" + String(durasiServo) + "s "); lcd.print("T:" + String(durasiTurun) + "s "); lcd.print("R:" + String(durasiRendam) + "m"); }