Pick an LED colour on a web page

Use your phone's colour picker on a web page served by the ESP32 to set the colour of the RGB LED module.
  • Level:Intermediate
  • Duration: 40 min
  • Ages 12+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Pick an LED colour on a web page – EEMENTOR STEM™ lesson

Every phone and computer has a built-in colour picker, and a web page can use it with a single line of HTML. In this lesson the ESP32 serves a page with a colour picker and a few favourite colours. Whatever you choose, the RGB LED module shows it a moment later, which is how many smart bulbs work.

What you'll learn

  • How to use the HTML colour picker
  • How a colour is written as a hex code like #FF8800
  • How to turn a hex code into red, green and blue values on the ESP32
  • How to dim an LED with analogWrite() on the ESP32

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • RGB LED module (45-in-1 Sensor Kit)
  • 3 resistors, 220 Ω (ESP32 IoT Starter Kit)
  • A 2.4 GHz Wi-Fi network
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)

Wiring

Breadboard wiring diagram: Pick an LED colour on a web page
Breadboard view. Check each connection against the wiring table below.
From Through To
ESP32 GPIO 27 220 Ω resistor RGB module R
ESP32 GPIO 26 220 Ω resistor RGB module G
ESP32 GPIO 25 220 Ω resistor RGB module B
RGB module − GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

The sketch

Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details (2.4 GHz only). Open the Serial Monitor at 115200 baud to see the address, then open it in a browser on a phone or computer on the same Wi-Fi.

#include <WiFi.h>
#include <WebServer.h>

const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const int RED_PIN = 27;
const int GREEN_PIN = 26;
const int BLUE_PIN = 25;

WebServer server(80);

const char PAGE[] = R"rawliteral(
<!DOCTYPE html><html><head><meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'><title>LED colour</title>
<style>
  body { font-family: sans-serif; padding: 16px; text-align: center; }
  input[type=color] { width: 160px; height: 160px; border: none; }
  .fav { width: 48px; height: 48px; border-radius: 50%; border: 2px solid #ccc; margin: 6px; }
</style></head><body>
<h1>LED colour</h1>
<input type='color' id='picker' value='#ff8800'>
<p>
  <button class='fav' style='background:#ff0000' onclick="pick('#ff0000')"></button>
  <button class='fav' style='background:#00ff00' onclick="pick('#00ff00')"></button>
  <button class='fav' style='background:#0000ff' onclick="pick('#0000ff')"></button>
  <button class='fav' style='background:#ffffff' onclick="pick('#ffffff')"></button>
  <button class='fav' style='background:#000000' onclick="pick('#000000')"></button>
</p>
<script>
function pick(colour) {
  document.getElementById('picker').value = colour;
  fetch('/set?c=' + colour.substring(1));      // send "ff8800" without the #
}
document.getElementById('picker').oninput = function () { pick(this.value); };
</script></body></html>
)rawliteral";

void setColour(long rgb) {
  analogWrite(RED_PIN, (rgb >> 16) & 0xFF);   // first two hex digits
  analogWrite(GREEN_PIN, (rgb >> 8) & 0xFF);  // middle two
  analogWrite(BLUE_PIN, rgb & 0xFF);          // last two
}

void setup() {
  Serial.begin(115200);
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
  setColour(0xFF8800);

  WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.print("Open http://");
  Serial.println(WiFi.localIP());

  server.on("/", []() { server.send(200, "text/html", PAGE); });
  server.on("/set", []() {
    String hex = server.arg("c");              // for example "ff8800"
    if (hex.length() == 6) {
      long rgb = strtol(hex.c_str(), NULL, 16);
      setColour(rgb);
      Serial.println("Colour #" + hex);
    }
    server.send(200, "text/plain", "ok");
  });
  server.begin();
}

void loop() {
  server.handleClient();
}

How it works

<input type='color'> makes the browser show its own colour picker. It reports the colour as a hex code: a # followed by six hexadecimal digits, two each for red, green and blue. In hexadecimal, the digits go from 0 to 9 and then A to F, so two digits count from 00 to FF, which is 0 to 255.

The page sends the six digits to the ESP32. strtol(…, 16) turns the text into one number, and the bit-shift operator >> slides it to the right to pick out each pair: shifting by 16 leaves the red part, by 8 the red and green, and & 0xFF keeps only the last two hex digits. analogWrite() then sets each colour's brightness with PWM.

Try this next

  • Add a "party" button that cycles through colours on the ESP32.
  • Remember the last colour with the Preferences library, so the LED comes back in the same colour after a power cut.
  • Add a brightness slider that scales all three colours.

Troubleshooting

  • It never connects to Wi-Fi: check the network name and password (both are case-sensitive) and make sure the network is 2.4 GHz.
  • The page doesn't open: the phone or computer must be on the same Wi-Fi as the ESP32, not on mobile data.
  • The colours are mixed up (red shows as green): swap the wires on R and G, or swap the pin numbers in the sketch.
  • White looks pinkish or bluish: the three colours have different brightness. Lower the strongest one, for example with * 0.7.
  • Black doesn't switch the LED off: you may have a common-anode LED; connect its common pin to 3V3 and use 255 - value.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit