Build a smart home hub with Blynk

One ESP32 that runs a room: it shows the climate, switches a lamp on when you walk in after dark, and turns into an alarm with phone alerts when you're away.
  • Level:Advanced
  • Duration: 2 h
  • Ages 13+
  • Platform: ESP32

Tools for this lesson

Helpful for this build. Open a tool to see tips and more projects that use it.

Build a smart home hub with Blynk – EEMENTOR STEM™ lesson

This final capstone brings all the Blynk lessons together in one device. Your smart home hub measures temperature and humidity, switches a lamp from the app, and has two personalities. At home, it's a helper: when it's dark and someone moves, the lamp switches on by itself and goes off again two minutes after the last movement. Away, it's a guard: any movement sounds the siren, switches the lamp on and sends an alert to your phone. One switch in the app changes between the two.

What you'll learn

  • How to make one device behave differently in different modes
  • How to combine several sensors into one decision
  • How to keep app controls and automatic rules from fighting each other
  • How to plan pins and power for a project with five parts

What you need

  • ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
  • DHT11 module, KY-015 (ESP32 IoT Starter Kit)
  • PIR motion sensor (ESP32 IoT Starter Kit)
  • Photoresistor module (45-in-1 Sensor Kit)
  • Relay module (45-in-1 Sensor Kit)
  • Active buzzer module (45-in-1 Sensor Kit)
  • A free Blynk account and the Blynk IoT app on a phone
  • Breadboard and jumper wires (ESP32 IoT Starter Kit)
  • A 2.4 GHz Wi-Fi network

Plan the rules

Before wiring anything, write down what the hub should do. Clear rules on paper make the code much easier.

Mode When this happens The hub does this
Home Movement while the room is dark Lamp on. It goes off 2 minutes after the last movement
Home You use the lamp switch in the app Lamp follows the switch and the automatic timer is cancelled
Away Any movement Siren for 30 seconds, lamp on, phone alert
Away You switch back to Home Siren off
Both Every 5 seconds Temperature and humidity are sent to the app

Wiring

The breadboard's + rail carries 3.3 V. The relay and the PIR sensor need 5 V, so they share one wire to the ESP32's 5V pin.

Breadboard wiring diagram: Build a smart home hub with Blynk
Breadboard view. Check each connection against the wiring table below.
From To
DHT11 S (signal) ESP32 GPIO 27
DHT11 + and − 3V3 and GND
Photoresistor module S ESP32 GPIO 34
Photoresistor module + and − 3V3 and GND
Relay module S ESP32 GPIO 26
Relay module + ESP32 5V
Relay module − GND
Active buzzer module S ESP32 GPIO 25
Active buzzer module + and − 3V3 and GND
PIR OUT ESP32 GPIO 14
PIR VCC 5V (same breadboard row as the relay's + pin)
PIR GND GND

Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.

The relay is your "lamp". You hear it click and see its LED. If you want a real light, let the relay switch a small battery-powered lamp or LED strip (up to 12 V). Never connect mains electricity to the relay.

Set up Blynk

In the Blynk console, create a new template called Smart home hub (hardware ESP32, connection type Wi-Fi) and add these datastreams. Connect the ESP32 to Blynk shows each step in detail.

Virtual pin Name Data type Range Phone widget
V0 Lamp Integer 0 – 1 Button (switch mode)
V1 Temperature Double 0 – 50, units °C Gauge
V2 Humidity Double 0 – 100, units % Gauge
V3 Away mode Integer 0 – 1 Button (switch mode)
V4 Status String n/a Value Display

Then open the template's Events & Notifications tab, add an event with the code intruder (name: Movement while away) and turn on push notifications for it. The event code must match the sketch exactly.

Save the template, create a new device from it and copy its three BLYNK_… lines. In the phone app, open the device, tap the wrench icon and add two Buttons in switch mode (V0 and V3), two Gauges (V1 and V2) and a Value Display (V4). Link each widget to its datastream.

Build it in stages

This is a bigger build than the earlier lessons, so don't wire everything at once. Add one part, test it, then add the next. When something stops working, you know it's the part you just added.

  1. Climate. Wire the DHT11, upload the sketch and check that the two gauges show values.
  2. Lamp. Add the relay module. The Lamp switch in the app now clicks the relay.
  3. Automatic light. Add the photoresistor and the PIR sensor. Give the PIR sensor a minute to settle. Cover the photoresistor and wave your hand: the lamp switches on, and the status line shows when.
  4. Guard. Add the buzzer. Switch Away mode on in the app and leave the sensor's view for 30 seconds. Then walk in.
Example screen for: Build a smart home hub with Blynk
Example screen with sample values. Yours may look different.

The sketch

Install the DHT sensor library by Adafruit.

Replace the three BLYNK_… lines at the top with the ones from your device's Device info page, and add your Wi-Fi name and password (2.4 GHz only). The BLYNK_… lines must stay above #include <BlynkSimpleEsp32.h>.

#define BLYNK_TEMPLATE_ID "YOUR_TEMPLATE_ID"
#define BLYNK_TEMPLATE_NAME "Smart home hub"
#define BLYNK_AUTH_TOKEN "YOUR_AUTH_TOKEN"
#define BLYNK_PRINT Serial          // show connection messages in the Serial Monitor

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <time.h>

char ssid[] = "YOUR_WIFI_NAME";
char pass[] = "YOUR_WIFI_PASSWORD";
const char* TIME_ZONE = "EET-2EEST,M3.5.0/3,M10.5.0/4";  // Estonia; change for your country

const int DHT_PIN = 27;
const int LIGHT_PIN = 34;
const int RELAY_PIN = 26;
const int BUZZER_PIN = 25;
const int PIR_PIN = 14;

const int DARK_BELOW = 30;                     // "dark" means less light than this (%)
const unsigned long LAMP_TIME = 120000;        // automatic light stays on for 2 minutes
const unsigned long SIREN_TIME = 30000;        // the siren sounds for 30 seconds
const unsigned long ARM_DELAY = 30000;         // time to leave after switching to Away

DHT dht(DHT_PIN, DHT11);
BlynkTimer timer;

bool away = false;
bool lampOn = false;
bool lampIsAuto = false;          // true when the hub switched the lamp on by itself
bool sirenOn = false;
bool motionBefore = false;
unsigned long lastMotion = 0;
unsigned long sirenStart = 0;
unsigned long awaySince = 0;

String timeNow() {
  struct tm t;
  if (!getLocalTime(&t, 10)) return "time not set yet";
  char text[20];
  strftime(text, sizeof(text), "%d.%m %H:%M", &t);
  return String(text);
}

void setLamp(bool on, bool automatic) {
  lampOn = on;
  lampIsAuto = on && automatic;
  digitalWrite(RELAY_PIN, on);
  Blynk.virtualWrite(V0, on);                  // keep the app's switch in step
}

void setSiren(bool on) {
  sirenOn = on;
  sirenStart = millis();
  digitalWrite(BUZZER_PIN, on);
}

BLYNK_WRITE(V0) {                              // lamp switch in the app
  setLamp(param.asInt(), false);
}

BLYNK_WRITE(V3) {                              // Away mode switch
  away = param.asInt();
  awaySince = millis();
  setSiren(false);
  Blynk.virtualWrite(V4, away ? "Away: guarding in 30 s" : "Home");
}

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V0, V3);
}

void sendClimate() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  if (isnan(temperature) || isnan(humidity)) return;
  Blynk.virtualWrite(V1, temperature);
  Blynk.virtualWrite(V2, humidity);
}

void onMotion() {
  lastMotion = millis();
  if (away) {
    if (millis() - awaySince < ARM_DELAY) return;        // still time to leave
    if (!sirenOn) {
      setSiren(true);
      setLamp(true, true);
      Blynk.logEvent("intruder", "Movement at " + timeNow());
      Blynk.virtualWrite(V4, "ALARM " + timeNow());
    }
  } else {
    int light = map(analogRead(LIGHT_PIN), 0, 4095, 100, 0);   // bright = high %
    if (light < DARK_BELOW && !lampOn) {
      setLamp(true, true);
      Blynk.virtualWrite(V4, "Light on, movement " + timeNow());
    }
  }
}

void checkHome() {
  bool motion = digitalRead(PIR_PIN) == HIGH;
  if (motion && !motionBefore) onMotion();               // a new movement starts
  if (motion) lastMotion = millis();                     // still moving: restart the timer
  motionBefore = motion;

  if (sirenOn && millis() - sirenStart >= SIREN_TIME) setSiren(false);

  if (lampIsAuto && !sirenOn && millis() - lastMotion >= LAMP_TIME) {
    setLamp(false, true);
    if (!away) Blynk.virtualWrite(V4, "Light off " + timeNow());
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(PIR_PIN, INPUT);
  dht.begin();
  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
  configTzTime(TIME_ZONE, "pool.ntp.org");     // real time from the internet
  timer.setInterval(5000L, sendClimate);       // climate every 5 seconds
  timer.setInterval(200L, checkHome);          // sensors five times per second
}

void loop() {
  Blynk.run();
  timer.run();
}

How it works

The hub has one variable that changes its whole behaviour: away. The same movement leads to completely different actions depending on that one value. Designing a device around a small number of clear modes is what keeps a growing project understandable.

The PIR sensor's output stays HIGH for several seconds after a movement. If the sketch reacted every time it read HIGH, it would send dozens of alerts. Instead, checkHome() compares the reading with the previous one and calls onMotion() only at the moment the signal changes from LOW to HIGH. This is called edge detection.

The lamp can be switched by you or by the hub, so the sketch remembers who did it. lampIsAuto is true only when the hub switched the lamp on by itself, and only then does the two-minute timer switch it off again. If you switch the lamp on in the app, it stays on until you switch it off. All changes go through setLamp(), which also writes the new state back to V0, so the switch in the app always shows what the lamp is really doing.

After you switch to Away, the hub ignores movement for 30 seconds so that you can leave the room. Two timers run in the background: one sends the climate every five seconds, the other checks the sensors five times per second. Neither uses delay(), so the hub always stays connected.

Where to go from here

You've now built data loggers, alarm systems, a game, a radar and connected devices that act on their own. The next step is a project of your own. Pick a problem at home or at school, write down the rules like you did here, choose the sensors, and build it in stages. When it works, share it with other makers on our project submission page.

Try this next

  • Add a third mode, "Night": movement switches the lamp on for only 20 seconds and never sounds the siren.
  • Send a second event when the temperature goes above 30 °C.
  • Add the flame sensor and sound the siren in every mode when it detects fire.
  • Add a second relay module for a fan and switch it on above 27 °C.

Troubleshooting

  • The device shows "Offline" in the app: check the Serial Monitor at 115200 baud. "Invalid auth token" means the BLYNK_AUTH_TOKEN line is wrong; if it never connects, check the Wi-Fi name and password, and that your network is 2.4 GHz.
  • The lamp never switches on by itself: the room isn't "dark" for the sensor. Cover the photoresistor to test, or raise DARK_BELOW. If the light reading is the wrong way round, swap 100, 0 to 0, 100.
  • The alarm doesn't react just after switching to Away: that's the 30-second leaving time. Wait and try again.
  • The relay or buzzer is on when it should be off: some modules switch on with LOW. Swap the logic in setLamp() or setSiren() by writing !on instead of on in the digitalWrite line.
  • The PIR sensor triggers all the time: wait a full minute after power-up, turn its sensitivity screw down, and keep it away from the relay and from warm air.
  • No notification arrives: check that the event code is exactly intruder and that notifications are switched on for it in the template.

Build it yourself

Everything used in this lesson comes in one kit, with parts tested by our engineers.

ESP32 IoT Starter Kit | Arduino IDE Compatible | Free Tutorials $57.00

Shop the kit