LoRaWAN Setup Guide
This guide covers connecting your Wireless Tracker to LoRaWAN networks including The Things Network (TTN), SnapEmu, and other LoRaWAN servers.
Prerequisites
Section titled “Prerequisites”- Heltec Wireless Tracker with LoRa antenna
- Gateway coverage in your area (or your own gateway)
- Account on your chosen LoRaWAN network server
- Arduino IDE or PlatformIO with Heltec libraries
Regional Frequencies
Section titled “Regional Frequencies”Choose the correct model for your region:
| Region | Frequency | Model |
|---|---|---|
| EU868 | 863-870 MHz | Wireless Tracker-HF |
| US915 | 902-928 MHz | Wireless Tracker-HF |
| AU915 | 915-928 MHz | Wireless Tracker-HF |
| AS923 | 920-925 MHz | Wireless Tracker-HF |
| KR920 | 920-923 MHz | Wireless Tracker-HF |
| CN470 | 470-510 MHz | Wireless Tracker-LF |
OTAA vs ABP
Section titled “OTAA vs ABP”| Method | Pros | Cons |
|---|---|---|
| OTAA (Over-The-Air Activation) | More secure, automatic session renewal | Requires join process |
| ABP (Activation By Personalization) | Immediate transmission | Less secure, manual key management |
Network Registration
Section titled “Network Registration”Register on TTN
Section titled “Register on TTN”-
Create account at thethingsnetwork.org
-
Create a new Application
-
Add an End Device:
- Select “Enter end device specifics manually”
- Frequency plan: Match your region (e.g., US915 FSB2)
- LoRaWAN version: 1.0.3
- Regional Parameters: RP001 Regional Parameters 1.0.3 revision A
-
Generate credentials:
- DevEUI: Generate or use chip’s MAC
- AppEUI: All zeros or generate
- AppKey: Generate (save this!)
-
Copy credentials for firmware
TTN Payload Decoder
Section titled “TTN Payload Decoder”function decodeUplink(input) { return { data: { // Parse your payload format here battery: input.bytes[0] / 10, latitude: ((input.bytes[1] << 24) | (input.bytes[2] << 16) | (input.bytes[3] << 8) | input.bytes[4]) / 1000000, longitude: ((input.bytes[5] << 24) | (input.bytes[6] << 16) | (input.bytes[7] << 8) | input.bytes[8]) / 1000000 }, warnings: [], errors: [] };}Register on SnapEmu
Section titled “Register on SnapEmu”-
Create account at snapemu.com
-
Configure your Heltec gateway to connect to SnapEmu
-
Add a new Node Device
-
Copy the generated credentials:
- DevEUI
- AppEUI
- AppKey
SnapEmu Features
Section titled “SnapEmu Features”- Automatic device provisioning for Heltec devices
- Built-in decoder library
- Real-time data visualization
- Historical data storage
Firmware Configuration
Section titled “Firmware Configuration”Basic LoRaWAN Example
Section titled “Basic LoRaWAN Example”#include "LoRaWan_APP.h"
// OTAA Credentials - Replace with your valuesuint8_t devEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Channel mask for US915 FSB2 (channels 8-15)uint16_t userChannelsMask[6] = { 0xFF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
// For EU868, use:// uint16_t userChannelsMask[6] = { 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
LoRaMacRegion_t loraWanRegion = LORAMAC_REGION_US915; // Change for your regionDeviceClass_t loraWanClass = CLASS_A;uint32_t appTxDutyCycle = 60000; // 60 second transmit intervalbool overTheAirActivation = true;bool loraWanAdr = true;bool isTxConfirmed = true;uint8_t appPort = 1;uint8_t confirmedNbTrials = 4;
void setup() { Serial.begin(115200); Mcu.begin(HELTEC_BOARD, SLOW_CLK_TPYE);
LoRaWAN.init(loraWanClass, loraWanRegion); LoRaWAN.setDefaultDR(3); // SF7-SF12 depending on region}
static void prepareTxFrame(uint8_t port) { appDataSize = 4;
// Example: Send battery voltage and status float voltage = readBatteryVoltage(); uint16_t vBat = (uint16_t)(voltage * 100);
appData[0] = (uint8_t)(vBat >> 8); appData[1] = (uint8_t)(vBat & 0xFF); appData[2] = 0x00; // Status byte appData[3] = 0x00; // Reserved}
void loop() { switch (deviceState) { case DEVICE_STATE_INIT: LoRaWAN.init(loraWanClass, loraWanRegion); deviceState = DEVICE_STATE_JOIN; break;
case DEVICE_STATE_JOIN: LoRaWAN.join(); break;
case DEVICE_STATE_SEND: prepareTxFrame(appPort); LoRaWAN.send(); deviceState = DEVICE_STATE_CYCLE; break;
case DEVICE_STATE_CYCLE: txDutyCycleTime = appTxDutyCycle + randr(-APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND); LoRaWAN.cycle(txDutyCycleTime); deviceState = DEVICE_STATE_SLEEP; break;
case DEVICE_STATE_SLEEP: LoRaWAN.sleep(loraWanClass); break;
default: deviceState = DEVICE_STATE_INIT; break; }}
float readBatteryVoltage() { pinMode(2, OUTPUT); digitalWrite(2, LOW); int raw = analogRead(1); digitalWrite(2, HIGH); return (raw / 4095.0) * 3.3 * 4.9;}Region Configuration
Section titled “Region Configuration”| Region | LoRaMacRegion_t | Default DR | Notes |
|---|---|---|---|
| EU868 | LORAMAC_REGION_EU868 | DR5 (SF7) | 1% duty cycle |
| US915 | LORAMAC_REGION_US915 | DR3 (SF7) | Use FSB2 for TTN |
| AU915 | LORAMAC_REGION_AU915 | DR3 (SF7) | Similar to US915 |
| AS923 | LORAMAC_REGION_AS923 | DR5 (SF7) | Multiple sub-bands |
| CN470 | LORAMAC_REGION_CN470 | DR3 (SF7) | LF model only |
Sending GPS Data
Section titled “Sending GPS Data”#include "TinyGPS++.h"
TinyGPSPlus gps;HardwareSerial GPSSerial(1);
void setup() { // Enable GNSS power (V1.1) pinMode(3, OUTPUT); digitalWrite(3, HIGH);
// Initialize GNSS serial GPSSerial.begin(115200, SERIAL_8N1, 33, 34);}
static void prepareTxFrame(uint8_t port) { // Read latest GPS data while (GPSSerial.available()) { gps.encode(GPSSerial.read()); }
if (gps.location.isValid()) { int32_t lat = gps.location.lat() * 1000000; int32_t lon = gps.location.lng() * 1000000;
appDataSize = 9;
// Latitude (4 bytes, big-endian) appData[0] = (lat >> 24) & 0xFF; appData[1] = (lat >> 16) & 0xFF; appData[2] = (lat >> 8) & 0xFF; appData[3] = lat & 0xFF;
// Longitude (4 bytes, big-endian) appData[4] = (lon >> 24) & 0xFF; appData[5] = (lon >> 16) & 0xFF; appData[6] = (lon >> 8) & 0xFF; appData[7] = lon & 0xFF;
// Satellites appData[8] = gps.satellites.value(); }}Troubleshooting
Section titled “Troubleshooting”Join Failures
Section titled “Join Failures”| Symptom | Cause | Solution |
|---|---|---|
| No join accept | Wrong credentials | Double-check DevEUI, AppEUI, AppKey |
| Timeout | No gateway | Verify gateway coverage |
| Repeated joins | Session expired | Check network server settings |
No Uplinks Received
Section titled “No Uplinks Received”- Verify antenna is connected
- Check frequency plan matches gateway
- Increase spreading factor (lower DR) for better range
- Monitor RSSI/SNR on gateway
Duty Cycle Exceeded
Section titled “Duty Cycle Exceeded”EU868 has strict 1% duty cycle limits:
// Increase transmit interval to respect duty cycleuint32_t appTxDutyCycle = 300000; // 5 minutes minimum for EU868