ESP32/ESP8266 RGB LED Strip with Color Picker Web Server

In this project we’ll show you how to remotely control an RGB LED strip with an ESP8266 or an ESP32 board using a web server with a color picker.

ESP32 or ESP8266 RGB LED Strip with Color Picker Web Server

We’ll control a 5V RGB LED strip and the code will be written in Arduino IDE.

To better understand this project, there are a few tutorials that you may want to take a look first (this step is optional):

Watch the Video Tutorial

You can watch the video tutorial or keep reading this page for the written instructions.

Project Overview

Before getting started, let’s see how this project works:

How it works ESP32/ESP8266 RGB LED Strip with Color Picker Web Server
  • The ESP32/ESP8266 web server displays a color picker.
  • When you chose a color, your browser makes a request on a URL that contains the R, G, and B parameters of the selected color.
  • Your ESP32/ESP8266 receives the request and splits the value for each color parameter.
  • Then, it sends a PWM signal with the corresponding value to the GPIOs that are controlling the strip.

Parts Required

For this project you need the following parts:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Schematic

For this project, we’ll be using an RGB LED strip that can be powered with 5V.

5V RGB LED Strip

Note: there are other similar strips that require 12V to operate. You can still use them with the code provided, but you need a suitable power supply.

In this example, we’ll be powering the LED strip and the ESP32 or ESP8266 using the same 5V power supply.

ESP32 – schematic diagram

Follow the next schematic diagram to connect the strip to your ESP32.

ESP32 5V RGB LED Strip Schematic Circuit

ESP8266 – Schematic diagram

Follow the next schematic diagram to connect the strip to your ESP8266.

ESP8266 5V RGB LED Strip Schematic Circuit

NPN Transistors

In this circuit, we’re using the S8050 NPN transistor. However, depending on how many LEDs you have in your strip, you might need to use a NPN transistor that can handle more continuous current in the collector pin.

ESP32/ESP8266 RGB LED Strip Circuit and Schematic NPN transistor

To determine the max current used by your LED strip, you can measure the current consumption when all the LEDs are at maximum brightness (when the color is white).

Since we’re using 12 LEDs, the maximum current is approximately 630mA at full brightness in white color. So, we can use the S8050 NPN transistor that can handle up to 700mA.

ESP32/ESP8266 RGB LED Strip Circuit and Schematic NPN transistor

Note: your strip consumes the maximum current when you set white color (this is the same as setting all three colors to the maximum brightness). Setting other colors draws less current, so you’ll probably won’t have your strip using the maximum current.

ESP32 Code

We’ll program the ESP32 using Arduino IDE, so make sure you have the ESP32 add-on installed before proceeding:

After assembling the circuit, copy the following code to your Arduino IDE to program the ESP32.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

// Load Wi-Fi library
#include <WiFi.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Decode HTTP GET value
String redString = "0";
String greenString = "0";
String blueString = "0";
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

// Variable to store the HTTP req  uest
String header;

// Red, green, and blue pins for PWM control
const int redPin = 13;     // 13 corresponds to GPIO13
const int greenPin = 12;   // 12 corresponds to GPIO12
const int bluePin = 14;    // 14 corresponds to GPIO14

// Setting PWM frequency, channels and bit resolution
const int freq = 5000;
const int redChannel = 0;
const int greenChannel = 1;
const int blueChannel = 2;
// Bit resolution 2^8 = 256
const int resolution = 8;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  // configure LED PWM functionalitites
  ledcSetup(redChannel, freq, resolution);
  ledcSetup(greenChannel, freq, resolution);
  ledcSetup(blueChannel, freq, resolution);
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(redPin, redChannel);
  ledcAttachPin(greenPin, greenChannel);
  ledcAttachPin(bluePin, blueChannel);
  
  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {            // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
                   
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
            client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
            client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
            client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
            client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
            client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
            client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
            // The HTTP response ends with another blank line
            client.println();

            // Request sample: /?r201g32b255&
            // Red = 201 | Green = 32 | Blue = 255
            if(header.indexOf("GET /?r") >= 0) {
              pos1 = header.indexOf('r');
              pos2 = header.indexOf('g');
              pos3 = header.indexOf('b');
              pos4 = header.indexOf('&');
              redString = header.substring(pos1+1, pos2);
              greenString = header.substring(pos2+1, pos3);
              blueString = header.substring(pos3+1, pos4);
              /*Serial.println(redString.toInt());
              Serial.println(greenString.toInt());
              Serial.println(blueString.toInt());*/
              ledcWrite(redChannel, redString.toInt());
              ledcWrite(greenChannel, greenString.toInt());
              ledcWrite(blueChannel, blueString.toInt());
            }
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

View raw code

Before uploading the code, don’t forget to insert your network credentials so that the ESP can connect to your local network.

const char* ssid     = "";
const char* password = "";

If you’ve built a web server with the ESP32 before, this code is not much different. It adds the color picker to the web page and decodes the request to control the strip color. So, we’ll just take a look at the relevant parts for this project.

ESP8266 Code

We’ll program the ESP8266 using the Arduino IDE. In order to upload code to your ESP8266, you need to install the ESP8266 add-on first, if you haven’t already (Install the ESP8266 Board in Arduino IDE).

After assembling the circuit, copy the following code to your Arduino IDE to program the ESP8266.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

// Load Wi-Fi library
#include <ESP8266WiFi.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set web server port number to 80
WiFiServer server(80);

// Decode HTTP GET value
String redString = "0";
String greenString = "0";
String blueString = "0";
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

// Variable to store the HTTP req  uest
String header;

// Red, green, and blue pins for PWM control
const int redPin = 13;     // 13 corresponds to GPIO13
const int greenPin = 12;   // 12 corresponds to GPIO12
const int bluePin = 14;    // 14 corresponds to GPIO14

// Setting PWM bit resolution
const int resolution = 256;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  
  // configure LED PWM resolution/range and set pins to LOW
  analogWriteRange(resolution);
  analogWrite(redPin, 0);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 0);
  
  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {            // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
                   
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
            client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
            client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
            client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
            client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
            client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
            client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
            // The HTTP response ends with another blank line
            client.println();

            // Request sample: /?r201g32b255&
            // Red = 201 | Green = 32 | Blue = 255
            if(header.indexOf("GET /?r") >= 0) {
              pos1 = header.indexOf('r');
              pos2 = header.indexOf('g');
              pos3 = header.indexOf('b');
              pos4 = header.indexOf('&');
              redString = header.substring(pos1+1, pos2);
              greenString = header.substring(pos2+1, pos3);
              blueString = header.substring(pos3+1, pos4);
              /*Serial.println(redString.toInt());
              Serial.println(greenString.toInt());
              Serial.println(blueString.toInt());*/
              analogWrite(redPin, redString.toInt());
              analogWrite(greenPin, greenString.toInt());
              analogWrite(bluePin, blueString.toInt());
            }
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

View raw code

Before uploading the code, don’t forget to insert your network credentials so that the ESP can connect to your local network.

const char* ssid     = "";
const char* password = "";

If you’ve built a web server with the ESP8266 before, this code is not much different. It adds the color picker to the web page and decodes the request to control the strip color. So, we’ll just take a look at the relevant parts for this project.

How the code works

The sketches for the ESP32 and ESP8266 are very similar with just a few differences when it comes to the Wi-Fi library and the way they generate PWM signals. We’ll explain that in this section.

The ESP32 sketch uses the WiFi.h library.

#include <WiFi.h>

The ESP8266 sketch uses the ESP8266WiFi.h library.

#include <ESP8266WiFi.h>

The following lines define string variables to hold the R, G, and B parameters from the request.

String redString = "0";
String greenString = "0";
String blueString = "0";

The next four variables are used to decode the HTTP request later on.

int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

Create three variables for the GPIOs that will control the strip R, G, and B parameters. In this case we’re using GPIO 13, GPIO 12, and GPIO 14.

const int redPin = 13;     
const int greenPin = 12;  
const int bluePin = 14; 

These GPIOs need to output PWM signals, so we need to configure the PWM properties first. Set the PWM signal frequency to 5000 Hz. Then, associate a PWM channel for each color (this is not needed in the ESP8266 sketch).

const int freq = 5000;
const int redChannel = 0;
const int greenChannel = 1;
const int blueChannel = 2;

And finally, set the resolution of the PWM channels to 8-bit (not needed in ESP8266 sketch).

const int resolution = 8;

In the setup(), assign the PWM properties to the PWM channels (not needed in ESP8266 sketch) .

ledcSetup(redChannel, freq, resolution);
ledcSetup(greenChannel, freq, resolution);
ledcSetup(blueChannel, freq, resolution);

Attach the PWM channels to the corresponding GPIOs (not needed in ESP8266 sketch).

ledcAttachPin(redPin, redChannel);
ledcAttachPin(greenPin, greenChannel);
ledcAttachPin(bluePin, blueChannel);

The following code section displays the color picker in your web page and makes a request based on the color you’ve picked.

client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");        client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
// The HTTP response ends with another blank line
client.println();

When you pick a color, you receive a request with the following format.

/?r201g32b255&

So, we need to split this string to get the R, G, and B parameters. The parameters are saved in redStringgreenString, and blueString variables and can have values between 0 and 255.

pos1 = header.indexOf('r');
pos2 = header.indexOf('g');
pos3 = header.indexOf('b');
pos4 = header.indexOf('&');
redString = header.substring(pos1+1, pos2);
greenString = header.substring(pos2+1, pos3);
blueString = header.substring(pos3+1, pos4);

To control the strip with the ESP32, use the ledcWrite() function to generate PWM signals with the values decoded from the HTTP request.

ledcWrite(redChannel, redString.toInt());
ledcWrite(greenChannel, greenString.toInt());
ledcWrite(blueChannel, blueString.toInt());

Note: learn more about PWM with ESP32: ESP32 PWM with Arduino IDE.

To control the strip with the ESP8266, we just need to use the analogWrite() function to generate PWM signals with the values decoded from the HTPP request.

analogWrite(redPin, redString.toInt());
analogWrite(greenPin, greenString.toInt());
analogWrite(bluePin, blueString.toInt())

Because we get the values in a string variable, we need to convert them to integers using the toInt() method.

Demonstration

After inserting your network credentials, select the right board and COM port and upload the code to your ESP32 or ESP8266.

After uploading, open the Serial Monitor at a baud rate of 115200 and press the ESP Enable/Reset button. You should get the board IP address.

Demonstration ESP32/ESP8266 RGB LED Strip

Open your browser and insert the ESP IP address. Now, use the color picker to choose a color for the strip.

Web Server Demonstration ESP32/ESP8266 RGB LED Strip

Then, you need to press the “Change Color” button for the color to take effect.

Demonstration ESP32/ESP8266 5V RGB LED Strip Web Server Color Picker

To turn off the RGB LED strip, select the black color.

The strongest colors (at the top of the color picker), are the ones that will produce better results.

ESP32/ESP8266 5V RGB LED Strip Web Server Color Picker

Now, you use the strip to decorate your house: under the bed, behind a TV, under the kitchen cabinet, and much more.

Wrapping Up

With this article you’ve learned how to control an RGB LED strip remotely using a web server with your ESP32 or ESP8266 on your local network.

We hope you’ve found this tutorial useful. If you like this project, you may also like:

This is an excerpt from our course: Learn ESP32 with Arduino IDE. If you like ESP32 and you want to learn more about it, we recommend enrolling in Learn ESP32 with Arduino IDE course.


Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

17 thoughts on “ESP32/ESP8266 RGB LED Strip with Color Picker Web Server”

    • Hi Bruce.
      Yes, you can use it depending on the number of LEDs you’re controlling.
      In our example, we’re using 12 LEDs. You can use that transistor with 12 LEDs. If you want to use more LEDs, you need to check the current the LEDs draw.
      Regards,
      Sara

  1. Hi, Can you list the pins and their connections, of the transistor ?
    I was hoping to see a circuit diagram of what is the “Base” of the transistor connected to ( in respect to the RGB strip) ? The “Collector” and the “Emitter” connected to ?
    Would appreciate that a lot.
    Would help non-electronic engineers too.
    I am using a 2N2222 transistor

    • Hi Shashi.
      The emitter connects to GND.
      The base connects to the ESP32/ESP8266 GPIOs through a 1k resistor.
      The collector connects to one of the strip color pins.
      I hope this helps.
      Regards,
      Sara

      • Thanks Sara. Tried your suggestion. Did not work !

        My project involves
        – I have 3 2N2222 Transistors instead of your 8050 transistor.
        – I am powering the ESP32 thru the USB cable connected to my Mac Book Air.
        The 1K resistor looks good. Both the ESP32 and the RGB strip are connected thru the same USB power supply from the power jack of the laptop ( I dont think it’d be a problem )

        My ESP32 device is a “ESP32DEV Kit V1″ – should not be different from your blog.
        I can see that the ESP32 connects to my Network, I also uncommented the
        ” Serial.println(redString.toInt());
        Serial.println(greenString.toInt());
        Serial.println(blueString.toInt());

        and I see in the serial console the different numbers .

        == Cut and Paste from Serial Monitor ==

        GET /?r254g104b255& HTTP/1.1
        Host: 192.168.1.21
        Connection: keep-alive
        Upgrade-Insecure-Requests: 1
        User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
        Referer: http://192.168.1.21/?r255g86b171&amp;
        Accept-Encoding: gzip, deflate
        Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,en-IN;q=0.7

        254
        104
        255
        Client disconnected.

        See the 254, 104 and 255 above.
        This is the color sequence sent from the web server to the ESP32.
        I have a WS2812 LED strip, 1 meter long and I bought it from Ali express. It works with Arduino – and not with ESP32 ! I dont have to add the Transistor & Resistor when connected to the Arduino Uno ( Using the Fast LED library for the Arduino Uno)

  2. Hi, The sketch comes back with an error regarding ledcSetup. I looked through several library files and cannot find which .h file to include. Am I missing something?

  3. Hi Sara,
    can you incorporate something like WiFiManager in your sketch so i can give this as present to some of my friends?
    So they dont need to use pc every time they start product, they are not hobby makers 🙂
    Tnx

  4. Hello Sara, is there a wifimanager for ESP32? because as it appears in the previous point, I can not tell a person or friend to access the arduino to change the SSID. Thank you

    • Hi Alberto.
      You can use this library: github.com/zhouhan0126/WIFIMANAGER-ESP32
      It should be compatible with the ESP32.
      Regards,
      Sara

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.