O SIM7600 MQTT permite que um ESP32 publique dados onde não existe Wi-Fi algum: estações de bombeamento, canteiros de obras, veículos, lavouras e gabinetes remotos. Neste tutorial você vai ligar um modem 4G LTE SIM7600, registrá-lo na rede móvel com TinyGSM, conectar o PubSubClient ao servidor MQTT público broker.connectmq.com através do modem e se recuperar de forma limpa de quedas de rede. Você também vai descobrir para onde vão de fato os dados móveis e como manter o consumo mensal baixo.
Como as peças se encaixam
O SIM7600 é um modem celular completo, com pilha TCP/IP própria. O ESP32 conversa com ele por uma UART usando comandos AT. O TinyGSM encapsula esses comandos em uma classe Client do Arduino, a TinyGsmClient, e como o PubSubClient aceita qualquer Client, o código MQTT é quase idêntico ao de um sketch com Wi-Fi.
| Camada | Componente | Responsabilidade |
|---|---|---|
| Aplicação | Seu sketch | Ler sensores, decidir o que publicar |
| MQTT | PubSubClient | CONNECT, PUBLISH, SUBSCRIBE, keep-alive |
| Transporte | TinyGsmClient | Abre sockets TCP dentro do modem via comandos AT |
| Modem | SIM7600 | Registro na rede, contexto PDP, TCP/IP |
| Rádio | Rede LTE e SIM | Cobertura, APN, plano de dados |
A maioria dos problemas com MQTT celular não é problema de MQTT. São problemas de alimentação, antena, SIM ou APN que aparecem como "o MQTT não conecta". Por isso o sketch verifica cada camada separadamente e registra onde falha.
Hardware
- Uma placa ESP32 com módulo SIM7600. Placas integradas como a série LilyGO T-SIM7600 são o começo mais fácil; um breakout SIM7600 separado mais um ESP32 DevKit também funciona.
- Um chip micro ou nano SIM com plano de dados ativo. Chips de dados para IoT são ideais; um chip de celular serve para testes.
- Uma antena LTE conectada à porta de antena principal. Nunca ligue o modem sem antena.
- Uma fonte capaz de fornecer os picos de corrente de transmissão do modem. Uma boa célula 18650 ou uma fonte de 5 V de pelo menos 2 A é uma base sensata.
A alimentação é a causa número um de falhas. Modems LTE puxam picos curtos e altos de corrente ao transmitir. Uma porta USB fraca ou fios finos causam quedas de tensão que reiniciam o modem no meio da conexão, e os sintomas parecem aleatórios: às vezes ele registra, às vezes não, às vezes desconecta após algumas mensagens.
| Sinal | Pino típico na LilyGO T-SIM7600 | Função |
|---|---|---|
| TX do modem para RX do ESP32 | GPIO 26 | Dados UART vindos do modem |
| RX do modem a partir do TX do ESP32 | GPIO 27 | Dados UART para o modem |
| PWRKEY | GPIO 4 | Pulso para ligar o modem |
| Habilitação de alimentação | GPIO 12 | Habilita a alimentação do modem em algumas revisões da placa |
A atribuição de pinos varia entre placas e revisões. Consulte a documentação da sua placa e ajuste os defines no sketch.
Bibliotecas
Instale pelo Library Manager da Arduino IDE:
- TinyGSM, de Volodymyr Shymanskyy.
- PubSubClient, de Nick O'Leary.
O TinyGSM precisa saber o modelo do modem em tempo de compilação, por isso #define TINY_GSM_MODEM_SIM7600 deve aparecer antes do include.
O sketch completo de SIM7600 MQTT
#define TINY_GSM_MODEM_SIM7600
#define TINY_GSM_RX_BUFFER 1024 // larger buffer for incoming MQTT data
#include <TinyGsmClient.h>
#include <PubSubClient.h>
// ---- Board pins (LilyGO T-SIM7600 defaults, adjust for your board) ----
#define MODEM_TX 27
#define MODEM_RX 26
#define MODEM_PWRKEY 4
#define MODEM_POWER 12
// ---- Cellular settings ----
const char APN[] = "internet"; // from your SIM provider
const char APN_USER[] = "";
const char APN_PASS[] = "";
const char SIM_PIN[] = ""; // leave empty if the SIM has no PIN
// ---- MQTT settings ----
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "lte-81c3e5"; // unique
const char* BASE = "connectmq/demo/lte-81c3e5";
HardwareSerial SerialAT(1);
TinyGsm modem(SerialAT);
TinyGsmClient gsmClient(modem);
PubSubClient mqtt(gsmClient);
unsigned long lastAttempt = 0, lastPublish = 0;
const unsigned long PUBLISH_INTERVAL = 60000; // one reading per minute
void powerOnModem() {
pinMode(MODEM_POWER, OUTPUT);
digitalWrite(MODEM_POWER, HIGH);
pinMode(MODEM_PWRKEY, OUTPUT);
digitalWrite(MODEM_PWRKEY, LOW);
delay(100);
digitalWrite(MODEM_PWRKEY, HIGH); // pulse to switch on
delay(1000);
digitalWrite(MODEM_PWRKEY, LOW);
}
bool ensureNetwork() {
if (!modem.isNetworkConnected()) {
Serial.println("Waiting for network registration...");
if (!modem.waitForNetwork(60000L)) {
Serial.println("No network: check antenna, SIM and coverage");
return false;
}
Serial.printf("Registered, signal quality %d\n", modem.getSignalQuality());
}
if (!modem.isGprsConnected()) {
Serial.printf("Opening data connection with APN %s\n", APN);
if (!modem.gprsConnect(APN, APN_USER, APN_PASS)) {
Serial.println("Data connection failed: check APN and data plan");
return false;
}
Serial.print("Local IP: ");
Serial.println(modem.localIP());
}
return true;
}
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 LTE");
return true;
}
void setup() {
Serial.begin(115200);
SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
powerOnModem();
Serial.println("Initializing modem...");
if (!modem.init()) {
Serial.println("init failed, trying restart");
modem.restart();
}
Serial.println("Modem: " + modem.getModemInfo());
if (strlen(SIM_PIN) && modem.getSimStatus() == SIM_LOCKED) modem.simUnlock(SIM_PIN);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setKeepAlive(120); // fewer pings, less data
mqtt.setSocketTimeout(15); // cellular round trips are slower
}
void loop() {
if (!mqtt.connected()) {
if (millis() - lastAttempt > 15000) {
lastAttempt = millis();
if (ensureNetwork()) connectMqtt();
}
return;
}
mqtt.loop();
if (millis() - lastPublish > PUBLISH_INTERVAL) {
lastPublish = millis();
char json[64];
snprintf(json, sizeof(json), "{\"t\":%.1f,\"csq\":%d}",
20.0 + (esp_random() % 100) / 10.0, modem.getSignalQuality());
mqtt.publish((String(BASE) + "/telemetry").c_str(), json);
}
}
O que observar no monitor serial
Uma inicialização saudável imprime a identificação do modem, Registered, signal quality N, o IP local e MQTT connected over LTE. A qualidade de sinal é o valor CSQ de 0 a 31, sendo que 99 significa desconhecido. Valores abaixo de cerca de 10 são marginais; reposicione a antena antes de culpar o software. Se o sketch para no registro, o problema é SIM, cobertura ou antena. Se registra, mas a conexão de dados falha, o APN está errado ou o plano não tem dados. Se ambos funcionam, mas o MQTT falha com estado -2, a conexão TCP está sendo bloqueada; alguns chips restritivos só permitem destinos de uma lista liberada.
Teste a partir do seu computador
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-81c3e5 -v -t "connectmq/demo/lte-81c3e5/#"
Você deve ver status online seguido de uma mensagem de telemetria a cada minuto. Envie um comando para verificar o caminho de descida, o que também prova que o NAT da operadora mantém a conexão aberta:
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-81c3e5 -t "connectmq/demo/lte-81c3e5/cmd" -m "ping"
O servidor MQTT público (gratuito) serve para a ativação inicial, mas tudo o que você publica ali pode ser lido por qualquer pessoa, então mude para credenciais próprias antes de o dispositivo sair da bancada.
Mantendo baixo o consumo de dados do SIM7600 MQTT
Planos celulares cobram por byte, e o MQTT só é eficiente se você o usar com eficiência. Estas são as alavancas que mais importam, mais ou menos em ordem de impacto:
- Evite reconexões. Cada nova conexão custa um handshake TCP, o CONNECT e o CONNACK do MQTT, as inscrições e, com TLS, um handshake completo incluindo a cadeia de certificados. Um dispositivo que reconecta a cada poucos minutos pode gastar mais dados conectando do que enviando telemetria. Corrija a causa raiz das quedas em vez de reconectar por timer.
- Ajuste o keep-alive. A cada período de keep-alive, o cliente envia um pequeno PINGREQ e o broker responde. Um keep-alive mais longo economiza dados, mas os gateways NAT das operadoras derrubam conexões ociosas depois de um tempo, e se o keep-alive for maior que isso, a conexão morre silenciosamente. Comece com cerca de dois minutos e ajuste conforme o que observar.
- Encurte os payloads. Use chaves JSON curtas (
"t"em vez de"temperature"), arredonde valores e omita campos que raramente mudam. - Agrupe leituras. Enviar dez leituras em uma única mensagem a cada dez minutos custa muito menos overhead do que dez mensagens separadas.
- Publique na mudança. Para valores que mudam devagar, publique só quando o valor variar além de um limite, mais um heartbeat periódico.
- Use tópicos curtos. O tópico é enviado com cada mensagem.
f/42/té mais barato que um caminho longo e descritivo, embora a legibilidade também importe; encontre um equilíbrio. - Fique de olho nas inscrições. Inscrições com curinga em tópicos movimentados podem trazer muito mais dados do que você espera.
Lembre-se de que as operadoras podem arredondar cada sessão ou período de cobrança para uma unidade mínima, então meça o consumo real no portal do seu provedor de SIM por alguns dias em vez de confiar em cálculos.
Segurança em links celulares
Em produção, use TLS na porta 8883 e o usuário, a senha e o client ID gerados no portal do ConnectMQ. No SIM7600 você tem duas opções. Algumas versões e forks do TinyGSM expõem um cliente seguro que usa o motor SSL embutido do modem, o que poupa memória do ESP32; verifique se a versão instalada suporta isso para o SIM7600. Como alternativa, rode o TLS no próprio ESP32 com uma biblioteca wrapper como a SSLClient sobre o TinyGsmClient. Em ambos os casos, valide o certificado do broker contra a raiz ISRG Root X1 em vez de desativar a verificação. O guia de ESP32 MQTT SSL explica a escolha do certificado e por que o NTP ou a hora da rede importam; o SIM7600 também pode fornecer a hora da rede.
Solução de problemas
- O modem nunca responde a AT. Pinos UART errados, baud rate errado ou o modem não está alimentado. Verifique o pino de habilitação de alimentação e o pulso de PWRKEY da sua placa.
- Registra só em 2G ou 3G, ou nem registra. A banda pode não ser suportada pela sua variante do SIM7600 (E, A, SA, G e outras cobrem regiões diferentes).
- Conecta e cai após alguns minutos de silêncio. Keep-alive maior que o timeout de NAT da operadora. Reduza-o.
- Resets por brownout durante a transmissão. A fonte não consegue fornecer a corrente de pico. Adicione um capacitor grande perto do modem e use fios mais grossos.
- Mensagens atrasadas em segundos. Normal em links celulares; a latência é maior e mais variável que no Wi-Fi. Projete levando isso em conta.
Para uma estratégia de reconexão mais robusta com backoff, adapte a máquina de estados da lógica de reconexão MQTT no ESP32. Se houver opção cabeada no local, compare com ESP32 Ethernet MQTT com W5500 e, para ativos em movimento, veja o rastreador GPS com ESP32 via MQTT.
Operando uma frota celular
Visitar dispositivos celulares é caro, então o lado do broker deve ser a última das suas preocupações. Um broker MQTT gerenciado mantém o endpoint disponível enquanto os dispositivos trocam de célula e reconectam. O ConnectMQ dá a cada dispositivo suas próprias credenciais, mostra o estado de conexão via $SYS/broker/connection/{clientId}/state e permite acompanhar o tráfego ao vivo no portal, o que ajuda quando você está tentando entender para onde vão os dados de um chip. Um broker MQTT na nuvem com hostname público também evita as configurações de APN privado e VPN que brokers auto-hospedados muitas vezes exigem para dispositivos celulares. Se este é o seu primeiro projeto com ESP32, comece pelo tutorial de IoT com ESP32.
Comece com o ConnectMQ
Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. Seus dispositivos SIM7600 podem publicar nele de qualquer lugar com cobertura, e você pode ver cada mensagem chegar no explorador de tópicos ao vivo.
Perguntas frequentes
O PubSubClient funciona com o SIM7600?
Sim. O TinyGSM fornece o TinyGsmClient, que implementa a interface Client do Arduino, então o PubSubClient usa os sockets TCP do modem exatamente como usaria o Wi-Fi.
Quantos dados o SIM7600 MQTT consome?
Depende principalmente da frequência de reconexões, do intervalo de keep-alive e do tamanho do payload. Um dispositivo que permanece conectado e envia mensagens compactas consome muito pouco; reconexões frequentes, principalmente com TLS, dominam o consumo. Meça no portal do seu provedor de SIM.
Qual APN devo usar?
O APN vem do seu provedor de SIM e normalmente está na documentação ou no portal IoT dele. Um APN errado deixa o modem se registrar na rede, mas impede a conexão de dados.
Posso usar MQTT sobre TLS com o SIM7600?
Sim, seja pelo motor SSL do modem, se a sua versão do TinyGSM suportar isso para o SIM7600, seja rodando o TLS no ESP32 com uma biblioteca wrapper sobre o TinyGsmClient. Sempre valide o certificado do broker.



