Light, distance and motion

TCS34725 colour sensor with ESP32

Colour readings from a TCS34725 mean little unless the light is controlled. Room lighting changes through the day, so the same object reads differently at noon and at night. The module's white LED fixes that when it is the main light: put the sensor at a fixed distance, block stray light with a small tube, and readings repeat. Good for sorting parts by colour or checking a liquid.

The sensor gives four numbers: red, green, blue and clear. They are not ready-made RGB colours for a display. Divide each by the clear value to get ratios, which change less with distance and brightness. Two settings control sensitivity: integration time from 2.4 to 700 ms, and gain of 1, 4, 16 or 60. Too much of either saturates at 65535, and then ratios are useless. A published calibration method starts at gain 1, raises the time until clear saturates, then steps it back. Accuracy also falls below 154 ms, according to ESPHome.

The address is 0x29 and cannot be changed. The LED pin floats by default, and that leaves the LED on. Ground it to turn it off, or drive it from a GPIO so it is lit only while sampling. That keeps it from running all day, and you can take one reading with the LED off and subtract it to remove room light. Boards with a regulator work from 3.3 V or 5 V, while others take 3.3 V only. Dark or shiny targets are hard, so test yours.

TCS34725 colour sensor wiring diagram for ESP32
Wiring diagram drawn by LCD Ultra Pro.

Specifications

OutputsRed, green, blue, clear (16-bit)
Integration time2.4–700 ms
Gain1, 4, 16, 60
I2C address0x29, fixed
LED pinFloating = on, GND = off

Power and logic levels

3.3 V: check your module first

SupplyChip 2.7–3.6 V, only regulated boards take 5 V
Signal level3.3 V
On an ESP32Without a regulator, 5 V can damage the sensor. Run it from 3V3, so the I2C lines stay at 3.3 V.

ESP32 pins, including those on a display board's connectors, work at 3.3 V and are not 5 V tolerant. Modules differ, so if in doubt, measure the signal before you connect it.

Wiring

TCS34725 colour sensorConnect toNote
VIN / VCC3V3
GNDGND
SDAGPIO 8Any free pin, set in Wire.begin()
SCLGPIO 9Any free pin, set in Wire.begin()
LEDGPIO 5Optional, low turns the LED off

Arduino code

#include <Wire.h>

const int SDA_PIN = 8, SCL_PIN = 9;
const uint8_t ADDR = 0x29;
const uint8_t CMD = 0x80, AUTO_INC = 0x20;

void writeReg(uint8_t reg, uint8_t value) {
  Wire.beginTransmission(ADDR);
  Wire.write(CMD | reg); Wire.write(value);
  Wire.endTransmission();
}

uint16_t read16(uint8_t reg) {
  Wire.beginTransmission(ADDR);
  Wire.write(CMD | AUTO_INC | reg);
  Wire.endTransmission();
  Wire.requestFrom(ADDR, (uint8_t)2);
  uint16_t v = Wire.read();
  return v | (Wire.read() << 8);
}

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);
  writeReg(0x00, 0x01);               // power on
  delay(3);
  writeReg(0x00, 0x03);               // ADC on
  writeReg(0x01, 0xC0);               // 64 cycles, about 154 ms
  writeReg(0x0F, 0x01);               // gain 4
}

void loop() {
  delay(200);
  float c = read16(0x14);
  if (c == 0) return;
  Serial.printf("clear %.0f  r %.2f  g %.2f  b %.2f\n", c,
                read16(0x16) / c, read16(0x18) / c, read16(0x1A) / c);
}

No extra library needed. Compiled for ESP32-S3 with arduino-esp32 3.x. Not yet tested by us on a physical sensor. Change the pins to match your board.

On a display

Read the value in your sketch and pass it to a label, or send it over MQTT and show it with an MQTT value in the editor.

Design a display for TCS34725 colour sensor

Boards with a ready connector

Only boards whose connectors we have surveyed. Others may still work on free GPIOs.

Elecrow CrowPanel ESP32 HMI 2.4"I2C port: SDA 22, SCL 21Not shared with the touch controller (it is on SPI) — free for sensors
Elecrow CrowPanel ESP32 HMI 2.8"I2C port: SDA 22, SCL 21Not shared with the touch controller (it is on SPI) — free for sensors
Elecrow CrowPanel ESP32 HMI 3.5"I2C port: SDA 22, SCL 21Not shared with the touch controller (it is on SPI) — free for sensors
Elecrow CrowPanel ESP32-S3 HMI 5.0"I2C port: SDA 19, SCL 20Same I2C bus as the GT911 touch (0x14 / 0x5D) and, on V3.0 boards, the PCA9557 touch-reset expander (0x18)
Elecrow CrowPanel ESP32-S3 HMI 7.0"I2C port: SDA 19, SCL 20Same I2C bus as the GT911 touch (0x14 / 0x5D) and, on V3.0 boards, the PCA9557 touch-reset expander (0x18)
LilyGO T-Display-S3-Pro 2.33"QWIIC RIGHT: SDA 5, SCL 6I2C only — same bus as the touch, the PMU (SY6970) and the light sensor
M5Stack AtomS3 0.85"Bottom I2C pins: SDA 38, SCL 39Same I2C bus as the built-in IMU (MPU6886, 0x68)
Makerfabs MaTouch ESP32-S3 Rotary IPS 2.1 RoundMabee I2C (J1): SDA 17, SCL 18Same I2C bus as the touch controller (CST826)
Makerfabs MaTouch ESP32-S3 Parallel TFT 4.3"Mabee I2C: SDA 17, SCL 18Same I2C bus as the touch controller (GT911)
Makerfabs MaTouch ESP32-S3 Parallel TFT with Touch 5.0"Mabee I2C: SDA 17, SCL 18Same I2C bus as the touch controller (GT911)
Makerfabs MaTouch ESP32-S3 Parallel TFT with Touch 7.0"Mabee I2C: SDA 17, SCL 18Same I2C bus as the touch controller (GT911)
Sunton ESP32-4827S043R/C 4.3"I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18.
Sunton ESP32-8048S043C 4.3"I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18.
Sunton ESP32-8048S050C 5.0"I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18.
Sunton ESP32-8048S070C 7.0"I2C header (P3): SDA 19, SCL 20Same I2C bus as the GT911 touch controller. P3 also carries GPIO 17 / 18.
Waveshare ESP32-S3 Touch LCD 2.1" roundI2C connector: SDA 15, SCL 7Same I2C bus as the touch controller, the IO expander, the RTC and the IMU (addresses 0x15/0x5D, 0x20, 0x51, 0x6B, 0x7E taken)
Waveshare ESP32-S3 Touch LCD 2.8"I2C connector: SDA 11, SCL 10Same I2C bus as the RTC and the IMU (0x51, 0x6B, 0x7E taken) — the touch has its own bus
Waveshare ESP32-S3 Touch LCD 2.8" Type BI2C connector: SDA 15, SCL 7Same I2C bus as the touch controller, the IO expander, the RTC and the IMU (addresses 0x15/0x5D, 0x20, 0x51, 0x6B, 0x7E taken)
Waveshare ESP32-S3-Touch-LCD-2.8CI2C connector: SDA 15, SCL 7Same I2C bus as the touch controller, the IO expander, the RTC and the IMU (addresses 0x15/0x5D, 0x20, 0x51, 0x6B, 0x7E taken)
Waveshare ESP32-S3-LCD-7BI2C connector (H1): SDA 8, SCL 9Same I2C bus as the touch controller (GT911) and the IO expander (CH422G)

Good to know

  • Control the light for repeatable results.
  • Compare ratios, not raw values.
  • Saturation at 65535 ruins a reading.
  • The LED stays on unless you ground it.

What it is good for

  • Colour sorting
  • Liquid and test strip checks
  • Ambient colour tint display

FAQ

Why do colours change during the day?

Room light is getting in. Use a shroud and the LED.

How do I turn off the LED?

Ground the LED pin, or drive it from a GPIO.

Why do all channels read 65535?

It is saturated. Reduce the gain or integration time.

Sources

Related parts

Use this information at your own risk. It is for general guidance only: the example code compiles, but it has not been tested on every part, and modules differ between sellers. Check the manufacturer's data before you build. Product names belong to their owners, and LCD Ultra Pro is not affiliated with them. See our Terms.