automacaoAvançadoArduinoRelésAutomaçãoWiFiMobile

Central de Automação com Arduino e Relés

Sistema completo de automação residencial com Arduino Uno, módulo de 8 relés, controle via app mobile e interface web para controlar lâmpadas, ventiladores e equipamentos.

20/07/2025
4-6 horas
R$ 120-180
Fixtron Circuits

🔧 Componentes Principais

Arduino Uno R3ESP8266 NodeMCUMódulo 8 RelésFonte 12V 3AOptoacopladoresResistoresTerminal blocks

🛠️ Ferramentas Necessárias

Arduino IDEMultímetroChaves de fendaAlicate desencapador

Central de Automação com Arduino e Relés

Construa uma central completa de automação residencial capaz de controlar até 8 dispositivos elétricos através de relés, com interface web responsiva, controle via smartphone e agendamento de tarefas. Sistema robusto e seguro para uso doméstico real.

🎯 O que você vai construir

Funcionalidades Principais:

  • Controle de 8 dispositivos via relés
  • Interface web responsiva com dashboard
  • App mobile para controle remoto
  • Agendamento automático de tarefas
  • Monitoramento em tempo real do status
  • Sistema de segurança com autenticação
  • Histórico de acionamentos
  • Controle por voz (Alexa/Google)

Dispositivos Compatíveis:

  • 💡 Lâmpadas e LED strips
  • 🌀 Ventiladores e exaustores
  • 🔌 Tomadas inteligentes
  • 🚿 Bombas d'água
  • 🚪 Fechaduras elétricas
  • ⚡ Qualquer dispositivo AC/DC até 10A

📋 Lista de Materiais

Componentes Principais

| Item | Quantidade | Preço Aprox. | Observações | |------|------------|--------------|-------------| | Arduino Uno R3 | 1 | R$ 35,00 | Ou compatível | | ESP8266 NodeMCU | 1 | R$ 25,00 | Para WiFi | | Módulo 8 Relés 5V | 1 | R$ 45,00 | Com optoacopladores | | Fonte 12V 3A | 1 | R$ 30,00 | Para alimentação | | Regulador 5V (7805) | 1 | R$ 3,00 | Para Arduino | | Capacitores 470µF | 2 | R$ 2,00 | Filtragem | | Resistores 10kΩ | 8 | R$ 1,00 | Pull-up | | LEDs 5mm | 10 | R$ 2,00 | Indicadores | | Resistores 330Ω | 10 | R$ 1,00 | Para LEDs | | Barra de terminais | 2 | R$ 8,00 | Conexões AC | | Placa perfurada | 1 | R$ 12,00 | Montagem | | Jumpers diversos | 1 lote | R$ 10,00 | Conexões | | Caixa plástica | 1 | R$ 15,00 | Proteção | | Total | | R$ 189,00 | |

Ferramentas Necessárias

  • 🔧 Ferro de solda (40W)
  • 🔌 Multímetro
  • ✂️ Alicate desencapador
  • 🪛 Chaves de fenda (pequenas)
  • 📏 Régua e estilete
  • IMPORTANTE: Conhecimento básico de eletricidade

⚠️ Segurança Elétrica

AVISOS CRÍTICOS:

  • 🚨 DESLIGUE A ENERGIA antes de fazer conexões AC
  • USE DISJUNTORES adequados para cada circuito
  • 🛡️ ISOLAMENTO TOTAL entre partes AC e DC
  • 🔒 CAIXA SELADA para proteção contra umidade
  • 📋 TESTE TUDO antes de energizar

Normas e Regulamentações:

  • Siga a NBR 5410 para instalações elétricas
  • Use DR (dispositivo residual) obrigatório
  • Contrate eletricista qualificado se necessário

🔌 Esquema de Ligação

Diagrama Principal

                    CENTRAL DE AUTOMAÇÃO
┌─────────────────────────────────────────────────────────────┐
│  ╭──────────╮     ╭──────────╮     ╭──────────────────╮     │
│  │ Fonte 12V│────▶│ Reg. 5V  │────▶│    Arduino Uno   │     │
│  ╰──────────╯     ╰──────────╯     ╰──────────────────╯     │
│                                             │               │
│  ╭──────────────╮                          │               │
│  │ ESP8266      │◀─────────────────────────┤               │
│  │ (WiFi)       │   I2C/UART               │               │
│  ╰──────────────╯                          │               │
│                                             │               │
│  ╭─────────────────────────────────────────┴─────────────╮ │
│  │              MÓDULO 8 RELÉS                           │ │
│  │  ╭───╮ ╭───╮ ╭───╮ ╭───╮ ╭───╮ ╭───╮ ╭───╮ ╭───╮    │ │
│  │  │R1 │ │R2 │ │R3 │ │R4 │ │R5 │ │R6 │ │R7 │ │R8 │    │ │
│  │  ╰─┬─╯ ╰─┬─╯ ╰─┬─╯ ╰─┬─╯ ╰─┬─╯ ╰─┬─╯ ╰─┬─╯ ╰─┬─╯    │ │
│  ╰────┼───┼───┼───┼───┼───┼───┼───┼─────────────────────╯ │
└───────┼───┼───┼───┼───┼───┼───┼───┼─────────────────────────┘
        │   │   │   │   │   │   │   │
    ╭───▼─╮ │   │   │   │   │   │   │      DISPOSITIVOS AC
    │ 💡  │ │   │   │   │   │   │   │
    │Lamp1│ │   │   │   │   │   │   │
    ╰─────╯ │   │   │   │   │   │   │
        ╭───▼─╮ │   │   │   │   │   │
        │ 🌀  │ │   │   │   │   │   │
        │Fan1 │ │   │   │   │   │   │
        ╰─────╯ │   │   │   │   │   │
            ╭───▼─╮ │   │   │   │   │
            │ 🔌  │ │   │   │   │   │
            │Tom1 │ │   │   │   │   │
            ╰─────╯ │   │   │   │   │
               ╭────▼─╮ │   │   │   │
               │ 💡   │ │   │   │   │
               │Lamp2 │ │   │   │   │
               ╰──────╯ │   │   │   │
                   ╭────▼─╮ │   │   │
                   │ 🚿   │ │   │   │
                   │Bomba │ │   │   │
                   ╰──────╯ │   │   │
                       ╭────▼─╮ │   │
                       │ 🚪   │ │   │
                       │Porta │ │   │
                       ╰──────╯ │   │
                           ╭────▼─╮ │
                           │ 💡   │ │
                           │LED   │ │
                           ╰──────╯ │
                               ╭────▼─╮
                               │ ⚡   │
                               │Extra │
                               ╰──────╯

Conexões Detalhadas

Arduino ↔ Módulo Relés

Arduino    →    Módulo Relés
D2         →    IN1
D3         →    IN2
D4         →    IN3
D5         →    IN4
D6         →    IN5
D7         →    IN6
D8         →    IN7
D9         →    IN8
5V         →    VCC
GND        →    GND

Arduino ↔ ESP8266

Arduino    →    ESP8266
A4 (SDA)   →    D2 (GPIO4)
A5 (SCL)   →    D1 (GPIO5)
5V         →    VIN
GND        →    GND

Alimentação

Fonte 12V → Regulador 7805 → Arduino (5V)
                           → Módulo Relés (5V)
                           → ESP8266 (via Arduino)

💻 Código do Projeto

1. Código do Arduino (Mestre)

#include <Wire.h>
#include <EEPROM.h>

// Definições dos pinos dos relés
const int RELAY_PINS[] = {2, 3, 4, 5, 6, 7, 8, 9};
const int NUM_RELAYS = 8;

// Estados dos relés
bool relayStates[NUM_RELAYS] = {false};

// Estrutura para dados dos dispositivos
struct Device {
  String name;
  bool state;
  bool isScheduled;
  int scheduleHour;
  int scheduleMinute;
  bool scheduleEnabled;
};

Device devices[NUM_RELAYS];

// Comunicação I2C
#define I2C_ADDRESS 8

void setup() {
  Serial.begin(115200);
  Serial.println("Iniciando Central de Automação...");
  
  // Configurar pinos dos relés
  for (int i = 0; i < NUM_RELAYS; i++) {
    pinMode(RELAY_PINS[i], OUTPUT);
    digitalWrite(RELAY_PINS[i], HIGH); // Relés são ativos em LOW
  }
  
  // Inicializar dispositivos
  initializeDevices();
  
  // Carregar estados salvos
  loadStatesFromEEPROM();
  
  // Configurar I2C como escravo
  Wire.begin(I2C_ADDRESS);
  Wire.onReceive(receiveI2C);
  Wire.onRequest(requestI2C);
  
  Serial.println("Sistema inicializado!");
  printDeviceStates();
}

void loop() {
  // Verificar agendamentos
  checkSchedules();
  
  // Aplicar estados dos relés
  updateRelays();
  
  // Debug serial
  if (Serial.available()) {
    processSerialCommand();
  }
  
  delay(1000);
}

void initializeDevices() {
  devices[0] = {"Lampada Sala", false, false, 0, 0, false};
  devices[1] = {"Ventilador Quarto", false, false, 0, 0, false};
  devices[2] = {"Tomada Cozinha", false, false, 0, 0, false};
  devices[3] = {"Lampada Quarto", false, false, 0, 0, false};
  devices[4] = {"Bomba Agua", false, false, 0, 0, false};
  devices[5] = {"Portao Eletrico", false, false, 0, 0, false};
  devices[6] = {"LED Decorativo", false, false, 0, 0, false};
  devices[7] = {"Dispositivo Extra", false, false, 0, 0, false};
}

void updateRelays() {
  for (int i = 0; i < NUM_RELAYS; i++) {
    if (relayStates[i] != devices[i].state) {
      relayStates[i] = devices[i].state;
      digitalWrite(RELAY_PINS[i], !relayStates[i]); // Inverter porque relé é ativo baixo
      
      Serial.print("Relay ");
      Serial.print(i + 1);
      Serial.print(" (");
      Serial.print(devices[i].name);
      Serial.print("): ");
      Serial.println(relayStates[i] ? "ON" : "OFF");
    }
  }
}

void checkSchedules() {
  // Para simplicidade, vamos simular horários
  // Em um projeto real, você usaria um RTC
  static unsigned long lastCheck = 0;
  if (millis() - lastCheck > 60000) { // Verificar a cada minuto
    lastCheck = millis();
    
    // Simular horário atual (você pode implementar RTC)
    int currentHour = (millis() / 3600000) % 24;
    int currentMinute = (millis() / 60000) % 60;
    
    for (int i = 0; i < NUM_RELAYS; i++) {
      if (devices[i].scheduleEnabled) {
        if (currentHour == devices[i].scheduleHour && 
            currentMinute == devices[i].scheduleMinute) {
          devices[i].state = !devices[i].state;
          Serial.print("Agendamento ativado para: ");
          Serial.println(devices[i].name);
        }
      }
    }
  }
}

void receiveI2C(int bytes) {
  String command = "";
  while (Wire.available()) {
    command += (char)Wire.read();
  }
  
  processCommand(command);
}

void requestI2C() {
  // Enviar estado atual como JSON simplificado
  String status = "{";
  for (int i = 0; i < NUM_RELAYS; i++) {
    status += "\"" + String(i) + "\":" + (devices[i].state ? "1" : "0");
    if (i < NUM_RELAYS - 1) status += ",";
  }
  status += "}";
  
  Wire.write(status.c_str());
}

void processCommand(String command) {
  Serial.print("Comando recebido: ");
  Serial.println(command);
  
  // Formato: "RELAY:1:ON" ou "RELAY:1:OFF"
  if (command.startsWith("RELAY:")) {
    int relayNum = command.substring(6, 7).toInt() - 1;
    String action = command.substring(8);
    
    if (relayNum >= 0 && relayNum < NUM_RELAYS) {
      if (action == "ON") {
        devices[relayNum].state = true;
      } else if (action == "OFF") {
        devices[relayNum].state = false;
      } else if (action == "TOGGLE") {
        devices[relayNum].state = !devices[relayNum].state;
      }
      
      saveStatesToEEPROM();
    }
  }
  
  // Formato: "SCHEDULE:1:18:30:1" (relay:hour:minute:enabled)
  if (command.startsWith("SCHEDULE:")) {
    int firstColon = command.indexOf(':', 9);
    int secondColon = command.indexOf(':', firstColon + 1);
    int thirdColon = command.indexOf(':', secondColon + 1);
    
    if (firstColon > 0 && secondColon > 0 && thirdColon > 0) {
      int relayNum = command.substring(9, firstColon).toInt() - 1;
      int hour = command.substring(firstColon + 1, secondColon).toInt();
      int minute = command.substring(secondColon + 1, thirdColon).toInt();
      bool enabled = command.substring(thirdColon + 1).toInt() == 1;
      
      if (relayNum >= 0 && relayNum < NUM_RELAYS) {
        devices[relayNum].scheduleHour = hour;
        devices[relayNum].scheduleMinute = minute;
        devices[relayNum].scheduleEnabled = enabled;
        saveStatesToEEPROM();
        
        Serial.print("Agendamento configurado: ");
        Serial.print(devices[relayNum].name);
        Serial.print(" às ");
        Serial.print(hour);
        Serial.print(":");
        Serial.println(minute);
      }
    }
  }
  
  // Comando para obter status
  if (command == "STATUS") {
    printDeviceStates();
  }
}

void processSerialCommand() {
  String command = Serial.readString();
  command.trim();
  processCommand(command);
}

void printDeviceStates() {
  Serial.println("\n=== ESTADO DOS DISPOSITIVOS ===");
  for (int i = 0; i < NUM_RELAYS; i++) {
    Serial.print(i + 1);
    Serial.print(". ");
    Serial.print(devices[i].name);
    Serial.print(": ");
    Serial.print(devices[i].state ? "ON" : "OFF");
    
    if (devices[i].scheduleEnabled) {
      Serial.print(" (Agendado: ");
      Serial.print(devices[i].scheduleHour);
      Serial.print(":");
      if (devices[i].scheduleMinute < 10) Serial.print("0");
      Serial.print(devices[i].scheduleMinute);
      Serial.print(")");
    }
    
    Serial.println();
  }
  Serial.println("==============================\n");
}

void saveStatesToEEPROM() {
  for (int i = 0; i < NUM_RELAYS; i++) {
    EEPROM.write(i, devices[i].state ? 1 : 0);
    EEPROM.write(i + 10, devices[i].scheduleHour);
    EEPROM.write(i + 20, devices[i].scheduleMinute);
    EEPROM.write(i + 30, devices[i].scheduleEnabled ? 1 : 0);
  }
}

void loadStatesFromEEPROM() {
  for (int i = 0; i < NUM_RELAYS; i++) {
    devices[i].state = EEPROM.read(i) == 1;
    devices[i].scheduleHour = EEPROM.read(i + 10);
    devices[i].scheduleMinute = EEPROM.read(i + 20);
    devices[i].scheduleEnabled = EEPROM.read(i + 30) == 1;
  }
}

2. Código do ESP8266 (WiFi Gateway)

#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <Wire.h>

// Configurações WiFi
const char* ssid = "SUA_REDE_WIFI";
const char* password = "SUA_SENHA_WIFI";

// Servidor web
AsyncWebServer server(80);

// Endereço I2C do Arduino
#define ARDUINO_I2C_ADDRESS 8

// Estados dos dispositivos
String deviceStates = "{}";

void setup() {
  Serial.begin(115200);
  
  // Inicializar I2C
  Wire.begin(4, 5); // SDA=GPIO4, SCL=GPIO5
  
  // Conectar WiFi
  WiFi.begin(ssid, password);
  Serial.print("Conectando ao WiFi");
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi conectado!");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
  
  // Configurar servidor web
  setupWebServer();
  
  Serial.println("Servidor web iniciado!");
}

void loop() {
  // Atualizar estados a cada 5 segundos
  static unsigned long lastUpdate = 0;
  if (millis() - lastUpdate > 5000) {
    updateDeviceStates();
    lastUpdate = millis();
  }
  
  delay(100);
}

void setupWebServer() {
  // Servir página principal
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", getIndexHTML());
  });
  
  // API para obter estados
  server.on("/api/states", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "application/json", deviceStates);
  });
  
  // API para controlar relés
  server.on("/api/control", HTTP_POST, [](AsyncWebServerRequest *request){
    if (request->hasParam("relay", true) && request->hasParam("action", true)) {
      String relay = request->getParam("relay", true)->value();
      String action = request->getParam("action", true)->value();
      
      String command = "RELAY:" + relay + ":" + action;
      sendCommandToArduino(command);
      
      request->send(200, "text/plain", "OK");
    } else {
      request->send(400, "text/plain", "Parâmetros inválidos");
    }
  });
  
  // API para agendamentos
  server.on("/api/schedule", HTTP_POST, [](AsyncWebServerRequest *request){
    if (request->hasParam("relay", true) && 
        request->hasParam("hour", true) && 
        request->hasParam("minute", true) &&
        request->hasParam("enabled", true)) {
      
      String relay = request->getParam("relay", true)->value();
      String hour = request->getParam("hour", true)->value();
      String minute = request->getParam("minute", true)->value();
      String enabled = request->getParam("enabled", true)->value();
      
      String command = "SCHEDULE:" + relay + ":" + hour + ":" + minute + ":" + enabled;
      sendCommandToArduino(command);
      
      request->send(200, "text/plain", "Agendamento configurado");
    } else {
      request->send(400, "text/plain", "Parâmetros inválidos");
    }
  });
  
  server.begin();
}

void sendCommandToArduino(String command) {
  Wire.beginTransmission(ARDUINO_I2C_ADDRESS);
  Wire.write(command.c_str());
  Wire.endTransmission();
  
  Serial.print("Comando enviado: ");
  Serial.println(command);
}

void updateDeviceStates() {
  Wire.requestFrom(ARDUINO_I2C_ADDRESS, 32);
  
  String response = "";
  while (Wire.available()) {
    response += (char)Wire.read();
  }
  
  if (response.length() > 0) {
    deviceStates = response;
  }
}

String getIndexHTML() {
  return R"(
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Central de Automação</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        h1 {
            text-align: center;
            color: white;
            margin-bottom: 30px;
            font-size: 2.5em;
            text-shadow: 0 2px 4px rgba(0,0,0,0.3);
        }
        
        .devices-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }
        
        .device-card {
            background: white;
            border-radius: 15px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            text-align: center;
            transition: transform 0.3s ease;
        }
        
        .device-card:hover {
            transform: translateY(-5px);
        }
        
        .device-icon {
            font-size: 3em;
            margin-bottom: 15px;
        }
        
        .device-name {
            font-size: 1.3em;
            font-weight: bold;
            margin-bottom: 15px;
            color: #333;
        }
        
        .device-status {
            padding: 8px 16px;
            border-radius: 20px;
            font-weight: bold;
            margin-bottom: 15px;
            display: inline-block;
        }
        
        .status-on {
            background: #d4edda;
            color: #155724;
        }
        
        .status-off {
            background: #f8d7da;
            color: #721c24;
        }
        
        .device-controls {
            display: flex;
            gap: 10px;
            justify-content: center;
        }
        
        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-weight: bold;
            transition: opacity 0.3s ease;
        }
        
        .btn:hover {
            opacity: 0.8;
        }
        
        .btn-on {
            background: #28a745;
            color: white;
        }
        
        .btn-off {
            background: #dc3545;
            color: white;
        }
        
        .btn-toggle {
            background: #17a2b8;
            color: white;
        }
        
        .schedule-section {
            background: white;
            border-radius: 15px;
            padding: 30px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            margin-top: 30px;
        }
        
        .schedule-form {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            align-items: end;
        }
        
        .form-group {
            display: flex;
            flex-direction: column;
        }
        
        label {
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }
        
        select, input {
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
        }
        
        .btn-schedule {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 12px 24px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-weight: bold;
        }
        
        .status-bar {
            text-align: center;
            color: white;
            margin-top: 20px;
            font-size: 0.9em;
        }
        
        @media (max-width: 768px) {
            .devices-grid {
                grid-template-columns: 1fr;
            }
            
            .schedule-form {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🏠 Central de Automação</h1>
        
        <div class="devices-grid" id="devicesGrid">
            <!-- Dispositivos serão carregados aqui -->
        </div>
        
        <div class="schedule-section">
            <h2>⏰ Agendamento de Tarefas</h2>
            <form class="schedule-form" onsubmit="scheduleDevice(event)">
                <div class="form-group">
                    <label>Dispositivo:</label>
                    <select id="scheduleDevice" required>
                        <option value="">Selecione...</option>
                        <option value="1">Lâmpada Sala</option>
                        <option value="2">Ventilador Quarto</option>
                        <option value="3">Tomada Cozinha</option>
                        <option value="4">Lâmpada Quarto</option>
                        <option value="5">Bomba Água</option>
                        <option value="6">Portão Elétrico</option>
                        <option value="7">LED Decorativo</option>
                        <option value="8">Dispositivo Extra</option>
                    </select>
                </div>
                
                <div class="form-group">
                    <label>Hora:</label>
                    <input type="number" id="scheduleHour" min="0" max="23" required>
                </div>
                
                <div class="form-group">
                    <label>Minuto:</label>
                    <input type="number" id="scheduleMinute" min="0" max="59" required>
                </div>
                
                <div class="form-group">
                    <label>Ativar:</label>
                    <select id="scheduleEnabled" required>
                        <option value="1">Sim</option>
                        <option value="0">Não</option>
                    </select>
                </div>
                
                <button type="submit" class="btn-schedule">
                    📅 Agendar
                </button>
            </form>
        </div>
        
        <div class="status-bar" id="statusBar">
            Última atualização: --
        </div>
    </div>

    <script>
        const deviceNames = [
            { name: "Lâmpada Sala", icon: "💡" },
            { name: "Ventilador Quarto", icon: "🌀" },
            { name: "Tomada Cozinha", icon: "🔌" },
            { name: "Lâmpada Quarto", icon: "💡" },
            { name: "Bomba Água", icon: "🚿" },
            { name: "Portão Elétrico", icon: "🚪" },
            { name: "LED Decorativo", icon: "✨" },
            { name: "Dispositivo Extra", icon: "⚡" }
        ];
        
        // Atualizar estados a cada 5 segundos
        setInterval(updateDeviceStates, 5000);
        updateDeviceStates();
        
        async function updateDeviceStates() {
            try {
                const response = await fetch('/api/states');
                const states = await response.json();
                
                renderDevices(states);
                
                const now = new Date();
                document.getElementById('statusBar').textContent = 
                    `Última atualização: ${now.toLocaleTimeString()}`;
                    
            } catch (error) {
                console.error('Erro ao buscar estados:', error);
                document.getElementById('statusBar').textContent = 
                    'Erro de conexão - Verificando...';
            }
        }
        
        function renderDevices(states) {
            const grid = document.getElementById('devicesGrid');
            grid.innerHTML = '';
            
            deviceNames.forEach((device, index) => {
                const isOn = states[index] === '1';
                
                const card = document.createElement('div');
                card.className = 'device-card';
                card.innerHTML = `
                    <div class="device-icon">${device.icon}</div>
                    <div class="device-name">${device.name}</div>
                    <div class="device-status ${isOn ? 'status-on' : 'status-off'}">
                        ${isOn ? 'LIGADO' : 'DESLIGADO'}
                    </div>
                    <div class="device-controls">
                        <button class="btn btn-on" onclick="controlDevice(${index + 1}, 'ON')">
                            ⚡ Ligar
                        </button>
                        <button class="btn btn-off" onclick="controlDevice(${index + 1}, 'OFF')">
                            ❌ Desligar
                        </button>
                        <button class="btn btn-toggle" onclick="controlDevice(${index + 1}, 'TOGGLE')">
                            🔄 Alternar
                        </button>
                    </div>
                `;
                
                grid.appendChild(card);
            });
        }
        
        async function controlDevice(relay, action) {
            try {
                const formData = new FormData();
                formData.append('relay', relay);
                formData.append('action', action);
                
                const response = await fetch('/api/control', {
                    method: 'POST',
                    body: formData
                });
                
                if (response.ok) {
                    // Atualizar estados imediatamente
                    setTimeout(updateDeviceStates, 500);
                } else {
                    alert('Erro ao controlar dispositivo!');
                }
            } catch (error) {
                console.error('Erro:', error);
                alert('Erro de conexão!');
            }
        }
        
        async function scheduleDevice(event) {
            event.preventDefault();
            
            const relay = document.getElementById('scheduleDevice').value;
            const hour = document.getElementById('scheduleHour').value;
            const minute = document.getElementById('scheduleMinute').value;
            const enabled = document.getElementById('scheduleEnabled').value;
            
            try {
                const formData = new FormData();
                formData.append('relay', relay);
                formData.append('hour', hour);
                formData.append('minute', minute);
                formData.append('enabled', enabled);
                
                const response = await fetch('/api/schedule', {
                    method: 'POST',
                    body: formData
                });
                
                if (response.ok) {
                    alert('Agendamento configurado com sucesso!');
                    event.target.reset();
                } else {
                    alert('Erro ao configurar agendamento!');
                }
            } catch (error) {
                console.error('Erro:', error);
                alert('Erro de conexão!');
            }
        }
    </script>
</body>
</html>
  )";
}

🔧 Montagem do Hardware

1. Preparação da Placa

  1. Corte a placa perfurada no tamanho adequado para a caixa
  2. Posicione os componentes antes de soldar
  3. Marque os furos para fixação na caixa

2. Soldagem dos Componentes

Regulador de Tensão:

Entrada 12V → Pin 1 (7805)
GND        → Pin 2 (7805) 
5V Saída   → Pin 3 (7805)

Circuito de Alimentação:

  • Capacitor 470µF na entrada (12V)
  • Capacitor 470µF na saída (5V)
  • LED indicador de energia com resistor 330Ω

3. Conexões dos Módulos

  1. Monte o Arduino em soquete para fácil remoção
  2. Conecte o módulo de relés com jumpers
  3. Instale o ESP8266 em área separada
  4. Use barra de terminais para conexões AC

4. Testes de Segurança

  • Teste de isolamento entre AC e DC
  • Verificação de curto-circuito
  • Teste de todos os relés sem carga
  • Medição de tensões com multímetro

📱 App Mobile (Bonus)

Interface React Native (Opcional)

Se você quiser criar um app mobile, aqui está um exemplo básico:

import React, { useState, useEffect } from 'react';
import { View, Text, Switch, StyleSheet, FlatList } from 'react-native';

const HomeAutomationApp = () => {
  const [devices, setDevices] = useState([]);
  
  useEffect(() => {
    fetchDeviceStates();
    const interval = setInterval(fetchDeviceStates, 5000);
    return () => clearInterval(interval);
  }, []);
  
  const fetchDeviceStates = async () => {
    try {
      const response = await fetch('http://192.168.1.100/api/states');
      const states = await response.json();
      
      const deviceList = Object.keys(states).map(key => ({
        id: parseInt(key) + 1,
        name: getDeviceName(parseInt(key)),
        state: states[key] === '1'
      }));
      
      setDevices(deviceList);
    } catch (error) {
      console.error('Erro ao buscar estados:', error);
    }
  };
  
  const toggleDevice = async (deviceId) => {
    try {
      const formData = new FormData();
      formData.append('relay', deviceId.toString());
      formData.append('action', 'TOGGLE');
      
      await fetch('http://192.168.1.100/api/control', {
        method: 'POST',
        body: formData
      });
      
      setTimeout(fetchDeviceStates, 500);
    } catch (error) {
      console.error('Erro ao controlar dispositivo:', error);
    }
  };
  
  const renderDevice = ({ item }) => (
    <View style={styles.deviceCard}>
      <Text style={styles.deviceName}>{item.name}</Text>
      <Switch
        value={item.state}
        onValueChange={() => toggleDevice(item.id)}
        trackColor={{ false: '#767577', true: '#81b0ff' }}
        thumbColor={item.state ? '#f5dd4b' : '#f4f3f4'}
      />
    </View>
  );
  
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Central de Automação</Text>
      <FlatList
        data={devices}
        renderItem={renderDevice}
        keyExtractor={item => item.id.toString()}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
    marginBottom: 20,
  },
  deviceCard: {
    backgroundColor: 'white',
    padding: 20,
    marginBottom: 10,
    borderRadius: 10,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  deviceName: {
    fontSize: 18,
    fontWeight: '500',
  },
});

function getDeviceName(index) {
  const names = [
    "Lâmpada Sala", "Ventilador Quarto", "Tomada Cozinha",
    "Lâmpada Quarto", "Bomba Água", "Portão Elétrico",
    "LED Decorativo", "Dispositivo Extra"
  ];
  return names[index] || `Dispositivo ${index + 1}`;
}

export default HomeAutomationApp;

🔧 Instalação e Configuração

1. Upload do Código

  1. Configure o Arduino IDE com as bibliotecas necessárias
  2. Carregue o código no Arduino primeiro
  3. Configure o ESP8266 com suas credenciais WiFi
  4. Carregue o código no ESP8266

2. Configuração de Rede

// No código do ESP8266, altere:
const char* ssid = "SUA_REDE_WIFI";
const char* password = "SUA_SENHA_WIFI";

3. Teste Inicial

  1. Abra o Serial Monitor (115200 baud)
  2. Verifique a conexão WiFi
  3. Anote o IP do ESP8266
  4. Teste comandos via Serial: RELAY:1:ON

4. Acesso Web

  1. Abra o navegador no IP do ESP8266
  2. Teste todos os controles da interface
  3. Configure agendamentos se necessário

🎯 Funcionalidades Avançadas

1. Integração com Alexa

// Código adicional para Alexa (usando biblioteca Sinric Pro)
#include <SinricPro.h>
#include <SinricProSwitch.h>

void setupSinricPro() {
  SinricProSwitch& mySwitch1 = SinricPro["DEVICE_ID_1"];
  mySwitch1.onPowerState(onPowerState);
  
  SinricPro.begin(APP_KEY, APP_SECRET);
}

bool onPowerState(const String &deviceId, bool &state) {
  // Encontrar qual relé corresponde ao deviceId
  int relayIndex = getRelayFromDeviceId(deviceId);
  
  if (relayIndex >= 0) {
    devices[relayIndex].state = state;
    return true;
  }
  return false;
}

2. Sensor de Presença

// Adicionar sensor PIR para automação
#define PIR_PIN A0
bool motionDetected = false;

void checkMotionSensor() {
  if (digitalRead(PIR_PIN) == HIGH && !motionDetected) {
    motionDetected = true;
    // Ligar lâmpadas automaticamente
    devices[0].state = true; // Lâmpada sala
    Serial.println("Movimento detectado - Lâmpadas ligadas");
  } else if (digitalRead(PIR_PIN) == LOW) {
    motionDetected = false;
  }
}

3. Sensor de Luminosidade

// LDR para controle automático de iluminação
#define LDR_PIN A1

void checkLightSensor() {
  int lightLevel = analogRead(LDR_PIN);
  
  // Se estiver escuro (valor alto no LDR)
  if (lightLevel > 800) {
    if (!devices[0].state) { // Se lâmpada estiver desligada
      devices[0].state = true;
      Serial.println("Escureceu - Lâmpada ligada automaticamente");
    }
  }
  // Se estiver claro
  else if (lightLevel < 300) {
    if (devices[0].state) { // Se lâmpada estiver ligada
      devices[0].state = false;
      Serial.println("Amanheceu - Lâmpada desligada automaticamente");
    }
  }
}

📊 Monitoramento e Logs

1. Sistema de Logs

// Adicionar sistema de logs
struct LogEntry {
  unsigned long timestamp;
  int relayId;
  bool state;
  String source; // "manual", "schedule", "sensor"
};

LogEntry logs[100];
int logIndex = 0;

void addLog(int relayId, bool state, String source) {
  logs[logIndex] = {millis(), relayId, state, source};
  logIndex = (logIndex + 1) % 100;
  
  Serial.print("LOG: Relay ");
  Serial.print(relayId);
  Serial.print(" -> ");
  Serial.print(state ? "ON" : "OFF");
  Serial.print(" (");
  Serial.print(source);
  Serial.println(")");
}

2. API de Histórico

// No ESP8266, adicionar endpoint para logs
server.on("/api/logs", HTTP_GET, [](AsyncWebServerRequest *request){
  DynamicJsonDocument doc(4096);
  JsonArray array = doc.createNestedArray("logs");
  
  // Solicitar logs do Arduino via I2C
  String logsJson = getLogsFromArduino();
  
  request->send(200, "application/json", logsJson);
});

🔍 Troubleshooting

Problemas Comuns

1. Relés não acionam:

  • ✅ Verificar alimentação 5V
  • ✅ Confirmar conexões dos pinos
  • ✅ Testar relés individualmente
  • ✅ Verificar se código está invertendo sinal

2. ESP8266 não conecta WiFi:

  • ✅ Verificar SSID e senha
  • ✅ Confirmar rede 2.4GHz
  • ✅ Verificar distância do roteador
  • ✅ Testar com hotspot do celular

3. Interface web não carrega:

  • ✅ Verificar IP do ESP8266
  • ✅ Confirmar que servidor iniciou
  • ✅ Testar ping para o dispositivo
  • ✅ Verificar firewall

4. Comunicação I2C falha:

  • ✅ Verificar pinos SDA/SCL
  • ✅ Confirmar endereços I2C
  • ✅ Testar com pull-ups externos
  • ✅ Verificar alimentação comum

Códigos de Debug

// Adicionar debug detalhado
void debugSystem() {
  Serial.println("\n=== DEBUG SISTEMA ===");
  Serial.print("Memória livre: ");
  Serial.println(freeMemory());
  
  Serial.print("WiFi conectado: ");
  Serial.println(WiFi.status() == WL_CONNECTED ? "SIM" : "NÃO");
  
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
  
  Serial.println("Estados dos relés:");
  for (int i = 0; i < NUM_RELAYS; i++) {
    Serial.print("  Relay ");
    Serial.print(i + 1);
    Serial.print(": ");
    Serial.println(digitalRead(RELAY_PINS[i]) == LOW ? "ON" : "OFF");
  }
  Serial.println("===================\n");
}

🚀 Melhorias Futuras

1. Banco de Dados

  • SQLite local para histórico
  • Backup automático na nuvem
  • Relatórios de consumo

2. Machine Learning

  • Padrões de uso para otimização
  • Previsão de consumo energético
  • Detecção de anomalias

3. Integração IoT

  • MQTT para comunicação
  • Home Assistant integration
  • Google Home / Alexa completa

4. Segurança Avançada

  • HTTPS com certificados
  • Autenticação JWT
  • Logs de segurança
  • Firewall de aplicação

📚 Recursos de Aprendizado

Documentação Técnica:

Tutoriais Relacionados:

  • "Comunicação I2C entre Arduino e ESP8266"
  • "Webserver Assíncrono com ESP8266"
  • "Controle de Relés com Arduino"
  • "Interface Web Responsiva para IoT"

🎉 Conclusão

Este projeto representa uma solução completa de automação residencial, combinando:

  • Hardware robusto com Arduino e ESP8266
  • Interface web moderna e responsiva
  • Controles múltiplos (web, mobile, voz)
  • Sistema de agendamento flexível
  • Arquitetura escalável para expansões

Habilidades Desenvolvidas:

  • Programação Arduino com comunicação I2C
  • Desenvolvimento web com ESP8266
  • Design de interface responsiva
  • Integração de sistemas complexos
  • Trabalho com relés e cargas AC
  • Protocolos de comunicação (HTTP, I2C)

Aplicações Reais:

  • 🏠 Residências - Controle total da casa
  • 🏢 Escritórios - Automação de iluminação
  • 🏭 Pequenas indústrias - Controle de equipamentos
  • 🌱 Estufas - Irrigação e ventilação automatizada

Próximo projeto: "Sistema de Irrigação Inteligente com Sensores de Solo"

Repositório completo: GitHub - Arduino Home Automation