Last active
December 17, 2025 08:57
-
-
Save ajangrahmat/9064d6e3626df01b5f0795cda48b65d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "DHT.h" | |
| #define NUM_BUTTONS 12 | |
| // Tombol input | |
| const int buttonPins[NUM_BUTTONS] = { | |
| 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44 | |
| }; | |
| // Output yang dikontrol (PIN 31 = dummy/tidak dipakai) | |
| const int outputPins[NUM_BUTTONS] = { | |
| 49, 51, 53, 37, 31, 31, 31, 47, 35, 45, 31, 31 | |
| }; | |
| const int l298nPins[] = {7, 6, 5, 4, 3, 2}; | |
| byte pinLDR = A0; | |
| byte pinSoil = A1; | |
| // --- Konfigurasi DHT11 --- | |
| #define DHTPIN 14 | |
| #define DHTTYPE DHT11 | |
| DHT dht(DHTPIN, DHTTYPE); | |
| // Nama tombol | |
| const char* buttonNames[NUM_BUTTONS] = { | |
| "Lampu Utama", "Lampu Kamar", "Lampu Tamu", "Colokan Terminal", | |
| "Tirai Tutup", "Tirai Buka", "Kipas", "Pompa Penyiram", | |
| "Solenoid Valve", "Solenoid Door", "Otomatis Pompa", "Otomatis Lampu" | |
| }; | |
| bool buttonState[NUM_BUTTONS]; | |
| bool lastButtonState[NUM_BUTTONS]; | |
| bool toggleState[NUM_BUTTONS]; | |
| unsigned long lastDebounceTime[NUM_BUTTONS]; | |
| const unsigned long debounceDelay = 50; | |
| // khusus solenoid door | |
| const int SOLENOID_DOOR_INDEX = 9; | |
| unsigned long solenoidStartTime = 0; | |
| bool solenoidActive = false; | |
| const unsigned long solenoidDuration = 5000; | |
| // Timer untuk sensor | |
| unsigned long lastSensorRead = 0; | |
| const unsigned long sensorInterval = 5000; | |
| // Variabel kontrol tirai | |
| bool tiraiMoving = false; | |
| int tiraiDirection = 0; // 0 = stop, 1 = buka, -1 = tutup | |
| unsigned long tiraiStopTime = 0; // Untuk auto-stop jika perlu | |
| void setup() { | |
| // Serial0 untuk debugging | |
| Serial.begin(115200); | |
| // Serial1 untuk komunikasi dengan ESP32 | |
| Serial1.begin(115200); | |
| dht.begin(); | |
| // Setup tombol dan relay | |
| for (int i = 0; i < NUM_BUTTONS; i++) { | |
| pinMode(buttonPins[i], INPUT_PULLUP); | |
| // Hanya setup pin yang bukan dummy | |
| if (outputPins[i] != 31) { | |
| pinMode(outputPins[i], OUTPUT); | |
| digitalWrite(outputPins[i], HIGH); // Relay aktif LOW: HIGH = MATI | |
| } | |
| buttonState[i] = HIGH; | |
| lastButtonState[i] = HIGH; | |
| toggleState[i] = false; // Semua mati di awal | |
| } | |
| // Setup motor driver | |
| for (int i = 0; i < 6; i++) { | |
| pinMode(l298nPins[i], OUTPUT); | |
| digitalWrite(l298nPins[i], LOW); | |
| } | |
| // Tampilkan info perintah | |
| Serial.println("==============================="); | |
| Serial.println("ARDUINO MEGA - SMART HOME SYSTEM"); | |
| Serial.println("Serial1: Connected to ESP32"); | |
| Serial.println("Serial: Debug monitor"); | |
| Serial.println("==============================="); | |
| // Kirim info ke ESP32 juga | |
| Serial1.println("ARDUINO_MEGA:READY"); | |
| } | |
| void loop() { | |
| // 1. Baca sensor setiap 5 detik | |
| if (millis() - lastSensorRead >= sensorInterval) { | |
| bacaSemuaSensor(); | |
| lastSensorRead = millis(); | |
| } | |
| // 2. Proses perintah dari ESP32 (Serial1) | |
| if (Serial1.available() > 0) { | |
| processSerialCommand(); | |
| } | |
| // 3. Proses tombol fisik - khusus untuk tirai (tombol 4 dan 5) | |
| prosesTombolTirai(); | |
| // 4. Proses tombol fisik lainnya | |
| for (int i = 0; i < NUM_BUTTONS; i++) { | |
| // Lewati tombol tirai (4 dan 5) karena sudah diproses di fungsi terpisah | |
| if (i == 4 || i == 5) continue; | |
| int reading = digitalRead(buttonPins[i]); | |
| if (reading != lastButtonState[i]) { | |
| lastDebounceTime[i] = millis(); | |
| } | |
| if ((millis() - lastDebounceTime[i]) > debounceDelay) { | |
| if (reading != buttonState[i]) { | |
| buttonState[i] = reading; | |
| if (buttonState[i] == LOW) { | |
| prosesTombolDitekan(i); | |
| } | |
| } | |
| } | |
| lastButtonState[i] = reading; | |
| } | |
| // 5. Cek timeout solenoid door | |
| if (solenoidActive && (millis() - solenoidStartTime >= solenoidDuration)) { | |
| digitalWrite(outputPins[SOLENOID_DOOR_INDEX], HIGH); | |
| solenoidActive = false; | |
| toggleState[SOLENOID_DOOR_INDEX] = false; | |
| Serial.println("Solenoid Door: OFF (5 detik selesai)"); | |
| Serial1.println("Solenoid Door: OFF (5 detik selesai)"); | |
| } | |
| } | |
| void prosesTombolTirai() { | |
| // Tombol 4: Tirai Tutup, Tombol 5: Tirai Buka | |
| bool tombolTutupDitekan = (digitalRead(buttonPins[4]) == LOW); | |
| bool tombolBukaDitekan = (digitalRead(buttonPins[5]) == LOW); | |
| // Jika kedua tombol ditekan, stop | |
| if (tombolTutupDitekan && tombolBukaDitekan) { | |
| if (tiraiMoving) { | |
| offTirai(); | |
| tiraiMoving = false; | |
| tiraiDirection = 0; | |
| Serial.println("Tirai: STOP (kedua tombol ditekan)"); | |
| Serial1.println("Tirai: STOP (kedua tombol ditekan)"); | |
| } | |
| } | |
| // Tombol tutup ditekan | |
| else if (tombolTutupDitekan) { | |
| if (!tiraiMoving || tiraiDirection != -1) { | |
| tutupTirai(45); | |
| tiraiMoving = true; | |
| tiraiDirection = -1; | |
| Serial.println("Tirai: TUTUP (tombol ditekan)"); | |
| Serial1.println("Tirai: TUTUP (tombol ditekan)"); | |
| } | |
| } | |
| // Tombol buka ditekan | |
| else if (tombolBukaDitekan) { | |
| if (!tiraiMoving || tiraiDirection != 1) { | |
| bukaTirai(45); | |
| tiraiMoving = true; | |
| tiraiDirection = 1; | |
| Serial.println("Tirai: BUKA (tombol ditekan)"); | |
| Serial1.println("Tirai: BUKA (tombol ditekan)"); | |
| } | |
| } | |
| // Tidak ada tombol yang ditekan | |
| else { | |
| if (tiraiMoving) { | |
| offTirai(); | |
| tiraiMoving = false; | |
| tiraiDirection = 0; | |
| Serial.println("Tirai: STOP (tombol dilepas)"); | |
| Serial1.println("Tirai: STOP (tombol dilepas)"); | |
| } | |
| } | |
| } | |
| void bacaSemuaSensor() { | |
| // Baca LDR | |
| int nilaiLDR = analogRead(pinLDR); | |
| String ldrStr = "LDR:" + String(nilaiLDR); | |
| Serial.println(ldrStr); | |
| Serial1.println(ldrStr); | |
| // Baca Soil Moisture | |
| int nilaiSoil = analogRead(pinSoil); | |
| String soilStr = "Soil:" + String(nilaiSoil); | |
| Serial.println(soilStr); | |
| Serial1.println(soilStr); | |
| // Baca DHT11 | |
| float kelembapan = dht.readHumidity(); | |
| float suhu = dht.readTemperature(); | |
| if (isnan(kelembapan) || isnan(suhu)) { | |
| Serial.println("DHT11:ERROR"); | |
| Serial1.println("DHT11:ERROR"); | |
| } else { | |
| String dhtStr = "DHT11:Suhu:" + String(suhu, 1) + ":Kelembapan:" + String(kelembapan, 1); | |
| Serial.print("DHT11 - Suhu: "); | |
| Serial.print(suhu); | |
| Serial.print("°C, Kelembapan: "); | |
| Serial.print(kelembapan); | |
| Serial.println("%"); | |
| Serial1.println(dhtStr); | |
| } | |
| Serial.println("---"); | |
| Serial1.println("SENSOR:DONE"); | |
| } | |
| void prosesTombolDitekan(int index) { | |
| // Tombol dengan pin dummy (31) tidak bisa dikontrol | |
| if (outputPins[index] == 31) { | |
| String msg = "Tombol " + String(buttonNames[index]) + ": Pin dummy"; | |
| Serial.println(msg); | |
| Serial1.println(msg); | |
| return; | |
| } | |
| if (index == SOLENOID_DOOR_INDEX) { | |
| // Tombol Solenoid Door - aktif 5 detik | |
| if (!solenoidActive) { | |
| solenoidActive = true; | |
| solenoidStartTime = millis(); | |
| digitalWrite(outputPins[index], LOW); | |
| toggleState[index] = true; | |
| Serial.println("Solenoid Door: AKTIF (5 detik)"); | |
| Serial1.println("Solenoid Door: AKTIF (5 detik)"); | |
| } | |
| } | |
| else if (index == 6) { | |
| // Tombol Kipas - toggle | |
| toggleState[index] = !toggleState[index]; | |
| digitalWrite(outputPins[index], toggleState[index] ? LOW : HIGH); | |
| String msg = String(buttonNames[index]) + ":" + (toggleState[index] ? "ON" : "OFF"); | |
| Serial.println(msg); | |
| Serial1.println(msg); | |
| if (toggleState[index]) { | |
| onKipas(50); | |
| } else { | |
| offKipas(); | |
| } | |
| } | |
| else { | |
| // Tombol toggle biasa (lampu, pompa, dll) | |
| toggleState[index] = !toggleState[index]; | |
| digitalWrite(outputPins[index], toggleState[index] ? LOW : HIGH); | |
| String msg = String(buttonNames[index]) + ":" + (toggleState[index] ? "ON" : "OFF"); | |
| Serial.println(msg); | |
| Serial1.println(msg); | |
| } | |
| } | |
| void processSerialCommand() { | |
| String command = Serial1.readStringUntil('\n'); | |
| command.trim(); | |
| if (command.length() == 0) return; | |
| Serial.print("[FROM ESP32]: "); | |
| Serial.println(command); | |
| if (command.startsWith("TOGGLE ")) { | |
| int index = command.substring(7).toInt(); | |
| handleToggleCommand(index); | |
| } | |
| else if (command.startsWith("ON ")) { | |
| int index = command.substring(3).toInt(); | |
| handleOnCommand(index); | |
| } | |
| else if (command.startsWith("OFF ")) { | |
| int index = command.substring(4).toInt(); | |
| handleOffCommand(index); | |
| } | |
| else if (command.startsWith("KIPASON ")) { | |
| int speed = command.substring(8).toInt(); | |
| speed = constrain(speed, 0, 255); | |
| onKipas(speed); | |
| if (outputPins[6] != 31) { | |
| digitalWrite(outputPins[6], LOW); | |
| toggleState[6] = true; | |
| } | |
| String msg = "Kipas: ON (speed " + String(speed) + ")"; | |
| Serial.println(msg); | |
| Serial1.println(msg); | |
| } | |
| else if (command == "KIPASOFF") { | |
| offKipas(); | |
| if (outputPins[6] != 31) { | |
| digitalWrite(outputPins[6], HIGH); | |
| toggleState[6] = false; | |
| } | |
| Serial.println("Kipas: OFF"); | |
| Serial1.println("Kipas: OFF"); | |
| } | |
| else if (command == "SOLENOID_DOOR") { | |
| if (!solenoidActive) { | |
| solenoidActive = true; | |
| solenoidStartTime = millis(); | |
| digitalWrite(outputPins[SOLENOID_DOOR_INDEX], LOW); | |
| toggleState[SOLENOID_DOOR_INDEX] = true; | |
| Serial.println("Solenoid Door: AKTIF (5 detik)"); | |
| Serial1.println("Solenoid Door: AKTIF (5 detik)"); | |
| } | |
| } | |
| else if (command == "TIRAIBUKA") { | |
| if (!tiraiMoving || tiraiDirection != 1) { | |
| bukaTirai(45); | |
| tiraiMoving = true; | |
| tiraiDirection = 1; | |
| Serial.println("Tirai: BUKA (perintah serial)"); | |
| Serial1.println("Tirai: BUKA (perintah serial)"); | |
| } | |
| } | |
| else if (command == "TIRAITUTUP") { | |
| if (!tiraiMoving || tiraiDirection != -1) { | |
| tutupTirai(45); | |
| tiraiMoving = true; | |
| tiraiDirection = -1; | |
| Serial.println("Tirai: TUTUP (perintah serial)"); | |
| Serial1.println("Tirai: TUTUP (perintah serial)"); | |
| } | |
| } | |
| else if (command == "TIRAISTOP") { | |
| if (tiraiMoving) { | |
| offTirai(); | |
| tiraiMoving = false; | |
| tiraiDirection = 0; | |
| Serial.println("Tirai: STOP (perintah serial)"); | |
| Serial1.println("Tirai: STOP (perintah serial)"); | |
| } | |
| } | |
| else if (command.startsWith("TIRAIBUKA ")) { | |
| // Format: TIRAIBUKA <durasi_ms> | |
| int durasi = command.substring(10).toInt(); | |
| durasi = constrain(durasi, 100, 30000); // Batasi 100ms - 30 detik | |
| if (!tiraiMoving || tiraiDirection != 1) { | |
| bukaTirai(45); | |
| tiraiMoving = true; | |
| tiraiDirection = 1; | |
| tiraiStopTime = millis() + durasi; | |
| Serial.println("Tirai: BUKA selama " + String(durasi) + "ms"); | |
| Serial1.println("Tirai: BUKA selama " + String(durasi) + "ms"); | |
| } | |
| } | |
| else if (command.startsWith("TIRAITUTUP ")) { | |
| // Format: TIRAITUTUP <durasi_ms> | |
| int durasi = command.substring(11).toInt(); | |
| durasi = constrain(durasi, 100, 30000); // Batasi 100ms - 30 detik | |
| if (!tiraiMoving || tiraiDirection != -1) { | |
| tutupTirai(45); | |
| tiraiMoving = true; | |
| tiraiDirection = -1; | |
| tiraiStopTime = millis() + durasi; | |
| Serial.println("Tirai: TUTUP selama " + String(durasi) + "ms"); | |
| Serial1.println("Tirai: TUTUP selama " + String(durasi) + "ms"); | |
| } | |
| } | |
| else if (command == "STATUS") { | |
| tampilkanStatus(); | |
| } | |
| else if (command == "PING") { | |
| Serial1.println("ARDUINO:ALIVE"); | |
| } | |
| else { | |
| Serial1.println("ERROR:Unknown command"); | |
| } | |
| // Cek auto-stop untuk tirai jika ada timer | |
| if (tiraiMoving && tiraiStopTime > 0 && millis() >= tiraiStopTime) { | |
| offTirai(); | |
| tiraiMoving = false; | |
| tiraiDirection = 0; | |
| tiraiStopTime = 0; | |
| Serial.println("Tirai: STOP (auto-stop timer)"); | |
| Serial1.println("Tirai: STOP (auto-stop timer)"); | |
| } | |
| } | |
| void handleToggleCommand(int index) { | |
| if (index >= 0 && index < NUM_BUTTONS) { | |
| if (outputPins[index] == 31) { | |
| Serial1.println("ERROR:Pin dummy"); | |
| } | |
| else if (index == SOLENOID_DOOR_INDEX) { | |
| if (!solenoidActive) { | |
| solenoidActive = true; | |
| solenoidStartTime = millis(); | |
| digitalWrite(outputPins[index], LOW); | |
| toggleState[index] = true; | |
| Serial1.println("Solenoid Door: AKTIF (5 detik)"); | |
| } | |
| } | |
| else { | |
| toggleState[index] = !toggleState[index]; | |
| digitalWrite(outputPins[index], toggleState[index] ? LOW : HIGH); | |
| String msg = String(buttonNames[index]) + ":" + (toggleState[index] ? "ON" : "OFF"); | |
| Serial1.println(msg); | |
| if (index == 6) { | |
| if (toggleState[index]) { | |
| onKipas(50); | |
| } else { | |
| offKipas(); | |
| } | |
| } | |
| } | |
| } else { | |
| Serial1.println("ERROR:Invalid index"); | |
| } | |
| } | |
| void handleOnCommand(int index) { | |
| if (index >= 0 && index < NUM_BUTTONS) { | |
| if (outputPins[index] == 31) { | |
| Serial1.println("ERROR:Pin dummy"); | |
| } | |
| else if (index == SOLENOID_DOOR_INDEX) { | |
| if (!solenoidActive) { | |
| solenoidActive = true; | |
| solenoidStartTime = millis(); | |
| digitalWrite(outputPins[index], LOW); | |
| toggleState[index] = true; | |
| Serial1.println("Solenoid Door: AKTIF (5 detik)"); | |
| } | |
| } | |
| else { | |
| // Set ke ON | |
| toggleState[index] = true; | |
| digitalWrite(outputPins[index], LOW); // Relay aktif LOW | |
| String msg = String(buttonNames[index]) + ":ON"; | |
| Serial1.println(msg); | |
| if (index == 6) { | |
| onKipas(50); | |
| } | |
| } | |
| } else { | |
| Serial1.println("ERROR:Invalid index"); | |
| } | |
| } | |
| void handleOffCommand(int index) { | |
| if (index >= 0 && index < NUM_BUTTONS) { | |
| if (outputPins[index] == 31) { | |
| Serial1.println("ERROR:Pin dummy"); | |
| } | |
| else if (index == SOLENOID_DOOR_INDEX) { | |
| // Untuk solenoid door, OFF hanya bisa via timeout | |
| Serial1.println("ERROR:Solenoid door auto off after 5s"); | |
| } | |
| else { | |
| // Set ke OFF | |
| toggleState[index] = false; | |
| digitalWrite(outputPins[index], HIGH); // Relay mati HIGH | |
| String msg = String(buttonNames[index]) + ":OFF"; | |
| Serial1.println(msg); | |
| if (index == 6) { | |
| offKipas(); | |
| } | |
| } | |
| } else { | |
| Serial1.println("ERROR:Invalid index"); | |
| } | |
| } | |
| void tampilkanStatus() { | |
| Serial1.println("=== STATUS SISTEM ==="); | |
| Serial1.println("PERANGKAT YANG TERKONTROL:"); | |
| for (int i = 0; i < NUM_BUTTONS; i++) { | |
| if (outputPins[i] != 31) { | |
| String statusLine = String(buttonNames[i]) + ":" + (toggleState[i] ? "ON" : "OFF"); | |
| Serial1.println(statusLine); | |
| } | |
| } | |
| // Status tirai | |
| String tiraiStatus; | |
| if (tiraiMoving) { | |
| tiraiStatus = "Tirai:" + String(tiraiDirection == 1 ? "BUKA" : "TUTUP"); | |
| } else { | |
| tiraiStatus = "Tirai:STOP"; | |
| } | |
| Serial1.println(tiraiStatus); | |
| Serial1.println("====================="); | |
| } | |
| void tutupTirai(int speed) { | |
| analogWrite(l298nPins[0], speed); | |
| digitalWrite(l298nPins[1], LOW); | |
| digitalWrite(l298nPins[2], HIGH); | |
| } | |
| void bukaTirai(int speed) { | |
| analogWrite(l298nPins[0], speed); | |
| digitalWrite(l298nPins[1], HIGH); | |
| digitalWrite(l298nPins[2], LOW); | |
| } | |
| void offTirai() { | |
| analogWrite(l298nPins[0], 0); | |
| digitalWrite(l298nPins[1], LOW); | |
| digitalWrite(l298nPins[2], LOW); | |
| } | |
| void onKipas(int speed) { | |
| analogWrite(l298nPins[5], speed); | |
| digitalWrite(l298nPins[4], HIGH); | |
| digitalWrite(l298nPins[3], LOW); | |
| } | |
| void offKipas() { | |
| analogWrite(l298nPins[5], 0); | |
| digitalWrite(l298nPins[4], LOW); | |
| digitalWrite(l298nPins[3], LOW); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment