Um nó ESP32 W5500 MQTT troca o Wi-Fi por um cabo de rede, o que muitas vezes é a diferença entre "quase sempre funciona" e "simplesmente funciona" dentro de um painel elétrico metálico ou no chão de fábrica, seja em uma planta em Joinville ou em um frigorífico no interior. Neste tutorial você vai conectar um ESP32 à Ethernet cabeada com um módulo SPI W5500, ou com um PHY LAN8720 em placas como a WT32-ETH01, tratar os eventos de link ativo e inativo e publicar dados de máquinas no broker.connectmq.com, o servidor MQTT público (gratuito) do ConnectMQ. O código MQTT quase não muda; o trabalho interessante está na camada de rede.
Por que Ethernet cabeada para ESP32 MQTT
O Wi-Fi é prático, mas frágil em ambientes industriais. Gabinetes de aço bloqueiam o sinal, motores e inversores geram ruído, os departamentos de TI restringem clientes sem fio e pontos de acesso são substituídos ou reconfigurados sem que ninguém avise a equipe de automação. A Ethernet elimina a maioria dessas variáveis:
| Fator | Wi-Fi | Ethernet cabeada |
|---|---|---|
| Dentro de um painel metálico | Sinal fraco ou inexistente | Não afetado |
| Ruído elétrico de inversores | Pode derrubar o link | Geralmente robusta com cabo blindado |
| Credenciais no dispositivo | SSID e senha necessários | Nenhuma para a camada de enlace |
| Consistência da latência | Varia com carga e interferência | Estável |
| Alimentação | Fonte separada | PoE opcional com um módulo adequado |
| Mobilidade | Sim | Não |
A contrapartida é o cabeamento e uma montagem de hardware um pouco mais complexa. Para um nó fixo que lê uma máquina, um medidor ou um dispositivo Modbus RS-485 e encaminha os dados para MQTT, a Ethernet cabeada costuma ser a escolha certa.
W5500 ou LAN8720?
Há duas formas comuns de dar uma porta Ethernet a um ESP32.
| W5500 | LAN8720 | |
|---|---|---|
| Interface | SPI, funciona com qualquer variante do ESP32 | RMII, exige o EMAC interno do ESP32 original |
| Pinos usados | 4 pinos SPI mais interrupção e reset | Cerca de 10 pinos fixos |
| Hardware típico | Pequeno módulo W5500, muitas placas S3 com Ethernet | WT32-ETH01, Olimex ESP32-POE, LilyGO T-ETH |
| Vazão | De sobra para MQTT | Maior, também acima do que o MQTT precisa |
| Suporte no Arduino-ESP32 3.x | Integrado ao ETH.h |
Integrado ao ETH.h |
Ambos são suportados nativamente pela biblioteca ETH no Arduino-ESP32 3.x, e ambos alimentam a mesma pilha de rede lwIP. Esse é o ponto-chave: assim que o link tem um endereço IP, NetworkClient, PubSubClient, DNS e TLS funcionam exatamente como no Wi-Fi. Se você está no core 2.x, atualize; o suporte ao W5500 no ETH.h chegou com o 3.x, e as antigas bibliotecas de contorno não são mais necessárias. A documentação do Arduino-ESP32 e os exemplos ETH que acompanham o core listam os PHYs suportados.
Ligando um módulo W5500
| Pino do W5500 | Pino do ESP32 | Observação |
|---|---|---|
| MOSI | GPIO 23 | Saída de dados SPI |
| MISO | GPIO 19 | Entrada de dados SPI |
| SCLK | GPIO 18 | Clock SPI |
| SCS / CS | GPIO 5 | Chip select |
| INT | GPIO 4 | Interrupção, recomendado |
| RST | GPIO 14 | Reset |
| 3.3V | 3V3 | Alguns módulos têm entrada de 5 V com regulador |
| GND | GND | Terra comum |
Mantenha os fios SPI curtos, abaixo de uns 10 cm em uma protoboard. O W5500 pode puxar uma corrente considerável durante a transmissão, então alimente-o com uma linha de 3,3 V firme, e não com o regulador fraco de uma placa USB-serial. A maioria dos problemas de link em protoboard acaba sendo de alimentação ou de fiação, não de software.
O sketch ESP32 W5500 MQTT
Este sketch usa o Arduino-ESP32 3.x e o PubSubClient. Ele acompanha o estado da Ethernet por eventos, conecta o MQTT apenas quando o link tem endereço IP e publica telemetria a cada cinco segundos, incluindo a velocidade do link.
#include <ETH.h>
#include <SPI.h>
#include <NetworkClient.h>
#include <PubSubClient.h>
// W5500 pins
#define ETH_PHY_TYPE ETH_PHY_W5500
#define ETH_PHY_ADDR 1
#define ETH_PHY_CS 5
#define ETH_PHY_IRQ 4
#define ETH_PHY_RST 14
#define ETH_SPI_SCK 18
#define ETH_SPI_MISO 19
#define ETH_SPI_MOSI 23
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "eth-node-6b2d90";
const char* BASE = "connectmq/demo/eth-node-6b2d90";
NetworkClient net;
PubSubClient mqtt(net);
volatile bool ethReady = false;
unsigned long lastAttempt = 0, lastPublish = 0;
void onNetworkEvent(arduino_event_id_t event) {
switch (event) {
case ARDUINO_EVENT_ETH_START:
ETH.setHostname("eth-node-6b2d90");
break;
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("Ethernet link up");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
Serial.printf("IP %s, %u Mbps, %s duplex\n", ETH.localIP().toString().c_str(),
ETH.linkSpeed(), ETH.fullDuplex() ? "full" : "half");
ethReady = true;
break;
case ARDUINO_EVENT_ETH_LOST_IP:
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("Ethernet link down");
ethReady = false;
break;
case ARDUINO_EVENT_ETH_STOP:
ethReady = false;
break;
default:
break;
}
}
void onMessage(char* topic, byte* payload, unsigned int length) {
Serial.printf("Command %s: %.*s\n", topic, (int)length, (const char*)payload);
}
bool connectMqtt() {
String status = String(BASE) + "/status";
if (!mqtt.connect(CLIENT_ID, nullptr, nullptr, status.c_str(), 1, true, "offline")) {
Serial.printf("MQTT failed, state=%d\n", mqtt.state());
return false;
}
mqtt.publish(status.c_str(), "online", true);
mqtt.subscribe((String(BASE) + "/cmd/#").c_str(), 1);
Serial.println("MQTT connected over Ethernet");
return true;
}
void setup() {
Serial.begin(115200);
Network.onEvent(onNetworkEvent);
SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI);
if (!ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI)) {
Serial.println("W5500 not detected, check wiring");
}
// Optional static IP for networks without DHCP:
// ETH.config(IPAddress(192,168,10,50), IPAddress(192,168,10,1),
// IPAddress(255,255,255,0), IPAddress(192,168,10,1));
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setKeepAlive(30);
mqtt.setSocketTimeout(5);
}
void loop() {
if (!ethReady) {
if (mqtt.connected()) mqtt.disconnect();
return;
}
if (!mqtt.connected()) {
if (millis() - lastAttempt > 5000) { lastAttempt = millis(); connectMqtt(); }
return;
}
mqtt.loop();
if (millis() - lastPublish > 5000) {
lastPublish = millis();
char json[128];
snprintf(json, sizeof(json), "{\"uptime\":%lu,\"link\":%u,\"heap\":%u}",
millis() / 1000, ETH.linkSpeed(), ESP.getFreeHeap());
mqtt.publish((String(BASE) + "/telemetry").c_str(), json);
}
}
Usando uma placa LAN8720
Em uma WT32-ETH01 ou placa LAN8720 semelhante, remova as linhas SPI e os defines do W5500 e inicie a Ethernet com os parâmetros RMII. Para a WT32-ETH01, os valores comuns são:
// type, PHY address, MDC, MDIO, power pin, clock mode
ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN);
Outras placas diferem no endereço do PHY, no pino de alimentação e no modo de clock, então consulte o esquema da placa ou o exemplo do fabricante. Tudo depois de ETH.begin(), incluindo os eventos e o código MQTT, permanece idêntico.
Teste o nó
Conecte o cabo, abra o monitor serial e procure a linha IP ... Mbps seguida de MQTT connected over Ethernet. Depois se inscreva a partir de qualquer computador:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-6b2d90 -v -t "connectmq/demo/eth-node-6b2d90/#"
Agora desconecte o cabo por vinte segundos e conecte de novo. O log serial deve mostrar link down, nenhuma tentativa de conexão MQTT enquanto o cabo está fora, depois link up, um novo evento de IP e uma reconexão. No assinante você verá status offline vindo do Last Will quando o keep-alive expirar, seguido de online após a recuperação. Vale a pena fazer esse "teste de puxar o cabo" em todo projeto de hardware novo; ele revela problemas de alimentação e de PHY que um teste de bancada com link estável nunca mostra.
O servidor MQTT público serve para este exercício e para protótipos, mas os dados dele podem ser lidos por qualquer pessoa. Dados de máquinas devem ficar em credenciais privadas.
Estruturando dados de máquinas para MQTT
A telemetria do sketch é propositalmente mínima. Em uma máquina real, decida cedo o que vai em cada mensagem e com que frequência. Algumas regras que funcionam bem na prática:
- Separe dados rápidos e lentos. Contadores, temperaturas e estados que mudam a cada segundo vão em um tópico
telemetryem intervalo fixo. Configuração, versão de firmware e números de série vão em um tópicoinfo, publicado como retido uma vez após cada conexão. - Publique estados apenas quando mudarem. Um estado de máquina como
RUNNING,IDLEouFAULTé mais útil como mensagem retida publicada só quando muda do que como um valor repetido a cada cinco segundos. - Inclua unidades e timestamp.
{"spindleTempC":41.2,"ts":1760600000}se descreve sozinho; um41.2isolado, não. - Mantenha os payloads pequenos. A Ethernet cabeada tem banda de sobra, mas o broker, seus dashboards e qualquer banco de dados a jusante pagam pelo excesso de verbosidade.
Se você publica em um broker ConnectMQ, essas convenções também tornam o explorador de tópicos ao vivo muito mais fácil de ler durante o comissionamento, porque cada máquina aparece como um ramo organizado com um punhado de tópicos significativos.
Checklist para implantação industrial
- Regras de firewall de saída. Redes de planta costumam bloquear tudo por padrão. Peça liberação de TCP 8883 de saída para o host do seu broker; você não precisa de regras de entrada, porque é o ESP32 que inicia a conexão.
- Use TLS na 8883. O
NetworkClientSecurefunciona sobre Ethernet exatamente como sobre Wi-Fi; siga ESP32 MQTT SSL com WiFiClientSecure e troque o nome da classe. - IP estático ou reserva DHCP. As equipes de operação querem conseguir encontrar o dispositivo. Uma reserva DHCP costuma ser mais fácil de gerenciar do que um endereço fixo no código.
- NTP para timestamps. Redes industriais podem bloquear NTP público; use o servidor de hora da planta.
- Watchdog. Combine o design orientado a eventos com o backoff da lógica de reconexão MQTT no ESP32 e um watchdog de hardware.
- Estrutura de tópicos. Use desde o primeiro dia uma hierarquia no estilo ISA-95, como
site/area/line/cell/device/telemetry; ela escala de um nó a uma planta inteira. - Alimentação e aterramento. Use fontes para trilho DIN, cabo blindado onde houver inversores e considere módulos PoE para dispensar um cabo de alimentação separado.
Contingência: Ethernet com backup celular
Para locais remotos, alguns projetos combinam Ethernet com um modem celular como backup. A camada MQTT continua a mesma; o firmware troca o Client que entrega ao PubSubClient. O guia ESP32 com SIM7600 4G LTE e MQTT mostra o lado celular.
De um nó a uma planta inteira
Quando alguns nós já estão publicando, o broker vira infraestrutura compartilhada da planta. Um broker MQTT gerenciado elimina a necessidade de rodar e atualizar um servidor na rede OT. O ConnectMQ detecta automaticamente estruturas de tópicos ISA-95 e Unified Namespace, então, quando seus tópicos seguem essa estrutura, a visão de dispositivos do portal agrupa seus nós Ethernet por site, área e linha, e regras de alerta por limite podem sinalizar um valor que sai da faixa normal. Usar um broker MQTT na nuvem também permite que a engenharia e o suporte remoto vejam os mesmos dados ao vivo sem acesso VPN à planta, e a mesma árvore de tópicos pode alimentar mais tarde um gêmeo digital da linha. Para a trilha completa de aprendizado com ESP32, veja o tutorial de IoT com ESP32.
Comece com o ConnectMQ
Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. Dê a cada nó Ethernet suas próprias credenciais e veja os dados das suas máquinas aparecerem no explorador de tópicos ao vivo em poucos minutos.
Perguntas frequentes
O PubSubClient funciona sobre Ethernet no ESP32?
Sim. O PubSubClient aceita qualquer Client do Arduino, e no Arduino-ESP32 3.x o NetworkClient funciona tanto sobre Wi-Fi quanto sobre Ethernet pela mesma pilha de rede.
Posso usar um W5500 com ESP32-S3 ou ESP32-C3?
Sim. O W5500 se conecta via SPI, então funciona em qualquer variante do ESP32 com pinos SPI livres. O LAN8720 precisa do EMAC interno, que, entre essas, só o ESP32 original tem.
Preciso da biblioteca Arduino Ethernet para um W5500?
Não no Arduino-ESP32 3.x. A biblioteca ETH integrada suporta o W5500 diretamente e se integra ao lwIP, então DNS, TLS e NetworkClient se comportam como no Wi-Fi.
O ESP32 pode usar Wi-Fi e Ethernet ao mesmo tempo?
Sim, as duas interfaces podem estar ativas. Garanta que o seu firmware saiba qual delas carrega a conexão MQTT e trate os eventos de ambas.



