Como automatizar portão eletrônico antigo com ESP32

Tutorial completo para transformar seu portão eletrônico em um sistema inteligente usando ESP32 e integração com assistentes de voz

Avançado
Sofia Andrade

Sofia Andrade

Especialista em IA

Seu portão eletrônico funciona perfeitamente, mas você sempre sonhou em controlá-lo pelo celular ou por comando de voz? Se o seu portão tem mais de 10 anos e não possui essas funcionalidades, este tutorial vai te mostrar como adicionar inteligência ao sistema existente sem precisar trocar a central.

Por que automatizar um portão antigo?

A maioria dos portões eletrônicos instalados entre 1995-2010 possui apenas controle remoto básico. Automatizar significa:

  • Controle remoto ilimitado: Abra de qualquer lugar do mundo
  • Integração com Alexa/Google: "Alexa, abra o portão"
  • Histórico de acessos: Veja quem entrou e quando
  • Múltiplos usuários: Compartilhe acesso com família
  • Notificações: Receba alerta quando alguém chegar

Material necessário

Componentes eletrônicos:

  • ESP32 DevKit V1 - R$ 30-50
  • Módulo relé 5V 1 canal - R$ 12-25
  • Sensor magnético reed switch - R$ 15-30
  • Fonte 5V 2A - R$ 22-35
  • Protoboard e jumpers - R$ 15-25
  • Caixa plástica vedada - R$ 15-25

Ferramentas:

  • Ferro de solda
  • Multímetro
  • Furadeira
  • Chaves de fenda/phillips

Custo total: R$ 110-190

⚠️ Importante: As marcas mencionadas neste tutorial (Broadlink, Sinric Pro, Home Assistant, etc.) são citadas apenas para fins educativos e informativos. Não possuímos qualquer parceria, vínculo comercial ou patrocínio com essas empresas. As recomendações são baseadas em funcionalidade técnica e disponibilidade no mercado brasileiro.

Como funciona o sistema

O ESP32 atua como um "intermediário inteligente" entre você e a central do portão:

  1. Detecção: Sensor magnético monitora se portão está aberto/fechado
  2. Comando: ESP32 recebe comando (app, Alexa, botão)
  3. Acionamento: Relé simula o botão do controle remoto original
  4. Feedback: Sistema confirma se portão abriu/fechou
  5. Histórico: Registra todos os acionamentos com data/hora

Preparando o ambiente de desenvolvimento

1. Instalar Arduino IDE

Baixe em: https://www.arduino.cc/en/software

2. Configurar ESP32 no Arduino IDE

  • Vá em Arquivo > Preferências
  • Em "URLs Adicionais", adicione:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  • Ferramentas > Placa > Gerenciador de Placas
  • Procure "esp32" e instale

3. Instalar bibliotecas necessárias

No Arduino IDE: Sketch > Incluir Biblioteca > Gerenciar Bibliotecas

Instale estas bibliotecas:

  • WiFi (já incluída no ESP32)
  • ESPAsyncWebServer por lacamera
  • AsyncTCP por dvarrel
  • ArduinoJson por Benoit Blanchon
  • NTPClient por Fabrice Weinberg

Montagem do circuito

Conexões ESP32:

ESP32Componente
GPIO 2LED indicador (opcional)
GPIO 4Pino IN do módulo relé
GPIO 18Reed switch (sensor portão)
5VVCC do relé
GNDGND do relé e reed switch

⚠️ Importante - Segurança:

  • NUNCA conecte o ESP32 diretamente na rede elétrica 110V/220V
  • Use sempre um relé adequado para isolar os circuitos
  • Desligue a energia antes de fazer qualquer conexão

Esquema de ligação na central do portão:

A maioria das centrais antigas possui dois fios para botão externo (normalmente rotulados como "BOTÃO" ou "BT"). O relé vai simular o pressionamento deste botão:

Central do Portão:

  • Fio 1 (BOTÃO +) → Terminal COM do relé
  • Fio 2 (BOTÃO -) → Terminal NA do relé

Código do ESP32

👀 Ver código completo do ESP32
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Configurações WiFi
const char* ssid = "SEU_WIFI";
const char* password = "SUA_SENHA";

// Pinos
const int RELAY_PIN = 4;
const int REED_PIN = 18;
const int LED_PIN = 2;

// Servidor web
AsyncWebServer server(80);

// NTP para timestamp
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", -3*3600, 60000);

// Variáveis de estado
bool portaoAberto = false;
unsigned long ultimoAcionamento = 0;
String historicoAcessos = "";

void setup() {
  Serial.begin(115200);
  
  // Configurar pinos
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(REED_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  
  digitalWrite(RELAY_PIN, LOW);
  digitalWrite(LED_PIN, LOW);
  
  // Conectar WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando ao WiFi...");
    digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Piscar LED
  }
  
  digitalWrite(LED_PIN, HIGH); // LED fixo quando conectado
  Serial.println("WiFi conectado!");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
  
  // Iniciar NTP
  timeClient.begin();
  
  // Configurar rotas do servidor web
  configurarRotas();
  
  // Iniciar servidor
  server.begin();
  Serial.println("Servidor iniciado!"
    </>);
}

void loop() {
  timeClient.update();
  
  // Ler estado do sensor
  bool estadoAtual = digitalRead(REED_PIN) == LOW; // LOW = portão aberto
  
  if (estadoAtual != portaoAberto) {
    portaoAberto = estadoAtual;
    String evento = portaoAberto ? "ABERTO" : "FECHADO";
    adicionarHistorico(evento + " (sensor)");
    Serial.println("Portão: " + evento);
  }
  
  delay(100);
}

void acionarPortao() {
  Serial.println("Acionando portão...");
  
  // Pulso no relé (simula pressionar botão)
  digitalWrite(RELAY_PIN, HIGH);
  delay(500); // 0.5 segundos
  digitalWrite(RELAY_PIN, LOW);
  
  ultimoAcionamento = millis();
  adicionarHistorico("ACIONADO (comando)");
}

void adicionarHistorico(String evento) {
  String timestamp = timeClient.getFormattedTime();
  String entrada = timestamp + " - " + evento + "\n";
  historicoAcessos = entrada + historicoAcessos;
  
  // Manter apenas últimas 50 entradas
  int contadorLinhas = 0;
  int posicao = 0;
  while ((posicao = historicoAcessos.indexOf('\n', posicao + 1)) != -1) {
    contadorLinhas++;
    if (contadorLinhas >= 50) {
      historicoAcessos = historicoAcessos.substring(0, posicao);
      break;
    }
  }
}

void configurarRotas() {
  // Página principal
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    String html = gerarPaginaHTML();
    request->send(200, "text/html", html);
  });
  
  // Acionar portão
  server.on("/acionar", HTTP_POST, [](AsyncWebServerRequest *request){
    acionarPortao();
    request->send(200, "application/json", "{\"status\":\"ok\",\"message\":\"Portão acionado\"}");
  });
  
  // Status do portão
  server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request){
    StaticJsonDocument<200> doc;
    doc["portaoAberto"] = portaoAberto;
    doc["ultimoAcionamento"] = ultimoAcionamento;
    doc["timestamp"] = timeClient.getFormattedTime();
    
    String response;
    serializeJson(doc, response);
    request->send(200, "application/json", response);
  });
  
  // Histórico
  server.on("/historico", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", historicoAcessos);
  });
}

String gerarPaginaHTML() {
  String html = R"(
<!DOCTYPE html>
<html>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <title>Controle do Portão</title>
    <style>
        body { font-family: Arial; text-align: center; margin: 20px; }
        .button { 
            background: #4CAF50; color: white; padding: 15px 30px; 
            border: none; border-radius: 5px; font-size: 18px; 
            cursor: pointer; margin: 10px;
        }
        .button:hover { background: #45a049; }
        .status { 
            padding: 10px; margin: 20px 0; border-radius: 5px; 
            font-weight: bold; font-size: 16px;
        }
        .aberto { background: #f44336; color: white; }
        .fechado { background: #4CAF50; color: white; }
        #historico { 
            text-align: left; background: #f5f5f5; 
            padding: 10px; border-radius: 5px; 
            font-family: monospace; white-space: pre-line;
            max-height: 300px; overflow-y: auto;
        }
    </style>
</head>
<body>
    <h1>🚪 Controle do Portão Inteligente</h1>
    
    <div id='status' class='status'>
        Carregando status...
    </div>
    
    <button class='button' onclick='acionarPortao()'>
        🔄 Acionar Portão
    </button>
    
    <h3>📋 Histórico de Acessos</h3>
    <div id='historico'>Carregando histórico...</div>
    
    <script>
        function atualizarStatus() {
            fetch('/status')
                .then(response => response.json())
                .then(data => {
                    const statusDiv = document.getElementById('status');
                    if (data.portaoAberto) {
                        statusDiv.textContent = '🔓 PORTÃO ABERTO';
                        statusDiv.className = 'status aberto';
                    } else {
                        statusDiv.textContent = '🔒 PORTÃO FECHADO';
                        statusDiv.className = 'status fechado';
                    }
                });
        }
        
        function acionarPortao() {
            fetch('/acionar', { method: 'POST' })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                    setTimeout(atualizarStatus, 2000); // Atualizar após 2s
                });
        }
        
        function atualizarHistorico() {
            fetch('/historico')
                .then(response => response.text())
                .then(data => {
                    document.getElementById('historico').textContent = data || 'Nenhum histórico ainda.';
                });
        }
        
        // Atualizar a cada 5 segundos
        setInterval(atualizarStatus, 5000);
        setInterval(atualizarHistorico, 10000);
        
        // Carregar inicial
        atualizarStatus();
        atualizarHistorico();
    </script>
</body>
</html>
  )";
  
  return html;
}

Interface Web Completa

O sistema inclui uma interface web responsiva com controle completo do portão:

Funcionalidades da interface:

  • 🚪 Status em tempo real: Portão aberto/fechado
  • 🔄 Botão de acionamento: Abrir/fechar remotamente
  • 📋 Histórico completo: Últimos 50 eventos
  • 📱 Design responsivo: Funciona em qualquer dispositivo
  • 🔄 Atualização automática: Status a cada 5 segundos

Instalação física

1. Localização do ESP32

Instale próximo à central do portão, em local protegido da chuva:

  • Dentro de caixa vedada IP65
  • Próximo a tomada 110V/220V
  • Com sinal WiFi adequado

2. Instalação do sensor reed switch

O sensor detecta se o portão está aberto/fechado:

  • Fixe o ímã na parte móvel do portão
  • Fixe o sensor na parte fixa (pilar/muro)
  • Distância máxima: 2cm entre ímã e sensor
  • Teste antes de fixar definitivamente

3. Conexão na central existente

⚠️ IMPORTANTE: Desligue a energia antes desta etapa

  • Localize os terminais "BOTÃO" na sua central
  • Desconecte um dos fios do botão existente (se houver)
  • Conecte os terminais COM e NA do relé nestes pontos
  • O botão original continuará funcionando normalmente

Configuração e teste

1. Upload do código

  1. Conecte ESP32 no computador via USB
  2. Selecione a placa: ESP32 Dev Module
  3. Selecione a porta COM correta
  4. Altere SSID e senha do WiFi no código
  5. Faça upload

2. Primeiro teste

  1. Abra o monitor serial (115200 baud)
  2. ESP32 deve conectar ao WiFi e exibir o IP
  3. Acesse o IP no navegador
  4. Teste o botão "Acionar Portão"

3. Teste do sensor

  • Aproxime/afaste o ímã do sensor
  • Status deve mudar na interface web
  • Histórico deve registrar as mudanças

Integração com Alexa

Para controle por voz, use o serviço Sinric Pro (gratuito para até 3 dispositivos):

1. Criar conta no Sinric Pro

  • Acesse: https://sinric.pro/
  • Crie conta gratuita
  • Adicione dispositivo tipo "Switch"

2. Código adicional para Alexa

Adicione estas linhas no início do código:

#include <SinricPro.h>
#include <SinricProSwitch.h>

#define SINRIC_APP_KEY    "SEU_APP_KEY"
#define SINRIC_APP_SECRET "SEU_APP_SECRET"
#define SINRIC_DEVICE_ID  "SEU_DEVICE_ID"

bool onPowerState(const String &deviceId, bool &state) {
  acionarPortao();
  state = true; // Sempre retorna true após acionar
  return true;
}

// No setup(), adicione:
SinricProSwitch& mySwitch = SinricPro[SINRIC_DEVICE_ID];
mySwitch.onPowerState(onPowerState);
SinricPro.begin(SINRIC_APP_KEY, SINRIC_APP_SECRET);

3. Vincular com Alexa

  1. Instale skill "Sinric Pro" na Alexa
  2. Faça login com sua conta
  3. Descubra dispositivos
  4. Comando: "Alexa, ligar portão"

Troubleshooting

Problema: ESP32 não conecta ao WiFi

Soluções:
  • Verificar SSID e senha no código
  • Testar com celular se WiFi está funcionando
  • Aproximar ESP32 do roteador
  • Verificar se rede é 2.4GHz (ESP32 não suporta 5GHz)

Problema: Portão não aciona

Verificações:
  • Relé está energizado? (LED do relé deve acender)
  • Conexões na central estão corretas?
  • Fios não estão invertidos?
  • Central do portão está ligada?

Problema: Sensor não detecta posição

Soluções:
  • Aproximar ímã do sensor (máximo 2cm)
  • Verificar polaridade do ímã
  • Testar sensor com multímetro
  • Verificar conexão dos fios

Problema: Interface web não carrega

Verificações:
  • ESP32 está conectado ao WiFi?
  • IP está correto?
  • Firewall não está bloqueando?
  • Tentar acessar por outro dispositivo

Melhorias avançadas

1. Notificação push no celular

Integrate com Pushover ou Telegram Bot:

  • Receba notificação quando portão abrir
  • Alerta se portão ficar aberto por muito tempo

2. Controle por aplicativo dedicado

Use Blynk para criar app personalizado:

  • Interface mais bonita
  • Widgets customizados
  • Histórico com gráficos

3. Backup de configurações

Salve configurações na memória EEPROM:

  • WiFi não precisa ser reprogramado
  • Configurações via interface web

4. Câmera de segurança

Adicione ESP32-CAM para:

  • Ver quem está no portão
  • Foto automática quando acionar
  • Stream de vídeo

Considerações de segurança

1. Segurança de rede

  • Use senha forte no WiFi
  • Considere criar rede separada (IoT)
  • Atualize firmware do roteador

2. Segurança física

  • Proteja ESP32 em caixa vedada
  • Dificulte acesso aos fios
  • Use fonte com proteção

3. Backup manual

  • Mantenha controle remoto original
  • Instale botão manual de emergência
  • Documente as conexões

Custo-benefício

Investimento e economia:

  • Investimento inicial: R$ 110-190
  • Economia vs. sistema novo: R$ 800-1500

Funcionalidades adicionais:

  • Controle remoto ilimitado
  • Integração com Alexa/Google
  • Histórico de acessos
  • Notificações personalizadas
  • Expansão futura (câmeras, sensores)

Conclusão

Automatizar um portão antigo com ESP32 é um projeto gratificante que combina eletrônica básica com programação e resulta em um sistema extremamente útil no dia a dia.

O sistema criado é robusto, confiável e pode ser expandido com diversas funcionalidades. Mais importante: você não precisa descartar seu equipamento antigo - apenas adiciona inteligência a ele.

Próximos passos sugeridos:

  1. Monte o circuito em protoboard primeiro
  2. Teste todas as funcionalidades
  3. Solde em placa perfurada para instalação definitiva
  4. Documente sua instalação específica
  5. Compartilhe sua experiência com a comunidade maker!

Tem alguma dúvida ou sugestão? A automação residencial é um mundo fascinante e este é apenas o primeiro passo de uma jornada muito interessante!

💡 Dica: Depois de dominar este projeto, você pode aplicar os mesmos conceitos para automatizar outros equipamentos antigos como interfones, sistemas de irrigação e equipamentos industriais.