#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// #include <DFRobotDFPlayerMini.h> // DFPlayer sementara dinonaktifkan
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// DFPlayerMini (komentar sementara)
// #include <SoftwareSerial.h>
// SoftwareSerial mySerial(16, 17); // RX, TX
// DFRobotDFPlayerMini myDFPlayer;
// Tombol Lantai
#define BTN_GF 13
#define BTN_1F 12
#define BTN_2F 14
// Tombol Fungsi
#define BTN_OPEN 27
#define BTN_CLOSE 26
#define BTN_LIGHT 15
#define BTN_EMG 3
// LED Indikator
#define LED_GF 4
#define LED_1F 5
#define LED_2F 23
#define LED_OPEN 19
#define LED_CLOSE 18
#define LED_LIGHT 2
// Simulasi Input dari MCU pusat
#define POS_GF 32
#define POS_1F 33
#define POS_2F 34
#define DIR_UP 35
#define DIR_DOWN 25
#define DOOR_OPEN_LIMIT 1
#define DOOR_CLOSE_LIMIT 0
bool lightStatus = false;
bool emergency = false;
int currentFloor = -1;
bool upDir = false;
bool downDir = false;
bool blinkState = false;
unsigned long lastBlink = 0;
void setup() {
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Starting...");
display.display();
delay(2000);
display.clearDisplay();
// Input
pinMode(BTN_GF, INPUT_PULLUP);
pinMode(BTN_1F, INPUT_PULLUP);
pinMode(BTN_2F, INPUT_PULLUP);
pinMode(BTN_OPEN, INPUT_PULLUP);
pinMode(BTN_CLOSE, INPUT_PULLUP);
pinMode(BTN_LIGHT, INPUT_PULLUP);
pinMode(BTN_EMG, INPUT_PULLUP);
pinMode(POS_GF, INPUT);
pinMode(POS_1F, INPUT);
pinMode(POS_2F, INPUT);
pinMode(DIR_UP, INPUT);
pinMode(DIR_DOWN, INPUT);
// Output
pinMode(LED_GF, OUTPUT);
pinMode(LED_1F, OUTPUT);
pinMode(LED_2F, OUTPUT);
pinMode(LED_OPEN, OUTPUT);
pinMode(LED_CLOSE, OUTPUT);
pinMode(LED_LIGHT, OUTPUT);
// mySerial.begin(9600);
// if (myDFPlayer.begin(mySerial)) {
// myDFPlayer.volume(25);
// }
}
void loop() {
checkEmergency();
updateFloor();
updateDirection();
if (!emergency) {
handleButtonFloor(BTN_GF, LED_GF, POS_GF);
handleButtonFloor(BTN_1F, LED_1F, POS_1F);
handleButtonFloor(BTN_2F, LED_2F, POS_2F);
handleOpenClose();
handleLightToggle();
}
updateDisplay();
}
void checkEmergency() {
static bool prevEMG = HIGH;
bool current = digitalRead(BTN_EMG);
// Toggle emergency status saat tombol ditekan
if (prevEMG == HIGH && current == LOW) {
emergency = !emergency;
// Matikan semua LED jika emergency aktif
if (emergency) {
digitalWrite(LED_GF, LOW);
digitalWrite(LED_1F, LOW);
digitalWrite(LED_2F, LOW);
digitalWrite(LED_OPEN, LOW);
digitalWrite(LED_CLOSE, LOW);
// myDFPlayer.play(1); // Suara emergency
}
}
prevEMG = current;
}
void updateFloor() {
if (digitalRead(POS_GF) == HIGH) currentFloor = 0;
else if (digitalRead(POS_1F) == HIGH) currentFloor = 1;
else if (digitalRead(POS_2F) == HIGH) currentFloor = 2;
else currentFloor = -1;
}
void updateDirection() {
upDir = digitalRead(DIR_UP) == HIGH;
downDir = digitalRead(DIR_DOWN) == HIGH;
if (upDir && downDir) {
// Prevent dual direction
upDir = false;
downDir = false;
}
}
void handleButtonFloor(int btnPin, int ledPin, int floorPin) {
bool pressed = digitalRead(btnPin) == LOW;
bool onFloor = digitalRead(floorPin) == HIGH;
if (pressed && !onFloor && currentFloor != -1) {
digitalWrite(ledPin, HIGH);
}
if (onFloor) {
digitalWrite(ledPin, LOW); // Auto reset if arrived
}
}
void handleOpenClose() {
bool openPressed = digitalRead(BTN_OPEN) == LOW;
bool closePressed = digitalRead(BTN_CLOSE) == LOW;
// Kondisi hanya aktif jika tidak emergency dan lift tidak bergerak
if (!emergency && !upDir && !downDir) {
if (openPressed) {
digitalWrite(LED_OPEN, HIGH);
digitalWrite(LED_CLOSE, LOW); // Interlock
} else if (closePressed) {
digitalWrite(LED_CLOSE, HIGH);
digitalWrite(LED_OPEN, LOW); // Interlock
}
}
// Reset otomatis berdasarkan sensor limit pintu
if (digitalRead(DOOR_OPEN_LIMIT) == HIGH) {
digitalWrite(LED_OPEN, LOW);
}
if (digitalRead(DOOR_CLOSE_LIMIT) == HIGH) {
digitalWrite(LED_CLOSE, LOW);
}
}
void handleLightToggle() {
static bool prevLight = HIGH;
bool current = digitalRead(BTN_LIGHT);
if (prevLight == HIGH && current == LOW) {
lightStatus = !lightStatus;
digitalWrite(LED_LIGHT, lightStatus ? HIGH : LOW);
}
prevLight = current;
}
void updateDisplay() {
display.clearDisplay();
if (emergency) {
display.setTextSize(1);
display.setCursor(0, 0);
display.print("EMERGENCY");
display.setCursor(0, 16);
display.print("Floor: ");
display.print(currentFloor == 0 ? "GF" : currentFloor == 1 ? "1F" : currentFloor == 2 ? "2F" : "-");
display.display();
return;
}
// Lantai di kiri tengah layar dengan ukuran besar
display.setTextSize(4);
display.setCursor(0, 16); // x = 0, y = tengah vertikal
if (currentFloor == 0) display.print("GF");
else if (currentFloor == 1) display.print("1F");
else if (currentFloor == 2) display.print("2F");
else display.print("--");
// Blinking panah arah
if (millis() - lastBlink > 170) {
blinkState = !blinkState;
lastBlink = millis();
}
if (blinkState) {
if (upDir && !downDir) drawUpArrow(100, 15);
if (downDir && !upDir) drawDownArrow(100, 15);
}
display.display();
}
void drawUpArrow(int x, int y) {
display.fillTriangle(x, y + 20, x + 10, y, x + 20, y + 20, SSD1306_WHITE);
}
void drawDownArrow(int x, int y) {
display.fillTriangle(x, y, x + 10, y + 20, x + 20, y, SSD1306_WHITE);
}