OC
OceanRemote
Low-code IoT platform
← Back to Course

LED and Relay Control Examples

šŸ’” LED and Relay Control - Complete Guide for IoT Automation

šŸ”Œ What You'll Learn in This Lesson:

  • Control LEDs as indicators for system status
  • Master relay modules to control water pumps, lights, and motors
  • Understand active LOW vs active HIGH relays
  • Build complete irrigation control systems
  • Add status indicators to your farm automation projects

šŸ“Š LED vs Relay - What's the Difference?

Component Purpose Typical Load Voltage
LED Visual indicator 20mA 3.3V
Relay Module Switch high-power devices 10A 250V AC / 30V DC Controls 110-240V AC
šŸ’” Understanding Relay Logic:

Most relay modules are active LOW:
digitalWrite(RELAY_PIN, LOW) → Relay ON (circuit closed)
digitalWrite(RELAY_PIN, HIGH) → Relay OFF (circuit open)

šŸ”Œ Complete Wiring Diagrams

šŸ’” LED Wiring (Indicator Light)

LED Connections (Current flows from Anode to Cathode):
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  ESP32 GPIO4  ───► 220Ī© Resistor ───► LED Anode (long leg)  │
│  ESP32 GND     ─────────────────────► LED Cathode (short leg)│
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Resistor calculation (Ohm's Law):
R = (V_source - V_LED) / I_LED
R = (3.3V - 2.0V) / 0.02A = 65Ī© minimum
220Ī© is safe for all LEDs (5-10mA)
    

šŸ’§ Relay Wiring (Water Pump)

Relay Module (Active LOW):
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  ESP32 GPIO5   ──────────────────────────► Relay IN pin    │
│  ESP32 3.3V    ──────────────────────────► Relay VCC       │
│  ESP32 GND     ──────────────────────────► Relay GND       │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

High-Power Circuit (Use thick wire!):
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  12V Battery (+)  ───► Relay COM ───► Relay NO  ───► Pump (+) │
│  12V Battery (-)  ────────────────────────────────► Pump (-) │
│                                                            │
│  When Relay ON: COM connected to NO → Pump runs           │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
    
āš ļø SAFETY WARNING:

Relays can control high voltage (110-240V AC)! Always:

  • Disconnect power when wiring
  • Use properly rated wire (at least 18 AWG for pumps)
  • Keep ESP32 and high-voltage circuits separated
  • Use an enclosure to prevent accidental contact

šŸ“– Complete LED Control Examples

1. Basic LED Blink (Indicator)

/*
 * Basic LED Blink - System Status Indicator
 * LED blinks to show system is running
 */

#define LED_PIN 4

void setup() {
    pinMode(LED_PIN, OUTPUT);
    Serial.begin(115200);
    Serial.println("āœ… System started - LED blinking");
}

void loop() {
    // Blink pattern: on for 1 second, off for 1 second
    digitalWrite(LED_PIN, HIGH);
    Serial.println("šŸ”“ LED ON");
    delay(1000);
    
    digitalWrite(LED_PIN, LOW);
    Serial.println("⚫ LED OFF");
    delay(1000);
}
    

2. Status LED - Shows WiFi Connection

/*
 * Status LED Indicator
 * LED behavior indicates system status
 * 
 * - Fast blink: Connecting to WiFi
 * - Slow blink: WiFi connected, working
 * - Solid ON: Error or maintenance mode
 */

#include 

#define STATUS_LED 4

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

void setup() {
    pinMode(STATUS_LED, OUTPUT);
    Serial.begin(115200);
    
    // Fast blink while connecting
    for (int i = 0; i < 10; i++) {
        digitalWrite(STATUS_LED, HIGH);
        delay(100);
        digitalWrite(STATUS_LED, LOW);
        delay(100);
    }
    
    Serial.println("šŸ“” Connecting to WiFi...");
    WiFi.begin(ssid, password);
    
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    
    Serial.println("\nāœ… WiFi connected!");
    
    // Slow blink pattern for normal operation
}

void normalBlink() {
    digitalWrite(STATUS_LED, HIGH);
    delay(2000);
    digitalWrite(STATUS_LED, LOW);
    delay(2000);
}

void errorBlink() {
    digitalWrite(STATUS_LED, HIGH);
    delay(500);
    digitalWrite(STATUS_LED, LOW);
    delay(500);
    digitalWrite(STATUS_LED, HIGH);
    delay(500);
    digitalWrite(STATUS_LED, LOW);
    delay(2000);
}

void loop() {
    if (WiFi.status() == WL_CONNECTED) {
        normalBlink();
    } else {
        errorBlink();
    }
}
    

šŸ’§ Complete Relay Control Examples

1. Basic Water Pump Control

/*
 * Basic Water Pump Control
 * Turn pump on/off with simple functions
 */

#define RELAY_PIN 5

void setup() {
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, HIGH);  // Start with pump OFF
    Serial.begin(115200);
    Serial.println("šŸ’§ Water pump controller ready");
}

void waterPump(int seconds) {
    Serial.printf("šŸ’§ Pump ON for %d seconds\n", seconds);
    digitalWrite(RELAY_PIN, LOW);   // Relay ON → Pump runs
    delay(seconds * 1000);
    digitalWrite(RELAY_PIN, HIGH);  // Relay OFF → Pump stops
    Serial.println("šŸ’§ Pump OFF");
}

void loop() {
    // Example: Water for 5 seconds every minute
    waterPump(5);
    delay(55000);  // Wait 55 seconds (total 60 seconds cycle)
}
    

2. Soil Moisture-Based Irrigation (Full Automation)

/*
 * Smart Irrigation System
 * Waters crops automatically based on soil moisture
 * 
 * Components:
 * - Soil moisture sensor on GPIO32
 * - Relay on GPIO5 (controls water pump)
 * - LED on GPIO4 (status indicator)
 */

#include 
#include 

// Pin definitions
#define SOIL_SENSOR_PIN 32
#define RELAY_PIN 5
#define STATUS_LED 4

// WiFi (for sending data)
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";
const char* token = "YOUR_TOKEN";

// Soil moisture calibration
const int DRY_VALUE = 3800;
const int WET_VALUE = 1500;
const int WATER_THRESHOLD = 35;   // Water below 35%
const int WATER_DURATION = 10;     // Water for 10 seconds

// System state
bool isWatering = false;
unsigned long wateringStartTime = 0;

void setup() {
    Serial.begin(115200);
    
    pinMode(RELAY_PIN, OUTPUT);
    pinMode(STATUS_LED, OUTPUT);
    digitalWrite(RELAY_PIN, HIGH);  // Pump OFF
    digitalWrite(STATUS_LED, LOW);
    
    Serial.println("========================================");
    Serial.println("🌱 Smart Irrigation System v1.0");
    Serial.println("   Waters automatically when soil is dry");
    Serial.println("========================================");
}

int readSoilMoisture() {
    int raw = analogRead(SOIL_SENSOR_PIN);
    int moisture = map(raw, DRY_VALUE, WET_VALUE, 0, 100);
    moisture = constrain(moisture, 0, 100);
    return moisture;
}

void startWatering() {
    isWatering = true;
    wateringStartTime = millis();
    digitalWrite(RELAY_PIN, LOW);   // Pump ON
    digitalWrite(STATUS_LED, HIGH); // LED ON to show watering
    Serial.println("šŸ’§ WATERING STARTED");
}

void stopWatering() {
    isWatering = false;
    digitalWrite(RELAY_PIN, HIGH);  // Pump OFF
    digitalWrite(STATUS_LED, LOW);  // LED OFF
    Serial.println("šŸ’§ WATERING STOPPED");
    
    // Optional: Send notification to cloud
    sendWateringComplete();
}

void sendWateringComplete() {
    if (WiFi.status() == WL_CONNECTED) {
        HTTPClient http;
        http.begin("https://api.oceanremote.net/device/state");
        http.addHeader("Content-Type", "application/x-www-form-urlencoded");
        
        String data = "token=" + String(token);
        data += "&irrigation=completed";
        http.POST(data);
        http.end();
    }
}

void loop() {
    if (isWatering) {
        // Check if watering duration is complete
        if (millis() - wateringStartTime >= (WATER_DURATION * 1000)) {
            stopWatering();
        }
    } else {
        // Check soil moisture and decide to water
        int moisture = readSoilMoisture();
        
        Serial.print("šŸ’§ Soil moisture: ");
        Serial.print(moisture);
        Serial.println("%");
        
        if (moisture < WATER_THRESHOLD) {
            Serial.println("āš ļø Soil too dry! Starting irrigation...");
            startWatering();
        }
        
        // Blink LED to show system is alive
        digitalWrite(STATUS_LED, HIGH);
        delay(50);
        digitalWrite(STATUS_LED, LOW);
    }
    
    delay(30000);  // Check soil every 30 seconds
}
    

3. Multi-Zone Irrigation System

/*
 * Multi-Zone Irrigation System
 * Control up to 5 separate watering zones
 * Perfect for farms with different crop sections
 */

#define ZONE1_RELAY 5
#define ZONE2_RELAY 16
#define ZONE3_RELAY 17
#define ZONE4_RELAY 18
#define ZONE5_RELAY 19

// Zone configuration
struct Zone {
    int relayPin;
    const char* name;
    int waterDuration;  // seconds
};

Zone zones[] = {
    {ZONE1_RELAY, "Tomatoes", 15},
    {ZONE2_RELAY, "Maize", 10},
    {ZONE3_RELAY, "Vegetables", 12},
    {ZONE4_RELAY, "Fruit Trees", 20},
    {ZONE5_RELAY, "Nursery", 8}
};

const int ZONE_COUNT = 5;

void setup() {
    Serial.begin(115200);
    
    for (int i = 0; i < ZONE_COUNT; i++) {
        pinMode(zones[i].relayPin, OUTPUT);
        digitalWrite(zones[i].relayPin, HIGH);  // All OFF initially
        Serial.printf("āœ… Zone %d: %s ready\n", i+1, zones[i].name);
    }
    
    Serial.println("\nšŸ’§ Multi-Zone Irrigation System Ready");
    Serial.println("   Watering zones in sequence...\n");
}

void waterZone(int zoneIndex) {
    Zone *z = &zones[zoneIndex];
    
    Serial.printf("šŸ’§ Watering Zone %d: %s (%d seconds)\n", 
                  zoneIndex + 1, z->name, z->waterDuration);
    
    digitalWrite(z->relayPin, LOW);   // Pump ON
    delay(z->waterDuration * 1000);
    digitalWrite(z->relayPin, HIGH);  // Pump OFF
    
    Serial.printf("āœ… Zone %d complete\n\n", zoneIndex + 1);
}

void loop() {
    for (int i = 0; i < ZONE_COUNT; i++) {
        waterZone(i);
        delay(5000);  // Pause between zones
    }
    
    Serial.println("šŸ”„ Complete cycle finished. Waiting 1 hour...\n");
    delay(3600000);  // Wait 1 hour before next cycle
}
    
šŸ“– Real-World Application - Ghanaian Vegetable Farm:

A small farm automated irrigation for 5 different vegetable sections:

  • šŸ’§ Setup: ESP32 + 5 relay module + 5 solenoid valves
  • šŸ’” LED indicators showed which zone was active
  • šŸ“ˆ Result: 40% water savings, 30% yield increase
  • ā° Time saved: Farmer saved 2 hours daily previously spent on manual watering

"Now I can water different sections automatically while I work on other tasks!" - Farmer, Ghana

šŸ“Š Relay Logic Reference

Relay Type ON Command OFF Command Most Common
Active LOW LOW (0) HIGH (1) āœ… 90% of modules
Active HIGH HIGH (1) LOW (0) Rare
šŸŽ‰ Congratulations!

You've mastered LED and relay control for farm automation!

āœ… LED status indicators for system feedback

āœ… Relay control for pumps, lights, and valves

āœ… Automatic soil moisture-based irrigation

āœ… Multi-zone irrigation systems

Your crops will now get water exactly when they need it!

šŸ“š Quick Reference - Digital Output:
pinMode(pin, OUTPUT);              // Configure pin as output
digitalWrite(pin, HIGH);           // Set pin to 3.3V
digitalWrite(pin, LOW);            // Set pin to 0V
digitalWrite(RELAY, LOW);          // Active LOW relay ON
digitalWrite(RELAY, HIGH);         // Active LOW relay OFF
šŸ’” Key Takeaways:
  • Apply these concepts directly to your farm or project.
  • Take notes on important details for the quiz.
  • Use the button below to track your progress.