Przejdź do głównej zawartości

Test transmisji LoRaWAN (bez czujnika)

Uproszczony test weryfikujący samo połączenie LoRaWAN: XIAO ESP32S3 → Grove Wio-E5 → bramka → TTN. Wysyłany jest licznik pakietów — żadnych czujników nie potrzeba.

Sprzęt

UrządzenieRola
XIAO ESP32S3mikrokontroler / LoRaWAN node
Grove – Wio-E5 (LoRa-E5)moduł LoRa (AT commands przez UART)
SenseCAP M2 Multi-Platform Gateway (SX1302, EU868)bramka LoRaWAN
Grove Shield for XIAOrozszerzenie złączy Grove na XIAO

Połączenie

Grove Wio-E5 wpinasz do portu UART na Grove Shield for XIAO.

XIAO ESP32S3 (przez Grove Shield for XIAO)
└─ [UART Grove port] ──► Grove Wio-E5
D6 / GPIO43 (TX) → E5 RX
D7 / GPIO44 (RX) → E5 TX

Konfiguracja bramki i TTN

Zarejestruj bramkę SenseCAP M2 (zobacz Bramka) na TTN, a następnie zarejestruj end-node OTAA w tej samej aplikacji TTN. Potrzebujesz: DevEUI, AppEUI, AppKey.

Kod

// UART do Grove Wio-E5
// TX = GPIO43 (D6), RX = GPIO44 (D7)
#define E5_SERIAL Serial1
#define E5_RX_PIN 44
#define E5_TX_PIN 43

// Klucze TTN — uzupełnij
const char* DEV_EUI = "XXXXXXXXXXXXXXXX";
const char* APP_EUI = "0000000000000000";
const char* APP_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

// Interwał wysyłania — minimum 60 s dla EU868 (duty cycle 1%)
const uint32_t SEND_INTERVAL_MS = 60000;

static uint32_t packetCount = 0;

// -------------------------------------------------------
bool sendAT(const char* cmd, const char* expected, uint32_t timeout_ms = 4000) {
while (E5_SERIAL.available()) E5_SERIAL.read();
E5_SERIAL.println(cmd);

String resp = "";
uint32_t t0 = millis();
while (millis() - t0 < timeout_ms) {
while (E5_SERIAL.available()) resp += (char)E5_SERIAL.read();
if (resp.indexOf(expected) >= 0) {
Serial.print("[OK] "); Serial.println(resp);
return true;
}
}
Serial.print("[FAIL] "); Serial.print(cmd);
Serial.print(" → "); Serial.println(resp);
return false;
}

bool joinOTAA() {
char buf[80];

sendAT("AT+RESET", "+RESET:", 3000);
delay(2000);

if (!sendAT("AT+MODE=LWOTAA", "+MODE: LWOTAA")) return false;
if (!sendAT("AT+DR=EU868", "+DR: EU868")) return false;
if (!sendAT("AT+CH=NUM,0-7", "+CH: NUM")) return false;
if (!sendAT("AT+CLASS=A", "+CLASS: A")) return false;

snprintf(buf, sizeof(buf), "AT+ID=DevEui,\"%s\"", DEV_EUI);
if (!sendAT(buf, "+ID: DevEui")) return false;

snprintf(buf, sizeof(buf), "AT+ID=AppEui,\"%s\"", APP_EUI);
if (!sendAT(buf, "+ID: AppEui")) return false;

snprintf(buf, sizeof(buf), "AT+KEY=AppKey,\"%s\"", APP_KEY);
if (!sendAT(buf, "+KEY: APPKEY")) return false;

Serial.println("Łączenie z siecią LoRaWAN (OTAA)...");
return sendAT("AT+JOIN", "+JOIN: Network joined", 30000);
}

void sendPayload(const uint8_t* data, uint8_t len) {
char cmd[len * 2 + 20];
strcpy(cmd, "AT+MSGHEX=\"");
for (uint8_t i = 0; i < len; i++) sprintf(cmd + strlen(cmd), "%02X", data[i]);
strcat(cmd, "\"");
sendAT(cmd, "+MSGHEX:", 10000);
}

// -------------------------------------------------------
void setup() {
Serial.begin(115200);
delay(1000);

E5_SERIAL.begin(9600, SERIAL_8N1, E5_RX_PIN, E5_TX_PIN);
delay(500);

if (!joinOTAA()) {
Serial.println("JOIN nieudany! Sprawdź: klucze TTN, zasięg bramki, pasmo EU868.");
while (1) delay(5000);
}
Serial.println("Połączono z LoRaWAN!");
}

void loop() {
packetCount++;

// Payload: 4 bajty — licznik pakietów (uint32, big-endian)
uint8_t payload[4];
payload[0] = (packetCount >> 24) & 0xFF;
payload[1] = (packetCount >> 16) & 0xFF;
payload[2] = (packetCount >> 8) & 0xFF;
payload[3] = packetCount & 0xFF;

Serial.printf("Wysyłam pakiet #%lu\n", (unsigned long)packetCount);
sendPayload(payload, sizeof(payload));

delay(SEND_INTERVAL_MS);
}

Dekoder payloadu na TTN

  1. TTN Console → aplikacja → Payload formattersUplink.
  2. Wybierz Custom Javascript formatter, wklej:
function decodeUplink(input) {
var b = input.bytes;
return {
data: {
counter: (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]
},
warnings: [],
errors: []
};
}

Weryfikacja

Serial Monitor (115200 baud):

[OK] +MODE: LWOTAA
[OK] +DR: EU868
...
Łączenie z siecią LoRaWAN (OTAA)...
[OK] +JOIN: Network joined
Połączono z LoRaWAN!
Wysyłam pakiet #1
[OK] +MSGHEX: Done
Wysyłam pakiet #2
...

W TTN Console → aplikacja → Live data każdy odebrany uplink powinien pokazać counter: 1, counter: 2 itd.

Problemy z JOIN
  • Bramka musi widnieć jako Connected w TTN Console.
  • Klucze muszą być identyczne w kodzie i na TTN.
  • Przy +JOIN: Join failed poczekaj minutę przed kolejną próbą (EU868 duty cycle).