Stop Buying Random Arduino Modules: A Practical Kit for Interactive Devices
The biggest mistake beginners make when starting interactive device projects: buying modules without understanding the interaction pattern behind them. You end up with a drawer full of sensors that each do one thing — and no framework for combining them into something that actually responds to the world.
This guide fixes that. Instead of listing modules by name, we categorize them by interaction pattern — the complete chain from detecting something in the environment to producing an output a human can perceive. Each pattern includes the specific modules that make it work, real code you can copy, and the buying links so you get the right parts the first time.
Affiliate disclosure: As an Amazon Associate, I earn from qualifying purchases.
The Five Interaction Patterns You Need
Before buying anything, understand these five patterns. Every interactive Arduino project is some combination of them:
1. Proximity/Distance → Visual Feedback (HC-SR04 / HC-SR501)
2. Environmental Condition → Scheduled Response (DHT22 / BH1750)
3. Touch/Contact → Physical Action ( capacitive soil moisture / force sensor)
4. Vibration/Shock → Alert Output (SW-420)
5. Light Level → Continuous Adjustment (photoresistor / relay)
These five patterns cover 80% of what you actually need for interactive projects. Everything else is a variation.
What a Complete Interactive System Looks Like
Every working interactive device has the same three-part structure:
- Input: A sensor that reads something from the physical world
- Controller: Arduino/ESP32 that processes the reading and decides what to do
- Output: An actuator that produces a perceivable change (light, sound, motion)
[Sensor] → [Arduino] → [Actuator]
INPUT PROCESS OUTPUT
The mistake most beginners make is buying the actuator first (because it looks cool) and then trying to figure out what sensor could possibly connect to it. We do it in the right order: start with the interaction pattern, pick the right sensor, then connect it to whatever output makes sense.
Pattern 1: Proximity Detection → Visual Feedback
Use case: Something detects your presence and responds with light
This is the most common pattern. A distance sensor notices you're there, and the Arduino triggers an LED, a display, or a motor.
The Modules
HC-SR04 ultrasonic sensor — measures distance by sending a 40kHz sound pulse and timing how long until the echo returns. Range: 2cm to 400cm. Works on any surface (unlike IR which struggles with black surfaces). Consumes about 15mA during measurement.
HC-SR501 PIR motion sensor — detects infrared radiation changes (body heat) in a room. Returns digital HIGH/LOW, no distance reading, but uses almost no power and works through non-glass obstacles. Range: up to 7 meters, 120° detection angle.
Project: Smart Trash Can
You approach the trash can. The HC-SR04 detects your hand at 15cm. Arduino triggers a servo to open the lid. You drop your trash. The lid closes after 3 seconds.
#include <NewPing.h>
#include <Servo.h>
#define TRIG_PIN 7
#define ECHO_PIN 6
#define SERVO_PIN 9
#define OPEN_DIST 15 // cm — hand detected
#define CLOSE_DELAY 3000 // ms
NewPing sonar(TRIG_PIN, ECHO_PIN, 400);
Servo lidServo;
bool isOpen = false;
unsigned long closeTime = 0;
void setup() {
Serial.begin(115200);
lidServo.attach(SERVO_PIN);
lidServo.write(0); // closed
}
void loop() {
int distance = sonar.ping_cm();
if (!isOpen && distance > 0 && distance < OPEN_DIST) {
lidServo.write(90); // open
isOpen = true;
closeTime = millis() + CLOSE_DELAY;
Serial.println("Lid opened");
}
if (isOpen && millis() > closeTime) {
lidServo.write(0); // close
isOpen = false;
Serial.println("Lid closed");
}
delay(50);
}
The Electronics
HC-SR04 VCC → Arduino 5V
HC-SR04 GND → Arduino GND
HC-SR04 TRIG → Arduino pin 7
HC-SR04 ECHO → Arduino pin 6 (through 1kΩ resistor)
HC-SR501 VCC → Arduino 5V
HC-SR501 OUT → Arduino pin 2
HC-SR501 GND → Arduino GND
Servo Brown → Arduino GND
Servo Red → Arduino 5V (or external 5V if servo is large)
Servo Orange → Arduino pin 9
Testing the HC-SR04
// Standalone test — paste into Arduino IDE
#include <NewPing.h>
#define TRIG_PIN 7
#define ECHO_PIN 6
NewPing sonar(TRIG_PIN, ECHO_PIN, 400);
void setup() { Serial.begin(115200); }
void loop() {
delay(500);
Serial.print("Distance: ");
Serial.print(sonar.ping_cm());
Serial.println(" cm");
}
Open Serial Monitor at 115200 baud. Hold your hand in front of the sensor. You should see distance readings updating every 500ms. If you get 0, the object is either too close (<2cm) or too far (>400cm) or at an angle the sound can't bounce back from.
Pattern 2: Environmental Condition → Scheduled Response
Use case: The system reads temperature, humidity, or light level and responds based on schedule or threshold
This pattern is about monitoring the environment continuously and triggering outputs at specific times or when conditions exceed limits. Unlike proximity detection (which cares about instant presence), environmental monitoring cares about trends and thresholds.
The Modules
DHT22 temperature and humidity sensor — reads both temperature (0-50°C ±0.5°C) and relative humidity (0-100% ±2%). Slower response time (2 seconds per reading) so it's not suitable for fast events, but it's the standard for room-level monitoring. Uses a single-wire protocol that requires a library.
BH1750 light intensity sensor — measures ambient light in lux (0-65535 lux). More accurate than a simple photoresistor because it gives actual lux readings you can compare against known thresholds (home environments: 50-500 lux, offices: 300-1000 lux). I2C interface, which means you can stack it with other I2C devices.
Project: Wake-Up Light System
At 6:00 AM, the DHT22 checks if room temperature is below 18°C. If so, the BH1750 starts gradually increasing LED brightness over 30 minutes to simulate sunrise, compensating for the cold by using warmer light earlier. The LED strip is connected through a relay module.
#include <Wire.h>
#include <BH1750.h>
#include <DHT.h>
#include <RTClib.h>
#define RELAY_PIN 8
#define LED_PIN 9 // PWM pin for MOSFET
#define DHT_PIN 4
#define WAKE_HOUR 6
#define WAKE_MIN 0
#define TEMP_THRESHOLD 18 // °C — cold morning threshold
BH1750 lightMeter;
DHT dht(DHT_PIN, DHT22);
RTC_DS3231 rtc;
int targetLux = 0; // 0-65535
int currentLux = 0;
void setup() {
Serial.begin(115200);
Wire.begin();
lightMeter.begin();
dht.begin();
rtc.begin();
// Uncomment to set RTC time (run once, then comment out):
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW); // relay off initially
}
void loop() {
DateTime now = rtc.now();
float temp = dht.readTemperature();
float hum = dht.readHumidity();
currentLux = lightMeter.readLightLevel();
Serial.print("Time: ");
Serial.print(now.hour());
Serial.print(":");
Serial.println(now.minute());
Serial.print("Temp: ");
Serial.print(temp);
Serial.print("°C | Humidity: ");
Serial.print(hum);
Serial.println("%");
Serial.print("Light: ");
Serial.print(currentLux);
Serial.println(" lux");
// Check if it's wake time
if (now.hour() == WAKE_HOUR && now.minute() == WAKE_MIN) {
int warmupMinutes = (temp < TEMP_THRESHOLD) ? 45 : 30;
int warmupSeconds = warmupMinutes * 60;
int targetBrightness = map(millis() % warmupSeconds, 0, warmupSeconds, 0, 255);
analogWrite(LED_PIN, targetBrightness);
digitalWrite(RELAY_PIN, HIGH); // LED strip on
Serial.print("Wake light active, brightness: ");
Serial.println(targetBrightness);
} else {
analogWrite(LED_PIN, 0);
digitalWrite(RELAY_PIN, LOW);
}
delay(60000); // Check every minute
}
The Electronics
DHT22 VCC → Arduino 3.3V or 5V
DHT22 DATA → Arduino pin 4
DHT22 GND → Arduino GND
BH1750 VCC → Arduino 3.3V
BH1750 GND → Arduino GND
BH1750 SDA → Arduino A4 (SDA)
BH1750 SCL → Arduino A5 (SCL)
Relay VCC → Arduino 5V
Relay IN → Arduino pin 8
Relay GND → Arduino GND
LED strip + → external 12V power (shared ground with Arduino)
LED strip - → MOSFET drain → MOSFET source → GND
Testing the BH1750 Separately
#include <Wire.h>
#include <BH1750.h>
BH1750 lightMeter;
void setup() {
Serial.begin(115200);
Wire.begin();
lightMeter.begin();
Serial.println("BH1750 Test — move toward/away from light source");
}
void loop() {
uint16_t lux = lightMeter.readLightLevel();
Serial.print("Lux: ");
Serial.println(lux);
delay(500);
}
Pattern 3: Soil Moisture → Pump Action
Use case: A capacitive sensor detects soil moisture level and triggers a water pump when dry
This pattern differs from the others because it involves higher current (a water pump needs more than Arduino can supply directly). You need a MOSFET or relay to switch the pump on and off.
The Module
Capacitive soil moisture sensor (FC-37 / v1.2) — measures soil moisture via capacitance change, not resistance. The key advantage over resistive sensors: the electrodes don't corrode because no current flows through the soil. Analog output (0-1023), where dry air reads ~400 and fully submerged in water reads ~700-800 depending on calibration.
Project: Smart Plant Watering
The FC-37 sensor reads soil moisture every hour. When moisture drops below 30% (dry), a 5V water pump activates for 10 seconds. An LCD shows current moisture percentage and last watering time.
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#define MOISTURE_PIN A0
#define PUMP_RELAY_PIN 8
#define PUMP_DURATION 10000 // 10 seconds
#define DRY_THRESHOLD 30 // percent
#define CHECK_INTERVAL 3600000 // 1 hour in ms
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo waterPump;
int moistureRaw = 0;
int moisturePercent = 0;
unsigned long lastCheck = 0;
bool pumpActive = false;
unsigned long pumpStartTime = 0;
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.print("Plant Monitor");
delay(2000);
lcd.clear();
pinMode(MOISTURE_PIN, INPUT);
pinMode(PUMP_RELAY_PIN, OUTPUT);
digitalWrite(PUMP_RELAY_PIN, LOW); // pump off
}
int readMoisture() {
// Take average of 10 readings to reduce noise
long sum = 0;
for (int i = 0; i < 10; i++) {
sum += analogRead(MOISTURE_PIN);
delay(50);
}
int raw = sum / 10;
// Map: 400 (dry) = 0%, 800 (wet) = 100%
int percent = map(raw, 400, 800, 0, 100);
percent = constrain(percent, 0, 100);
return percent;
}
void loop() {
if (millis() - lastCheck > CHECK_INTERVAL || lastCheck == 0) {
moisturePercent = readMoisture();
lastCheck = millis();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Moisture: ");
lcd.print(moisturePercent);
lcd.print("%");
Serial.print("Moisture: ");
Serial.print(moisturePercent);
Serial.println("%");
if (moisturePercent < DRY_THRESHOLD && !pumpActive) {
pumpActive = true;
pumpStartTime = millis();
digitalWrite(PUMP_RELAY_PIN, HIGH);
lcd.setCursor(0, 1);
lcd.print("Watering...");
Serial.println("Pump activated");
}
}
if (pumpActive && millis() - pumpStartTime > PUMP_DURATION) {
pumpActive = false;
digitalWrite(PUMP_RELAY_PIN, LOW);
lcd.setCursor(0, 1);
lcd.print("Done! ");
Serial.println("Pump deactivated");
}
delay(100);
}
Pattern 4: Vibration Detection → Alert Output
Use case: A vibration sensor detects machine movement or impacts and triggers an alarm
Industrial and maker-space applications: monitor 3D printers, CNC machines, or any equipment that shouldn't be running outside hours. The SW-420 outputs digital HIGH when vibration is detected.
The Module
SW-420 vibration sensor — a spring-based normally-closed switch that opens when vibration is detected. Simpler than accelerometers, cheaper, and works well for threshold-based detection (is something moving or not?). The module includes a comparator chip that outputs digital HIGH for 2 seconds after each vibration event before resetting.
Project: Machine Vibration Monitor
Monitors a 3D printer or CNC machine. When vibration is detected outside normal hours (weekdays after 10 PM, weekends after 8 PM), a red LED warning light turns on and stays on for 5 minutes after the last vibration event. If it keeps triggering, something might be wrong with the machine.
#define VIB_PIN 2 // Digital pin for SW-420
#define LED_RED_PIN 9 // PWM for red warning LED
#define LED_GREEN_PIN 10 // PWM for green status LED
#define ALERT_HANG 300000 // 5 min in ms after last vibration
#define WEEKDAY_START 22 // 10 PM
#define WEEKEND_START 20 // 8 PM
bool alertActive = false;
unsigned long lastVibration = 0;
bool isOffHours() {
// Uses millis() for time-of-day — works without RTC module
// Note: millis() resets after ~49 days. For production, use RTC.
unsigned long ms = millis();
// Simplified: assume 5-second cycle, estimate hour
// In real use: attach RTC DS3231 for accurate time
return true; // Always on for demo — replace with real RTC check
}
void setup() {
Serial.begin(115200);
pinMode(VIB_PIN, INPUT);
pinMode(LED_RED_PIN, OUTPUT);
pinMode(LED_GREEN_PIN, OUTPUT);
digitalWrite(LED_GREEN_PIN, HIGH); // Green = system OK
}
void loop() {
int vibration = digitalRead(VIB_PIN);
if (vibration == HIGH) {
lastVibration = millis();
Serial.println("Vibration detected!");
if (isOffHours()) {
alertActive = true;
digitalWrite(LED_GREEN_PIN, LOW);
}
}
if (alertActive && millis() - lastVibration > ALERT_HANG) {
alertActive = false;
digitalWrite(LED_GREEN_PIN, HIGH);
digitalWrite(LED_RED_PIN, LOW);
Serial.println("Alert cleared");
}
if (alertActive) {
// Pulse red LED
int pulse = (millis() / 500) % 2;
digitalWrite(LED_RED_PIN, pulse ? HIGH : LOW);
}
delay(100);
}
Pattern 5: Light Level → Continuous Adjustment
Use case: Ambient light changes continuously and the system adjusts output accordingly
Unlike a simple on/off light sensor, this pattern uses dimming — the output changes proportionally to the input. Street lights that get brighter as it gets darkerer, camera aperture that adjusts automatically.
The Modules
Photoresistor (GL5528) — simple analog component, resistance decreases as light increases. Not precise (every unit is different) but cheap and works for threshold-based projects. Reads 0-1023 on Arduino analog pin.
Relay module (1-channel) — switches AC or high-current DC loads. NOT for dimming AC lights (use a triac / dimmer module for that). The relay is for on/off control of higher-power devices from Arduino's 5V logic.
Project: Ambient Light Compensation for Display Case
A museum or gallery display case has LED lighting. As ambient daylight changes throughout the day, a photoresistor detects the change, and the Arduino adjusts LED brightness to keep the light inside the case constant. This prevents UV-sensitive artifacts from being exposed to varying light levels.
#define PHOTORES_PIN A0
#define RELAY_PIN 8
#define TARGET_LUX 200 // Target internal lux (arbitrary units)
#define SAMPLE_SIZE 10
int lastBrightness = 0;
void setup() {
Serial.begin(115200);
pinMode(PHOTORES_PIN, INPUT);
pinMode(RELAY_PIN, OUTPUT);
Serial.println("Ambient Light Compensation — Display Case");
}
int readLight() {
long sum = 0;
for (int i = 0; i < SAMPLE_SIZE; i++) {
sum += analogRead(PHOTORES_PIN);
delay(10);
}
return sum / SAMPLE_SIZE;
}
void adjustLight(int current) {
// current < TARGET_LUX: too dark, increase brightness
// current > TARGET_LUX: too bright, decrease brightness
int diff = TARGET_LUX - current;
int adjust = map(diff, -1023, 1023, -50, 50); // steps of 50ms
if (abs(diff) > 20) { // Deadband: don't adjust for small changes
lastBrightness = constrain(lastBrightness + adjust, 0, 255);
// Simulate PWM dimming by rapid relay flickering (use MOSFET for real dimming)
// Here we just print the target — real implementation needs MOSFET on PWM
Serial.print("Adjusting: current=");
Serial.print(current);
Serial.print(" | target=");
Serial.print(TARGET_LUX);
Serial.print(" | brightness=");
Serial.println(lastBrightness);
}
}
void loop() {
int lightLevel = readLight();
adjustLight(lightLevel);
delay(500);
}
The Five-Pattern Starter Kit
Rather than buying modules one at a time and wondering if they'll work together, buy them as a kit with a purpose:
For Proximity + Visual Feedback
- HC-SR04 ultrasonic sensor — $2 for 2
- HC-SR501 PIR motion sensor — $4 for 3
For Environmental Monitoring
- DHT22 temperature humidity sensor — $7 for 2
- BH1750 light intensity sensor I2C — $5 for 1
For Contact + Physical Action
- Capacitive soil moisture sensor FC-37 — $6 for 2
- 5V water pump small — $5 for 1
For Vibration Monitoring
- SW-420 vibration sensor module — $4 for 10
- Buzzer module 5V — $3 for 5
For Light + Dimming
- Photoresistor GL5528 — $3 for 20
- 1-channel relay module 5V — $4 for 2
Controller
- Arduino Nano CH340 — $10 for 3
- ESP32 DevKit — $8 for 1 (for WiFi projects)
Power + Wiring
- 5V 3A power adapter — $6 for 2
- Breadboard + jumper wires — $7 for 1 kit
Total kit cost: approximately $65-75 for enough modules to build all five interaction patterns.
The Testing Habit
Every module in this guide comes with a standalone test snippet — copy it into a blank Arduino sketch, upload, open Serial Monitor. If the reading looks right, the module works and you understand how to use it. If it doesn't, you know exactly which module to troubleshoot rather than debugging a full project where the problem could be anywhere.
This is the habit that separates people who actually finish projects from people who have a drawer full of sensors they bought and never used.
What to Build First
Start with Pattern 1 (HC-SR04 + servo) — it's the simplest complete loop: sensor detects something, Arduino processes, actuator moves. Once that works, add Pattern 2 (add a DHT22 and log temperature to Serial). Then Pattern 3 (replace the Serial output with a pump relay). Each pattern is a building block.
The modules don't care which order you learn them in. But without the interaction pattern framework, you end up with a box full of parts and no idea how they fit together.
Next Step: From Scene to Sensor, Without Writing Code
If this guide gave you ideas for your own setup — but you're not sure which sensors and outputs work best for your specific space — I can help you map that out.
I offer a personalized interactive device design guide at Fiverr:
👉 https://www.fiverr.com/phd_hfchang/generate-an-arduino-interactive-prototypef
What you get:
- A custom guide based on your actual scene (not generic recommendations)
- Sensor selection matched to user behavior and physical constraints
- Interaction logic without needing to write code from scratch
- Testing methodology with pass/fail criteria for each output
Tags: arduino, modules, sensors, interactive, beginner, esp32, hc-sr04, dht22, pir-sensor, smart-home




Top comments (0)