Last active
April 5, 2025 23:16
-
-
Save bmatusiak/6badef678d574abae9619de8d6eacb46 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Garage Door and Light Control with ESP32_Relay 4 - Conversation Summary: | |
This code implements a garage door and light control system using an ESP32_Relay 4 board. | |
It includes: | |
1. WiFi Connectivity: The ESP32 hosts a web server to control the garage door and light via a web interface. | |
2. Garage Door Control: | |
* Uses two relays to control the motor direction. | |
* Limit switches to stop the motor when the door is fully open or closed. | |
* A physical button that can be held for 3 seconds to control the door, or tapped for light control. | |
* Web interface control of the door. | |
* Dynamic button state updates on the web interface using JavaScript and JSON. | |
3. Light Control: | |
* A relay to control the light. | |
* A motion sensor to automatically turn the light on/off. | |
* Control of the light via the physical button (tap) and the web interface. | |
* Light state updates on the web interface. | |
4. Web Interface: | |
* A single HTML page with buttons for door and light control. | |
* JavaScript to dynamically update the button states based on the ESP32's status. | |
* JSON communication between the ESP32 and the web page for status updates. | |
5. Button control: | |
* Short tap of button toggles light | |
* Long hold of button changes garage door state. | |
6. Status updates: | |
* The web page updates every 5 seconds, to reflect current door and light states. | |
Pinout (ESP32_Relay 4): | |
- 5V: Do not use for programming | |
- TX: 3.3V level (Unused in this application) | |
- RX: 3.3V level (Unused in this application) | |
- GND: Ground | |
- GPIO0: 3.3V level (Connected to a push button for programming, Unused during normal operation) | |
- GPIO23: Status LED | |
- GPIO32: Relay #1 (Garage Door - Direction 1) | |
- GPIO33: Relay #2 (Garage Door - Direction 2) / Motion Sensor Input (Verify if this is correct Motion sensor input pin) | |
- GPIO25: Relay #3 (Light) | |
- GPIO26: Relay #4 (Unused in this application) | |
- GPIO27: Open Limit Switch Input | |
- GPIO15: Door Button Input | |
- Other GPIO Pins: Unused in this application | |
*/ | |
#include <WiFi.h> | |
#include <WebServer.h> | |
#include <ArduinoJson.h> | |
// WiFi credentials | |
const char* ssid = "YOUR_WIFI_SSID"; | |
const char* password = "YOUR_WIFI_PASSWORD"; | |
// Garage Door Pins - Adjusted for your pinout | |
const int doorRelayPin1 = 32; // Relay #1 | |
const int doorRelayPin2 = 33; // Relay #2 | |
const int openLimitPin = 27; // Assuming this is still correct | |
const int closeLimitPin = 26; // Assuming this is still correct | |
const int doorButtonPin = 15; // Assuming this is still correct | |
// Light Pins - Adjusted for your pinout | |
const int lightRelayPin = 25; // Relay #3 | |
const int motionSensorPin = 33; // Relay 2? is this correct? | |
// ESP32 Built-in LED - Adjusted for your pinout | |
const int builtInLedPin = 23; // Status LED | |
// Debouncing variables | |
unsigned long lastButtonPress = 0; | |
unsigned long debounceDelay = 50; | |
unsigned long buttonHoldStartTime = 0; | |
const unsigned long buttonHoldDuration = 3000; // 3 seconds | |
// Door State | |
enum DoorState { | |
CLOSED, | |
OPENING, | |
OPEN, | |
CLOSING, | |
STOPPED | |
}; | |
DoorState currentState = CLOSED; | |
// Light State | |
bool lightOn = false; | |
WebServer server(80); | |
// setup(): Initializes the ESP32, connects to WiFi, and sets up the web server. | |
void setup() { | |
Serial.begin(115200); | |
pinMode(doorRelayPin1, OUTPUT); | |
pinMode(doorRelayPin2, OUTPUT); | |
pinMode(openLimitPin, INPUT_PULLUP); | |
pinMode(closeLimitPin, INPUT_PULLUP); | |
pinMode(doorButtonPin, INPUT_PULLUP); | |
pinMode(lightRelayPin, OUTPUT); | |
pinMode(motionSensorPin, INPUT); // Verify this is correct | |
pinMode(builtInLedPin, OUTPUT); | |
digitalWrite(doorRelayPin1, LOW); | |
digitalWrite(doorRelayPin2, LOW); | |
digitalWrite(lightRelayPin, LOW); | |
digitalWrite(builtInLedPin, LOW); | |
WiFi.begin(ssid, password); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(1000); | |
Serial.println("Connecting to WiFi..."); | |
} | |
Serial.println("Connected to WiFi"); | |
Serial.print("IP Address: "); | |
Serial.println(WiFi.localIP()); | |
server.on("/", handleRoot); | |
server.on("/door", handleDoor); | |
server.on("/status", handleStatus); | |
server.on("/light", handleLight); | |
server.begin(); | |
} | |
// loop(): Handles web server clients, checks door button, limit switches, and motion sensor. | |
void loop() { | |
server.handleClient(); | |
checkDoorButton(); | |
checkLimitSwitches(); | |
checkMotionSensor(); | |
} | |
// handleRoot(): Generates the HTML page with door and light control buttons and JavaScript for status updates. | |
void handleRoot() { | |
String html = "<!DOCTYPE html><html><head><title>Garage Door Control</title>"; | |
html += "<script>"; | |
html += "function updateStatus() {"; | |
html += " fetch('/status')"; | |
html += " .then(response => response.json())"; | |
html += " .then(data => {"; | |
html += " let doorButton = document.getElementById('doorButton');"; | |
html += " let lightButton = document.getElementById('lightButton');"; | |
html += " if (data.state === 'OPEN') {"; | |
html += " doorButton.textContent = 'Close Door';"; | |
html += " doorButton.disabled = false;"; | |
html += " } else if (data.state === 'CLOSED' || data.state === 'STOPPED') {"; | |
html += " doorButton.textContent = 'Open Door';"; | |
html += " doorButton.disabled = false;"; | |
html += " } else if (data.state === 'OPENING' || data.state === 'CLOSING') {"; | |
html += " doorButton.textContent = data.state + '...';"; | |
html += " doorButton.disabled = true;"; | |
html += " }"; | |
html += " lightButton.textContent = data.light ? 'Light Off' : 'Light On';"; | |
html += " });"; | |
html += "}"; | |
html += "function triggerDoor() { fetch('/door'); }"; | |
html += "function triggerLight() { fetch('/light'); }"; | |
html += "setInterval(updateStatus, 5000);"; | |
html += "</script></head><body>"; | |
html += "<h1>Garage Door Control</h1>"; | |
html += "<button id='doorButton' onclick=\"triggerDoor()\">Open Door</button><br><br>"; | |
html += "<button id='lightButton' onclick=\"triggerLight()\">Light On</button>"; | |
html += "<script>updateStatus();</script>"; | |
html += "</body></html>"; | |
server.send(200, "text/html", html); | |
} | |
// handleDoor(): Triggers the door's open/close/stop actions and sends an OK response. | |
void handleDoor() { | |
if (currentState == CLOSED || currentState == STOPPED) { | |
openDoor(); | |
} else if (currentState == OPEN) { | |
closeDoor(); | |
} else if (currentState == OPENING || currentState == CLOSING) { | |
stopDoor(); | |
} | |
server.send(200, "text/plain", "OK"); | |
} | |
// handleStatus(): Sends the current door and light status as a JSON response. | |
void handleStatus() { | |
StaticJsonDocument doc; | |
String stateString; | |
switch (currentState) { | |
case CLOSED: stateString = "CLOSED"; break; | |
case OPENING: stateString = "OPENING"; break; | |
case OPEN: stateString = "OPEN"; break; | |
case CLOSING: stateString = "CLOSING"; break; | |
case STOPPED: stateString = "STOPPED"; break; | |
default: stateString = "UNKNOWN"; break; | |
} | |
doc["state"] = stateString; | |
doc["light"] = lightOn; | |
String jsonString; | |
serializeJson(doc, jsonString); | |
server.send(200, "application/json", jsonString); | |
} | |
// handleLight(): Toggles the light state and sends an OK response. | |
void handleLight() { | |
toggleLight(); | |
server.send(200, "text/plain", "OK"); | |
} | |
// checkDoorButton(): Checks the physical door button for short press (light toggle) or long press (door control). | |
void checkDoorButton() { | |
if (digitalRead(doorButtonPin) == LOW) { | |
if (buttonHoldStartTime == 0) { | |
buttonHoldStartTime = millis(); | |
} else if ((millis() - buttonHoldStartTime) >= buttonHoldDuration) { | |
if (currentState == CLOSED || currentState == STOPPED) { | |
openDoor(); | |
} else if (currentState == OPEN) { | |
closeDoor(); | |
} else if (currentState == OPENING || currentState == CLOSING) { | |
stopDoor(); | |
} | |
buttonHoldStartTime = 0; | |
} | |
} else { | |
if (buttonHoldStartTime > 0 && (millis() - buttonHoldStartTime) < buttonHoldDuration) { | |
toggleLight(); | |
} | |
buttonHoldStartTime = 0; | |
} | |
} | |
// toggleLight(): Toggles the light state and updates the light relay. | |
void toggleLight() { | |
lightOn = !lightOn; | |
digitalWrite(lightRelayPin, lightOn); | |
Serial.println(lightOn ? "Light On (tap/web)" : "Light Off (tap/web)"); | |
} | |
// checkLimitSwitches(): Checks the limit switches and stops the door motor when a limit is reached. | |
void checkLimitSwitches() { | |
if (digitalRead(openLimitPin) == LOW && currentState == OPENING) { | |
stopDoor(); | |
currentState = OPEN; | |
Serial.println("Door Open Limit Reached"); | |
} | |
if (digitalRead(closeLimitPin) == LOW && currentState == CLOSING) { | |
stopDoor(); | |
currentState = CLOSED; | |
Serial.println("Door Closed Limit Reached"); | |
} | |
} | |
// openDoor(): Activates the relays to open the garage door. | |
void openDoor() { | |
digitalWrite(doorRelayPin1, HIGH); | |
digitalWrite(doorRelayPin2, LOW); | |
currentState = OPENING; | |
Serial.println("Opening Door"); | |
digitalWrite(builtInLedPin, HIGH); | |
} | |
// closeDoor(): Activates the relays to close the garage door. | |
void closeDoor() { | |
digitalWrite(doorRelayPin1, LOW); | |
digitalWrite(doorRelayPin2, HIGH); | |
currentState = CLOSING; | |
Serial.println("Closing Door"); | |
digitalWrite(builtInLedPin, HIGH); | |
} | |
// stopDoor(): Deactivates the relays to stop the garage door motor. | |
void stopDoor() { | |
digitalWrite(doorRelayPin1, LOW); | |
digitalWrite(doorRelayPin2, LOW); | |
currentState = STOPPED; | |
Serial.println("Door Stopped"); | |
digitalWrite(builtInLedPin, LOW); | |
} | |
// checkMotionSensor(): Checks the motion sensor and turns the light on/off accordingly. | |
void checkMotionSensor() { | |
if (digitalRead(motionSensorPin) == HIGH) { | |
if (!lightOn) { | |
turnLightOn(); | |
} | |
} else { | |
turnLightOff(); | |
} | |
} | |
// turnLightOn(): Turns the light on and updates the light relay. | |
void turnLightOn() { | |
digitalWrite(lightRelayPin, HIGH); | |
lightOn = true; | |
Serial.println("Light On (motion)"); | |
} | |
// turnLightOff(): Turns the light off and updates the light relay. | |
void turnLightOff() { | |
digitalWrite(lightRelayPin, LOW); | |
lightOn = false; | |
Serial.println("Light Off (no motion)"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment