#include <DHT.h>
#include <ESP32Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_SSD1306.h>
// Pin Definitions
#define DHT_PIN 4
#define PIR_PIN 13
#define LDR_PIN 34
#define MQ2_PIN 36
#define SERVO1_PIN 12 // Engsel pintu kiri
#define SERVO2_PIN 14 // Engsel pintu kanan
#define SERVO3_PIN 27 // Jendela
#define SERVO4_PIN 33 // Kipas angin
#define SERVO5_PIN 32 // Gembok pintu
#define RGB_R_PIN 25 // LED Merah
#define RGB_G_PIN 26 // LED Hijau
#define RGB_B_PIN 2 // LED Biru
// Sensor dan Actuator Objects
DHT dht(DHT_PIN, DHT22);
Servo servoPintuKiri, servoPintuKanan, servoJendela, servoKipas, servoGembok;
// Display Objects
LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
// System Variables
unsigned long lastMotionTime = 0;
const unsigned long INACTIVE_TIMEOUT = 1200000;
const int LDR_THRESHOLD = 500;
const float TEMP_THRESHOLD = 30.0;
const int MQ2_THRESHOLD = 300;
// Status Variables
bool pintuTerbuka = true;
bool jendelaTerbuka = false;
bool kipasNyala = false;
bool lampuNyala = false;
String statusSistem = "Sistem Siap";
void setup() {
Serial.begin(115200);
dht.begin();
servoPintuKiri.attach(SERVO1_PIN);
servoPintuKanan.attach(SERVO2_PIN);
servoJendela.attach(SERVO3_PIN);
servoKipas.attach(SERVO4_PIN);
servoGembok.attach(SERVO5_PIN);
pinMode(PIR_PIN, INPUT);
pinMode(RGB_R_PIN, OUTPUT);
pinMode(RGB_G_PIN, OUTPUT);
pinMode(RGB_B_PIN, OUTPUT);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Smart Indekos");
lcd.setCursor(0, 1);
lcd.print("Sistem Aktif");
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED initialization failed!");
}
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(0, 0);
oled.println("Smart Indekos");
oled.println("System Ready");
oled.display();
initializeServos();
lastMotionTime = millis();
}
void loop() {
float suhu = dht.readTemperature();
float kelembapan = dht.readHumidity();
int aktivitas = digitalRead(PIR_PIN);
int intensitasCahaya = analogRead(LDR_PIN);
int nilaiGas = analogRead(MQ2_PIN);
if (isnan(suhu) || isnan(kelembapan)) {
suhu = 25.0;
kelembapan = 50.0;
}
if (aktivitas == HIGH) {
lastMotionTime = millis();
}
kontrolPintu();
kontrolSuhu(suhu);
kontrolPencahayaan(intensitasCahaya);
kontrolGas(nilaiGas);
updateOLED(suhu, kelembapan, nilaiGas);
updateLCD();
printDebugInfo(suhu, kelembapan, aktivitas, intensitasCahaya, nilaiGas);
delay(1000);
}
void initializeServos() {
servoPintuKiri.write(90);
servoPintuKanan.write(90);
servoJendela.write(0);
servoKipas.write(90);
servoGembok.write(0);
pintuTerbuka = true;
jendelaTerbuka = false;
kipasNyala = false;
}
void kontrolPintu() {
unsigned long waktuTidakAktif = millis() - lastMotionTime;
if (waktuTidakAktif > INACTIVE_TIMEOUT && pintuTerbuka) {
servoPintuKiri.write(0);
servoPintuKanan.write(0);
servoGembok.write(180);
pintuTerbuka = false;
statusSistem = "Pintu Terkunci";
} else if (waktuTidakAktif <= INACTIVE_TIMEOUT && !pintuTerbuka) {
servoGembok.write(0);
delay(500);
servoPintuKiri.write(90);
servoPintuKanan.write(90);
pintuTerbuka = true;
statusSistem = "Pintu Terbuka";
}
}
void kontrolSuhu(float suhu) {
static unsigned long lastKipasMove = 0;
static bool kipasPosition = false;
if (suhu > TEMP_THRESHOLD) {
if (!jendelaTerbuka) {
servoJendela.write(180);
jendelaTerbuka = true;
statusSistem = "Jendela Dibuka";
}
if (!kipasNyala) {
kipasNyala = true;
statusSistem = "Kipas Dinyalakan";
}
if (millis() - lastKipasMove > 500) {
servoKipas.write(kipasPosition ? 180 : 0);
kipasPosition = !kipasPosition;
lastKipasMove = millis();
}
} else {
if (jendelaTerbuka) {
servoJendela.write(0);
jendelaTerbuka = false;
statusSistem = "Jendela Ditutup";
}
if (kipasNyala) {
servoKipas.write(90);
kipasNyala = false;
statusSistem = "Kipas Dimatikan";
}
}
}
void kontrolPencahayaan(int intensitasCahaya) {
if (intensitasCahaya < LDR_THRESHOLD) {
if (!lampuNyala) {
digitalWrite(RGB_R_PIN, HIGH);
digitalWrite(RGB_G_PIN, HIGH);
digitalWrite(RGB_B_PIN, HIGH);
lampuNyala = true;
statusSistem = "Lampu Dinyalakan";
}
} else {
if (lampuNyala) {
digitalWrite(RGB_R_PIN, LOW);
digitalWrite(RGB_G_PIN, LOW);
digitalWrite(RGB_B_PIN, LOW);
lampuNyala = false;
statusSistem = "Lampu Dimatikan";
}
}
}
void kontrolGas(int nilaiGas) {
if (nilaiGas > MQ2_THRESHOLD) {
statusSistem = "Gas Terdeteksi!";
digitalWrite(RGB_R_PIN, HIGH);
digitalWrite(RGB_G_PIN, LOW);
digitalWrite(RGB_B_PIN, LOW);
} else if (!lampuNyala) {
digitalWrite(RGB_R_PIN, LOW);
digitalWrite(RGB_G_PIN, LOW);
digitalWrite(RGB_B_PIN, LOW);
}
}
void updateOLED(float suhu, float kelembapan, int nilaiGas) {
oled.clearDisplay();
oled.setTextSize(1);
oled.setCursor(0, 0);
oled.println("=== INDEKOS DATA ===");
oled.setCursor(0, 15);
oled.print("Suhu: "); oled.print(suhu, 1); oled.println(" C");
oled.setCursor(0, 25);
oled.print("Kelembapan: "); oled.print(kelembapan, 1); oled.println(" %");
oled.setCursor(0, 35);
oled.print("Gas: "); oled.println(nilaiGas);
oled.setCursor(0, 45);
oled.print("P: "); oled.print(pintuTerbuka ? "Buka" : "Tutup");
oled.print(" J: "); oled.print(jendelaTerbuka ? "Buka" : "Tutup");
oled.print(" K: "); oled.print(kipasNyala ? "ON" : "OFF");
oled.display();
}
void updateLCD() {
lcd.setCursor(0, 0);
lcd.print(statusSistem);
for (int i = statusSistem.length(); i < 16; i++) lcd.print(" ");
lcd.setCursor(0, 1);
unsigned long waktuTidakAktif = (millis() - lastMotionTime) / 1000;
if (waktuTidakAktif < 60) {
lcd.print("Aktif: "); lcd.print(waktuTidakAktif); lcd.print("s ");
} else if (waktuTidakAktif < 3600) {
lcd.print("Aktif: "); lcd.print(waktuTidakAktif / 60); lcd.print("m ");
} else {
lcd.print("Tidak Aktif ");
}
}
void printDebugInfo(float suhu, float kelembapan, int aktivitas, int cahaya, int nilaiGas) {
Serial.println("=== DEBUG INFO ===");
Serial.print("Suhu: "); Serial.print(suhu); Serial.println(" C");
Serial.print("Kelembapan: "); Serial.print(kelembapan); Serial.println(" %");
Serial.print("Aktivitas: "); Serial.println(aktivitas ? "TERDETEKSI" : "TIDAK ADA");
Serial.print("Cahaya: "); Serial.println(cahaya);
Serial.print("Gas: "); Serial.println(nilaiGas);
Serial.print("Waktu tidak aktif: "); Serial.println((millis() - lastMotionTime) / 1000);
Serial.print("Pintu: "); Serial.println(pintuTerbuka ? "TERBUKA" : "TERTUTUP");
Serial.print("Jendela: "); Serial.println(jendelaTerbuka ? "TERBUKA" : "TERTUTUP");
Serial.print("Kipas: "); Serial.println(kipasNyala ? "NYALA" : "MATI");
Serial.print("Lampu: "); Serial.println(lampuNyala ? "NYALA" : "MATI");
Serial.println("==================");
}