Advanced4–6 hours17+4 parts needed

Parent info

Cost: ~$31
Time: 4–6 hours
Age: 17+
Difficulty: ●●●
Soldering: No soldering needed
What they'll learn: Microcontroller programming

Parts you need

Affiliate links — we may earn a small commission

ESP32-S3-DevKitC-1
Sensor Bundle (your choice)
OLED Display 0.96" (I2C)
Breadboard + Jumper Wires
🎮

Try this circuit in your browser!

Run the code, press the buttons and watch what happens — before you buy any parts. No account needed.

Open in Simulator →

No instructions. You are the engineer.

Every other project in this series gave you a problem to solve, a sensor to use, and code to upload. This one is different.

You’re going to design a device that solves a problem YOU chose. The ESP32 is your platform. The sensors are your palette. The code is yours to write (or adapt). The problem is real.

This is what engineers actually do.

Budget: ~$35 | Time: 4–6 hours | Difficulty: ●●●●●


What you’ll need

Part What it does Price
ESP32-S3-DevKitC-1 Your platform for everything ~$12
Sensors (your choice) Chosen based on your problem ~$10
OLED display For your output interface ~$4
Breadboard + wires Prototyping base ~$5

Total: ~$35 approximate | Choose additional components for your specific problem.


Phase 1: Define the problem

Time: ~60 minutes — this is the most important phase

A real engineering project starts with a problem statement, not a solution. The common mistake: “I want to build a device that does X.” Better: “People/things have problem Y, and I think a device could solve it.”

Problem statement template:

“In [context], [person/system] experiences [problem] because [root cause]. A [type of device] could help by [proposed solution].”

Example problem statements:

School context:

  • “In our school library, students don’t know which study rooms are occupied without physically checking. A door sensor + web dashboard could show occupancy on a central display.”
  • “Athletes at our school can’t easily track their hydration during practice. A wearable moisture + time device could remind them to drink at intervals.”

Home context:

  • “My family’s refrigerator is left open accidentally, leading to food waste. A door sensor + alarm could alert within 60 seconds of it being open.”
  • “My elderly grandparent sometimes forgets to take medication. A pill dispenser that sounds an alert at set times could help.”

Environmental context:

  • “The school parking lot has poor visibility for drivers backing out. Ultrasonic distance sensors + LED alerts could warn when a pedestrian is in the blind spot.”
  • “The school greenhouse doesn’t have temperature/humidity monitoring. Sensors + alerts could prevent plant damage.”

Write YOUR problem statement. It must be:

  1. Specific (names the exact context and person)
  2. Real (an actual problem, not hypothetical)
  3. Solvable with ESP32 capabilities
  4. Measurable (how will you know if it worked?)

Phase 2: Map requirements

Time: ~30 minutes

Good engineers write requirements before building. Fill in this table:

Functional requirements (what it MUST do):

# Requirement How you’ll test it
F1
F2
F3

Non-functional requirements (how well it must do it):

# Requirement Target
NF1 Power (battery life or wired?)
NF2 Response time
NF3 Size/portability
NF4 Cost constraint <$35

Example — School room occupancy monitor:

  • F1: Detect whether room door is open or closed (test: open/close 10 times, verify 10/10 correct)
  • F2: Display occupancy on a screen visible from the hallway (test: readable from 2m)
  • F3: Update within 2 seconds of door state change (test: time with stopwatch)
  • NF1: Run on USB power (wired is acceptable for fixed installation)
  • NF2: Response ≤2 seconds
  • NF3: Fits on door frame, <15cm total

Phase 3: Choose your sensors

Sensor reference table — match to your problem:

Sensor Measures Cost Use case
HC-SR04 Distance (2–400cm) $4 Proximity, presence
PIR Motion $3 Occupancy, trigger
DS18B20 Temperature $4 Thermal monitoring
DHT22 Temp + Humidity $5 Environment, comfort
Soil moisture Moisture in substrate $3 Plant watering
Load cell + HX711 Weight/force $8 Dispensing, quantity
Reed switch Magnet/door contact $1 Door open/closed
LDR Light level $1 Presence, daylight
Push button Manual input $1 User control
SG90 servo Physical actuation $3 Movement, dispensing
Buzzer Audio alert $2 Alarm, notification
WS2812B LED Visual indicator $5/strip Status display

Pick 1–3 sensors that address your problem. More sensors = more complexity.


Phase 4: Design the system

Time: ~30 minutes

Draw a system block diagram (on paper is fine):

[INPUT SENSORS] → [ESP32] → [OUTPUTS]
       |              |           |
   DS18B20         Process     OLED Display
   Reed switch     Logic       LED strip
                   WiFi        Buzzer
                   Storage     Web page

Then write your data flow:

  1. What does the ESP32 read, and how often?
  2. What calculation or logic does it perform?
  3. What does it output based on that calculation?

Example — Medication reminder:

  1. Read: DS3231 RTC (real-time clock) every minute
  2. Logic: Compare current time to preset alarm times
  3. Output: If time matches → buzz 3 times, light LED red, log to display

Phase 5: Build the hardware prototype

Time: ~60 minutes

Prototype on breadboard first — never build final until it works.

Universal ESP32 wiring template:

Analog sensors → GPIO1-10 (ADC-capable pins)                     C6: GPIO0-6
Digital sensors → GPIO1-18, GPIO21, GPIO38-47 (most GPIO pins)   C6: GPIO0-7, 9-11, 15, 18-23
I2C devices    → GPIO8 (SDA), GPIO9 (SCL)                        C6: GPIO6 (SDA), GPIO7 (SCL)
SPI devices    → GPIO12 (CLK), GPIO11 (MOSI), GPIO13 (MISO), GPIO10 (CS)
                                                                 C6: GPIO23, 22, 21, 18
Servos/PWM     → GPIO14, 15, 16                                  C6: GPIO5, 4, 3
LEDs           → Any GPIO with 220Ω resistor
Buttons        → Any GPIO with INPUT_PULLUP + connect to GND

Prototype rules:

  • Use female-to-male jumper wires for sensor modules
  • Label each wire with masking tape
  • Test each component individually before combining

Phase 6: Write the code

Time: ~90 minutes

Code architecture template (copy and adapt):

The big picture first. This is a framework — a skeleton you fill in for your specific problem. It shows the correct structure for any ESP32 project:

  • Four separate functions keep the code organized: readSensors (gather data), processLogic (make decisions), updateOutputs (act on those decisions), handleWeb (serve the web page).
  • The loop() function calls them in order, every 100ms — like a heartbeat with four distinct phases.
  • This separation means you can fix one part (e.g., the display) without breaking the sensor reading.

Adapt this skeleton to your specific sensors, outputs, and logic:

// ========== CHOOSE YOUR BOARD ==========
// Uncomment the line for YOUR board:
#define BOARD_S3    // ESP32-S3-DevKitC-1
//#define BOARD_C6  // ESP32-C6-DevKitC-1
// ========================================

#ifdef BOARD_S3
  #define PIN_SDA   8
  #define PIN_SCL   9
#endif
#ifdef BOARD_C6
  #define PIN_SDA   6
  #define PIN_SCL   7
#endif

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASS";

void readSensors() {
}

void processLogic() {
}

void updateOutputs() {
}

void handleWeb() {
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  readSensors();
  processLogic();
  updateOutputs();
  handleWeb();
  delay(100);
}

Line-by-line: what every line does and why

Lines 1–2: Borrowing ready-made tools

#include <WiFi.h>
#include <WebServer.h>

#include means “grab this instruction book.” You will add more #include lines for your specific sensors (e.g., #include <DHT.h> for a temperature sensor). Start with these two if your project needs a web interface.


Lines 4–5: WiFi credentials

const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASS";

const char* means “a piece of text that never changes.” ssid is your WiFi network name, password is the WiFi password. Replace these before uploading. The * (pointer) tells the computer where in memory to find the text.


Lines 7–9: readSensors() — gather data, nothing else

void readSensors() {
}

void means this function gives nothing back — it just does work. Fill this with analogRead(), digitalRead(), or sensor library calls. Store results in global variables (variables declared outside any function, at the top of the file) so other functions can use them. The golden rule: this function only reads. It never makes decisions.


Lines 11–13: processLogic() — make decisions

void processLogic() {
}

This function reads the global sensor variables and decides what to do. Example: “if temperature > 30°C, set alarmActive = true.” It updates state variables but does NOT yet turn on the buzzer — that’s the job of updateOutputs. Keeping decisions separate from actions makes debugging much easier.


Lines 15–17: updateOutputs() — act on decisions

void updateOutputs() {
}

This function looks at the state variables set by processLogic and drives the hardware. Turn on an LED, beep a buzzer, update the OLED display, move a servo. Everything physical happens here.


Lines 19–21: handleWeb() — serve the web page

void handleWeb() {
}

If your project has a web interface, put server.handleClient() here. This must be called repeatedly for the web server to respond to requests. If you don’t need WiFi, leave this empty or delete it.


Lines 23–27: setup() — the morning routine

void setup() {
  Serial.begin(115200);
}

setup() runs once when the ESP32 powers on. Serial.begin(115200) opens the “phone line” to your computer through USB at a speed of 115200 baud. Add your initialization code here: start the WiFi, initialize sensors, configure pin modes. Anything that needs to happen once at startup goes here.


Lines 29–35: loop() — the heartbeat

void loop() {
  readSensors();
  processLogic();
  updateOutputs();
  handleWeb();
  delay(100);
}

loop() runs forever, over and over, as long as the ESP32 has power. The four function calls happen in the right order every 100 milliseconds. delay(100) pauses 100ms between each loop — that’s 10 updates per second. Adjust this number based on how fast your sensor needs to be read (a temperature sensor is fine at 1 update/second; a motion detector might need 50 updates/second).


The whole thing in one sentence

This skeleton enforces a clean pipeline: read sensors → make decisions → drive outputs → serve web, repeating 10 times per second, so each part of your project stays independent and easy to debug.

First thing to try: add Serial.println("loop running"); inside loop() and open Serial Monitor. You should see “loop running” printing 10 times per second. Then add one sensor read and print its value — verify it makes sense before adding any logic or outputs.

Debugging tip: Use Serial.println() to print every important value. Watch Serial Monitor as you develop. Fix one thing at a time.


Phase 7: Test against requirements

Time: ~30 minutes

Go back to your requirements table from Phase 2. Test each one systematically.

Requirement Expected Actual Pass/Fail Notes
F1:
F2:
NF2: Response ≤2s 2s __ s

If something fails: Don’t give up. Debug the specific requirement. Change ONE thing at a time.


Phase 8: Iterate and refine

Time: varies

Real engineering is iterative. First prototype never works perfectly. Common improvements:

  • Accuracy: Average multiple sensor readings, add filtering
  • Responsiveness: Reduce delays, optimize loop timing
  • Reliability: Add error handling for disconnected sensors
  • Usability: Better display layout, clearer labels, intuitive controls

Document what you changed and why.


Phase 9: Present your project

Presentation structure (5–10 minutes):

  1. Problem statement (1 min): What problem did you identify? Why does it matter?
  2. Solution overview (1 min): What does your device do?
  3. Live demo (2–3 min): Show it working. Demonstrate the key functionality.
  4. How it works (1–2 min): Explain the sensors, the logic, the code structure.
  5. Requirements review (1 min): What requirements did you meet? Which didn’t you meet, and why?
  6. What you’d do differently (1 min): Engineering reflection.

The strongest capstone presentations answer: “Why does this matter? Who benefits? What would it take to make this a real product?”

Presentation tip: If your device fails during the demo (it happens to everyone), don’t panic. Say: “The device isn’t responding right now, which gives me a chance to walk you through what should happen and what I think is causing the failure.” Engineers debug in public. That’s a skill too.


What just happened

You went through the engineering design process:

  1. Define the problem
  2. Research requirements
  3. Design a solution
  4. Prototype
  5. Test
  6. Iterate

This is exactly what engineers at Apple, Tesla, and NASA do — at much larger scale with more constraints. The process is identical.

The ESP32 gives you a professional-grade platform: 240MHz dual-core processor, WiFi, Bluetooth, 12-bit ADC, I2C/SPI/UART — hardware that was enterprise-level 10 years ago. You used it to solve a real problem. That’s what engineers do.

Curriculum connections:

  • NGSS HS-ETS1-1: Analyze a major global challenge to specify qualitative and quantitative criteria and constraints for solutions
  • NGSS HS-ETS1-2: Design a solution to a complex real-world problem by breaking it into smaller, manageable problems
  • NGSS HS-ETS1-3: Evaluate a solution to a complex real-world problem based on prioritized criteria and trade-offs
  • NGSS HS-ETS1-4: Use a computer simulation to model the impact of proposed solutions

AP Computer Science Principles covers the same concepts computationally — but you built something physical. The code you wrote controls atoms in the real world, not just pixels on a screen.


Capstone checklist

Before you present, confirm you have:

  • Written problem statement (specific, real, measurable)
  • Requirements table with pass/fail results
  • Working hardware prototype (or a documented failure with analysis)
  • Code with comments explaining each section
  • System block diagram (even hand-drawn)
  • Test results table
  • “What I’d do differently” section
  • Estimate: what would it cost to manufacture 100 of these?

Ideas if you’re stuck

If nothing comes to mind, try these domains:

School: Room temperature logger, cafeteria loudness monitor, bathroom occupancy indicator, water bottle reminder bracelet

Sports: Heart rate logger for training, jump height measurer (accelerometer), pitch count tracker (baseball)

Home: Plant watering reminder, window open/rain detector, mailbox letter notifier, energy usage monitor

Accessibility: Blind spot alert for wheelchair, pill reminder dispenser, loud alarm for hearing-impaired

Environmental: School garden monitor, local air quality tracker, light pollution measurer

Pick the one you’d actually use. The best capstone projects solve problems their builders actually have.


Troubleshooting the design process

Problem Fix
“I don’t know what to build” Ask: “What’s something I do every day that wastes time or causes frustration?” That’s usually a solvable problem.
“My sensor doesn’t work” Isolate it. Build the minimal sketch: just read that one sensor, print to Serial. Everything else off.
“My code is a mess” Refactor using the loop() structure above: readSensors(), processLogic(), updateOutputs(). Separation of concerns.
“It works on my desk but not in real use” Power issue (USB vs. battery), sensor placement, environmental interference. Test in the real environment.
“I ran out of time” Present your partial prototype honestly. Explain what works, what doesn’t, and what you’d need to finish it. That’s professional.
Affiliate disclosure: Some links on this page are affiliate links. If you buy through them, we may earn a small commission at no extra cost to you.