⚠ Bezpečnosť na prvom mieste: Relay moduly pracujú s 230V sieťovým napätím. Zapojenie vždy rob pri odpojenom napájaní. Ak si nie si istý, nechaj inštaláciu elektrikárovi. Autor nenesie zodpovednosť za škody spôsobené nesprávnym zapojením.

Výber relay modulu

ParameterBežný 5V relay modulSolid State Relay (SSR)
Riadiace napätie5V (aj 3,3V cez tranzistor)3–32V DC priamo
Spínací čas~10 ms<1 ms
Zvukklik pri spínanítiché
Záťaž (230V)10A / 2300W25–40A
Cena~0,50 €5–15 €
Odporúčanieprototypy, nízka záťažprodukcia, výkonné spotrebiče

Zapojenie relay modulu k ESP32

Väčšina lacných relay modulov funguje na logiku active LOW — relay sa aktivuje keď GPIO = LOW (0V), nie HIGH. Toto je dôležité vedieť pri programovaní.

ESP32 GPIO26 ──→ IN (relay modul)
ESP32 GND     ──→ GND (relay modul)
5V zdroj      ──→ VCC (relay modul)

// Pozor: ESP32 je 3,3V zariadenie. Ak relay modul vyžaduje 5V
// signál na IN, použi tranzistor (napr. 2N2222) alebo
// level shifter, alebo relay modul s optoisolátorm kompatibilným s 3,3V.

ESP32 kód — HTTP API server

ESP32 beží vlastný HTTP server, ktorý prijíma príkazy od Laravel backendu. Toto je jednoduchší prístup ako MQTT pre jednoduché on/off ovládanie.

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>

#define RELAY_PIN 26
#define API_KEY   "tajny-esp32-kluc"

WebServer server(80);
bool relayState = false;

void handleRelay() {
    if (server.header("X-API-Key") != API_KEY) {
        server.send(401, "application/json", "{\"error\":\"Unauthorized\"}");
        return;
    }

    StaticJsonDocument<64> body;
    deserializeJson(body, server.arg("plain"));
    String action = body["action"].as<String>();

    if (action == "on") {
        digitalWrite(RELAY_PIN, LOW);   // active LOW
        relayState = true;
    } else if (action == "off") {
        digitalWrite(RELAY_PIN, HIGH);
        relayState = false;
    } else if (action == "toggle") {
        relayState = !relayState;
        digitalWrite(RELAY_PIN, relayState ? LOW : HIGH);
    }

    StaticJsonDocument<64> resp;
    resp["state"] = relayState ? "on" : "off";
    String out;
    serializeJson(resp, out);
    server.send(200, "application/json", out);
}

void handleStatus() {
    StaticJsonDocument<64> resp;
    resp["state"] = relayState ? "on" : "off";
    resp["uptime"] = millis() / 1000;
    String out;
    serializeJson(resp, out);
    server.send(200, "application/json", out);
}

void setup() {
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, HIGH); // relay OFF pri štarte (active LOW)

    WiFi.begin("SSID", "PASS");
    while (WiFi.status() != WL_CONNECTED) delay(500);

    server.on("/relay", HTTP_POST, handleRelay);
    server.on("/status", HTTP_GET, handleStatus);
    server.begin();
    Serial.println("ESP32 IP: " + WiFi.localIP().toString());
}

void loop() {
    server.handleClient();
}

Laravel backend — ovládanie a logovanie

// app/Http/Controllers/RelayController.php
class RelayController extends Controller
{
    public function toggle(Request $request, string $deviceIp): JsonResponse
    {
        $request->validate(['action' => 'required|in:on,off,toggle']);

        $response = Http::withHeaders(['X-API-Key' => config('iot.esp32_key')])
            ->post("http://{$deviceIp}/relay", ['action' => $request->action]);

        RelayLog::create([
            'device_ip' => $deviceIp,
            'action'    => $request->action,
            'state'     => $response->json('state'),
            'user_id'   => auth()->id(),
        ]);

        return response()->json($response->json());
    }

    public function status(string $deviceIp): JsonResponse
    {
        $response = Http::get("http://{$deviceIp}/status");
        return response()->json($response->json());
    }
}

Plánovanie cez n8n

Cron triggery v n8n umožnia automaticky zapínať/vypínať zariadenia podľa rozvrhu bez toho, aby si musel písať ďalší kód.

// n8n workflow — zapni čerpadlo každý deň o 7:00
Cron trigger (0 7 * * *)
  → HTTP Request: POST http://laravel.local/api/relay/192.168.1.50
  → Body: {"action": "on"}
  → Header: Authorization: Bearer {api_token}

// o 7:30 vypni
Cron trigger (30 7 * * *)
  → HTTP Request: POST http://laravel.local/api/relay/192.168.1.50
  → Body: {"action": "off"}

Bezpečnostné pravidlá