
ESP32-S3 board
The brain that runs your uploaded sketch.
TinySkiff ESP32-S3 Lab · Day 17 of 30
Every knob and button so far has been something you operated. Today a photoresistor and one fixed resistor turn the room's light into a voltage, the ADC turns that voltage into a number, and the number sets an LED's brightness — cover the sensor with your hand and the lamp answers.
TSK-DAY17-NIGHTLAMP
Hand this to an agent so it can pull the lesson packet and coach you step by step.
01 First, know the pieces
Seven things, one of them new. Tap Define on any part you haven't met — the answer opens as a field note you can read and dismiss without losing your place.

The brain that runs your uploaded sketch.

Spreads the pins into rows you can reach and label.

Today's sensor — its resistance follows the light falling on it.

The lamp itself — it only works one way round.

Sits in series with the LED to keep the current gentle.

Pairs with the photoresistor to turn light into a readable voltage.

Temporary, solder-free connections.
02 Make the physical circuit
The official Freenove diagram is your chart — schematic on top, the same circuit built on a breadboard below. Click it to enlarge. Two small circuits share the board today: the divider that reads the light, and the LED that answers it.
Mind the LED's legs. The LED only lights one way round — long leg toward GPIO 14 through the 220 Ω resistor, short leg to ground. The photoresistor has no polarity, so either leg can face either way. Unplug USB before you move any wire.
03 One action at a time
This is the main path — you can finish the day without opening a single field note. Tap each step as you go to keep your place.
Seat the ESP32-S3 on the GPIO extension board and keep USB unplugged while you wire.
Place the photoresistor on the breadboard — its two legs are interchangeable.
Run the 10 kΩ resistor from the 3.3V rail to one leg of the photoresistor, and take the photoresistor's other leg to GND.
Wire the point where the resistor and the photoresistor meet — the divider's midpoint — to GPIO 1.
Place the LED so its long leg (+) heads toward GPIO 14 and its short leg (−) toward ground.
Put the 220 Ω resistor in series between GPIO 14 and the LED's long leg.
Compare every wire to the chart before you plug in USB.
Open Sketch_11.1_NightLamp.ino in Arduino IDE and upload it.
Cup a hand over the photoresistor, then light it with a phone torch — watch the LED answer each move.
04 Read just enough code
The whole sketch is five working lines. One line in setup attaches the LED pin to a PWM channel; the loop reads the light and maps it straight onto the lamp's brightness. Switch to MicroPython if you'd rather see the same idea in Python — the wiring never changes.
#define PIN_ANALOG_IN 1
#define PIN_LED 14
#define CHAN 0
#define LIGHT_MIN 372
#define LIGHT_MAX 2048
void setup() {
ledcAttachChannel(PIN_LED, 1000, 12, CHAN);
}
void loop() {
int adcVal = analogRead(PIN_ANALOG_IN); //read adc
int pwmVal = map(constrain(adcVal, LIGHT_MIN, LIGHT_MAX), LIGHT_MIN, LIGHT_MAX, 0, 4095); // adcVal re-map to pwmVal
ledcWrite(PIN_LED, pwmVal); // set the pulse width.
delay(10);
}
analogRead(PIN_ANALOG_IN)Reads the divider's midpoint voltage on GPIO 1 as a number from 0 to 4095. constrain(adcVal, LIGHT_MIN, LIGHT_MAX)Fences the reading inside the 372–2048 window before map stretches that window across the full brightness scale — this is where constrain earns its keep. ledcWrite(PIN_LED, pwmVal)Sets the lamp's brightness on GPIO 14 — 0 is dark and 4095 is full. Optional side path · same circuit
pwm =PWM(Pin(14,Pin.OUT),1000)
adc=ADC(Pin(1))
adc.atten(ADC.ATTN_11DB)
adc.width(ADC.WIDTH_12BIT)
adcValue=adc.read()
pwmValue=remap(adcValue,0,4095,0,1023)
pwm.duty(pwmValue)
print(adcValue,pwmValue)
adc.atten(ADC.ATTN_11DB)Widens the ADC's range so it can read the divider all the way up to 3.3V.remap(adcValue,0,4095,0,1023)Stretches the full 12-bit reading onto MicroPython's 10-bit duty scale — the same map idea with different numbers.Same pins, same wiring. This version maps the whole 0–4095 range straight onto a 10-bit duty, so its response curve is gentler than Arduino's constrained window — the idea is identical. Run it in Thonny if MicroPython is set up; otherwise skip it — it should never block the Arduino-first path.
05 Understand, don't memorise
The whole day is one chain of four conversions, each small enough to hold in your head, running many times a second.
The photoresistor's resistance follows the light falling on it.
The 10 kΩ divider turns that resistance into a voltage on GPIO 1.
analogRead measures the voltage as a value from 0 to 4095.
constrain and map squeeze the reading into a PWM level for the LED.
light → resistance → voltage → number → brightness
A room rarely swings the ADC across its whole range. constrain fences the reading inside a realistic window, and map stretches that window over the full 0–4095 brightness scale, so the lamp spends all its range on light levels your room actually produces.
On its own the photoresistor only changes resistance, which a pin can't read directly. Paired with a fixed resistor it forms a divider, and the midpoint voltage rises and falls with the light — exactly the kind of signal the ADC measures.
06 Know it worked
Nothing prints to the screen today — the proof is the lamp answering your hand.
Which direction is which follows how the divider sits on your board — the proof is the slide itself, steady and repeatable each time you cover and light the sensor.
07 Make the idea yours
Same working circuit, two edits to the numbers. It fits inside today's 25 minutes.
Add Serial.begin(115200); to setup and Serial.println(adcVal); to the loop, re-upload, and open Serial Monitor. Note the values at your room's darkest and brightest, then write those into LIGHT_MIN and LIGHT_MAX.
Swap the last two arguments of map so 0 and 4095 trade places, then re-upload. Whatever your lamp did before, it now does in reverse — set it so darkness makes it glow, and you have a true night lamp.
Logbook
08 Learn it with a hand on the tiller
Every lesson ships with a code and a machine-readable packet, so an agent can guide you with full context.
TSK-DAY17-NIGHTLAMP
How the agent should behave: guide one physical connection at a time, wait for you to confirm, explain terms on request, and always check wiring, board, port, and USB before changing code.