Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ESP32 Scheduled Motor Control with Deep Sleep
- DESCRIPTION:
- • Run a motor at two configurable times of day while deep-sleeping between operations.
- FEATURES:
- • Schedules motor to run for 30 seconds at two daily times (configurable)
- • Uses deep sleep between operations for maximum battery efficiency
- • Web-based setup interface for time sync and schedule configuration
- • Built-in LED status indicators during setup and operation
- • RTC memory storage preserves settings through deep sleep cycles
- • Automatic timeout protection (enters sleep if no configuration within 4 minutes)
- HARDWARE REQUIREMENTS:
- • ESP32 development board
- • MOSFET (for motor control) connected to GPIO 33
- • Motor connected through MOSFET
- • Built-in LED on GPIO 2 (most ESP32 boards)
- SETUP PROCESS:
- 1. Upload sketch to ESP32
- 2. Connect to WiFi network "ESP32-Motor-Timer" (password: 12345678)
- 3. Navigate to the IP address shown in Serial Monitor, usually 192.168.4.1
- 4. Sync current time from your browser
- 5. Set morning and evening schedule times
- 6. ESP32 automatically enters scheduled operation mode
- OPERATION:
- • ESP32 sleeps in deep sleep mode (uses ~10µA)
- • Wakes up at scheduled times
- • Runs motor for 30 seconds with LED indication
- • Calculates next wake time and returns to deep sleep
- • Cycle repeats indefinitely
- DEFAULT SCHEDULE:
- • Morning: 12:30 (configurable via web interface)
- • Evening: 19:30 (configurable via web interface)
- TROUBLESHOOTING:
- • If setup doesn't complete, ESP32 sleeps for 3 hours then restarts setup
- • Power cycle to restart setup process
- • Check Serial Monitor (115200 baud) for debugging information
- • Time is automatically adjusted for Portuguese Summer Time (+1 hour)
- */
- #include <ESP32Time.h> // https://github.com/fbiego/ESP32Time
- #include <WiFi.h>
- #define uS_TO_S_FACTOR 1000000ULL // Conversion factor for micro seconds to seconds
- #define MOTOR_ON_TIME 30 // Motor run time in seconds
- #define MOTOR_PIN 33 // GPIO pin connected to MOSFET gate
- #define LED_PIN 2 // Built-in LED for status indication
- // WiFi credentials for initial time sync
- const char *ssid = "ESP32-Motor-Timer";
- const char *password = "12345678";
- //ESP32Time rtc;
- ESP32Time rtc(3600); // offset in seconds GMT+1 Portugal Summer Time
- WiFiServer server(80);
- // RTC memory variables (survive deep sleep)
- RTC_DATA_ATTR bool timeWasSet = false;
- RTC_DATA_ATTR bool scheduleWasSet = false;
- RTC_DATA_ATTR int bootCount = 0;
- RTC_DATA_ATTR unsigned long webServerStartTime = 0;
- // Schedule times (stored in RTC memory - user configurable)
- RTC_DATA_ATTR int MORNING_HOUR = 12; // Default values
- RTC_DATA_ATTR int MORNING_MINUTE = 30;
- RTC_DATA_ATTR int EVENING_HOUR = 19;
- RTC_DATA_ATTR int EVENING_MINUTE = 30;
- void setup() {
- Serial.begin(115200);
- delay(1000);
- bootCount++;
- Serial.println("Boot count: " + String(bootCount));
- // Initialize pins
- pinMode(MOTOR_PIN, OUTPUT);
- pinMode(LED_PIN, OUTPUT);
- digitalWrite(MOTOR_PIN, LOW); // Ensure motor is off initially
- printWakeupReason();
- // Check if this is a scheduled wake-up and both time and schedule have been set
- if (timeWasSet && scheduleWasSet && esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TIMER) {
- handleScheduledWakeup();
- } else {
- // First boot, manual reset, or incomplete setup - need web interface
- webServerStartTime = millis();
- setupWebServer();
- }
- }
- void loop() {
- // Handle web server for time and schedule setting
- if (!timeWasSet || !scheduleWasSet) {
- // Check for 4-minute timeout
- if (millis() - webServerStartTime > 240000) { // 4 minutes = 120,000 ms
- Serial.println("Web server timeout - entering 3-hour sleep to save battery");
- esp_sleep_enable_timer_wakeup(3 * 3600 * uS_TO_S_FACTOR); // 3 hours
- esp_deep_sleep_start();
- }
- handleWebClient();
- }
- }
- void handleScheduledWakeup() {
- Serial.println("\n=== Scheduled Wake-up ===");
- Serial.println("Current time: " + rtc.getTime("%A, %B %d %Y %H:%M:%S"));
- // Run the motor
- runMotor();
- // Calculate next wake-up time
- scheduleNextWakeup();
- }
- void runMotor() {
- Serial.println("Starting motor...");
- // Blink LED to indicate motor operation
- digitalWrite(LED_PIN, HIGH);
- // Turn on motor via MOSFET
- digitalWrite(MOTOR_PIN, HIGH);
- // Run for specified time with status updates
- for (int i = MOTOR_ON_TIME; i > 0; i--) {
- Serial.println("Motor running... " + String(i) + "s remaining");
- delay(1000);
- // Blink LED every 5 seconds during operation
- if (i % 5 == 0) {
- digitalWrite(LED_PIN, LOW);
- delay(100);
- digitalWrite(LED_PIN, HIGH);
- }
- }
- // Turn off motor
- digitalWrite(MOTOR_PIN, LOW);
- digitalWrite(LED_PIN, LOW);
- Serial.println("Motor stopped.");
- }
- void scheduleNextWakeup() {
- struct tm timeinfo = rtc.getTimeStruct();
- int currentHour = timeinfo.tm_hour;
- int currentMinute = timeinfo.tm_min;
- // Calculate seconds until next scheduled time
- unsigned long sleepTime = calculateSleepTime(currentHour, currentMinute);
- Serial.println("Next wake-up in " + String(sleepTime / 3600) + " hours and " +
- String((sleepTime % 3600) / 60) + " minutes");
- // Configure and enter deep sleep
- esp_sleep_enable_timer_wakeup(sleepTime * uS_TO_S_FACTOR);
- Serial.println("Entering deep sleep...");
- Serial.flush();
- esp_deep_sleep_start();
- }
- unsigned long calculateSleepTime(int currentHour, int currentMinute) {
- int currentTotalMinutes = currentHour * 60 + currentMinute;
- int morningTotalMinutes = MORNING_HOUR * 60 + MORNING_MINUTE;
- int eveningTotalMinutes = EVENING_HOUR * 60 + EVENING_MINUTE;
- int nextWakeupMinutes;
- if (currentTotalMinutes < morningTotalMinutes) {
- // Before morning time - wake up at morning time
- nextWakeupMinutes = morningTotalMinutes;
- } else if (currentTotalMinutes < eveningTotalMinutes) {
- // Between morning and evening - wake up at evening time
- nextWakeupMinutes = eveningTotalMinutes;
- } else {
- // After evening time - wake up next morning
- nextWakeupMinutes = morningTotalMinutes + (24 * 60); // Next day
- }
- int sleepMinutes = nextWakeupMinutes - currentTotalMinutes;
- return sleepMinutes * 60; // Convert to seconds
- }
- void setupWebServer() {
- Serial.println("\n=== Setting up Web Server for Configuration ===");
- Serial.println("Connect to WiFi network: " + String(ssid));
- Serial.println("Password: " + String(password));
- Serial.println("TIMEOUT: 4 minutes (will sleep for 3 hours if no configuration)");
- WiFi.softAP(ssid, password);
- IPAddress IP = WiFi.softAPIP();
- Serial.println("Web interface: http://" + IP.toString());
- server.begin();
- // Blink LED to indicate setup mode
- for (int i = 0; i < 10; i++) {
- digitalWrite(LED_PIN, HIGH);
- delay(200);
- digitalWrite(LED_PIN, LOW);
- delay(200);
- }
- }
- void handleWebClient() {
- WiFiClient client = server.available();
- if (client) {
- Serial.println("Client connected");
- String currentLine = "";
- while (client.connected()) {
- if (client.available()) {
- char c = client.read();
- if (c == '\n') {
- if (currentLine.length() == 0) {
- sendWebPage(client);
- break;
- } else {
- currentLine = "";
- }
- } else if (c != '\r') {
- currentLine += c;
- }
- if (currentLine.endsWith("POST /syncTime")) {
- handleTimeSyncRequest(client);
- } else if (currentLine.endsWith("POST /setSchedule")) {
- handleScheduleRequest(client);
- }
- }
- }
- client.stop();
- }
- }
- void sendWebPage(WiFiClient &client) {
- // Calculate remaining time
- unsigned long elapsed = millis() - webServerStartTime;
- unsigned long remaining = (120000 - elapsed) / 1000; // seconds remaining
- client.println("HTTP/1.1 200 OK");
- client.println("Content-type:text/html");
- client.println();
- client.println("<!DOCTYPE html><html>");
- client.println("<head><title>ESP32 Motor Timer Setup</title>");
- client.println("<meta name='viewport' content='width=device-width, initial-scale=1'>");
- client.println("<style>");
- client.println("body{font-family:Arial;text-align:center;padding:20px;background:#f0f0f0;}");
- client.println(".container{max-width:500px;margin:0 auto;background:white;padding:30px;border-radius:10px;box-shadow:0 2px 10px rgba(0,0,0,0.1);}");
- client.println("input,button{padding:10px;margin:5px;font-size:16px;border:1px solid #ddd;border-radius:5px;}");
- client.println("button{background:#4CAF50;color:white;border:none;cursor:pointer;padding:15px 30px;}");
- client.println("button:hover{background:#45a049;}");
- client.println(".timeout{color:red;font-weight:bold;}");
- client.println(".step{margin:20px 0;padding:15px;background:#f9f9f9;border-radius:5px;}");
- client.println("</style></head>");
- client.println("<body>");
- client.println("<div class='container'>");
- client.println("<h1>ESP32 Motor Timer Setup</h1>");
- client.println("<div class='timeout'> Timeout: <span id='countdown'>" + String(remaining) + "</span> seconds</div>");
- // Step 1: Time sync
- client.println("<div class='step'>");
- client.println("<h3>Step 1: Set Current Time</h3>");
- if (timeWasSet) {
- client.println("<p>Time set: " + rtc.getTime("%H:%M:%S %d/%m/%Y") + "</p>");
- } else {
- client.println("<h4 id='currentTime'></h4>");
- client.println("<form action='/syncTime' method='POST'>");
- client.println("<input type='hidden' name='epochTime' id='hiddenEpochTime'>");
- client.println("<button type='submit'>Sync Time</button>");
- client.println("</form>");
- }
- client.println("</div>");
- // Step 2: Schedule setup
- client.println("<div class='step'>");
- client.println("<h3>Step 2: Set Motor Schedule</h3>");
- if (scheduleWasSet) {
- client.println("<p>✅ Schedule set:</p>");
- client.println("<p>Morning: " + String(MORNING_HOUR) + ":" + String(MORNING_MINUTE < 10 ? "0" : "") + String(MORNING_MINUTE) + "</p>");
- client.println("<p>Evening: " + String(EVENING_HOUR) + ":" + String(EVENING_MINUTE < 10 ? "0" : "") + String(EVENING_MINUTE) + "</p>");
- client.println("<p>Motor runs for 30 seconds each time</p>");
- } else {
- client.println("<form action='/setSchedule' method='POST'>");
- client.println("<div>");
- client.println("<h4>Morning Time:</h4>");
- client.println("Hour: <input type='number' name='morningHour' min='0' max='23' value='" + String(MORNING_HOUR) + "' required> ");
- client.println("Minute: <input type='number' name='morningMinute' min='0' max='59' value='" + String(MORNING_MINUTE) + "' required>");
- client.println("</div>");
- client.println("<div>");
- client.println("<h4>Evening Time:</h4>");
- client.println("Hour: <input type='number' name='eveningHour' min='0' max='23' value='" + String(EVENING_HOUR) + "' required> ");
- client.println("Minute: <input type='number' name='eveningMinute' min='0' max='59' value='" + String(EVENING_MINUTE) + "' required>");
- client.println("</div>");
- client.println("<button type='submit'>Set Schedule</button>");
- client.println("</form>");
- }
- client.println("</div>");
- if (timeWasSet && scheduleWasSet) {
- client.println("<div class='step'>");
- client.println("<h3>✅ Setup Complete!</h3>");
- client.println("<p>ESP32 will now enter scheduled operation mode.</p>");
- client.println("<button onclick='window.location.reload()'>Start Operation</button>");
- client.println("</div>");
- }
- client.println("</div>");
- // JavaScript for time updates and countdown
- client.println("<script>");
- client.println("var countdown = " + String(remaining) + ";");
- client.println("function updateTime(){");
- client.println("var now=new Date();");
- client.println("document.getElementById('currentTime').innerHTML='Current Time: '+now.toLocaleString();");
- client.println("var epoch=Math.floor(now.getTime()/1000);");
- client.println("document.getElementById('hiddenEpochTime').value=epoch;");
- client.println("}");
- client.println("function updateCountdown(){");
- client.println("countdown--;");
- client.println("document.getElementById('countdown').innerHTML=countdown;");
- client.println("if(countdown<=0){");
- client.println("document.body.innerHTML='<h2>Timeout reached - ESP32 entering sleep mode</h2>';");
- client.println("}");
- client.println("}");
- client.println("setInterval(updateTime,1000);");
- client.println("setInterval(updateCountdown,1000);");
- client.println("updateTime();");
- client.println("</script></body></html>");
- client.println();
- }
- void handleTimeSyncRequest(WiFiClient &client) {
- String requestBody = "";
- while (client.available()) {
- requestBody += (char)client.read();
- }
- int epochIndex = requestBody.indexOf("epochTime=");
- if (epochIndex != -1) {
- long epochTime = requestBody.substring(epochIndex + 10).toInt();
- rtc.setTime(epochTime);
- timeWasSet = true;
- Serial.println("Time synchronized: " + rtc.getTime("%A, %B %d %Y %H:%M:%S"));
- // Send redirect back to main page
- client.println("HTTP/1.1 302 Found");
- client.println("Location: /");
- client.println();
- }
- }
- void handleScheduleRequest(WiFiClient &client) {
- String requestBody = "";
- while (client.available()) {
- requestBody += (char)client.read();
- }
- // Parse form data
- int morningHourIndex = requestBody.indexOf("morningHour=");
- int morningMinuteIndex = requestBody.indexOf("morningMinute=");
- int eveningHourIndex = requestBody.indexOf("eveningHour=");
- int eveningMinuteIndex = requestBody.indexOf("eveningMinute=");
- if (morningHourIndex != -1 && morningMinuteIndex != -1 &&
- eveningHourIndex != -1 && eveningMinuteIndex != -1) {
- // Extract values
- String morningHourStr = extractFormValue(requestBody, "morningHour=");
- String morningMinuteStr = extractFormValue(requestBody, "morningMinute=");
- String eveningHourStr = extractFormValue(requestBody, "eveningHour=");
- String eveningMinuteStr = extractFormValue(requestBody, "eveningMinute=");
- MORNING_HOUR = morningHourStr.toInt();
- MORNING_MINUTE = morningMinuteStr.toInt();
- EVENING_HOUR = eveningHourStr.toInt();
- EVENING_MINUTE = eveningMinuteStr.toInt();
- // Validate times
- if (MORNING_HOUR >= 0 && MORNING_HOUR <= 23 && MORNING_MINUTE >= 0 && MORNING_MINUTE <= 59 &&
- EVENING_HOUR >= 0 && EVENING_HOUR <= 23 && EVENING_MINUTE >= 0 && EVENING_MINUTE <= 59) {
- scheduleWasSet = true;
- Serial.println("Schedule set:");
- Serial.println("Morning: " + String(MORNING_HOUR) + ":" + String(MORNING_MINUTE));
- Serial.println("Evening: " + String(EVENING_HOUR) + ":" + String(EVENING_MINUTE));
- // If both time and schedule are set, start operation
- if (timeWasSet && scheduleWasSet) {
- delay(2000); // Allow user to see confirmation
- struct tm timeinfo = rtc.getTimeStruct();
- scheduleNextWakeup();
- }
- }
- }
- // Send redirect back to main page
- client.println("HTTP/1.1 302 Found");
- client.println("Location: /");
- client.println();
- }
- String extractFormValue(String data, String fieldName) {
- int startIndex = data.indexOf(fieldName);
- if (startIndex == -1) return "";
- startIndex += fieldName.length();
- int endIndex = data.indexOf("&", startIndex);
- if (endIndex == -1) endIndex = data.length();
- return data.substring(startIndex, endIndex);
- }
- void printWakeupReason() {
- esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
- switch (wakeup_reason) {
- case ESP_SLEEP_WAKEUP_TIMER:
- Serial.println("Wake-up: Scheduled timer");
- break;
- case ESP_SLEEP_WAKEUP_EXT0:
- Serial.println("Wake-up: External signal RTC_IO");
- break;
- case ESP_SLEEP_WAKEUP_EXT1:
- Serial.println("Wake-up: External signal RTC_CNTL");
- break;
- default:
- Serial.println("Wake-up: Power on or reset");
- break;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement