Basic LED nightlight

Hello, and thanks for taking the time to read this! I have recently started using Arduino for a project in my Computer Technology class. The project requires students to use an input on a breadboard ( Photoresistor or Pushbutton) to control an LED. The LED must also be able to be controlled through the web in some way as well. The code is written for an ESP8266, and the code to connect to a wifi network has been provided for us. (We are all complete beginners)

My chosen project is a simple night light. It uses a photoresistor to turn the LED on or off, depending on the room's brightness. I want to be able to control the LED manually through the web as well. I am seeing problems with the Wi-Fi connection, as the ESP consistently connects and re-connects to the Wi-Fi network.

Through my testing, I have been able to get the photoresistor to work as intended, but I am struggling with the online portion. When I click the button to control the LED manually on my device, it turns on (or off, whatever the situation may be) for a fraction of a second, and then returns to the photoresistor loop. Any suggestions to make it smoother? All help would be appreciated.

Original Code( Only turns LED on or off on the web, no photoreistor)

#include <ArduinoOTA.h>

// Include the ESP8266 Library. This library is automatically provided by the ESP8266 Board Manager and does not need to be installed manually.
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

String codeVersion = "Version 3.2056  Jan 7, 2025 Lyon";
const long utcOffsetInSeconds = -14400;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

// WiFi Router Login - change these to your router settings
const char* SSID = "SSID";
const char* password = "notrealpassword";


String request;   //web request
String min_str ="";

const int LEDPin0 = D2;  //Light 1

int ledStatus0 = 0;      //status of the LED

int timeout=0;

int current_time;
int i=0;

// Create the ESP Web Server on port 80
WiFiServer WebServer(80);
// Web Client
WiFiClient client;

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.println(codeVersion);

  //setup pin modes
  pinMode(LEDPin0,OUTPUT);
  digitalWrite(LEDPin0, LOW);
    
  // Connect to WiFi network
  Serial.println();
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.setSleepMode(WIFI_LIGHT_SLEEP);   //added to keep wifi awake other options are WIFI_NONE_SLEEP WIFI_LIGHT_SLEEP and WIFI_MODEM_SLEEP
  Serial.print("Connecting to ");
  Serial.println(SSID);
  WiFi.begin(SSID, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("Connected to WiFi");
  
  timeClient.begin();

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  
  
  // Start the Web Server
  WebServer.begin();
  Serial.println("Web Server started");
  
  ArduinoOTA.begin();

  // Print the IP address
  Serial.print("You can connect to the ESP8266 at this URL: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
}

void loop() 
{
  ArduinoOTA.handle(); 
  current_time=timeClient.getHours()*60 + timeClient.getMinutes();
    
  delay(500);  
  // Check if a user has connected
  client = WebServer.available();
  if (!client) 
  {//restart loop
    return;
  }
  
  // Wait until the user sends some data
  Serial.println("New User");
  delay(400);
  while (!client.available()) 
  {
    delay(1);
    timeout++;
    if(timeout>10000)
    {
      Serial.print("INFINITE LOOP BREAK!");
      break;
    }
  }
  timeout=0;

  
  
  
  timeClient.update();
  Serial.print(daysOfTheWeek[timeClient.getDay()]);
  Serial.print(", ");
  Serial.print(timeClient.getHours());
  Serial.print(":");
  Serial.print(timeClient.getMinutes());
  Serial.print(":");
  Serial.println(timeClient.getSeconds());
  
   
  // Read the first line of the request
  request = client.readStringUntil('\r\n');
  Serial.println(request);
  client.flush();

  // Process the request:
  //Lights
  
   
  //turn on if requested to turn on
  if (request.indexOf("/LED0=ON") != -1)  
  {
    digitalWrite(LEDPin0, HIGH);
    ledStatus0 = 1;
  }
  //turn off if requested to turn off
  if (request.indexOf("/LED0=OFF") != -1) 
  {
    digitalWrite(LEDPin0, LOW);
    ledStatus0 = 0;
  }
  
  // Return the response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html; charset=UTF-8");
  client.println("");
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.print("<meta http-equiv=\"refresh\" content=\"30; url=/\"/>");
  //updates webpage every 30 seconds
  
  client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css\" integrity=\"sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh\" crossorigin=\"anonymous\">");
  client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
  client.println("<style>.switch {  position: relative;  display: inline-block;  width: 60px;  height: 34px;}");
  client.println(".switch input {   opacity: 0;  width: 0;  height: 0;}");
  client.println(".slider {  position: absolute;  cursor: pointer;  top: 0;  left: 0;  right: 0;  bottom: 0;  background-color: #ccc;  -webkit-transition: .4s;  transition: .4s;}");
  client.println(".slider:before {  position: absolute;  content: \"\";  height: 26px;  width: 26px;  left: 4px;  bottom: 4px;  background-color: white;  -webkit-transition: .4s;  transition: .4s;}");
  client.println("input:checked + .slider { background-color: #2196F3;}");
  client.println("input:focus + .slider {  box-shadow: 0 0 1px #2196F3;}");
  client.println("input:checked + .slider:before { -webkit-transform: translateX(26px);  -ms-transform: translateX(26px);  transform: translateX(26px);}");
  client.println("/* Rounded sliders */.slider.round {  border-radius: 34px;}");
  client.println(".slider.round:before {  border-radius: 50%;}");
  client.println("</style>");

  client.println("<title>Lyon Demo</title>");
  client.println("</head>");
  client.println("<body>");
  client.println("<div class=\"jumbotron\"> <h2>Lyon Demo </h2></div>");
  client.println("<a href=\"/\" class=\"btn btn-primary\">Refresh</a>");
  
  client.println("<br></br>");
  client.println("Time: ");
  client.print(timeClient.getHours());
  client.print(":");
  if (timeClient.getMinutes()<10)
  { 
    min_str="0"+String(timeClient.getMinutes());
  }
  else
  {    
    min_str=String(timeClient.getMinutes());
  }
  client.print(min_str);
  
  client.println("</br>");
  client.println("</br>");

  //check the LED status
  
   if (ledStatus0 == 0) 
  {
     client.println("<a href=\"/LED0=ON \" class=\"btn btn-secondary btn-lg active\" role=\"button\" aria-pressed=\"true\">Turn LED &nbsp ON</a>");
  }
  else
  {
     client.println("<a href=\"/LED0=OFF\" class=\"btn btn-primary btn-lg active\" role=\"button\" aria-pressed=\"true\">Turn LED OFF</a>");
  }
   
  client.println("</p>");
  client.println("</br>");
  client.println("</br>");
  client.println("</body>");
  client.println("</html>");
  delay(1);
  Serial.println("User disconnected");
  Serial.println("");
    }

Here is my modified code-

#include <ArduinoOTA.h>




// Include the ESP8266 Library. This library is automatically provided by the ESP8266 Board Manager and does not need to be installed manually.
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>




String codeVersion = "Version 3.2056  Jan 7, 2025 Lyon";
const long utcOffsetInSeconds = -14400;




char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};




// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);




// WiFi Router Login - change these to your router settings
const char* SSID = "notrealwifi";
const char* password = "notrealpassword";








String request;   //web request
String min_str ="";




const int LEDPin0 = D2;  //Light 1
int AnaPin1= A0;




int ledStatus0 = 0;      //status of the LED




int timeout=0;




int current_time;
int i=0;


bool userOver= true;
bool compLight= true;




// Create the ESP Web Server on port 80
WiFiServer WebServer(80);
// Web Client
WiFiClient client;




void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.println(codeVersion);




  //setup pin modes
  pinMode(LEDPin0,OUTPUT);
  pinMode(AnaPin1,INPUT);
  digitalWrite(LEDPin0, LOW);
   
  // Connect to WiFi network
  Serial.println();
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.setSleepMode(WIFI_LIGHT_SLEEP);   //added to keep wifi awake other options are WIFI_NONE_SLEEP WIFI_LIGHT_SLEEP and WIFI_MODEM_SLEEP
  Serial.print("Connecting to ");
  Serial.println(SSID);
  WiFi.begin(SSID, password);




  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("Connected to WiFi");
 
  timeClient.begin();




  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
 
 
  // Start the Web Server
  WebServer.begin();
  Serial.println("Web Server started");
 
  ArduinoOTA.begin();




  // Print the IP address
  Serial.print("You can connect to the ESP8266 at this URL: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
}




void loop()
{
  int value = analogRead(AnaPin1);
  Serial.println(value);


  if(value< 400){
  compLight= true;
  digitalWrite(LEDPin0, HIGH);}
  else{
    compLight= true;
    digitalWrite(LEDPin0,LOW);
  }
  ArduinoOTA.handle();
  current_time=timeClient.getHours()*60 + timeClient.getMinutes();
   
  delay(500);  
  // Check if a user has connected
  client = WebServer.available();
  if (!client)
  {//restart loop
    return;
  }
 
  // Wait until the user sends some data
  Serial.println("New User");
  delay(400);
  while (!client.available())
  {
    delay(1);
    timeout++;
    if(timeout>10000)
    {
      Serial.print("INFINITE LOOP BREAK!");
      break;
    }
  }
  timeout=0;




 
 
 
  timeClient.update();
  Serial.print(daysOfTheWeek[timeClient.getDay()]);
  Serial.print(", ");
  Serial.print(timeClient.getHours());
  Serial.print(":");
  Serial.print(timeClient.getMinutes());
  Serial.print(":");
  Serial.println(timeClient.getSeconds());
 
   
  // Read the first line of the request
  request = client.readStringUntil('\r\n');
  Serial.println(request);
  client.flush();








  // Process the request:
  //Lights
 
   
  //turn on if requested to turn on




  if (request.indexOf("/LED0=ON") != -1)  
  {
    if(compLight== true && userOver== true){
    digitalWrite(LEDPin0, HIGH);
    ledStatus0 = 1;
    }
  }
  //turn off if requested to turn off
  if (request.indexOf("/LED0=OFF") != -1)
  {
    if(compLight== true && userOver== true){
    digitalWrite(LEDPin0, LOW);
    ledStatus0 = 0;
    }
  }
 
  // Return the response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html; charset=UTF-8");
  client.println("");
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.print("<meta http-equiv=\"refresh\" content=\"2; url=/\"/>");
  //updates webpage every 2 seconds
 
  client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css\" integrity=\"sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh\" crossorigin=\"anonymous\">");
  client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
  client.println("<style>.switch {  position: relative;  display: inline-block;  width: 60px;  height: 34px;}");
  client.println(".switch input {   opacity: 0;  width: 0;  height: 0;}");
  client.println(".slider {  position: absolute;  cursor: pointer;  top: 0;  left: 0;  right: 0;  bottom: 0;  background-color: #ccc;  -webkit-transition: .4s;  transition: .4s;}");
  client.println(".slider:before {  position: absolute;  content: \"\";  height: 26px;  width: 26px;  left: 4px;  bottom: 4px;  background-color: white;  -webkit-transition: .4s;  transition: .4s;}");
  client.println("input:checked + .slider { background-color: #2196F3;}");
  client.println("input:focus + .slider {  box-shadow: 0 0 1px #2196F3;}");
  client.println("input:checked + .slider:before { -webkit-transform: translateX(26px);  -ms-transform: translateX(26px);  transform: translateX(26px);}");
  client.println("/* Rounded sliders */.slider.round {  border-radius: 34px;}");
  client.println(".slider.round:before {  border-radius: 50%;}");
  client.println("</style>");




  client.println("<title>Light Status </title>");
  client.println("</head>");
  client.println("<body>");
  client.println("<div class=\"jumbotron\"> <h2>Light Status </h2></div>");
  client.println("<a href=\"/\" class=\"btn btn-primary\">Refresh</a>");
 
  client.println("<br></br>");
  client.println("Time: ");
  client.print(timeClient.getHours());
  client.print(":");
  if (timeClient.getMinutes()<10)
  {
    min_str="0"+String(timeClient.getMinutes());
  }
  else
  {    
    min_str=String(timeClient.getMinutes());
  }
  client.print(min_str);
 
  client.println("</br>");
  client.println("</br>");




  //check the LED status
 
   if (value >= 400)
  {
     client.println("<a href=\"/LED0=ON \" class=\"btn btn-secondary btn-lg active\" role=\"button\" aria-pressed=\"true\">Turn LED &nbsp ON</a>");
  }
  else
  {
     client.println("<a href=\"/LED0=OFF\" class=\"btn btn-primary btn-lg active\" role=\"button\" aria-pressed=\"true\">Turn LED OFF</a>");
  }
   
  client.println("</p>");
  client.println("</br>");
  client.println("</br>");
  client.println("</body>");
  client.println("</html>");
  delay(1);
  Serial.println("User disconnected");
  Serial.println("");
    }

You d been thrown into the deep end of the pool with some of that code, I can't read it very well from where I sit.

This appears to be your addition

  //check the LED status
 
   if (value >= 400)
  {
     client.println("<a href=\"/LED0=ON \" class=\"btn btn-secondary btn-lg active\" role=\"button\" aria-pressed=\"true\">Turn LED &nbsp ON</a>");
  }
  else
  {
     client.println("<a href=\"/LED0=OFF\" class=\"btn btn-primary btn-lg active\" role=\"button\" aria-pressed=\"true\">Turn LED OFF</a>");
  }
   

which if you've mined the original for the magic certainly looks plausible.

The big problem anyone can see is that you will be hammering unnecessarily, turning off something which is already off or on if already on at some unknown high rate.

Find or create a variabke that tracks the current state at the remote end, and send the message to turn off only if the remote end is known to be on, and on only if the remote end is known to be on.

As I suggest, there may be such a variable aready, probably even. A whizzier approach that might be possible with ideas gleaned from coming to a better understanding of the sketch you are modifying would be to query the remote so it would tell you the state and thus inform you decision to tell it what to do or not.

Another issue will come up if value is hovering around 400. This would cause on and off messages to fly; the solution to that is to add hysteresis to the decision. Think of a home thermostat - it turns on the heat when the temperature goes too low and off when heating gets it to be too high, two different points.

In code it coukd not be simpler:

  if (value > 600) turnOffTheLED();

  if (value < 500) turnOnThe LED();

Two if statements, look Ma nothing more. Here I have a so-called deadband where the LED will be not changed - if it was on it stays on, and so forth.

Hysteresis is a basic concept in control systems, one of my favorites can you tell? And is worth a google and a minute or two.

I may have completely misunderstood everything, sadly that happens to me more than you wanna know, blame it this time on the tiny window I am looking at this through and the condition of the road I am being bounced along as I type.

HTH

a7

Sorry, now I see

int value = analogRead(AnaPin1);
  Serial.println(value);


  if (value < 400) {
    compLight= true;
    digitalWrite(LEDPin0, HIGH);
  }
  else {
    compLight= true;   // quite sure you mean false here, whaddya think?
    digitalWrite(LEDPin0,LOW);
  }

  ArduinoOTA.handle();
  current_time=timeClient.getHours()*60 + timeClient.getMinutes();
   
  delay(500);  

which may be what you added. The delay will address one problem I pointed at, but at great cost as you cripple your loop, a Bad Idea. You're telling the processor to literally nothing to advance any kind of processes. To share the resource which is processing time delay() should be avoided like a chef would avoid deflavorants.

I hand-formatted your code. Until you write code in a standard format by habit, avail yourself of the IDE Autoformat tool. It makes code easier to read, and certain errors easier to spot. Doing yourself and us a favor.

a7

Sure is a LOT of code to "turn on and off a basic LED"

Haha I thought so too. Most of the code is just for the wifi connection (From what I understand).

Thanks a lot! the assignment really is a lot to take in at once, I was kind of just thrown into it with little prior knowledge. But I will definitely try to implement some of these suggestions.

Here you have to decide how you handle priorities.

I'd probably have a mode which you can switch via the web browser and would have two states: Automatic and Manual. Automatic means the device is controlled by the photocell only. Manual means the device is controlled only via the Web browser, that is you switch it either on or off, again via the browser.
One variant of this is to have a rule that if the device has been switched by the Web browser then it retains that state for say one hour then reverts back to control by the photocell.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.