In this entertaining project, you will connect a TCS3200D/TCS230 color sensor to an ESP32 and stream the detected colors to a web browser in real-time. The web page features a playful animated Minion character whose skin color updates live based on what the sensor sees. To simplify building the web interface and managing WebSocket communication, this project uses the DIYables ESP32 WebApps library.
Here is a summary of what happens:
The ESP32 reads RGB color data from the TCS3200D/TCS230 sensor
It converts the RGB values into a HEX color code (e.g., #FF8000)
The HEX code is streamed to the web browser over WebSocket
A fun animated Minion on the web page instantly changes its body, arms, and eyelid colors to match
A step-by-step video walkthrough is also available at the bottom of this tutorial.
Disclosure: Some of the links in this section are Amazon affiliate links, meaning we may earn a commission at no additional cost to you if you make a purchase through them. Additionally, some links direct you to products from our own brand, DIYables .
Prerequisites
If you are new to the TCS3200D/TCS230 color sensor or DIYables ESP32 WebApps, the following tutorials will help you get up to speed:
Every second, the ESP32 reads the color sensor by switching between the red, green, and blue filters using the S2/S3 control pins, and measuring the pulse width on the OUT pin.
The raw pulse width values are converted to 0–255 RGB values using calibration data (obtained from the sensor calibration step).
The RGB values are formatted into a HEX color string such as #FF8000.
This color string is broadcast to all connected web browsers via WebSocket through the DIYables ESP32 WebApps library.
On the web page, JavaScript receives the color and instantly applies it to the Minion character's body, arms, and eyelids.
ESP32 Code - Color Sensor Minion Web App
This project consists of 4 files:
ColorSensorESP32.ino - Main sketch: initializes the sensor, reads colors, and sends them to the web page
CustomWebApp.h - Header file: declares the custom web app page class
CustomWebApp.cpp - Implementation file: manages WebSocket messaging using the "Color sensor:" identifier
custom_page_html.h - Web page: the animated Minion built with HTML/CSS/JavaScript that reacts to incoming colors
ColorSensorESP32.ino
/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-color-sensor-via-web */#include <DIYables_ESP32_Platform.h>#include <DIYablesWebApps.h>#include"CustomWebApp.h"// CHANGE THESE TO YOUR WIFI DETAILSconstchar WIFI_SSID[] = "YOUR_WIFI_SSID";constchar WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";// Configure TCS3200 pins for ESP32constint S0 = 17;constint S1 = 16;constint S2 = 18;constint S3 = 5;constint sensorOut = 19;// Create server and pagesESP32ServerFactory serverFactory;DIYablesWebAppServerwebAppsServer(serverFactory, 80, 81);DIYablesHomePage homePage;CustomWebAppPage customPage;unsignedlong lastColorRead = 0;voidsetup() {Serial.begin(9600);delay(1000);Serial.println("Starting Custom WebApp...");// Initialize TCS3200 pinspinMode(S0, OUTPUT);pinMode(S1, OUTPUT);pinMode(S2, OUTPUT);pinMode(S3, OUTPUT);pinMode(sensorOut, INPUT);// Set frequency scaling to 20%digitalWrite(S0, HIGH);digitalWrite(S1, LOW);// Add pages to serverwebAppsServer.addApp(&homePage);webAppsServer.addApp(&customPage);// Start WiFi and web serverif (!webAppsServer.begin(WIFI_SSID, WIFI_PASSWORD)) {while (1) {Serial.println("Failed to connect to WiFi!");delay(1000); } }Serial.println("Custom WebApp ready!"); customPage.sendToWeb("Arduino is ready!");}voidloop() {// Handle web serverwebAppsServer.loop();// Send sensor data every 1 secondif (millis() - lastColorRead > 1000) {// Read Red colordigitalWrite(S2, LOW);digitalWrite(S3, LOW);int r = map(pulseIn(sensorOut, LOW), 31, 150, 255, 0);// Read Green colordigitalWrite(S2, HIGH);digitalWrite(S3, HIGH);int g = map(pulseIn(sensorOut, LOW), 35, 180, 255, 0);// Read Blue colordigitalWrite(S2, LOW);digitalWrite(S3, HIGH);int b = map(pulseIn(sensorOut, LOW), 30, 150, 255, 0);// Convert to HEX color and send to Webchar hexColor[8]; sprintf(hexColor, "#%02X%02X%02X", constrain(r, 0, 255), constrain(g, 0, 255), constrain(b, 0, 255)); customPage.sendToWeb(String(hexColor));Serial.println("Sent to Minion: " + String(hexColor)); lastColorRead = millis(); }}
CustomWebApp.h
/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-color-sensor-via-web */#ifndef CUSTOM_WEBAPP_H#define CUSTOM_WEBAPP_H#include <DIYablesWebApps.h>/** * Simple Custom WebApp Page * * This is a template for creating your own custom web applications. * It provides basic controls like buttons and sliders that communicate * with your Arduino in real-time. */class CustomWebAppPage : public DIYablesWebAppPageBase {private:// WebSocket message identifier for this custom appstaticconstString APP_IDENTIFIER;public: CustomWebAppPage();// ========================================// REQUIRED METHODS - USED BY LIBRARY - DON'T CHANGE THESE!// ========================================void handleHTTPRequest(IWebClient& client) override;void handleWebSocketMessage(IWebSocket& ws, const char* message, uint16_tlength) override;const char* getPageInfo() constoverride;String getNavigationInfo() constoverride;// ========================================// YOUR METHODS - USE THESE IN YOUR CODE!// ========================================void onCustomMessageReceived(void (*callback)(const String& payload));void sendToWeb(const String& message);};#endif
CustomWebApp.cpp
/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-color-sensor-via-web */#include"CustomWebApp.h"#include"custom_page_html.h"// Define the static member - WebSocket message identifier for this custom appconstString CustomWebAppPage::APP_IDENTIFIER = "Color sensor:";// Callback function for handling messages from web browservoid (*customMessageCallback)(const String& payload) = nullptr;CustomWebAppPage::CustomWebAppPage() : DIYablesWebAppPageBase("/custom") {}void CustomWebAppPage::handleHTTPRequest(IWebClient& client) {// Send the HTML page to web browser sendHTTPHeader(client); client.print(CUSTOM_PAGE_HTML);}void CustomWebAppPage::handleWebSocketMessage(IWebSocket& ws, const char* message, uint16_tlength) {String messageStr = String(message, length);Serial.print("Color sensor WebApp received: ");Serial.println(messageStr);// Only handle messages that start with our app identifierif (messageStr.startsWith(APP_IDENTIFIER)) {String payload = messageStr.substring(APP_IDENTIFIER.length()); // Remove identifier// Call your callback function with the payloadif (customMessageCallback) { customMessageCallback(payload); } }}void CustomWebAppPage::onCustomMessageReceived(void (*callback)(const String& payload)) { customMessageCallback = callback;}void CustomWebAppPage::sendToWeb(const String& message) {// Send message to web browser with app identifierString fullMessage = APP_IDENTIFIER + message; broadcastToAllClients(fullMessage.c_str());}const char* CustomWebAppPage::getPageInfo() const {return"🔧 Color sensor WebApp";}String CustomWebAppPage::getNavigationInfo() const {String result = "<a href=\""; result += getPagePath(); result += "\" class=\"app-card custom\" style=\"background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);\">"; result += "<h3>🔧 Color sensor WebApp</h3>"; result += "<p>Simple template for your own apps</p>"; result += "</a>";return result;}
Run the calibration first using the TCS3200D/TCS230 calibration guide for ESP32. Write down your calibration results (redMin, redMax, greenMin, greenMax, blueMin, blueMax).
Connect the hardware as shown in the wiring diagram above.
Plug the ESP32 board into your computer with a USB cable.
Open the Arduino IDE.
Choose the correct ESP32 board (e.g., ESP32 Dev Module) and the correct COM port.
Go to the Libraries icon on the left sidebar of the Arduino IDE.
Search for "DIYables ESP32 WebApps" and locate the library by DIYables.
Click Install to install it.
When prompted about additional dependencies, click Install All.
Create a new sketch in Arduino IDE and name it ColorSensorESP32.
Copy all 4 files listed above into the project. Your Arduino IDE should show 4 tabs like this:
In ColorSensorESP32.ino, replace the Wi-Fi credentials with your own network details:
Replace the calibration values in the map() calls inside loop() with the numbers you recorded during calibration. For instance, if your calibration produced redMin = 42, redMax = 210, greenMin = 55, greenMax = 185, blueMin = 60, blueMax = 172, update the lines to:
int r = map(pulseIn(sensorOut, LOW), 42, 210, 255, 0);int g = map(pulseIn(sensorOut, LOW), 55, 185, 255, 0);int b = map(pulseIn(sensorOut, LOW), 60, 172, 255, 0);
Click the Upload button to flash the code to the ESP32.
Open the Serial Monitor. You should see something like:
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
Starting Custom WebApp...
Custom WebApp ready!
INFO: Added app /
INFO: Added app /custom
DIYables ESP32 WebApp Library
Network connected!
IP address: 192.168.0.5
HTTP server started on port 80
WebSocket server started on port 81
==========================================
DIYables WebApp Ready!
==========================================
📱 Web Interface: http://192.168.0.5
🔗 WebSocket: ws://192.168.0.5:81
📋 Available Applications:
🏠 Home Page: http://192.168.0.5/
🔧 Color sensor WebApp: http://192.168.0.5/custom
==========================================
Sent to Minion: #FFD200
Sent to Minion: #00C832
Sent to Minion: #0028FF
Ln 11, Col 1
ESP32 Dev Module on COM15
2
If nothing appears, try pressing the reset button on the ESP32.
Copy the IP address shown in the Serial Monitor and open it in a web browser on your phone or computer.
For example: http://192.168.0.5
On the home page, tap the Color sensor WebApp card to open the Minion page.
Alternatively, go directly to http://[IP_ADDRESS]/custom.
You will see the animated laughing Minion on your screen.
Hold a colored object near the TCS3200 sensor — the Minion's skin color will update instantly to reflect the detected color!
You can follow the step-by-step video guide below.
Understanding the Code
ESP32 Side (ColorSensorESP32.ino)
The main sketch performs these tasks:
Sets up the TCS3200 sensor: Configures S0/S1 for 20% frequency scaling and prepares S2/S3 for filter selection.
Samples color once per second: Inside loop(), the ESP32 cycles through the red, green, and blue color filters, measures the pulse width with pulseIn(), and converts each reading to a 0–255 value using map() with your calibration data.
Formats as HEX: The three RGB values are combined into a HEX string (e.g., #FF8000) using sprintf() and constrain().
Broadcasts to browsers: The HEX color is transmitted to every connected web client through customPage.sendToWeb().
Web Page Side (custom_page_html.h)
The HTML file contains:
A CSS-only animated Minion: The character features blinking eyes, a laughing mouth with a wagging tongue, and pupils that move randomly — all powered by CSS animations and a small JavaScript interval.
WebSocket listener: JavaScript opens a persistent connection to the ESP32's WebSocket server on port 81 and processes incoming color messages.
Live color application: Each received HEX color is smoothly applied to the Minion's body, arms, and eyelids using a CSS transition for a fluid visual effect.
Automatic reconnection: If the WebSocket disconnects, the page retries the connection every 2 seconds without user intervention.
Responsive layout: The Minion automatically scales to fit any screen size, from phones to desktops.
Message Protocol
This project follows the DIYables ESP32 WebApps custom app framework. Messages are tagged with the identifier "Color sensor:":
ESP32 sends: Color sensor:#FF8000 (identifier prefix + HEX color value)
Browser receives: JavaScript strips the Color sensor: prefix and applies the remaining #FF8000 to the Minion
Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!