Chameleon Lamp

by liuqianmama1204 in Circuits > Arduino

16 Views, 0 Favorites, 0 Comments

Chameleon Lamp

22.jpg

Chameleon Lamp.sensor reads the RGB color dataand LED strip emits color.

EZ, safe and secure.Good for babies' growth.Little naive for teens.

Supplies

111.jpg

Key Components

1.**Rechargeable 5V Power Supply**

2.**ESP32-S3 Development Board**

3.**TCS34725 Color Sensor** (pins bent to the back side)

4.**WS2812B LED Strip** (60 LEDs, 5V)

5.**Switch** (Dupont wire version)

6.**Three types of Dupont wires**

7.**Electrical tape, scissors** (need to understand the wire twisting and splicing technique)


**Optional:**

***For soldering experts**: Soldering wire, soldering iron.

***For soldering beginners**: DO NOT TRY.Be aware of the dangers.


---


### 5V Power Supply Options

**Option 1 (Requires soldering/basic wiring):**

*Two 18650 batteries

*MT3608 Boost Converter Module (requires a flathead screwdriver to adjust voltage)

*TP4056 Charging Module

*Multimeter


**Option 2 (No soldering required):**

* All-in-one 5V rechargeable battery pack (power bank style)

The Power

112.jpg

- **If using an all-in-one battery pack:**

Red wire → switch pin 1

Black wire → ESP32 GND

- **If using the 3-module (battery + charger + booster) setup:**

Battery red → charger module B+

Charger module OUT+ → booster module VIN+

Booster module OUT+ → switch pin A

Battery black → charger module B-

Charger module OUT- → booster module VIN-

Booster module OUT- → ESP32 GND

*Use a flathead screwdriver and multimeter to adjust booster output to 5V.*


**Note:** Keep the switch OFF. Ask the switch manufacturer which side is OFF.

soldering, wiring, Dupont connectors omitted as discussed. Repeated info blanked a bit.

Circuit Connection

564e6b4f42815161e2eb6fe459397f13.jpg

2. ESP32 Section:**

5V → switch pin B

GND → LED strip GND (black/white wire)

GND → power supply (-)

GND → sensor GND

3V3 → sensor VIN

13 → LED strip DIN (green wire)

16 → sensor SDA

17 → sensor SCL

Pins 2 & 4 → connect Dupont wires (expose male pins for touch)


**3. Sensor:**

VIN → board 3V3

GND → board GND

SDA/SCL → board pins 16/17


**4. LED Strip (pay attention to arrow direction):**

Red → switch pin B

Green → board pin 13

White → board GND

Enclosure

b4e90336efe2caabe7831553f8ad170b.jpg

**Enclosure — ensure the following are exposed:**


0. Switch

1. Sensor (facing outward)

2. ESP32 — COM port

3. Battery charging port

*(Only use 5V slow charging!)*

4. ESP32 touch jumpers on pins 2 and 4

Code

b5c08fe29c654e71741cd2b0afe45e62.jpg



**Key points:**


1. **Touch sensor (jumper wire)**

- Capacitance increases when touched.

- Take 50 baseline capacitance readings, discard the highest and lowest 10, calculate the average 、

- Capacitance > avg + 10000 → considered touched.


2. **Color sensor**

- The built-in light source is slightly orange‑red, so G and B values need extra gain.


3. **Color mapping**

- I use a mapping function that only outputs **12 saturated colors**.

- Can be modified if needed.


4. **Behavior**

- Automatically reads the color and updates the LED strip **every 10 seconds**.

- **Jumper on pin 2** → changes mode.

- **Jumper on pin 4** → triggers an immediate color reading and update.


as follows:::



#include <Wire.h>

#include "Adafruit_TCS34725.h"

#include <FastLED.h>


#define LED_PIN 13

#define TOUCH_PIN 4

#define BTN_PIN 2

#define NUM_LEDS 60

#define BRIGHTNESS 120


Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);

CRGB leds[NUM_LEDS];

CRGB currentColor = CRGB::White;

int currentMode = 0;


int base4 = 0, base2 = 0;

unsigned long lastAutoUpdate = 0;


int readStableTouch(int pin) {

int readings[50];

for (int i = 0; i < 50; i++) {

readings[i] = touchRead(pin);

delay(10);

}

for (int i = 0; i < 49; i++) {

for (int j = i + 1; j < 50; j++) {

if (readings[i] > readings[j]) {

int temp = readings[i];

readings[i] = readings[j];

readings[j] = temp;

}

}

}

long sum = 0;

for (int i = 10; i < 40; i++) sum += readings[i];

return sum / 30;

}


void setup() {

Serial.begin(115200);

delay(100);

Serial.println("Chameleon Lamp Starting...");


Wire.begin(16, 17);

FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);

FastLED.setBrightness(BRIGHTNESS);


fill_solid(leds, NUM_LEDS, CRGB::White);

FastLED.show();

delay(500);

fill_solid(leds, NUM_LEDS, CRGB::Black);

FastLED.show();


if (!tcs.begin()) {

Serial.println("Sensor ERROR!");

while (1) delay(1000);

}

Serial.println("Sensor OK");


base4 = readStableTouch(TOUCH_PIN);

base2 = readStableTouch(BTN_PIN);

Serial.print("Base4="); Serial.print(base4);

Serial.print(" Base2="); Serial.println(base2);


updateColor();

currentMode = 0;

fill_solid(leds, NUM_LEDS, currentColor);

FastLED.show();

}


void loop() {

int val4 = touchRead(TOUCH_PIN);

int val2 = touchRead(BTN_PIN);


bool touch4 = (val4 > base4 + 8000);

bool touch2 = (val2 > base2 + 8000);


static bool last4 = false, last2 = false;


if (touch4 && !last4) {

Serial.println("Touch GPIO4");

updateColor();

if (currentMode == 0) {

fill_solid(leds, NUM_LEDS, currentColor);

FastLED.show();

}

delay(200);

}

last4 = touch4;


if (touch2 && !last2) {

Serial.println("Touch GPIO2");

currentMode = (currentMode + 1) % 3;

Serial.print("Mode="); Serial.println(currentMode);

delay(200);

}

last2 = touch2;


if (millis() - lastAutoUpdate > 10000) {

lastAutoUpdate = millis();

updateColor();

if (currentMode == 0) {

fill_solid(leds, NUM_LEDS, currentColor);

FastLED.show();

}

}


runAnimations();

FastLED.show();

delay(20);

}


void updateColor() {

uint16_t r, g, b, c;

tcs.getRawData(&r, &g, &b, &c);

currentColor = mapTo12Color(r, g, b);

Serial.print("Color: R="); Serial.print(currentColor.r);

Serial.print(" G="); Serial.print(currentColor.g);

Serial.print(" B="); Serial.println(currentColor.b);

}


CRGB mapTo12Color(uint16_t r_raw, uint16_t g_raw, uint16_t b_raw) {

float r = r_raw * 1.0;

float g = g_raw * 1.6;

float b = b_raw * 2.1;

float maxVal = max(r, max(g, b));

if (maxVal > 0) { r = r / maxVal * 220; g = g / maxVal * 220; b = b / maxVal * 220; }

float rf = r / 220.0, gf = g / 220.0, bf = b / 220.0;

float maxRGB = max(rf, max(gf, bf)), minRGB = min(rf, min(gf, bf));

float delta = maxRGB - minRGB;

if (delta < 0.05) return CRGB(220, 220, 220);

float hue = 0;

if (maxRGB == rf) hue = 60 * fmod(((gf - bf) / delta), 6);

else if (maxRGB == gf) hue = 60 * (((bf - rf) / delta) + 2);

else hue = 60 * (((rf - gf) / delta) + 4);

if (hue < 0) hue += 360;

int idx = ((int)(hue / 30)) % 12;

CRGB colors[12] = {

CRGB(220, 0, 0), CRGB(220, 110, 0), CRGB(220, 220, 0),

CRGB(110, 220, 0), CRGB(0, 220, 0), CRGB(0, 220, 110),

CRGB(0, 220, 220), CRGB(0, 110, 220), CRGB(0, 0, 220),

CRGB(110, 0, 220), CRGB(220, 0, 220), CRGB(220, 0, 110)

};

return colors[idx];

}


void runAnimations() {

switch (currentMode) {

case 0: break;

case 1:

{ static unsigned long last = 0; static bool on = true;

if (millis() - last > 200) { last = millis(); on = !on;

if (on) fill_solid(leds, NUM_LEDS, currentColor);

else fill_solid(leds, NUM_LEDS, CRGB::Black); } }

break;

case 2:

{ static unsigned long last = 0; static int step = 0;

if (millis() - last > 100) { last = millis();

if (step < 3) fill_solid(leds, NUM_LEDS, currentColor);

else if (step < 4) fill_solid(leds, NUM_LEDS, CRGB::Black);

else if (step < 7) fill_solid(leds, NUM_LEDS, currentColor);

else if (step < 8) fill_solid(leds, NUM_LEDS, CRGB::Black);

else if (step < 11) fill_solid(leds, NUM_LEDS, currentColor);

else fill_solid(leds, NUM_LEDS, CRGB::Black);

step++; if (step >= 12) { step = 0; delay(500); } } }

break;

}

}