#include <Servo.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#include <Wire.h>
#include <Adafruit_FT6206.h>
#include <Keypad.h>
#include <Stepper.h>
Servo doorLock;
Adafruit_FT6206 ctp = Adafruit_FT6206();
const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
uint8_t colPins[COLS] = { 13, 12, 11, 10 };
uint8_t rowPins[ROWS] = { A0, A1, A2, A3 };
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 41, 39, 37, 35);
#define TFT_CS 53
#define TFT_DC 48
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Color definitions - in 5:6:5
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define WHITE 0xFFFF
#define menuButtonWidth 200
#define menuButtonHeight 40
#define buttonMargin 10
#define headingHeight 30
#define numberOfRooms 5
const int roomButtonWidth = 140;
const int roomButtonHeight = 40;
const int buttonRadius = 50;
int currentRoom;
bool lightState[numberOfRooms] = {false, false, false, false}; // Add array to track light states
bool motorState[numberOfRooms] = {false, false, false, false, false}; // Add array to track motor states
int activeMenu = 0;
unsigned long lastTouchTime = 0;
unsigned long lastDoorCheckTime = 0;
unsigned long lastLightCheckTime = 0;
const unsigned long touchInterval = 100;
const unsigned long doorCheckInterval = 100;
const unsigned long lightCheckInterval = 5000;
unsigned long lastTimeCheck = 0;
const unsigned long checkInterval = 1000; // 1 second
unsigned long gateOpenTime = 0;
unsigned long lastGateCheckTime = 0;
const unsigned long gateOpenDuration = 10000; // 10 seconds
#define buzzerPin 8
#define photoResistorPin 47
#define lightPin 4
#define triggerPin 45
#define echoPin 43
#define intercomButton 3
int outsideLightsPin[] = {A4, A5};
int doorStatusLed[] = {7, 6, 5};
int lightPins[numberOfRooms] = {29, 25, 27, 31};
void setup(void) {
Serial.begin(115200);
while (!Serial) delay(10);
Serial.println(F("Cap Touch Paint!"));
tft.begin();
doorLock.attach(9);
doorLock.write(90);
myStepper.setSpeed(60);
for (int i = 0; i < numberOfRooms; i++) {
pinMode(lightPins[i], OUTPUT);
digitalWrite(lightPins[i], LOW);
}
for (int i = 0; i < 3; i++) {
pinMode(doorStatusLed[i], OUTPUT);
}
for (int i = 0; i < 2; i++){
pinMode(outsideLightsPin[i], OUTPUT);
}
pinMode(intercomButton, INPUT_PULLUP);
pinMode(photoResistorPin, INPUT);
pinMode(lightPin, OUTPUT);
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
if (!ctp.begin(40, &Wire)) {
Serial.println("Couldn't start FT6206 touchscreen controller");
while (1) delay(10);
}
Serial.println("Capacitive touchscreen started");
mainMenuDisplay();
}
void mainMenuDisplay() {
String buttonLabels[] = {"Bedroom", "Kitchen", "Lounge", "Garage", "Gate"};
int totalButtonHeight = (menuButtonHeight + buttonMargin) * 5;
int totalHeight = totalButtonHeight + headingHeight;
int startY = (tft.height() - totalHeight) / 2;
tft.fillScreen(WHITE);
tft.setTextSize(3);
tft.setTextColor(BLACK);
tft.setCursor(40, 10);
tft.print("Main Menu");
for (int i = 0; i < 5; i++) {
int buttonY = startY + headingHeight + i * (menuButtonHeight + buttonMargin);
tft.fillRect(20, buttonY, menuButtonWidth, menuButtonHeight, BLUE);
tft.drawRect(20, buttonY, menuButtonWidth, menuButtonHeight, BLACK);
int textX = 20 + (menuButtonWidth - buttonLabels[i].length() * 7) / 2;
int textY = buttonY + (menuButtonHeight - 10) / 2;
tft.setTextColor(WHITE);
tft.setTextSize(2);
tft.setCursor(textX, textY);
tft.print(buttonLabels[i]);
}
activeMenu = 0;
}
void roomMenu(int currentRoom) {
String rooms[] = {"Bedroom", "Kitchen", "Lounge", "Garage", "Gate"};
if (currentRoom >= 0 && currentRoom < sizeof(rooms) / sizeof(rooms[0])) {
tft.fillScreen(WHITE);
tft.setCursor(50, 10);
tft.setTextColor(BLACK);
tft.setTextSize(3);
tft.println(rooms[currentRoom]);
tft.setCursor(20, 60);
if (lightState[currentRoom]) {
tft.fillRoundRect(20, 100, 200, 40, 50, RED);
tft.setTextColor(BLACK);
tft.setTextSize(2);
tft.setCursor(75, 110);
tft.print("LIGHT OFF");
} else {
tft.fillRoundRect(20, 100, 200, 40, 50, GREEN);
tft.setTextColor(BLACK);
tft.setCursor(75, 110);
tft.setTextSize(2);
tft.print("LIGHT ON");
}
tft.drawRoundRect(20, 100, 200, 40, 50, BLACK);
tft.setCursor(20, 160);
if (motorState[currentRoom]){
tft.fillRoundRect(20, 180, 200, 40, 50, RED);
tft.setTextColor(BLACK);
tft.setCursor(95, 190);
tft.setTextSize(2);
tft.print("CLOSE");
}else {
tft.fillRoundRect(20, 180, 200, 40, 50, GREEN);
tft.setTextColor(BLACK);
tft.setCursor(95, 190);
tft.setTextSize(2);
tft.print("OPEN");
}
tft.drawRoundRect(20, 180, 200, 40, 50, BLACK);
tft.setCursor(10, 230);
tft.fillRoundRect(20, 270, 100, 40, 50, BLUE);
tft.drawRoundRect(20, 270, 100, 40, 50, BLACK);
tft.setTextColor(BLACK);
tft.setTextSize(2);
tft.setCursor(50, 280);
tft.print("Back");
}
activeMenu = 1;
}
void toggleLightState(int roomIndex) {
lightState[roomIndex] = !lightState[roomIndex];
digitalWrite(lightPins[roomIndex], lightState[roomIndex] ? HIGH : LOW);
}
void toggleMotorState(int roomIndex) {
motorState[roomIndex] = !motorState[roomIndex];
if (motorState[roomIndex]) {
Serial.println("Motor: clockwise");
myStepper.step(stepsPerRevolution);
gateOpenTime = millis(); // Start the timer
if (currentRoom == 4) {
tft.setCursor(10, 60);
tft.setTextSize(2);
tft.print("GATE OPENING");
}
} else {
Serial.println("Motor: counterclockwise");
myStepper.step(-stepsPerRevolution);
}
}
void mapMainMenuTouch(int x, int y) {
if (x > 20 && x < (20 + menuButtonWidth)) {
int buttonIndex = -1;
if (y > 50 && y < 90) {
buttonIndex = 0;
} else if (y > 100 && y < 140) {
buttonIndex = 1;
} else if (y > 150 && y < 190) {
buttonIndex = 2;
} else if (y > 200 && y < 240) {
buttonIndex = 3;
} else if (y > 250 && y < 290) {
buttonIndex = 4;
}
if (buttonIndex != -1) {
currentRoom = buttonIndex;
roomMenu(buttonIndex);
}
}
}
void mapRoomMenuTouch(int x, int y) {
if (x > 20 && x < 220) {
if (y > 100 && y < 140) {
toggleLightState(currentRoom);
roomMenu(currentRoom); // Update room menu to reflect new light state
} else if (y > 180 && y < 220) {
toggleMotorState(currentRoom);
roomMenu(currentRoom); // Update room menu to reflect new motor state
} else if (y > 270 && y < 310) {
mainMenuDisplay();
}
}
}
void checkGateAutoClose() {
unsigned long currentTime = millis();
if (motorState[4] && (currentTime - gateOpenTime) >= gateOpenDuration) {
// Close the gate
toggleMotorState(4);
tft.fillRect(70, 60, 100, 30, WHITE); // Clear the message area
tft.fillRoundRect(20, 180, 200, 40, 50, GREEN);
tft.setTextColor(BLACK);
tft.setCursor(95, 190);
tft.setTextSize(2);
tft.print("OPEN");
tft.drawRoundRect(20, 180, 200, 40, 50, BLACK);
}
}
void loop() {
unsigned long currentTime = millis();
if (ctp.touched()) {
TS_Point p = ctp.getPoint();
p.x = map(p.x, 0, 240, 240, 0);
p.y = map(p.y, 0, 320, 320, 0);
if (currentTime - lastTouchTime >= touchInterval) {
lastTouchTime = currentTime;
if (activeMenu == 0) {
mapMainMenuTouch(p.x, p.y);
} else if (activeMenu == 1) {
mapRoomMenuTouch(p.x, p.y);
}
}
}
//Close the gate automatically if not closed for more than 10seconds
if (motorState[4] && (currentTime - lastGateCheckTime >= checkInterval)) {
lastGateCheckTime = currentTime;
checkGateAutoClose();
}
intercom();
unlockDoor();
timeOfTheDay();
}
void buzzKnock() {
int knockDuration = 200; // Duration of each knock in milliseconds
int pauseDuration = 100; // Pause duration between knocks in milliseconds
int numberOfKnocks = 3; // Number of knocks
for (int i = 0; i < numberOfKnocks; i++) {
tone(buzzerPin, 1000); // Play tone at 1000 Hz
delay(knockDuration); // Wait for knock duration
noTone(buzzerPin); // Stop tone
delay(pauseDuration); // Wait for pause duration
}
}
void intercom(){
bool ring = digitalRead(intercomButton) == LOW;
if (ring){
buzzKnock();
currentRoom = 4;
roomMenu(currentRoom);
tft.setCursor(45, 60);
tft.println("Hi it's John");
}
}
long readUltrasonicDistance() {
digitalWrite(triggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(triggerPin, LOW);
int duration = pulseIn(echoPin, HIGH);
long distance = duration / 58;
return distance;
}
void timeOfTheDay() {
unsigned long currentTime = millis();
// Check if it's time to update
if (currentTime - lastTimeCheck >= checkInterval) {
lastTimeCheck = currentTime;
bool dark = digitalRead(photoResistorPin) == HIGH;
float distance = readUltrasonicDistance();
// Handle light based on darkness and distance
if (dark && distance <= 100) {
digitalWrite(lightPin, HIGH);
} else {
digitalWrite(lightPin, LOW);
}
// Handle outside lights based on darkness
for (int i = 0; i < 2; i++) {
digitalWrite(outsideLightsPin[i], dark ? HIGH : LOW);
}
}
}
void updateDoorStatusDisplay(const char* message) {
tft.fillRect(0, 320 - 40, 240, 40, WHITE); // Clear the message area
tft.setCursor(50, 320 - 30);
tft.setTextColor(BLACK);
tft.setTextSize(2);
tft.print(message);
}
void unlockDoor() {
String unlockPin = "1234";
static String enteredPin;
char key = keypad.getKey();
digitalWrite(doorStatusLed[0], HIGH);
digitalWrite(doorStatusLed[1], LOW);
digitalWrite(doorStatusLed[2], LOW);
if (key != NO_KEY) {
if (key == '#') {
if (enteredPin == unlockPin) {
// Check if it's dark outside
bool dark = digitalRead(photoResistorPin) == HIGH;
timeOfTheDay();
digitalWrite(doorStatusLed[0], LOW);
digitalWrite(doorStatusLed[1], HIGH);
digitalWrite(doorStatusLed[2], LOW);
if (dark) {
digitalWrite(lightPins[2], HIGH); // Turn on the lounge light
lightState[2] = true;
}
doorLock.write(0);
delay(5000);
updateDoorStatusDisplay("DOOR OPEN"); // Display "DOOR OPEN"
doorLock.write(90);
updateDoorStatusDisplay("DOOR CLOSED"); // Display "DOOR CLOSED"
} else {
tone(buzzerPin, 500);
delay(2000);
noTone(buzzerPin);
}
enteredPin = "";
} else {
enteredPin += key;
}
}
}
Garage/Curtain/
Gate Motor
Garage
Light
Gate
intecom
Outside Lights
Touch Control
Closed 0steps
distance < 100
when dark
light turns ON
Unlocked
Locked
Open -198steps
Time of day check
photoresistor
Bed
Light
Main Door
Lounge
Light
Kitchen
Light
Entrance
Light
Door Status
Light