SIM7600 MQTT permite que un ESP32 publique datos donde no hay Wi-Fi en absoluto: estaciones de bombeo, obras, vehículos, explotaciones agrícolas y armarios remotos. En este tutorial encenderás un módem SIM7600 4G LTE, lo registrarás en la red móvil con TinyGSM, conectarás PubSubClient a broker.connectmq.com a través del módem y te recuperarás limpiamente de las caídas de red. También aprenderás adónde van realmente los datos móviles y cómo mantener bajo tu consumo mensual.
Cómo encajan las piezas
El SIM7600 es un módem celular completo con su propia pila TCP/IP. El ESP32 se comunica con él por una UART mediante comandos AT. TinyGSM envuelve esos comandos en una clase Client de Arduino, TinyGsmClient, y como PubSubClient acepta cualquier Client, el código MQTT es casi idéntico al de un sketch con Wi-Fi.
| Capa | Componente | Responsabilidad |
|---|---|---|
| Aplicación | Tu sketch | Leer sensores, decidir qué publicar |
| MQTT | PubSubClient | CONNECT, PUBLISH, SUBSCRIBE, keep-alive |
| Transporte | TinyGsmClient | Abre sockets TCP dentro del módem mediante comandos AT |
| Módem | SIM7600 | Registro en la red, contexto PDP, TCP/IP |
| Radio | Red LTE y SIM | Cobertura, APN, plan de datos |
La mayoría de los problemas de MQTT por red celular no son problemas de MQTT. Son problemas de alimentación, antena, SIM o APN que se manifiestan como "MQTT no conecta". Por eso el sketch comprueba cada capa por separado y registra dónde falla.
Hardware
- Una placa ESP32 con un módulo SIM7600. Las placas integradas como la serie LilyGO T-SIM7600 son el comienzo más sencillo; una placa de conexión SIM7600 por separado junto a un ESP32 DevKit también funciona.
- Una micro o nano SIM con un plan de datos activo. Las SIM de datos para IoT son ideales; una SIM de móvil sirve para pruebas.
- Una antena LTE conectada al puerto de antena principal. Nunca alimentes el módem sin antena.
- Una fuente de alimentación capaz de entregar los picos de corriente del módem al transmitir. Una buena celda 18650 o una fuente de 5 V de al menos 2 A es una base razonable.
La alimentación es la causa número uno de fallos. Los módems LTE consumen ráfagas cortas de corriente elevada al transmitir. Un puerto USB débil o unos cables finos provocan caídas de tensión que reinician el módem en mitad de la conexión, y los síntomas parecen aleatorios: unas veces se registra, otras no, otras se desconecta tras unos pocos mensajes.
| Señal | Pin típico en LilyGO T-SIM7600 | Función |
|---|---|---|
| TX del módem a RX del ESP32 | GPIO 26 | Datos UART desde el módem |
| RX del módem desde TX del ESP32 | GPIO 27 | Datos UART hacia el módem |
| PWRKEY | GPIO 4 | Pulso para encender el módem |
| Habilitación de alimentación | GPIO 12 | Activa la alimentación del módem en algunas revisiones de placa |
La asignación de pines difiere entre placas y revisiones. Consulta la documentación de tu placa y ajusta los defines del sketch.
Librerías
Instálalas desde el gestor de librerías de Arduino:
- TinyGSM de Volodymyr Shymanskyy.
- PubSubClient de Nick O'Leary.
TinyGSM necesita conocer el modelo de módem en tiempo de compilación, por eso #define TINY_GSM_MODEM_SIM7600 debe aparecer antes del include.
El sketch completo de SIM7600 MQTT
#define TINY_GSM_MODEM_SIM7600
#define TINY_GSM_RX_BUFFER 1024 // búfer mayor para los datos MQTT entrantes
#include <TinyGsmClient.h>
#include <PubSubClient.h>
// ---- Pines de la placa (valores por defecto de LilyGO T-SIM7600, ajústalos a tu placa) ----
#define MODEM_TX 27
#define MODEM_RX 26
#define MODEM_PWRKEY 4
#define MODEM_POWER 12
// ---- Ajustes celulares ----
const char APN[] = "internet"; // de tu proveedor de SIM
const char APN_USER[] = "";
const char APN_PASS[] = "";
const char SIM_PIN[] = ""; // déjalo vacío si la SIM no tiene PIN
// ---- Ajustes MQTT ----
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "lte-81c3e5"; // único
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; // una lectura por minuto
void powerOnModem() {
pinMode(MODEM_POWER, OUTPUT);
digitalWrite(MODEM_POWER, HIGH);
pinMode(MODEM_PWRKEY, OUTPUT);
digitalWrite(MODEM_PWRKEY, LOW);
delay(100);
digitalWrite(MODEM_PWRKEY, HIGH); // pulso de encendido
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); // menos pings, menos datos
mqtt.setSocketTimeout(15); // los viajes de ida y vuelta por red celular son más lentos
}
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);
}
}
Qué buscar en el monitor serie
Un arranque correcto imprime la identificación del módem, Registered, signal quality N, la IP local y MQTT connected over LTE. La calidad de señal es el valor CSQ de 0 a 31, donde 99 significa desconocido. Los valores por debajo de 10 aproximadamente son marginales; recoloca la antena antes de culpar al software. Si el sketch se detiene en el registro, el problema es la SIM, la cobertura o la antena. Si se registra pero falla la conexión de datos, el APN es incorrecto o el plan no tiene datos. Si ambas cosas funcionan pero MQTT falla con estado -2, la conexión TCP está siendo bloqueada; algunas SIM restrictivas solo permiten destinos incluidos en una lista blanca.
Prueba desde tu ordenador
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-81c3e5 -v -t "connectmq/demo/lte-81c3e5/#"
Deberías ver status online seguido de un mensaje de telemetría cada minuto. Envía un comando para verificar el canal de bajada, lo que además demuestra que el NAT del operador mantiene abierta la conexión:
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-81c3e5 -t "connectmq/demo/lte-81c3e5/cmd" -m "ping"
El servidor MQTT público gratuito vale para la puesta en marcha, pero todo lo que publiques allí lo puede leer cualquiera, así que cambia a tus propias credenciales antes de que el dispositivo salga del banco de pruebas.
Mantener bajo el consumo de datos de SIM7600 MQTT
Los planes celulares facturan por byte, y MQTT solo es eficiente si lo usas con eficiencia. Estas son las palancas que más importan, aproximadamente por orden de impacto:
- Evita las reconexiones. Cada conexión nueva cuesta un handshake TCP, el CONNECT y CONNACK de MQTT, las suscripciones y, con TLS, un handshake completo incluida la cadena de certificados. Un dispositivo que se reconecta cada pocos minutos puede gastar más datos en conectarse que en telemetría. Corrige la causa raíz de las caídas en lugar de reconectar con un temporizador.
- Ajusta el keep-alive. En cada periodo de keep-alive el cliente envía un pequeño PINGREQ y el broker responde. Un keep-alive más largo ahorra datos, pero las pasarelas NAT de los operadores cortan las conexiones inactivas al cabo de un tiempo, y si el keep-alive es más largo que eso, la conexión muere en silencio. Empieza en torno a dos minutos y ajústalo según lo que observes.
- Acorta los payloads. Usa claves JSON cortas (
"t"en lugar de"temperature"), redondea los valores y omite los campos que rara vez cambian. - Agrupa lecturas. Enviar diez lecturas en un solo mensaje cada diez minutos cuesta mucha menos sobrecarga que diez mensajes por separado.
- Publica cuando haya cambios. Para valores que cambian despacio, publica solo cuando el valor se mueva más allá de un umbral, más un latido periódico.
- Usa topics cortos. El topic se envía con cada mensaje.
f/42/tes más barato que una ruta larga y descriptiva, aunque la legibilidad también importa; busca un equilibrio. - Vigila las suscripciones. Las suscripciones con comodines a topics con mucho tráfico pueden traer muchos más datos de los que esperas.
Recuerda que los operadores pueden redondear cada sesión o periodo de facturación a una unidad mínima, así que mide el consumo real en el portal de tu proveedor de SIM durante unos días en lugar de fiarte de los cálculos.
Seguridad en enlaces celulares
En producción, usa TLS en el puerto 8883 y el usuario, la contraseña y el client ID generados en el portal de ConnectMQ. En el SIM7600 tienes dos opciones. Algunas versiones y forks de TinyGSM exponen un cliente seguro que usa el motor SSL integrado del módem, lo que ahorra memoria en el ESP32; comprueba si tu versión instalada lo soporta para el SIM7600. Como alternativa, ejecuta TLS en el propio ESP32 con una librería envoltorio como SSLClient sobre TinyGsmClient. En ambos casos, verifica el certificado del broker contra la raíz ISRG Root X1 en lugar de desactivar la verificación. La guía de ESP32 MQTT SSL explica la elección del certificado y por qué importa la hora de NTP o de la red; el SIM7600 también puede proporcionar la hora de la red.
Solución de problemas
- El módem nunca responde a AT. Pines UART incorrectos, velocidad en baudios incorrecta o el módem no está alimentado. Comprueba el pin de habilitación de alimentación y el pulso PWRKEY de tu placa.
- Se registra solo en 2G o 3G, o no se registra. Puede que la banda no esté soportada por tu variante de SIM7600 (E, A, SA, G y otras cubren regiones distintas).
- Conecta y se cae tras unos minutos de silencio. Keep-alive más largo que el timeout del NAT del operador. Acórtalo.
- Reinicios por brownout durante la transmisión. La fuente no puede entregar la corriente de pico. Añade un condensador grande cerca del módem y usa cables más gruesos.
- Mensajes con segundos de retraso. Es normal en enlaces celulares; la latencia es mayor y más variable que en Wi-Fi. Diseña teniéndolo en cuenta.
Para una estrategia de reconexión más robusta con backoff, adapta la máquina de estados de lógica de reconexión MQTT en ESP32. Si el dispositivo tiene una opción cableada en el emplazamiento, compárala con ESP32 Ethernet MQTT con W5500, y para activos en movimiento consulta el rastreador GPS con ESP32 por MQTT.
Gestionar una flota celular
Visitar dispositivos celulares sale caro, así que el lado del broker debería ser lo último que te preocupe. Un broker MQTT gestionado mantiene el endpoint disponible mientras los dispositivos pasan de una celda a otra y se reconectan. ConnectMQ da a cada dispositivo sus propias credenciales, muestra el estado de conexión a través de $SYS/broker/connection/{clientId}/state y te permite ver el tráfico en vivo en el portal, algo útil cuando intentas entender adónde van los datos de una SIM. Un broker MQTT en la nube con un hostname público también evita las configuraciones de APN privado y VPN que los brokers autoalojados suelen requerir para dispositivos celulares. Si este es tu primer proyecto con ESP32, empieza por el tutorial de IoT con ESP32.
Empieza con ConnectMQ
Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito. Tus dispositivos SIM7600 pueden publicar en él desde cualquier lugar con cobertura, y puedes ver llegar cada mensaje en el explorador de topics en vivo.
Preguntas frecuentes
¿Funciona PubSubClient con el SIM7600?
Sí. TinyGSM proporciona TinyGsmClient, que implementa la interfaz Client de Arduino, así que PubSubClient usa los sockets TCP del módem exactamente igual que usaría el Wi-Fi.
¿Cuántos datos consume SIM7600 MQTT?
Depende sobre todo de la frecuencia de reconexión, el intervalo de keep-alive y el tamaño del payload. Un dispositivo que se mantiene conectado y envía mensajes compactos consume muy poco; las reconexiones frecuentes, sobre todo con TLS, dominan el consumo. Mídelo en el portal de tu proveedor de SIM.
¿Qué APN debo usar?
El APN lo proporciona tu proveedor de SIM y suele figurar en su documentación o en su portal de IoT. Un APN incorrecto permite que el módem se registre en la red pero impide la conexión de datos.
¿Puedo usar MQTT sobre TLS con el SIM7600?
Sí, ya sea mediante el motor SSL del módem si tu versión de TinyGSM lo soporta para el SIM7600, o ejecutando TLS en el ESP32 con una librería envoltorio sobre TinyGsmClient. Verifica siempre el certificado del broker.



