On this page
What you are building
You build one device: an ESP32 sensor node on a breadboard. It reads four inputs, decides what to do using a timer or a threshold, drives an output, and reports what it sees to the network you built in Module 01.
Every part of the build follows the same loop: input, decide, output. A switch or a sensor is the input. The microcontroller decides. A light, a relay, or a message on the network is the output. You learn each piece on its own, then wire them into the loop.
The kit is small, and most of it is cheap or salvaged: an ESP32 board, a breadboard and jumper wires, four sensors (motion, magnetic, temperature, light), a few output parts (an LED, a transistor, a relay), and a resistor assortment. Each unit names the exact part as you reach it.
Electricity
Three quantities describe everything in the circuit. Voltage is the push, measured in volts. Current is the flow, measured in amps. Resistance is how much the path holds the flow back, measured in ohms. The water analogy holds: voltage is pressure, current is the flow rate, resistance is a narrow pipe.
One formula ties them together, Ohm's law: V = I × R. Rearranged, current is I = V / R and resistance is R = V / I. That is most of the math you need.
A worked example you will use in the build: you want about 20 milliamps through an LED on the 3.3 volt supply. The LED itself drops roughly 2 volts, which leaves 1.3 volts across the resistor. R = V / I = 1.3 / 0.02 = 65 ohms, so you reach for the nearest common value, 68 or 100 ohms.
The other formula is power, P = V × I, in watts. It matters because every part carries a power rating, and a part run past its rating heats up and fails. A quarter-watt resistor cannot carry whole watts.
The circuit, and how it is drawn
A circuit is a complete loop: current leaves a pin or the supply, runs through the parts, and returns to ground. Break the loop anywhere and the flow stops. You will meet that loop drawn three ways in this module, and you read all three. First, the symbols they use.
Here is one real circuit, a GPIO driving an LED through a resistor to ground, drawn all three ways. They say exactly the same thing.
| From | To |
|---|---|
| GPIO5 | resistor, end A |
| resistor, end B | LED, long leg + |
| LED, short leg − | GND |
The switch
A switch is the simplest thing in electronics: it completes a circuit or breaks it. Closed, current flows; open, it stops. A push button is a switch you hold down. A reed switch is one a magnet closes. A sensor, as the next unit shows, is a switch the world closes for you.
The ESP32 reads a switch on a GPIO pin (general-purpose input/output). The pin reads HIGH (near 3.3 volts) or LOW (near 0). The trap is a pin connected to nothing: it floats and reads random noise. You fix that with a pull resistor. A pull-down ties the pin to ground so it rests LOW until the switch pulls it HIGH; a pull-up does the reverse. The ESP32 has built-in pull-ups you turn on in code with INPUT_PULLUP.
One more real-world catch: a mechanical switch does not close cleanly. The contacts bounce for a few milliseconds, so a single press can read as several. You debounce it, either in code by ignoring further changes for a short window, or in hardware with a small capacitor.
Reading the world
A sensor is an automatic switch. Some are exactly that: a PIR closes when it sees motion, a reed switch closes near a magnet. The ESP32 reads those as digital, HIGH or LOW, the same way it reads a button.
Others do not snap on and off; they slide. A photoresistor's resistance falls as the light rises; a thermistor's changes with heat. These are analog: a voltage somewhere between 0 and 3.3 volts. The ESP32 reads them with its ADC (analog-to-digital converter), which turns that voltage into a number from 0 to 4095.
Two limits decide how you wire every sensor, and getting them wrong is the most common beginner failure:
Identify your hardware
This is the whole kit. Most of it is cheap or salvaged, and the few parts where the exact one matters are marked. The board is the one piece to buy deliberately: this build assumes an ESP32-S3-DevKitC-1 carrying the N16R8 module, and the pin numbers and the unusable pins below are specific to it.
The breadboard, the jumper wires, and the resistor assortment carry across every later unit; each sensor unit names its own part as you reach it. Before wiring anything, learn the board: click each pin to see its job, and the few to leave alone.
Set up the Arduino IDE
Install the Arduino IDE, add ESP32 board support, select your board and port, and flash the Blink example. Blink uses the onboard LED, so it proves the toolchain end to end before you wire anything. Open the serial monitor at 115200 baud.
Power and the breadboard
You learn how the breadboard rows and power rails connect, and how to power the ESP32 safely from USB or a supply. Most first faults live here: the wrong rail, reversed power, or a short.
Button and LED
Wire a push button as an input and an LED as an output: press the button, the LED lights. This is the whole loop at its simplest, and where you handle debounce in code.
| From | To | Why |
|---|---|---|
| GPIO5 | resistor, end A | drives the LED |
| resistor, end B | LED long leg + | limits current |
| LED short leg − | − rail (GND) | completes the loop |
| GPIO4 | button terminal A | the input pin |
| button terminal B | − rail (GND) | a press pulls GPIO4 low |
INPUT_PULLUP ties GPIO4 to 3.3 V through an internal ~45k resistor, so an open button reads HIGH and a press (straight to ground) reads LOW, drawing only 3.3 V ÷ 45k ≈ 73 µA. Use plain INPUT and the open pin floats, reading noise.Drive a real load
An LED draws little; a GPIO pin can source only a small current, roughly 20 milliamps in safe use and about 40 at its absolute limit. To switch a relay, a lamp, or a buzzer, you drive a transistor or MOSFET from the pin, and put a flyback diode across a relay coil.
| From | To | Why |
|---|---|---|
| GPIO5 | 1k resistor → transistor base | a tiny base current |
| transistor emitter | − rail (GND) | low-side switch |
| transistor collector | relay coil pin 1 | switches the coil |
| relay coil pin 2 | +5V rail | coil runs on 5V, not 3.3 |
| flyback diode (band to +5V) | across the coil | absorbs the turn-off spike |
Add a timer
You make the output hold after the input, keeping the LED or relay on for a set time, three ways: the RC time constant, the 555 timer, and the ESP32's own millis(). That completes a working input-decide-output loop before you add a single sensor.
| Way to make a delay | Needs | Trade-off |
|---|---|---|
| RC time constant | a resistor + a capacitor | simple, but approximate and fixed |
| 555 timer | the 555 chip + R + C | a dedicated timer, no code |
| millis() (this build) | nothing, code only | exact, adjustable, never blocks |
millis() instead: it reads the ESP32's running clock, so the hold time costs no parts, is exact, and can change in code. Paired with the non-blocking pattern from the firmware unit, it never freezes the loop the way delay() would.Motion
Replace the button with a PIR motion sensor (HC-SR501), an automatic switch that closes when it detects movement. Wire it, read its output, and set its warm-up and retrigger behavior.
| From | To | Why |
|---|---|---|
| HC-SR501 VCC | +5V rail | the module needs 5V |
| HC-SR501 OUT (middle) | GPIO4 | digital input, HIGH on motion |
| HC-SR501 GND | − rail (GND) | ground |
Magnetic
Add a reed or hall sensor, a switch a magnet closes. Wire it to watch a door or a drawer, and read it the same way you read the button.
| From | To | Why |
|---|---|---|
| GPIO4 | reed switch, end A | the input pin |
| reed switch, end B | − rail (GND) | a magnet pulls GPIO4 low |
INPUT_PULLUP so it idles HIGH, and a closed reed pulls it to ground and reads LOW. No external resistor, the chip supplies the pull-up. It is non-polar, so either leg can go to the pin. Mount the reed on the frame and the magnet on the door or lid: together they sit closed, apart they open, so the pin tells you whether the door is shut.Light
This is your first analog read. A photoresistor in a voltage divider gives the ESP32 a voltage that changes with light, which you read on an ADC1 pin: not on or off, but how much.
| From | To | Why |
|---|---|---|
| 3V3 rail | LDR, end A | top of the divider |
| LDR, end B | 10k resistor, end A (midpoint) | the sensed node |
| midpoint | GPIO1 (ADC1) | the ADC reads this voltage |
| 10k resistor, end B | − rail (GND) | bottom of the divider |
analogRead() swings with the light. Pick the fixed resistor near the LDR's mid-range so the swing lands in a useful part of the scale.Temperature
Read heat two ways: a thermistor on the analog divider, or a DS18B20 over the 1-Wire bus. Pick the one whose interface you will reuse most.
| From | To | Why |
|---|---|---|
| DS18B20 VDD | 3V3 rail | power |
| DS18B20 GND | − rail (GND) | ground |
| DS18B20 DQ | GPIO4 | the 1-Wire data line |
| 4.7k resistor | DQ ↔ 3V3 | pull-up: holds the line HIGH |
-127 (its disconnected value) or finds no device at all. Use a real pull-up, not INPUT_PULLUP; the internal pull-up is too weak for the 1-Wire timing. The TO-92 pin order (GND–DQ–VDD shown) varies by maker, and reversing VDD and GND can cook the part, so confirm the printing on your sensor before powering up.Put it on the network
Connect the node to WiFi and tie it into the network from Module 01. It reports readings and alerts to your server, takes commands so you can control its output from your server, and updates over the air so you can reprogram it without a cable.
Verify and own it
Run the whole node: it senses, decides, acts, and reports.
Before you call it finished, build it once from a brief, with no walkthrough. Make every decision yourself.
You own one more thing too: reading a symptom back to its cause. Work through the faults that catch everyone before you meet them on the bench.
Then the honest part: it works on a breadboard, but it is not deployable as is. Soldering makes it permanent, CAD prints its enclosure, and Salvage sources its parts. Those are the next skills.
Glossary
Plain definitions for every term, as it is used in this build.
- 1-Wire
- A one-data-line bus, plus power and ground, used by the DS18B20 temperature sensor. The data line needs a 4.7k pull-up resistor.
- 555 timer
- A small timer chip that makes a fixed delay or a steady pulse from one resistor and one capacitor, with no code. One of three ways this module holds an output on after a trigger; the others are the RC time constant and the ESP32's millis().
- ADC
- Analog-to-digital converter. Turns a voltage between 0 and 3.3 volts into a number from 0 to 4095, so the ESP32 can read an analog sensor. Use ADC1 (GPIO 1 to 10); ADC2 stops working with WiFi on.
- debounce
- Ignoring the few milliseconds of contact bounce after a switch closes, so one press reads as one press, not several. Done in code or with a small capacitor.
- duty cycle
- The fraction of time a signal is on. A part driven at 30 percent duty cycle is on for 30 percent of each period; used to dim or slow without changing the voltage.
- flyback diode
- A diode across a relay or motor coil that absorbs the voltage spike when the coil switches off. Without it, that spike can destroy the transistor driving the coil.
- GPIO
- General-purpose input/output. A pin you can read (input) or drive (output) in code. The ESP32's GPIO is 3.3 volt logic.
- Hall sensor
- A magnetic sensor, like a reed switch but solid-state: no moving contact, it reports a nearby magnet electronically. Used the same way as a reed switch to tell whether a door or lid is open.
- level shifter
- A small circuit that translates a signal between two voltages, for example a 5 volt sensor output down to the 3.3 volts the ESP32 can safely read. Needed whenever a part's output swings above 3.3 volts.
- MOSFET
- A transistor used as an electronic switch. A small voltage on its gate lets a much larger current flow, so a 3.3 volt pin can switch a relay, a lamp, or a motor.
- OTA
- Over-the-air update. Reflashing the ESP32's firmware over WiFi instead of with a cable.
- PIR
- Passive infrared sensor. Detects motion from the infrared a warm body gives off, and outputs a digital HIGH when it triggers. The HC-SR501 is the common part.
- pull-up / pull-down
- A resistor that ties an input pin to a known state, high or low, so it does not float and read noise. The ESP32 has built-in pull-ups (INPUT_PULLUP).
- reed switch
- A switch that closes when a magnet is near. Read as a digital input, the same as a button; used to tell whether a door or lid is open.
- thermistor
- A resistor whose resistance changes with temperature. Read as an analog value through a voltage divider.
- TO-92
- The small black half-cylinder plastic package with three legs in a row, used by the 2N2222 transistor and the DS18B20 sensor. The flat printed face is the reference for which leg is which.
- transistor
- A part that switches or amplifies: a small current or voltage on one leg controls a much larger current through the other two, so a 3.3 volt pin can switch a load it could never drive directly. The 2N2222 (an NPN bipolar transistor) is this module's part; a MOSFET does the same job with a voltage on its gate.
- voltage divider
- Two resistors in series that split a voltage. With a sensor (a photoresistor or thermistor) as one of them, the middle voltage tracks the sensor and the ADC reads it.