Hi Anish! Project time — and this is the biggest one yet. The Smart Room System combines almost everything we’ve built so far:
- LDR — senses room darkness
- IR remote — for mode switching and manual control
- Sound sensor — clap-to-toggle
- LCD — status display
- LED — the “room light” (stand-in for a real lamp)
- Buzzer — alerts when modes change
Three modes:
- AUTO — LED turns on automatically when the room is dark
- MANUAL — remote controls the LED directly
- CLAP — a clap toggles the LED
This is the kind of thing a working home-automation prototype looks like. By the end, you’ll have built a gadget with four inputs, three outputs, and a coherent user interface. Real engineering.
What you need today #
- Arduino Uno + USB cable
- Breadboard (ideally big, or two breadboards side by side)
- LCD with I2C (Day 15)
- LDR + 10kΩ resistor (Day 9)
- IR receiver (Day 19)
- Sound sensor (Day 20)
- 1 LED + 220Ω resistor
- Buzzer (Day 11)
- Lots of jumper wires
Pin plan #
Write this down or tape it to your breadboard — you’ll thank yourself later.
| Pin | What |
|---|---|
| A0 | LDR (analog) |
| A4 | LCD SDA (I2C) |
| A5 | LCD SCL (I2C) |
| 2 | Sound D0 (digital in) |
| 8 | LED |
| 10 | Buzzer |
| 11 | IR receiver OUT |
Power: 5V and GND rails shared across all modules.
The circuit #
graph TB
subgraph Sensors["Sensors (inputs)"]
PIN_A0["A0 ← LDR"]
PIN_2["Pin 2 ← Sound D0"]
PIN_11["Pin 11 ← IR OUT"]
end
subgraph Actuators["Actuators (outputs)"]
PIN_8["Pin 8 → LED (+220Ω)"]
PIN_10["Pin 10 → Buzzer"]
end
subgraph Display["Display"]
A4["A4 ↔ LCD SDA"]
A5["A5 ↔ LCD SCL"]
end
Wire one module at a time and use a Serial.println after each to sanity-check. “LCD wired — print Hello, works. Now add LDR — read A0, works. Now add IR…” etc. If you try to wire everything at once and it doesn’t work, you won’t know which part broke.
The code #
This is a long one. Read it top to bottom, then we’ll break it down.
|
|
Upload. Initial screen says Mode: AUTO (light). Cover the LDR — LED turns on. Press the remote’s mode button — beep, screen changes to MANUAL (IR). Press volume-up — LED on. Vol-down — off. Press mode button again — beep, CLAP mode. Clap — LED toggles. Cycle again back to AUTO.
What’s worth noticing #
Read the code structure. This is what good Arduino code looks like.
Named constants at the top #
|
|
Instead of writing if (mode == 0) and if (mode == 1) throughout the code, we give names to the mode numbers. Now if (mode == MODE_AUTO) reads like English. Future-you can tell at a glance what the code is checking.
This is how pros handle “magic numbers” — constants with meaningful names.
Forward declarations #
|
|
These are lines that tell Arduino “these functions exist; you’ll see them defined below.” Technically not required if you define your functions before setup() and loop(), but good practice for longer sketches — it’s a clean summary of all the functions in this file, right at the top.
Clean loop()
#
|
|
Four lines. That’s all. Each one is a verb: “handle IR”, “handle light (if auto)”, “handle sound (if clap)”, “update the LED”. If you read this to a human engineer, they’d understand the program in 5 seconds.
This is a huge contrast to an amateur sketch that crams 100 lines of logic into loop(). Break things into functions; your code becomes readable.
updateLED() is the single source of truth
#
Notice how every handler only writes to ledState (the variable), never directly to the LED pin. The actual digitalWrite(LED_PIN, ...) happens in exactly one place: updateLED().
This is a pattern called single source of truth. It means:
- You always know who’s deciding the LED state (whichever handler set
ledStatemost recently) - You don’t have to hunt through the code looking for
digitalWrite(LED_PIN, ...)calls when debugging - If you want to add something like “blink the LED fast instead of steady-on”, you change
updateLED()once and every mode picks it up
As projects get bigger, this pattern saves you from bugs where two different pieces of code fight over the same output.
Reusable helper: beep()
#
|
|
Two lines. Seems pointless — why not just call tone(BUZZ_PIN, freq, duration) directly? Because beep(1500, 100) reads more clearly, AND if I ever change the buzzer pin I only update one spot. Small win, big habit.
Try this #
-
Add a 4th mode: OFF. LED stays off regardless of input. Cycle becomes AUTO → MANUAL → CLAP → OFF → AUTO.
-
Show live light reading on the LCD in AUTO mode (row 0, after “Mode:”). Like a dashboard.
-
Different beep pitches per mode. Each mode change beeps at a different frequency — AUTO beeps at 500 Hz, MANUAL at 1000 Hz, CLAP at 2000 Hz. Use a
switchinsideshowMode():1 2 3 4 5switch (mode) { case MODE_AUTO: beep(500, 100); break; case MODE_MANUAL: beep(1000, 100); break; case MODE_CLAP: beep(2000, 100); break; }switch/caseis a cleaner alternative to a long chain ofif/else if. Thebreakkeyword jumps out of the switch when the case matches. -
Auto-off timer. In CLAP mode, if the LED has been on for 30 seconds and no new claps, turn it off automatically. Use
millis()to track when the LED last turned on.
What you learned today #
- How to architect a multi-input, multi-output project
- Named mode constants (
const int MODE_AUTO = 0;) - Forward declarations for a clean function list at the top
- A tiny, readable
loop()that calls helpers - Single source of truth — one function owns the output
- Simple helpers (like
beep()) improve readability switch / caseas an alternative toelse ifchains (in the challenges)
What is next #
You’ve now completed the sensors and smart control chapter. From here on, it’s about your own ideas. For Days 23-26, we’ll plan, build, debug, and demo a final project you design. No more new components — just combining what you already know into something you thought of yourself.
Day 23 starts with brainstorming. Pick a project that excites you. It can be anything.
Massively great work, Anish. You just built a smart home prototype from a handful of electronic parts.