In this project, we will create a WiFi-controlled scheduled relay using a NodeMCU v3, which can be turned on and off at specific times set via a web interface. The current GMT will be displayed live on the server. This project is perfect for automating devices such as lights or fans, ensuring they operate according to a schedule.

Disclaimer:

Advertisements

In the last article, we saw how to make a Wi-Fi-based remote-controlled relay. In this article, we’ll take it a step further by adding a scheduling feature to the setup. Why is this necessary? Sometimes we are too busy to activate the switch/relay manually. By adding a schedule, the device can operate automatically at predefined times.

WiFi Controlled Scheduled Relay

Components Needed:

  • NodeMCU v3
  • Relay module
  • Breadboard and jumper wires
  • Power supply

You may have similar components which you can use if possible.

Circuit diagram:

WiFi Controlled Scheduled Relay

Setting Up the Arduino IDE:

  1. Install the Arduino IDE and the necessary libraries (ESP8266WiFi, ESP8266WebServer, WiFiUdp, and NTPClient).
  2. Add the NodeMCU board to the Arduino IDE:
    • Open Arduino IDE, go to File > Preferences.
    • In the “Additional Boards Manager URLs” field, add http://arduino.esp8266.com/stable/package_esp8266com_index.json.
    • Go to Tools > Board > Boards Manager, search for ESP8266 and install it.

Arduino Code:

Ensure that all the necessary libraries are installed, and the NodeMCU board is added to the Arduino IDE. Then, select ‘NodeMCU 1.0’ as the board.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <NTPClient.h>

// WiFi credentials
const char* ssid = "Your_SSID";
const char* password = "SSID_Password";

// NTP Client setup
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000); // Update time every 60 seconds

ESP8266WebServer server(80);

const int relayPin = D1; // GPIO5
time_t onTime = 0, offTime = 0;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW); // Start with the relay off

  server.on("/", handleRoot);
  server.on("/on", handleRelayOn);
  server.on("/off", handleRelayOff);
  server.on("/set_timer", handleSetTimer);
  server.on("/submit_time", handleSubmitTime);
  server.on("/get_time", handleGetTime); // Add endpoint to get current time

  server.begin();
  Serial.println("HTTP server started");

  // Initialize NTP client
  timeClient.begin();
}

void handleRoot() {
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">WiFi Relay Control</h1>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/on\">Turn On</a></p>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/off\">Turn Off</a></p>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/set_timer\">Set Timer</a></p>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleRelayOn() {
  digitalWrite(relayPin, HIGH);
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">Relay is ON</h1>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/off\"><strong>Turn Off</strong></a></p>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleRelayOff() {
  digitalWrite(relayPin, LOW);
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">Relay is OFF</h1>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/on\">Turn On</a></p>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleSetTimer() {
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">Set Timer</h1>";
  html += "<form action=\"/submit_time\" method=\"POST\" style=\"font-weight:bold;\">";
  html += "On Time: <input type=\"time\" name=\"on_time\"><br>";
  html += "Off Time: <input type=\"time\" name=\"off_time\"><br>";
  html += "<input type=\"submit\" value=\"Submit\">";
  html += "</form>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleSubmitTime() {
  if (server.hasArg("on_time") && server.hasArg("off_time")) {
    String onTimeString = server.arg("on_time");
    String offTimeString = server.arg("off_time");

    // Parse the time input (HH:MM) into hours and minutes
    int onHour = onTimeString.substring(0, 2).toInt();
    int onMinute = onTimeString.substring(3, 5).toInt();
    int offHour = offTimeString.substring(0, 2).toInt();
    int offMinute = offTimeString.substring(3, 5).toInt();

    // Convert the time to a timestamp (seconds since midnight)
    onTime = (onHour * 3600 + onMinute * 60);
    offTime = (offHour * 3600 + offMinute * 60);

    // Print the on and off times to the serial monitor
    Serial.print("Relay will turn ON at: ");
    Serial.print(onHour);
    Serial.print(":");
    if (onMinute < 10) {
      Serial.print("0");
    }
    Serial.println(onMinute);

    Serial.print("Relay will turn OFF at: ");
    Serial.print(offHour);
    Serial.print(":");
    if (offMinute < 10) {
      Serial.print("0");
    }
    Serial.println(offMinute);

    String response = "<html><body style=\"background-color:lightblue;\">";
    response += "<h1 style=\"font-weight:bold;\">Timer Set</h1>";
    response += "<p style=\"font-weight:bold;\">Relay will turn ON at " + onTimeString + "</p>";
    response += "<p style=\"font-weight:bold;\">Relay will turn OFF at " + offTimeString + "</p>";
    response += "<p style=\"font-weight:bold;\"><a href=\"/\">Back</a></p>";
    response += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
    response += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
    response += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
    response += "</body></html>";
    server.send(200, "text/html", response);
  } else {
    server.send(400, "text/html", "<html><body style=\"background-color:lightblue;\"><h1 style=\"font-weight:bold;\">Invalid Input</h1><p style=\"font-weight:bold;\"><a href=\"/set_timer\">Try Again</a></p></body></html>");
  }
}

void handleGetTime() {
  server.send(200, "text/plain", timeClient.getFormattedTime());
}

void loop() {
  server.handleClient();
  timeClient.update();

  time_t now = timeClient.getEpochTime() % 86400; // Get current time in seconds since midnight

  // Print the actual server time to the serial monitor
  Serial.print("Current server time: ");
  Serial.println(timeClient.getFormattedTime());

  if (now == onTime) {
    digitalWrite(relayPin, HIGH);
  }

  if (now == offTime) {
    digitalWrite(relayPin, LOW);
  }

  delay(1000); // Add a delay to prevent flooding the serial monitor
}

Code explanation:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <NTPClient.h>

// WiFi credentials
const char* ssid = "Your_SSID";
const char* password = "SSID_Password";

// NTP Client setup
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000); // Update time every 60 seconds

ESP8266WebServer server(80);

const int relayPin = D1; // GPIO5
time_t onTime = 0, offTime = 0;

Libraries and Constants: We include the necessary libraries and define WiFi credentials, NTP client setup, and pin assignments.

WiFi Credentials: Update ssid and password with your WiFi network details.

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW); // Start with the relay off

  server.on("/", handleRoot);
  server.on("/on", handleRelayOn);
  server.on("/off", handleRelayOff);
  server.on("/set_timer", handleSetTimer);
  server.on("/submit_time", handleSubmitTime);
  server.on("/get_time", handleGetTime); // Add endpoint to get current time

  server.begin();
  Serial.println("HTTP server started");

  // Initialize NTP client
  timeClient.begin();
}

Setup Function: This function sets up the WiFi connection, initializes the relay pin, and starts the web server.

NTP Client: The timeClient is initialized to get the current time from the NTP server.

void handleRoot() {
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">WiFi Relay Control</h1>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/on\">Turn On</a></p>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/off\">Turn Off</a></p>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/set_timer\">Set Timer</a></p>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

Handle Root: This function generates the main web page with links to turn the relay on/off and set the timer. It also includes a script to update the current GMT time every second.

void handleRelayOn() {
  digitalWrite(relayPin, HIGH);
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">Relay is ON</h1>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/off\"><strong>Turn Off</strong></a></p>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleRelayOff() {
  digitalWrite(relayPin, LOW);
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">Relay is OFF</h1>";
  html += "<p style=\"font-weight:bold;\"><a href=\"/on\">Turn On</a></p>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

Handle Relay On/Off: These functions turn the relay on or off and generate a web page to indicate the relay’s current state. They also include the script to update the current GMT time every second.

void handleSetTimer() {
  String html = "<html><body style=\"background-color:lightblue;\">";
  html += "<h1 style=\"font-weight:bold;\">Set Timer</h1>";
  html += "<form action=\"/submit_time\" method=\"POST\" style=\"font-weight:bold;\">";
  html += "On Time: <input type=\"time\" name=\"on_time\"><br>";
  html += "Off Time: <input type=\"time\" name=\"off_time\"><br>";
  html += "<input type=\"submit\" value=\"Submit\">";
  html += "</form>";
  html += "<p style=\"font-weight:bold;\">Note: Time is according to GMT</p>";
  html += "<p style=\"font-weight:bold;\">Current GMT Time: <span id=\"gmtTime\"></span></p>";
  html += "<script>function updateTime() { fetch('/get_time').then(response => response.text()).then(data => { document.getElementById('gmtTime').innerText = data; }); } setInterval(updateTime, 1000); updateTime();</script>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

Handle Set Timer: This function generates a form to set the on and off times for the relay. It includes the script to update the current GMT time every second.

void handleSubmitTime() {
  if (server.hasArg("on_time") && server.hasArg("off_time")) {
    String onTimeString = server.arg("on_time");
    String offTimeString = server.arg("off_time");

    // Parse the time input (HH:MM) into hours and minutes
    int onHour = onTimeString.substring(0, 2).toInt();
    int onMinute = onTimeString.substring(3, 5).toInt();
    int offHour = offTimeString.substring(0, 2).toInt();
    int offMinute = offTimeString.substring(3, 5).toInt();

    // Convert the time to a timestamp (seconds since midnight)
    onTime = (onHour * 3600 + onMinute * 60);
    offTime

Testing the project:

Like the previous system, run this system and check the serial terminal for the IP address. Ensure your SSID and passwords are correct first. Then browse this through any browser to access the server. You’ll get an interface like this:

WiFi Controlled Scheduled Relay

Now click Turn On/ Off to turn on/off the relay directly or set a timer to do it. Enjoy the game!

Conclusion:

This is a really exciting and useful project. I’m planning to use it to feed my pets. What other ideas do you have for this project? Share your thoughts in the comments below. I hope this project helps you a lot. See you soon!

For Professional Designs or Help:

Loading

Read more:

Categories: ESP32

MKDas

Mithun K. Das. B.Sc. in Electrical and Electronic Engineering (EEE) from KUET. Senior Embedded Systems Designer at a leading international company. Welcome to my personal blog! I share articles on various electronics topics, breaking them down into simple and easy-to-understand explanations, especially for beginners. My goal is to make learning electronics accessible and enjoyable for everyone. If you have any questions or need further assistance, feel free to reach out through the Contact Us page. Thank you for visiting, and happy learning!

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *