Step by step project to Control LED Light Strips with your phone using Arduino

Home » Projects » Arduino Projects » Step by step project to Control LED Light Strips with your phone using Arduino

Web-Controlled RGB LED Strip: DIY Arduino Project

Arduino remote control LED Strip via a web server - control LED strip with your phone or any device of your choice

In this project, we will create an Arduino-controlled RGB LED strip accessible through a local network interface, allowing control from any smart device, including your phone. This interface, presented as a webpage, offers easy LAN access. Through this control interface, you can communicate with the Arduino and the LED strip’s electronic components, granting complete control over lighting effects, including customizable blinking and timing.

Our project aims to let users change LED strip colors and lighting effects conveniently from their phones or other devices. It’s an excellent choice for individuals seeking to infuse creativity into their home or workspace while enhancing their electronics knowledge and experience the insight of Fullstack WEB developing. Upon completion, you’ll have a fully operational web-controlled LED Strip lighting system to proudly share with friends and family.

You can download the code of this project here. The code will be fully explained in the software section below.

What will we learn

In the Web-Controlled RGB LED Strip DIY project, you will learn how to use an Arduino and an Ethernet shield to create a small HTTP web server on your LAN that controls an RGB LED strip with an interactive web interface. You will also discover how to use the relay unit of the Arduino to enable a stronger voltage source to power up the RGB LED strip. Additionally, you will become familiar with JavaScript and HTML and use them to create the control interface for the LED strip

Programming languages used in this project:

  • C (Arduino compatible)
  • HTML
  • CSS
  • JavaScript

Hardware

In terms of hardware the projects is fairly simple. The Ethernet shield is applied pin to pin directly on the UNO board. We need to connect the 4 wires of the LED strip to the Arduino, however we cannot connect it directly to the GPIO ( general purpose input output ) pins because they cannot supply enough current and voltage to the strip as the strip uses 12V and up to 1A of current. Therefore we will use MOSFET transistors to transfer power from the Arduino Vin pin which is connected to the 12V power jack. Therefore the strip will be powered from the supply. The MOSFET transistors in this circuit will act like switches that are turned on and off electrically, and it can do that thousands of times a second. So we’ll control them via the Arduino GPIO pins. In addition, we shall use PWM pins. When using PWM (Pulse Width Modulation) we turn the transistor and the LEDs on and off a few thousand times a second while controlling the width of the pulse which will allow us to control the brightness of the LEDs on the strip.

First thing put the Arduino Ethernet shield directly on the Arduino. Now we use the GPIO of the Arduino via the Ethernet shield.

Now, we will need to program a web server on the Arduino and we need to connect it to the network using a Modem or a Router. I used a TP-Link TL-WR841N Router which supports Ethernet connection and Wireless. For which the default IP is 192.168.0.1 and the login details are User: admin Password: admin. We will connect an Ethernet cable to the Shield’s Ethernet port. We may use a Second cable to connect to a PC or use the wireless interface.

Software

This project is an improvement of the previous LED control project.  Most of this project and its added value is the software and is the bigger challenge, as it is in the industry of WEB development. We will cover the front end and the back end.  We will go through the full design and development of the web pages and the server and the benefits of the use of various programming languages C, JavaScript, HTML and CSS which developers use in the industry. So you will experience the glory of Full Stack WEB development. I’m going to assume that you are somewhat familiar with the programming languages we are going to use and know the basics.

Arduino

An Arduino is a microcontroller based development board which is programmable using the ArduinoIDE. The IDE allows us to write code in C and to compile it and upload it on to the controller’s internal flash memory. Then the processor of the chip reads through the commands and executes them. We need to turn this in to a Server which will host connecting clients, handle requests and upload the site’s hyper text to the user’s browser to display the pages. To do so we must transmit the code on HTTP protocol to the client’s address. The shield will handle that but we will have to pass it to the shield as plain text. We can use the println() function to transmit the entire code of the site, however this is very much memory consuming to do it. So we prefer to minimize the use of that and store the web code in files instead. Fortunately the Ethernet shield we are using supports an SD card slot and we can store the files on it and load them from there when needed. The physical layer of the system looks like this:

The Ethernet shield is the primary data link device that handles packet transfers via the Ethernet protocol.

Arduino as the server will operate per the following algorithm:

Summary of the server code

The Arduino board will communicate with the Ethernet shield via SPI. In the ArduinoIDE we will load the necessary libraries to handle all the hardware:

#include <SPI.h>

#include <Ethernet.h>

#include <SD.h>

 

At this stage we will set a PORT an IP and a MAC address. For this project we will set a static IP which will work with our gateway 192.168.0.1 on port 80.

 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

#define IP IPAddress(192,168,0,12);

EthernetServer server(80);

 

In the setup we should initialize the SD card with function “SD.begin()” and it should return TRUE. To start the server we use “Ethernet.begin()”  with our IP and MAC of choice and then enter the loop.

In the loop, we shall await until a connection request it received. If so, we must check that he sends appropriate HTTP packets and the load the suited request page or action, whether it’s a login request page or LED output update. So I instructed the Arduino to

The authentication details for this server will be:

User: “root”

Password: “1234”

If client pressed the login button then the server shall expect the following HTTP request: “user=root&pass=1234”. Otherwise the server will respond with 401.

It is important for the server to respond to each and every request with the appropriate response code. Remember to send a 200 when the request is accepted, as well as the type of content we are to load; HTML, CSS etc.

With that said, here is the full code for the Arduino LED strip control server with detailed comments:

Copy to Clipboard
// Arduino WebPage LED strip control server
// Author: Robotics & Energy
// April,  2023
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#define REQ_BUF_SZ 50 // size of buffer used to capture HTTP requests
//RGB LED Pins
#define RED 3
#define GREEN 5
#define BLUE 6
#define PWR 2
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
#define IP IPAddress(192,168,0,12) //Gateway: 192.168.0.1
EthernetServer server(80);       // create a server at port 80
File webFile;                    // handle to files on SD card
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
byte req_index = 0;              // index into HTTP_req buffer
bool root = false;               // login indicator
//----------------------------------------------------------------------------------------------------------------
// sets every element of str to 0 (clears array)
void StrClear(char *str, char len)
{
    for (int i = 0; i < len; i++) 
        str[i] = 0;
}
// searches for the string sfind in the string str
// returns position if string found
// returns 0 if string not found
byte StrContains(char *str, char *sfind)
{
    //byte len = strlen(str); 
    #define LEN strlen(str) 
    byte found = 0;
    byte index = 0;
      
    if (strlen(sfind) > LEN) return 0;
    while (index < LEN) 
    {
        if (str[index] == sfind[found]) 
        {
            found++;
            if (strlen(sfind) == found) return index;    
        }
        else found = 0;
        index++;
    }
    return 0;
}
void controlHandler(unsigned long int dataRGB) // dataRGB = 1255255255 (VRRRGGGBBB)
{   
    byte P =(byte)((dataRGB / 1000000000)      );
    byte R =(byte)((dataRGB / 1000000)   % 1000);
    byte G =(byte)((dataRGB / 1000)      % 1000); 
    byte B =(byte)((dataRGB)             % 1000);  
    
    digitalWrite(PWR,   P);
    analogWrite(RED,    R);
    analogWrite(GREEN,  G); 
    analogWrite(BLUE,   B);
}
//------------------------------------------------------------------------------------------------------------
void setup()
{
    //Outputs
    pinMode(13, OUTPUT);
    pinMode(RED, OUTPUT);
    pinMode(GREEN, OUTPUT);
    pinMode(BLUE, OUTPUT);
    pinMode(PWR, OUTPUT);
    digitalWrite(13, LOW);
    digitalWrite(PWR, LOW);
    analogWrite(RED, 0);
    analogWrite(GREEN, 0);
    analogWrite(BLUE, 0);
       
    Serial.begin(230400);   // for debugging, also defins the connection speed so make it big!   
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) 
    {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    Ethernet.begin(mac, IP);  // initialize Ethernet device => Ethernet.begin(mac, ip);
    server.begin();           // start to listen for clients
}
void loop()
{ 
    EthernetClient client = server.available();  // try to get client
    if (client) // got client?
    {  
        bool currentLineIsBlank = true;
        while (client.connected()) 
        {
            if (client.available()) // client data available to read
            {   
                char c = client.read(); // read 1 byte (character) from client
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) 
                {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                Serial.print(c);    // print HTTP request character to serial monitor
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) 
                { 
                    if(root)
                    {
                      if(StrContains(HTTP_req, "GET / ") || StrContains(HTTP_req, "GET /login.htm"))                            
                      {
                          root = false;
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("login.htm");      
                      }
                      else if(StrContains(HTTP_req, "control.htm"))
                      {
                          root = true;
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("control.htm");        
                      }
                      else if(StrContains(HTTP_req, "main.htm"))
                      {
                          root = true;
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("main.htm");        
                      }
                      else if (StrContains(HTTP_req, "elec.jpg")) 
                      {
                          client.println("HTTP/1.1 200 OK");
                          client.println();
                          webFile = SD.open("elec.jpg");
                      }
                      else if (StrContains(HTTP_req, "style.css")) 
                      {
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/css");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("style.css");
                      }
                      else if (StrContains(HTTP_req, "click?")) 
                      {
                          client.println("HTTP/1.1 200 OK");
                          client.println();
                          // Get RGB values from the HTTP packet
                          unsigned long int result = 0; 
                          sscanf(HTTP_req, "GET /click?=%lux HTTP/1.1", &result);
                          controlHandler(result);
                      }
                      else
                      {
                          client.println("HTTP/4.5 404 Not Found");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("404.htm");
                      }
                    }
                    else
                    {
                      if(StrContains(HTTP_req, "GET / ") || StrContains(HTTP_req, "GET /login.htm"))      
                      {
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("login.htm");      
                      }
                      else if(StrContains(HTTP_req, "user=root&pass=1234"))
                      {
                          root = true;
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("main.htm");        
                      }
                      else if (StrContains(HTTP_req, "style.css")) 
                      {
                          client.println("HTTP/1.1 200 OK");
                          client.println("Content-Type: text/css");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("style.css");
                      } 
                      else
                      {
                          client.println("HTTP/4.2 401 Unauthorized");
                          client.println("Content-Type: text/html");
                          client.println("Connnection: close");
                          client.println();
                          webFile = SD.open("401.htm");
                      }
                    }
                   if (webFile) 
                   {
                        while(webFile.available()) 
                        {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }                 
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') 
                {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') 
                {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)

The application layer

Website interface code breakdown:

Okay, so we will start programming the files that will be stored on the SD card which will be all the web pages. Each page’s code will be a different file ending with ‘.htm’ extension as for html. In addition, there will be a CSS file where we’ll design all the graphics of the site including the flashing RGB LED. We can edit them in any text editing program e.g. notepad++, though I recommend using Visual Studio Code. We do not need to program and activate the Arduino to transmit the pages yet, we may rather open them and run them directly on the browser to view how they look.

The files we will have are:

login. htm – Login page

 main.htm – Menu page

control.htm – LED control page UI

404.htm – Page not found error if the user typed something wrong in the URL

401.htm – Unauthorized page if the authentication failed

style.css – Graphical design of the pages

elec.jpg – A background image for the control page

login.htm

Let’s start with the login page.  So let’s open up our editor of choice and write:

Copy to Clipboard
<!DOCTYPE HTML> 
<html>
    <head>
        <script>
        </script>
    </head>
    <body>
    </body> 
</html>

Between the <head></head> tags we’ll write the title, link the CSS file:

Copy to Clipboard
<title>Login</title>
<link rel="stylesheet" href="style.css"/>

 Also we shall define the login function and time function in Javascript.  So we open <Script></Script> tags and write:

Copy to Clipboard
<Script>
            function login()
            {
                const user = document.querySelector('#user');
                const pass = document.querySelector('#pass');
                const self = event.target;
                self.disabled = true;
                fetch(`user=${user.value}&pass=${pass.value}`).then(reply => {
                    if (reply.status == 200) 
                    {
                        window.location = 'main.htm';
                    } 
                    else 
                    {
                        pass.value = '';
                    }
                    self.disabled = false;
                }).catch(e => {
                    self.disabled = false;
                })
            }
        
            function timeFunction()
            {
                var now = new Date();
                return now.toLocaleString();                
            }           
            setInterval("timeFunction()", 1000);
            var displayTime = timeFunction();
        </Script>

This function, when called, will take data written in the “#user” and “#pass” fields and send it to the server as HTTP request. For instance, if we write “user” “1234” the request will be a string:

“user=user&pass=1234”

timeFunction() requests and returns the local time of the system.

Now, between the <body></body > tags lets first add an h3 header that will display the login time and execute a script that will call the time function within a single line:

Copy to Clipboard
<h3>Time: <script>document.write(timeFunction());</script></h3>

Next, we shall make a class and a form class for the login box where there will be two fields; user and password. And the type of text for the password field will be defined as “password” to censor its characters and an id should be given so that the login() function could address them:

Copy to Clipboard
 <body>  
        <h3>Time: <script>document.write(timeFunction());</script></h3>
        
        <div class="login">
            <form>
                Username:<input type="text" id="user"/><br/>            
                Password:<input type="password" id="pass"/><br/>
                <button >

The design and position of the login box is in style.css will be tagged “.login” which is the name of the class we assigned. It would be identified by <div class=”login”> and the browser will find the code for it and use the code to present it accordingly.

Copy to Clipboard
.login {
  position: absolute;
  top: calc(50% - 35px);
  left: calc(50% - 125px);
  border: 1px solid white;
  width: 250px;
  height: 80px;
  padding: 10px;
}

Let’s write the design and position for the Login button as well. Its design will be tagged “#btnSubmit” which is the ID we assigned. It would be identified by < button id=”btnSubmit”> </button> and the browser will find the code for it and use the code to present it accordingly.

Copy to Clipboard
#btnSubmit {
  position: absolute;
  margin: 10px;
  left: 100px;
}

Please notice; in CSS we sign class object with a dot “.” And id of an object with a sharp “#”.

Main.htm

If the authentication was successful then we want to load the menu page. For now, let’s assume that the login button requests Main.htm.

First let’s make a welcome class is style.css where we’ll position everything relative to the center of the screen. That way the figure will stay centered on different screen sizes and even if the user will change the size of the window.

Copy to Clipboard
.welcome{
  position: absolute;
  top: 35px;
  left: calc(50% - 100px);
}

These would be the two options for this project: continue to control page or logout. However this page may potentially be used to contain access to plenty other pages or data bases in a bigger scale project like a smart house control. Where every device it connected to the IOT. And there will be a list of plenty of devices to connect to and control, like AC, power management, cameras, etc. But in our case the code is short:

Copy to Clipboard
<!DOCTYPE HTML>
<html>
    <head>
        <title>Main page</title>
        <link rel="stylesheet" href="style.css"/>
    </head>
    <body>
        <div class="welcome">
            <h1>Welcome root!</h1>
            |<a href="control.htm">Go to control page</a>|
            <a href="login.htm">Logout</a>|     
        <div>
    </body>
</html>

The function “href” will immediately send a request to the server to load the given page.

Control.htm

We shall start by creating the LED figure in style.css

Now lets do a LED class style which will contain all of the figure’s elements:

Copy to Clipboard
.LED {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}

Next we shall build the figure using simpler shapes; mainly rectangles. The head of the LED is a square with two rounded edges so we will round them with border –radius. To make a nice shadow effect I used box-shadow: inset 0 0 20px rgba(0,0,0,1), 0 0 30px 0 rgba(0,0,0,1); The base is a rectangle with similar parameters except of the dimensions and corners. The legs are rectangles with different box-shadow parameters.  The code is below:

Please note the dot in the name “.LED” which indicates that “LED” is a class in the HTML code.

In CSS we sign class object with a dot “.” And id of an object with a sharp “#”. We’ll start by creating the head if the LED which will be a square with rounded edges, and a shadow around it:

Copy to Clipboard
.sqr {
  box-shadow: inset 0 0 20px rgba(0, 0, 0, 1), 0 0 30px 0 rgba(0, 0, 0, 1); /* create shadow */   
  background-color: rgba(100, 100, 100, 1);
  width: 8em;
  height: 160px;
  border-top-left-radius: 50%;   /* round the redge */  border-top-right-radius: 50%;
}

Bottom ring will be a regular rectangle, with a little shift to emphasize the flat spot.

Copy to Clipboard
.rctngl {
  box-shadow: inset 0 0 20px rgba(0, 0, 0, 1),
    0 0 30px 0 rgba(0, 0, 0, 1);
  background-color: rgba(100, 100, 100, 1);
  width: 10em;
  height: 20px;
}

All LED legs have same properties, they’re just long rectangles”

Copy to Clipboard
.ledleg {
  font-family: arial;
  background-color: #666666;
  box-shadow: -3px 2px 2px 2px rgba(0, 0, 0, 0.5);
  width: 5%;
  height: 120px;
}

Except for the 12V which would be a bit longer if it were an RGB LED and not a LED strip. So in HTML we will define the class of the 12V as “ledleg” and its id will be “power12”:

Copy to Clipboard
#power12{
  height: 140px;
}

All the legs should be evenly spaced in a row and not one under the other. So later in HTML we will put them in a container that we will program to do so this way:

Copy to Clipboard
.spaced-led-legs-container {
  margin-bottom: 3%; /* next container will be 3% of page size lower */  display: flex;
  justify-content: space-around; /* apply spacing */ 
}

“display: flex;” makes it a Flexible Box Layout Module, makes it easier to design flexible responsive layout structure without using float or positioning.

Now let’s get to control.htm file which is written is HTML and Javascript. Because the code is fairly long, I shall break it in to pieces and explain them.

First, the structure of the code before we start coding is this:

Copy to Clipboard
<!DOCTYPE HTML>
<html>
    <head>
        <title>LED Control</title>
        <link rel="stylesheet" href="style.css"/>
        
        <style>
            body
            {
                background-image: url("elec.jpg");
            }
        </style>
        <script>
            /* Javascript code */        </script>
    </head>

    <body>
        <!-- body of the page --> 
    </body>

</html>

We’ll write the head of the page just like previous pages, but with an additional <style></style> tags where we’ll add the background image “elec.jpg” using “background-image:” followed by the url function and the location of the image in the files. If the image is in the same folder as the control file, like in our case here, then the location is not needed, only the filename.

Next we add the <script></script> tags where the javascript code will be. And then the <body></body> tags. In the <script></script> tags we need to write function that sends the input to the Arduino. But first let’s program the body, where we’ll display the LED figure with check boxes on the legs, the sliders and the pattern selector. Each of these parts will be configured in a “container” which we will use to store that section of controls, and we will use this container to define its properties in CSS.

So, to display the LED figure and checkboxes on the page let’s write:

Copy to Clipboard
<body>
    <div class="main-container">
        <h1>Control page</h1>
        <div class="LED">
            <div class="sqr"></div>
            <div class="rctngl"></div>
            <div class="spaced-led-legs-container">
                <div class="ledleg">R<input type="checkbox" name="Red" onClick="clickFunc()"></div>
                <div class="ledleg" id="power12">12V<input type="checkbox" name="Vin" onClick="clickFunc()"></div>
                <div class="ledleg">G<input type="checkbox" name="Green" onClick="clickFunc()"></div>
                <div class="ledleg">B<input type="checkbox" name="Blue" onClick="clickFunc()"></div>
            </div>

Please notice that we created a “main-container”. Where all the controls will be. After the header <h1> we’ve created the LED <div>, there we will construct the LED object, so following that we add “sqr” then “rctngl” then “spaced-led-legs-container” one under the other. HTML will put them in this exact order upon displaying the page, like a sandwich. Inside “spaced-led-legs-container” we put 4 “ledleg” class divs with their names “R”, “12V”, “G” and “B”. Also we add <input type=”checkbox”> to create a checkbox in the same area.  The line onClick=”clickFunc()” will call the “clickFunc()” function that we’ll define between the <script> tags. 

Back to CSS let’s center the main container, make it flexible and make the sub containers in it to follow one another in a column order. Like a sandwich.

Copy to Clipboard
.main-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

Next we make the slider and the slider container within the main container:

In the control.htm file, let’s create 3 “range” type inputs with an ID for each. Define minimum, maximum and starting values. Define a callback function oninput=”sliderValues()” which will call the function sliderValues() when the slider is dragged and its value changes.

Copy to Clipboard
<div class="slider-container">
     <input type="range" id="slideR" min="0" max="255" value="0" oninput="sliderValues()">
     <input type="range" id="slideG" min="0" max="255" value="0" oninput="sliderValues()">
     <input type="range" id="slideB" min="0" max="255" value="0" oninput="sliderValues()">
</div>

So we add an input type “range” which will create a slider, but we want them side by side with spacing. So let’s edit the “.slider-container” class in CSS and make a flexible row direction for them:

Copy to Clipboard
.slider-container {
  display: flex;
  flex-direction: row;
  justify-content: center;
}

Now let’s design all “range” input types to look nicer than default. In CSS we can use “input[type=…]” to make all inputs of the same type to look alike, and design them as we want. We shall make the slider vertical, adjust its height and width, and define the shape and size of the cursor. For some reason Mozilla Firefox compiles the cursor size differently so we need to use “&::-webkit-slider-thum” for regular browsers and “ &::-moz-range-thumb” for Mozilla:

Copy to Clipboard
input[type="range"] {
  width: 15%;
  cursor: pointer;
  appearance: slider-vertical;
  height: 150px;

/* edit thumb size*/  &::-webkit-slider-thumb {
    transform: scale(2);
  }
/* edit thumb size for mozilla browser*/  &::-moz-range-thumb {
    transform: scale(2);
  }
}

Now we want each slider to have the color that it influences. So we use each slider’s ID and design it in CSS:

Copy to Clipboard
input#slideR[type=range] {
  accent-color: Red;
}

input#slideG[type=range] {
  accent-color: Green;
}

input#slideB[type=range] {
  accent-color: Blue;
}

“accent-color:” will make the slider fill the color as we move the cursor up.

Now let’s create the selector and its contents.

Copy to Clipboard
<div class="pattern-selector-container">
                <p>Select Pattern</p>
                <select onchange="playPattern(this.value)">
                    <option value="0">No Pattern</option>
                    <option value="1">Blink</option>
                    <option value="2">Flash</option>
                    <option value="3">Sweep</option>
                </select>
            </div>   

As you can see, it is a <select> tag and in it are <option> tags. We made each option to have a value and a text. Therefore upon selecting an option, the function “playPattern()” will be called with the particular value of the option selected, so we will later know which pattern was selected when we’ll define the function in Javascript.

Let’s design the scale and position of the pattern selector container in CSS:

Copy to Clipboard
.pattern-selector-container{
  margin-top: 5%;
  transform: scale(2);
}

Javascript

Now we’ve designed the entire page using HTML and CSS and it should look like this:

But the controls do not yet do anything because we didn’t program them. We shall now go to the <script></script> tags and write the code for the call back function of each control.
Our callback functions are:

Copy to Clipboard
function clickFunc(); // CheckBox click callback. Also used to turn LED on/off via HTTP request to server
function sliderValues(); // Slider value changed callback
function playPattern(this.value); // Pattern changed callback

These will be the main functions but we shall define other functions to help simplify the code.

Copy to Clipboard
function httpGet(theUrl) // HTTP message handler
function rgb(r, g, b) // Return RGB values as a string
function checkboxOn(name) // see if CheckBox is checked True / False
function sliderValue(name) // Return Slider value as an Integer
function inputHandle() // Read Sliders and CheckBoxes and modify output_var and RGB values
function ledColor(color) // Paint the LED figure and turn shadow to a helo or vice versa
function patternMode(mode, colorID, updown) // Modify RGB values according to active pattern

All modified data for the values of Red Green and Blue colors, as well as timers and the data to be transmitted to the server will be stored in global variables which we will declare at the top of the script:

Copy to Clipboard
        var output_var;         // RGB Value format: VRRRGGGBBB
        var last_output;        // To prevent unnecessary traffic
        var slRvalue;           // Value of red
        var slGvalue;           // Value of green
        var slBvalue;           // Value of blue
        let timerR;             // Pattern timer for red
        let timerG;             // Pattern timer for green
        let timerB;             // Pattern timer for blue
        var isPatterned = false;// Track pattern mode

Summary of the code functionality:

The “clickFunc();” is used several times in the code; not only when checkbox is clicked but also when the blink and flash patterns are activated. The function calls the function “inputHandle()” which collects data from the checkboxes and sliders with “document.getElementsByName(“name”)[0].checked” command and outputs the RGB color code for the LED using “rgb()”. Also this function will store a coded value in a global variable “output_var” that will later be transmitted to the server to activate the necessary pins.
Next, the function “ledColor()” is called to paint the LED in the interface according to “inputHandle()” using “document.getElementsByClassName(“sqr”)[0].style”.
Finally, we want to send a request to the server to update outputs in the physical world. So upon click we shall execute function httpGet() which will send the request in a form of: “click?=1255255255x”. Where the number 1255255255 actually represents each value for RGB and if the LED is on, which in this case will turn the LED in full bright white.

Full JavaScript code is as follows:

Copy to Clipboard
<script>
        var output_var;         // RGB Value format: VRRRGGGBBB
        var last_output;        // To prevent unnecessary traffic
        var slRvalue;           // Value of red
        var slGvalue;           // Value of green
        var slBvalue;           // Value of blue
        let timerR;             // Pattern timer for red
        let timerG;             // Pattern timer for green
        let timerB;             // Pattern timer for blue
        var isPatterned = false;// Track pattern mode

        function httpGet(theUrl) // HTTP message handler
        {
            var xmlHttp = new XMLHttpRequest();
            xmlHttp.open("GET", theUrl, false); // false for synchronous request
            xmlHttp.send(null);
            return xmlHttp.responseText;
        }

        function rgb(r, g, b) // Return RGB values as a string
        {
            return "rgb(" + r + "," + g + "," + b + ")";
        }

        function checkboxOn(name) // see if CheckBox is checked True / False
        {
            return document.getElementsByName(name)[0].checked;
        }

        function sliderValue(name) // Return Slider value as an Integer
        {
            return parseInt(document.getElementById(name).value); // Value is a string in this case
        }

        function sliderValues() // Slider value changed callback
        {
            if (!isPatterned) {
                slRvalue = sliderValue("slideR");
                slGvalue = sliderValue("slideG");
                slBvalue = sliderValue("slideB");
                clickFunc();
            }
        }

        function inputHandle() // Read Sliders and CheckBoxes and modify output_var and RGB values
        {
            var valueR = 0;
            var valueG = 0;
            var valueB = 0;
            output_var = 0;
            if (checkboxOn("Vin"))                    // Voltage leg on?
            {
                output_var += 1 * 1000000000;         // place value in correct position in 'output_var'
                if (checkboxOn("Red"))                // Red leg on?
                {
                    output_var += slRvalue * 1000000; // place value in correct position in 'output_var'
                    valueR = slRvalue;
                }
                if (checkboxOn("Green"))              // Green leg on?
                {
                    output_var += slGvalue * 1000;    // place value in correct position in 'output_var'
                    valueG = slGvalue;
                }
                if (checkboxOn("Blue"))               // Blue leg on?
                {
                    output_var += slBvalue;
                    valueB = slBvalue;
                }
                if (valueR > 55 || valueG > 55 || valueB > 55) 
                {
                    return rgb(valueR, valueG, valueB);
                }
                else return rgb(100, 100, 100);      // if LED is too dim
            }
            else return rgb(100, 100, 100);
        }

        function ledColor(color) // Paint the LED figure and turn shadow to a helo or vice versa
        {
            var shade;
            if (color == rgb(100, 100, 100))
                shade = "inset 0 0 20px rgba(0,0,0,1), 0 0 30px 0 rgba(0,0,0,1)";
            else 
            {
                shade = "inset 0 0 20px rgba(0,0,0,1), 0 0 150px 0 ";
                shade = shade.concat(color);
            }
            document.getElementsByClassName("sqr")[0].style.backgroundColor = color;
            document.getElementsByClassName("sqr")[0].style.boxShadow = shade;
            document.getElementsByClassName("rctngl")[0].style.backgroundColor = color;
            document.getElementsByClassName("rctngl")[0].style.boxShadow = shade;
        }

        function clickFunc() // CheckBox click callback. Also used to turn LED on/off via HTTP request to server
        {
            ledColor(inputHandle());
            if (output_var != last_output) 
            {
                last_output = output_var;
                httpGet("click?=" + output_var.toString() + "x");
            }
        }

        function patternMode(mode, colorID, updown) // Modify RGB values according to active pattern
        {
            if (mode == 1)      // Blink
            {
                switch (colorID) {
                    case "Red":
                        if (updown == 100) slRvalue = 255;
                        if (updown == 0) slRvalue = 0;
                        break;
                    case "Green":
                        if (updown == 100) slGvalue = 255;
                        if (updown == 0) slGvalue = 0;
                        break;
                    case "Blue":
                        if (updown == 100) slBvalue = 255;
                        if (updown == 0) slBvalue = 0;
                        break;
                }
            }

            else if (mode == 2) // Flash
            {       
                if (updown == 100 && checkboxOn(colorID)) 
                {
                    switch (colorID) 
                    {
                        case "Red":
                            slRvalue = 255;
                            slGvalue = 0;
                            slBvalue = 0;
                            break;
                        case "Green":
                            slRvalue = 0;
                            slGvalue = 255;
                            slBvalue = 0;
                            break;
                        case "Blue":
                            slRvalue = 0;
                            slGvalue = 0;
                            slBvalue = 255;
                            break;
                    }
                }
            }

            else if (mode == 3) // Sweep
            {
                updown = Math.floor(updown * 2.5);
                switch (colorID) {
                    case "Red":
                        slRvalue = updown;
                        break;
                    case "Green":
                        slGvalue = updown;
                        break;
                    case "Blue":
                        slBvalue = updown;
                        break;
                }
            }
            clickFunc();
        }

        function playPattern(patternId) // Pattern changed callback
        {
            var modeId = parseInt(patternId);
            var countR = 0;
            var countG = 0;
            var countB = 0;
            var Rflag = false;
            var Gflag = false;
            var Bflag = false;
            clearTimeout(timerR); // Declared globally 
            clearTimeout(timerG);
            clearTimeout(timerB);

            if (modeId == 0) isPatterned = false;
            else {
                isPatterned = true;

                // Timer for Red pattern
                timerR = setTimeout(function tick() {
                    timerR = setTimeout(tick, (sliderValue("slideR") / 10) + 5);
                    Rflag ? countR-- : countR++;
                    if (countR == 100) Rflag = true;
                    if (countR == 0) Rflag = false;
                    patternMode(modeId, "Red", countR);
                }, (sliderValue("slideR") / 10) + 5);

                // Timer for Green pattern
                timerG = setTimeout(function tick() {
                    timerG = setTimeout(tick, (sliderValue("slideG") / 10) + 5);
                    Gflag ? countG-- : countG++;
                    if (countG == 100) Gflag = true;
                    if (countG == 0) Gflag = false;
                    patternMode(modeId, "Green", countG);
                }, (sliderValue("slideG") / 10) + 5);

                // Timer for Blue pattern
                timerB = setTimeout(function tick() {
                    timerB = setTimeout(tick, (sliderValue("slideB") / 10) + 5);
                    Bflag ? countB-- : countB++;
                    if (countB == 100) Bflag = true;
                    if (countB == 0) Bflag = false;
                    patternMode(modeId, "Blue", countB);
                }, (sliderValue("slideB") / 10) + 5);
            }
        }

    </script>

Error pages

Every web server needs to know to handle errors. Here we’re expected to handle two types of errors:
● 401 – Authentication fail, or wrong password in other words.
● 404 – Page not found. May occur if the user entered something in the URL.
We will make a file to handle each:

401.htm

Copy to Clipboard
<!DOCTYPE HTML>
<head><title>401 Error</title></head>
<body><style>body{background-color: lightblue;}</style><h1>401: Authentication error.<br/>Are you authorized!?</h1></body>

404.htm

Copy to Clipboard
<!DOCTYPE HTML>
<head><title>404 Error</title></head>
<body><style>body{background-color: lightblue;}</style><h1>404 No such page.</h1></body>

There is no need to edit the pages in CSS. And that concludes our Website coding.

 

Summary

Through this project, we’ve gained a hands-on understanding of creating a website and configuring a web server on an Arduino. We experienced the fundamentals of web development and the exciting world of IoT. Our exploration, particularly in using the web server to control an LED strip, extended to include the integration of the MOSFET and the relay module to manage current and voltage according to each component’s requirements. This project equips us with the basics to create a more advanced and practical projects.

Thank you

We thank you for learning and hopefully completing our project. 

We would like to know what you think about our Web-Controlled RGB LED Strip Arduino Project