Skip to content

Instantly share code, notes, and snippets.

@ajangrahmat
Last active December 17, 2025 08:57
Show Gist options
  • Select an option

  • Save ajangrahmat/9064d6e3626df01b5f0795cda48b65d5 to your computer and use it in GitHub Desktop.

Select an option

Save ajangrahmat/9064d6e3626df01b5f0795cda48b65d5 to your computer and use it in GitHub Desktop.
#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