#include <TM1637Display.h>
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <IRremote.h>
// --- PIN DEFINITIONS ---
const int CLK = 2;
const int DIO = 3;
#define SERVO1 5
#define SERVO2 6
int receiver_pin = 9;
// --- SETTINGS ---
const int correctCode[4] = {1, 2, 3, 4};
int enteredCode[4] = {0, 0, 0, 0};
int codeIndex = 0;
int currentAngle = 180;
bool systemOn = false;
bool codeValidated = false;
// --- MOVEMENT & TIMING ---
unsigned long lastActionTime = 0;
unsigned long lastIRTime = 0;
int movingDirection = 0; // 0 = stop, 1 = opening, -1 = closing
TM1637Display display(CLK, DIO);
Servo servo1;
Servo servo2;
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
display.setBrightness(7);
servo1.attach(SERVO1);
servo2.attach(SERVO2);
lcd.begin(16, 2);
IrReceiver.begin(receiver_pin, ENABLE_LED_FEEDBACK);
setDoorAngle(180);
updatePowerState();
}
void loop() {
// 1. CHECK IR RECEIVER
if (IrReceiver.decode()) {
int key = IrReceiver.decodedIRData.command;
IrReceiver.resume();
lastIRTime = millis(); // Track when we last saw ANY signal
// POWER BUTTON (162)
if (key == 162 ) {
systemOn = !systemOn;
updatePowerState();
return;
}
if (systemOn) {
// MASTER CLEAR (176)
if (key == 176) { resetSystem(); return; }
if (codeValidated) {
delay(1000);
lastActionTime = millis();
if (key == 168) { autoOpenClose(); } // PLAY
else if (key == 2) { movingDirection = 1; } // PLUS -> Start Opening
else if (key == 152) { movingDirection = -1; } // MINUS -> Start Closing
}
else {
int digit = mapKeyToDigit(key);
if (digit != -1 && codeIndex < 4) {
lastActionTime = millis();
enteredCode[codeIndex] = digit;
display.showNumberDec(digit, false, 1, codeIndex);
lcd.setCursor(codeIndex, 1);
lcd.print(digit);
codeIndex++;
if (codeIndex == 4) checkCode();
}
}
}
}
// 2. CONTINUOUS MOVEMENT LOGIC
// This runs EVERY loop, not just when IR is decoded
//if (systemOn && codeValidated) {
// Stop moving if the remote stops sending signals for more than 200ms
if (millis() - lastIRTime > 200) {
movingDirection = 0;
}
if (movingDirection == 1 && currentAngle > 90) {
currentAngle -= 1; // Smooth step
setDoorAngle(currentAngle);
delay(15); // Controls speed
}
else if (movingDirection == -1 && currentAngle < 180) {
currentAngle += 1;
setDoorAngle(currentAngle);
delay(15);
}
//}
// 3. AUTO-RESET & AUTO-CLOSE (5 seconds of inactivity)
// Trigger if: 1. System is On AND
// 2. (The code is already correct OR the user has started typing) AND
// 3. The door isn't currently moving
if (systemOn && (codeValidated || codeIndex > 0) && movingDirection == 0) {
if (millis() - lastActionTime > 5000) {
if (codeValidated && currentAngle < 180) {
autoCloseSequence(); // Close the door if it was open
} else {
resetSystem(); // Just clear the screen if they were mid-typing
}
}
}
}
void autoCloseSequence() {
lcd.setCursor(0, 1);
lcd.print("Auto-Closing... ");
while (currentAngle < 180) {
currentAngle += 1;
setDoorAngle(currentAngle);
delay(20);
}
resetSystem();
}
void autoOpenClose() {
lcd.clear();
lcd.print("Mode: PLAY");
lcd.setCursor(0, 1);
lcd.print("Auto-Opening... ");
//setDoorAngle(90);
while (currentAngle > 90) {
currentAngle -= 1;
setDoorAngle(currentAngle);
delay(20);
}
currentAngle = 90;
for (int i = 5; i > 0; i--) {
display.showNumberDec(i);
delay(1000);
}
autoCloseSequence();
}
void checkCode() {
bool match = true;
for(int i = 0; i < 4; i++) {
if(enteredCode[i] != correctCode[i]) match = false;
}
if (match) {
codeValidated = true;
lastActionTime = millis();
lcd.clear();
lcd.print("Access Granted");
lcd.setCursor(0, 1);
lcd.print("PLAY / +/- Keys");
} else {
lcd.clear();
lcd.print("Wrong Code!");
display.showNumberDec(8888);
delay(2000);
resetSystem();
}
}
void setDoorAngle(int angle) {
servo1.write(angle);
servo2.write(180 - angle);
// Show 0-100% on 7-segment
int percent = map(angle, 180, 90, 0, 100);
display.showNumberDec(percent);
}
void updatePowerState() {
if (systemOn) {
lcd.backlight();
resetSystem();
} else {
lcd.clear();
lcd.noBacklight();
display.clear();
codeValidated = false;
currentAngle = 180;
setDoorAngle(180);
}
}
void resetSystem() {
codeIndex = 0;
codeValidated = false;
movingDirection = 0;
for (int i = 0; i < 4; i++) { enteredCode[i] = 0; }
//if (systemOn) {
lcd.clear();
lcd.print("Enter Code:");
uint8_t dashes[] = {0x40, 0x40, 0x40, 0x40};
display.setSegments(dashes);
// }
}
int mapKeyToDigit(int key) {
if (key == 48) return 1;
if (key == 24) return 2;
if (key == 122) return 3;
if (key == 16) return 4;
if (key == 56) return 5;
if (key == 90) return 6;
if (key == 66) return 7;
if (key == 74) return 8;
if (key == 82) return 9;
if (key == 104) return 0;
return -1;
}servo1
servo2