🛠 Uplinks confirmés robustes et duty cycle
Objetivos
Garantizar la fiabilidad de los envíos LoRaWAN de la MKR WAN 1310: uplinks confirmados con ACK, respeto del límite mínimo de firmware de una emisión cada 2 minutos (duty cycle EU, no modificable), cola de espera en RAM, backoff en caso de fallo y solución al error del contador de tramas que bloquea la emisión tras ~255 envíos (issue MKRWAN #141).
Material
- 1 placa MKR WAN 1310 + antena de 868 MHz, ya unida en OTAA (ver el tutorial TTN)
- Cuenta TTN para verificar los ACK en el lado del servidor
Código completo
// Uplink confirme robuste avec file d'attente — MKR WAN 1310
#include <MKRWAN.h>
LoRaModem modem;
String appEui = "0000000000000000";
String appKey = "00000000000000000000000000000000";
const int TAILLE_FILE = 8;
String file[TAILLE_FILE];
int tete = 0, queue = 0, nbFile = 0;
unsigned long dernierEnvoi = 0;
unsigned long totalEnvois = 0;
void setup {
Serial.begin(115200);
while (!Serial);
if (!modem.begin(EU868)) { Serial.println("Module KO"); while (1); }
// Le bug #141 (blocage apres ~255 trames) se contourne en re-joignant
// periodiquement : rebegin + joinOTAA tous les 200 envois.
if (!modem.joinOTAA(appEui, appKey)) { Serial.println("Join KO"); while (1); }
modem.minPollInterval(60);
}
void loop {
// Production : ici un capteur ou un bouton empile des messages
if (millis % 60000 < 100 && nbFile < TAILLE_FILE) {
file[queue] = "T=" + String(analogRead(A0));
queue = (queue + 1) % TAILLE_FILE; nbFile++;
}
// Consommation : 1 message / 2 min maximum (plancher firmware EU)
if (nbFile > 0 && millis - dernierEnvoi >= 125000UL) {
modem.beginPacket;
modem.print(file[tete]);
int err = modem.endPacket(true); // true = uplink_confirme (attend ACK)
if (err > 0) {
tete = (tete + 1) % TAILLE_FILE; nbFile--;
totalEnvois++;
Serial.println("ACK recu");
} else {
Serial.println("Sans ACK : on garde en file, backoff 2 min");
}
dernierEnvoi = millis;
if (totalEnvois > 0 && totalEnvois % 200 == 0) {
modem.begin(EU868); // reinitialise le compteur de trames
modem.joinOTAA(appEui, appKey);
}
}
}
Verificación esperada
Cada mensaje confirmado desaparece de la cola y aparece como «confirmado» en los datos en vivo de TTN; un mensaje sin ACK permanece en la cola y se reintenta en el siguiente ciclo. Tras varias horas, la emisión ya no se bloquea gracias a la reconexión periódica.
Errores frecuentes
- Creer que
endPacket(true)es infalible: sin ACK, la función devuelve un error pero no reenvía por sí sola — es el sketch quien debe retomar el control. - Intentar rellenar el hueco con
delay(1000)entre dos envíos: el firmware rechaza cualquier emisión con menos de 2 minutos de intervalo, independientemente de la configuración del software. - Olvidar la solución al error #141 y ver la placa «muda» tras 255 tramas sin ningún mensaje de error.
- No tener en cuenta la cola llena: a partir de 8 mensajes, decidir entre sobrescribir, descartar o almacenar en la flash de 2 MB (ver el tutorial Eslov + flash).
- En clase A, los downlinks solo llegan en las dos ventanas RX siguientes a un uplink: un ACK de servidor invisible suele significar una ventana perdida, no una clave errónea.
Otros tutoriales para esta placa
Ejemplos de código para esta placa
join-otaa.inoArduinouplink-confirme.inoArduinodownlink.inoArduinoactivation-abp.inoArduinosuivi-adr.inoArduinoclasse-c.inoArduino