ESP32 home automation system with relay module and Android app control

ESP32 Home Automation — 4-Channel Relay, RGB LED & Android App over WiFi


Imagine walking into a room and controlling every light, fan, and appliance from your phone — no voice assistant, no subscription, no cloud. Just your ESP32 on the same WiFi network as your Android phone, responding to your commands in milliseconds.

In this tutorial you will build a complete home automation system from scratch. The ESP32 connects to your home WiFi, runs a lightweight HTTP server, and controls four mains-voltage devices through an optocoupler relay module. An RGB LED gives you live visual status. A simple Android app (built in MIT App Inventor — no coding needed) sends on/off commands over your local network.

This project is safe, practical, and fully offline — no data leaves your home network.

⚠️
Mains voltage safety: The relay output side connects to 230V/120V AC. Always wire the AC side with the power disconnected. If you are not confident working with mains voltage, use a qualified electrician for the final connection. The ESP32/relay control side is safe low-voltage (3.3V/5V).

What You Need

Component Qty Purpose
ESP32 38-pin Dev Board (WROOM) 1 Main controller — WiFi HTTP server
4-Channel Relay Module (Optocoupler, 5V) 1 Switches mains-voltage appliances safely
RGB LED (Common Cathode) 1 Visual status — connecting / idle / active
Resistors (220Ω) 3 Current limiting for R, G, B pins
Breadboard 1 Prototyping connections
Jumper Wires (M-M, M-F) Several Connecting components
USB Cable + 5V Power Supply 1 Powering the ESP32 and relay module
Android Phone 1 Runs the control app on local WiFi
Home WiFi Router 1 Local network for ESP32 ↔ Android communication
💡
Libraries needed in Arduino IDE: Install WiFi.h and WebServer.h — both are included with the ESP32 board package. Go to Boards Manager, search esp32 by Espressif and install it if you haven't already.

How It Works

The system uses a simple client-server model entirely on your local WiFi network. No internet, no cloud, no third-party service required.

  1. ESP32 boots and connects to WiFi

    It joins your home network and gets a local IP address (e.g. 192.168.1.105). The RGB LED turns orange while connecting and green once connected.

  2. HTTP server starts on port 80

    The ESP32 listens for incoming HTTP GET requests on routes like /relay/1/on and /relay/1/off.

  3. Android app sends commands

    When you tap a button in the app, it sends a GET request to the ESP32's IP address. The ESP32 responds with a JSON confirmation.

  4. Relay switches the appliance

    The optocoupler relay module electrically isolates the low-voltage control side from the mains side, keeping your ESP32 safe. LOW signal = relay ON (active-low module).

  5. RGB LED reflects overall status

    Orange = connecting, Green = idle/connected, Blue = at least one relay active. You can see the system state at a glance.

📶
Why local WiFi? Keeping everything on your local network means zero latency, zero dependency on the internet, and complete privacy. Commands reach the relay in under 50ms.

Wiring Diagram

Connect all components as shown below. The relay module requires 5V — use the VIN pin on the ESP32 (which passes USB 5V through). The RGB LED and all control signals run at 3.3V from the ESP32 GPIOs.

ESP32 38-pin home automation wiring diagram with 4-channel relay, RGB LED and pin colour legend
ESP32 38-pin · 4-Channel Relay (Optocoupler) · RGB LED — full wiring with colour legend & pin mapping

4-Channel Relay → ESP32

Relay Pin ESP32 GPIO Controls
VCCVIN (5V)Relay module power
GNDGNDCommon ground
IN1GPIO 26Light 1
IN2GPIO 27Light 2
IN3GPIO 14Fan
IN4GPIO 12Appliance / spare

RGB LED → ESP32

LED Pin ESP32 GPIO Notes
Red (R)GPIO 25Via 220Ω resistor
Green (G)GPIO 33Via 220Ω resistor
Blue (B)GPIO 32Via 220Ω resistor
Cathode (–)GNDCommon cathode to ground
💡
Active-LOW relay: Most optocoupler relay modules trigger when the IN pin is pulled LOW. The code initialises all relay pins HIGH (off) and sets them LOW to switch on. If your module behaves inverted, swap HIGH/LOW in the code.

ESP32 Code

Upload this sketch via Arduino IDE. Set your board to ESP32 Dev Module, select your COM port, and replace YOUR_WIFI_SSID and YOUR_WIFI_PASSWORD with your router credentials.

Arduino / C++
#include <WiFi.h>
#include <WebServer.h>

// ── WiFi credentials ─────────────────────────────────────
const char* ssid     = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

// ── Relay pins (active-LOW with optocoupler module) ───────
#define RELAY1_PIN 26   // Light 1
#define RELAY2_PIN 27   // Light 2
#define RELAY3_PIN 14   // Fan
#define RELAY4_PIN 12   // Appliance

// ── RGB LED pins ──────────────────────────────────────────
#define RED_PIN   25
#define GREEN_PIN 33
#define BLUE_PIN  32

WebServer server(80);

bool relay1 = false;
bool relay2 = false;
bool relay3 = false;
bool relay4 = false;

// ── RGB helpers ───────────────────────────────────────────
void setRGB(bool r, bool g, bool b) {
  digitalWrite(RED_PIN,   r ? HIGH : LOW);
  digitalWrite(GREEN_PIN, g ? HIGH : LOW);
  digitalWrite(BLUE_PIN,  b ? HIGH : LOW);
}

void updateStatusLED() {
  bool anyOn = relay1 || relay2 || relay3 || relay4;
  if (anyOn) setRGB(false, false, true);   // Blue  = relay(s) active
  else       setRGB(false, true,  false);  // Green = idle, connected
}

// ── Relay control helper ──────────────────────────────────
void setRelay(int num, bool state) {
  int pin;
  switch (num) {
    case 1: pin = RELAY1_PIN; relay1 = state; break;
    case 2: pin = RELAY2_PIN; relay2 = state; break;
    case 3: pin = RELAY3_PIN; relay3 = state; break;
    case 4: pin = RELAY4_PIN; relay4 = state; break;
    default: server.send(400, "application/json", "{\"error\":\"Invalid relay\"}"); return;
  }
  digitalWrite(pin, state ? LOW : HIGH);  // active-LOW module
  updateStatusLED();
  server.send(200, "application/json",
    "{\"relay\":" + String(num) + ",\"state\":\"" + (state ? "on" : "off") + "\"}");
}

// ── HTTP route handlers ───────────────────────────────────
void handleStatus() {
  String json = "{\"relay1\":" + String(relay1 ? "true" : "false") +
                ",\"relay2\":" + String(relay2 ? "true" : "false") +
                ",\"relay3\":" + String(relay3 ? "true" : "false") +
                ",\"relay4\":" + String(relay4 ? "true" : "false") + "}";
  server.send(200, "application/json", json);
}

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

  // Relay pins — all OFF at boot (HIGH = off for active-low)
  int relayPins[] = { RELAY1_PIN, RELAY2_PIN, RELAY3_PIN, RELAY4_PIN };
  for (int i = 0; i < 4; i++) {
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(relayPins[i], HIGH);
  }

  // RGB LED
  pinMode(RED_PIN,   OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN,  OUTPUT);
  setRGB(true, false, false);  // Red = not yet connected

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    // Blink orange while connecting
    setRGB(true, false, false);
    delay(200);
    setRGB(false, false, false);
  }

  Serial.println("\nConnected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
  setRGB(false, true, false);  // Green = connected, idle

  // Register HTTP routes
  server.on("/relay/1/on",  []() { setRelay(1, true); });
  server.on("/relay/1/off", []() { setRelay(1, false); });
  server.on("/relay/2/on",  []() { setRelay(2, true); });
  server.on("/relay/2/off", []() { setRelay(2, false); });
  server.on("/relay/3/on",  []() { setRelay(3, true); });
  server.on("/relay/3/off", []() { setRelay(3, false); });
  server.on("/relay/4/on",  []() { setRelay(4, true); });
  server.on("/relay/4/off", []() { setRelay(4, false); });
  server.on("/status",      handleStatus);

  server.begin();
  Serial.println("HTTP server started");
  Serial.println("Control URL: http://" + WiFi.localIP().toString());
}

void loop() {
  server.handleClient();
}
📋
Find the IP address: Open Serial Monitor at 115200 baud after uploading. The ESP32 will print its local IP address (e.g. 192.168.1.105). You will need this for the Android app. You can also check it in your router's connected devices list.

Android App

The Android app is built using MIT App Inventor — a free visual drag-and-drop builder. No Java or Kotlin needed. You create the UI by placing buttons and set up the logic with blocks, similar to Scratch.

App Inventor setup

  1. Open MIT App Inventor

    Go to appinventor.mit.edu and sign in with a Google account.

  2. Create a new project

    Start a new project and name it HomeAutomation.

  3. Add buttons in Designer view

    In the Designer view, add a Label for the title and 8 Buttons — one ON and one OFF for each relay.

  4. Label each button

    Name them: Light 1 ON / Light 1 OFF / Light 2 ON / Light 2 OFF / Fan ON / Fan OFF / App4 ON / App4 OFF.

  5. Add the Web component

    From the Connectivity palette, drag a Web component onto the screen. It appears below the viewer as a non-visible component.

App Inventor blocks

Switch to the Blocks view and wire up each button. For each button, the pattern is identical — only the URL changes:

MIT App Inventor — Block Logic (pseudocode)
// Replace 192.168.1.105 with your ESP32's actual IP address
// ─────────────────────────────────────────────────────────

// When Light1_ON button is clicked:
Web1.Url = "http://192.168.1.105/relay/1/on"
Web1.Get()

// When Light1_OFF button is clicked:
Web1.Url = "http://192.168.1.105/relay/1/off"
Web1.Get()

// When Light2_ON button is clicked:
Web1.Url = "http://192.168.1.105/relay/2/on"
Web1.Get()

// When Fan_ON button is clicked:
Web1.Url = "http://192.168.1.105/relay/3/on"
Web1.Get()

// When Appliance_ON button is clicked:
Web1.Url = "http://192.168.1.105/relay/4/on"
Web1.Get()

// Repeat the same OFF pattern for each button
// ─────────────────────────────────────────────────────────
// To check status — GET http://192.168.1.105/status
// Response: {"relay1":false,"relay2":true,"relay3":false,"relay4":false}
📱
Testing during development: Install the MIT AI2 Companion app on your Android phone. In App Inventor, click Connect → AI Companion and scan the QR code to run your app live on your phone without building an APK.

Build & install the APK

When the app is working correctly, go to Build → Android App (.apk). App Inventor will generate a download link. Transfer the APK to your phone and install it. Make sure Install from unknown sources is enabled in your phone settings.

Testing Your Build

  1. Upload and open Serial Monitor

    Upload the sketch and open Serial Monitor at 115200 baud. Wait for the IP address to appear and the RGB LED to turn green.

  2. Test relay via browser

    From any browser on the same WiFi, open http://<ESP32-IP>/relay/1/on. The first relay should click ON and the LED turns blue.

  3. Check the status endpoint

    Open http://<ESP32-IP>/status and confirm the JSON response shows "relay1": true.

  4. Test via the Android app

    Open the Android app and tap Light 1 ON — the relay should click and the LED stay blue. Tap Light 1 OFF — relay clicks off, LED returns green.

  5. Test all four relays at low voltage

    Run each relay one by one before connecting any mains wiring. Use an LED with a resistor or a 5V USB bulb to confirm switching safely.

⚠️
Test everything at low voltage first. Connect an LED with a resistor or a 5V USB bulb to the relay output to confirm switching before connecting any 230V/120V appliance.

Next Steps

  • Add a web dashboard — The ESP32 can serve an HTML page with toggle buttons directly from its HTTP server. No app needed — works on any browser on your network.
  • Timer schedules — Use the time.h library with NTP to automatically switch relays on/off at set times (e.g. turn off lights at midnight).
  • MQTT protocol — Replace the HTTP server with MQTT (using the PubSubClient library) for faster, more reliable messaging and integration with Home Assistant.
  • Voice control — Connect to Google Assistant or Alexa via IFTTT webhooks — they can call your ESP32's HTTP endpoints.
  • More relays — Chain a second 4-channel relay module to control 8 devices total. ESP32 has plenty of GPIO pins remaining.
  • Current sensing — Add a PZEM-004T module to the relay output to monitor actual power consumption per channel.

Want to build IoT and home automation projects with expert guidance?

Ask About IoT Courses