TokoSportBandung

LoRaWAN Network Architecture for Large-Scale IoT Deployment

By Rizky Pratama· · 12 min read

Deploying a LoRaWAN network at scale requires far more than dropping gateways on rooftops and flashing end devices with default firmware. The interplay between physical layer modulation parameters, MAC-layer scheduling, network server topology, and regional regulatory constraints determines whether a deployment handles hundreds or tens of thousands of devices reliably. This guide examines each architectural layer in depth, with production-tested configurations and firmware examples.

LoRa Physical Layer and Link Budget Engineering

The LoRa modulation technique uses Chirp Spread Spectrum (CSS) across configurable spreading factors (SF7 through SF12) and bandwidths (125, 250, or 500 kHz). Each step up in spreading factor doubles the time-on-air but gains approximately 2.5 dB in receiver sensitivity. Understanding this tradeoff is fundamental to network planning.

Link Budget Calculation

The link budget determines maximum communication distance. For a Semtech SX1276 transceiver at SF12/125kHz, receiver sensitivity reaches -137 dBm. Combined with +14 dBm transmit power and antenna gains, the total link budget is:

Link Budget = Tx Power + Tx Antenna Gain + Rx Antenna Gain - Rx Sensitivity
           = 14 dBm + 2.15 dBi + 6 dBi - (-137 dBm)
           = 159.15 dB

Path Loss (Okumura-Hata urban model, 868 MHz):
  PL(dB) = 69.55 + 26.16*log10(f) - 13.82*log10(h_b) - a(h_m)
         + (44.9 - 6.55*log10(h_b)) * log10(d)

Where:
  f = 868 MHz, h_b = gateway height (m)
  h_m = device height (m), d = distance (km)
  a(h_m) = correction factor for device antenna height

For practical deployments, always include a fade margin of 10-15 dB to account for temporal fading, vegetation absorption, and building penetration losses. Indoor devices behind concrete walls may experience an additional 15-25 dB attenuation depending on wall thickness and construction materials.

Spreading Factor Distribution Strategy

In a well-designed network, the Adaptive Data Rate (ADR) algorithm distributes devices across spreading factors to maximize aggregate throughput. Devices closer to gateways operate at SF7 with shorter airtime, while devices at the edge use SF12. The following table shows the practical impact:

Spreading FactorBit Rate (bps)Time on Air (20B)Sensitivity (dBm)Max Payload
SF7 / 125kHz5,47056 ms-123242 bytes
SF8 / 125kHz3,125103 ms-126242 bytes
SF9 / 125kHz1,760185 ms-129115 bytes
SF10 / 125kHz980370 ms-13251 bytes
SF11 / 125kHz440741 ms-134.551 bytes
SF12 / 125kHz2501,483 ms-13751 bytes

Gateway Architecture and Placement Optimization

LoRaWAN gateways bridge the RF domain to IP-based network infrastructure. Modern concentrator boards based on the Semtech SX1302/SX1303 chipset support 8 simultaneous demodulation channels plus a high-speed SF5/SF6 channel, replacing the older SX1301 with significantly reduced power consumption (typically 800 mW vs. 4W).

Multi-Gateway Redundancy

Production deployments should ensure that every device is within range of at least two gateways. This provides path diversity for improved packet delivery ratio and enables seamless gateway maintenance. The network server performs deduplication across gateways, selecting the frame with the best RSSI/SNR for processing while discarding duplicates.

In our smart city deployment across Bandung, overlapping coverage from 12 gateways achieved a 99.7% packet delivery ratio across 4,200 sensor nodes. Single-gateway zones dropped to 94.2% during adverse weather conditions. The 5.5% improvement justified the additional gateway cost.

Gateway Configuration with the SX1302 HAL

Configuring a Semtech SX1302-based gateway involves setting up the concentrator channels, GPS synchronization for Class B beacon support, and the packet forwarder connection to the network server. Here is a stripped configuration for the EU868 band plan:

/* gateway_conf.c - SX1302 concentrator configuration */
#include "loragw_hal.h"
#include "loragw_gps.h"

static struct lgw_conf_board_s board_conf = {
    .lorawan_public = true,
    .clksrc = 0,         /* radio_0 provides clock */
    .full_duplex = false,
    .com_type = LGW_COM_SPI,
    .com_path = "/dev/spidev0.0"
};

/* IF chain configuration for EU868 channels */
static struct lgw_conf_rxif_s ifconf[8] = {
    { .enable = true, .rf_chain = 0, .freq_hz = -400000 },  /* 868.1 MHz */
    { .enable = true, .rf_chain = 0, .freq_hz = -200000 },  /* 868.3 MHz */
    { .enable = true, .rf_chain = 0, .freq_hz =  0 },       /* 868.5 MHz */
    { .enable = true, .rf_chain = 0, .freq_hz =  200000 },  /* 867.1 MHz */
    { .enable = true, .rf_chain = 0, .freq_hz =  400000 },  /* 867.3 MHz */
    { .enable = true, .rf_chain = 1, .freq_hz = -400000 },  /* 867.5 MHz */
    { .enable = true, .rf_chain = 1, .freq_hz = -200000 },  /* 867.7 MHz */
    { .enable = true, .rf_chain = 1, .freq_hz =  0 }        /* 867.9 MHz */
};

int gateway_init(void) {
    lgw_board_setconf(&board_conf);

    struct lgw_conf_rxrf_s rfconf;
    memset(&rfconf, 0, sizeof(rfconf));
    rfconf.enable = true;
    rfconf.freq_hz = 868500000;  /* Radio 0 center freq */
    rfconf.type = LGW_RADIO_TYPE_SX1250;
    rfconf.tx_enable = true;
    rfconf.single_input_mode = false;
    lgw_rxrf_setconf(0, &rfconf);

    for (int i = 0; i < 8; i++) {
        lgw_rxif_setconf(i, &ifconf[i]);
    }

    return lgw_start();
}

Network Server Design for Scalability

The network server sits at the core of the LoRaWAN architecture, handling device authentication, frame deduplication, MAC command processing, ADR management, and routing application payloads to the appropriate application servers. For deployments exceeding 10,000 devices, the network server architecture must be horizontally scalable.

ADR Algorithm Implementation

The ADR algorithm on the network server side collects SNR history and computes optimal transmission parameters. A robust implementation maintains a sliding window of the last 20 uplink frames and applies hysteresis to prevent oscillation:

/* adr_engine.c - Adaptive Data Rate calculation */
#include <math.h>
#include "lorawan_mac.h"

#define ADR_HISTORY_SIZE  20
#define ADR_MARGIN_DB     10.0f  /* Installation margin */

/* Required SNR per spreading factor (dB) */
static const float snr_table[] = {
    [DR_SF12] = -20.0f,
    [DR_SF11] = -17.5f,
    [DR_SF10] = -15.0f,
    [DR_SF9]  = -12.5f,
    [DR_SF8]  = -10.0f,
    [DR_SF7]  =  -7.5f,
};

adr_result_t compute_adr(device_session_t *dev) {
    adr_result_t result = { .dr = dev->current_dr, .tx_power = dev->tx_power };

    if (dev->adr_frame_count < ADR_HISTORY_SIZE)
        return result;  /* Not enough data */

    /* Find max SNR in history window */
    float max_snr = -150.0f;
    for (int i = 0; i < ADR_HISTORY_SIZE; i++) {
        if (dev->snr_history[i] > max_snr)
            max_snr = dev->snr_history[i];
    }

    /* Calculate SNR margin above demodulation floor */
    float snr_margin = max_snr - snr_table[dev->current_dr] - ADR_MARGIN_DB;
    int steps = (int)floorf(snr_margin / 3.0f);

    /* First: increase data rate (lower SF) */
    while (steps > 0 && result.dr < DR_SF7) {
        result.dr++;
        steps--;
    }

    /* Then: reduce TX power in 3dB steps */
    while (steps > 0 && result.tx_power > TX_POWER_MIN) {
        result.tx_power -= 3;
        steps--;
    }

    return result;
}

The 10 dB installation margin accounts for temporal fading and ensures devices maintain connectivity even during adverse propagation conditions. In environments with high RF interference (industrial sites, dense urban canyons), increasing this margin to 15 dB prevents excessive ADR churn.

End Device Firmware Architecture

Production-grade end device firmware must handle LoRaWAN MAC layer complexity while maintaining strict power budgets. The Zephyr RTOS provides a mature LoRaWAN subsystem built on the LoRaMac-node stack, supporting all three device classes with proper power management integration.

Low-Power Sensor Node Implementation

The following implementation demonstrates a Class A sensor node on an STM32WL55-based module, integrating deep sleep between transmission cycles:

/* lorawan_sensor.c - Class A environmental sensor node */
#include <zephyr/kernel.h>
#include <zephyr/lorawan/lorawan.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/pm/pm.h>

#define LORAWAN_DEV_EUI   { 0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F, 0x70 }
#define LORAWAN_APP_EUI   { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }
#define LORAWAN_APP_KEY   { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, \
                            0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }

#define TX_INTERVAL_SEC   900  /* 15-minute reporting interval */
#define FPORT_SENSOR      10

static void dl_callback(uint8_t port, bool pending,
                        int16_t rssi, int8_t snr,
                        uint8_t len, const uint8_t *data) {
    if (port == 1 && len >= 2) {
        /* Parse downlink command: adjust TX interval */
        uint16_t new_interval = (data[0] << 8) | data[1];
        /* Apply new interval with bounds checking */
    }
}

static int encode_sensor_payload(uint8_t *buf, size_t max_len) {
    const struct device *bme = DEVICE_DT_GET_ONE(bosch_bme280);
    struct sensor_value temp, hum, press;

    sensor_sample_fetch(bme);
    sensor_channel_get(bme, SENSOR_CHAN_AMBIENT_TEMP, &temp);
    sensor_channel_get(bme, SENSOR_CHAN_HUMIDITY, &hum);
    sensor_channel_get(bme, SENSOR_CHAN_PRESS, &press);

    /* Cayenne LPP encoding for interoperability */
    int idx = 0;
    buf[idx++] = 0x01;  /* Channel 1 */
    buf[idx++] = 0x67;  /* Temperature */
    int16_t t = (int16_t)(sensor_value_to_double(&temp) * 10);
    buf[idx++] = (t >> 8) & 0xFF;
    buf[idx++] = t & 0xFF;

    buf[idx++] = 0x02;  /* Channel 2 */
    buf[idx++] = 0x68;  /* Humidity */
    buf[idx++] = (uint8_t)(sensor_value_to_double(&hum) * 2);

    buf[idx++] = 0x03;  /* Channel 3 */
    buf[idx++] = 0x73;  /* Barometric Pressure */
    uint16_t p = (uint16_t)(sensor_value_to_double(&press) * 10);
    buf[idx++] = (p >> 8) & 0xFF;
    buf[idx++] = p & 0xFF;

    return idx;
}

int main(void) {
    struct lorawan_join_config join_cfg = {
        .mode = LORAWAN_ACT_OTAA,
        .dev_eui = LORAWAN_DEV_EUI,
        .otaa = {
            .app_eui = LORAWAN_APP_EUI,
            .app_key = LORAWAN_APP_KEY,
        }
    };

    lorawan_start();
    lorawan_set_class(LORAWAN_CLASS_A);
    lorawan_enable_adr(true);
    lorawan_register_downlink_callback(&(struct lorawan_downlink_cb){
        .port = LW_RECV_PORT_ANY,
        .cb = dl_callback
    });

    int ret = lorawan_join(&join_cfg);
    if (ret < 0) {
        /* Exponential backoff retry with jitter */
        return -1;
    }

    while (1) {
        uint8_t payload[32];
        int len = encode_sensor_payload(payload, sizeof(payload));

        lorawan_send(FPORT_SENSOR, payload, len,
                     LORAWAN_MSG_UNCONFIRMED);

        /* Enter STOP2 deep sleep for TX_INTERVAL_SEC */
        k_sleep(K_SECONDS(TX_INTERVAL_SEC));
    }
}

Channel Plan and Regulatory Compliance

LoRaWAN operates in unlicensed ISM bands with region-specific duty cycle and dwell time restrictions. Non-compliance can result in regulatory penalties and interference with other spectrum users. The firmware must enforce these constraints regardless of application-layer demands.

Regional Parameters Summary

RegionBand (MHz)ChannelsMax EIRPDuty CycleDwell Time
EU868863-87016+16 dBm0.1%-1%None
US915902-92872+30 dBmNone400 ms
AS923915-92816+16 dBm1%400 ms
AU915915-92872+30 dBmNone400 ms
CN470470-51096+19.15 dBmNoneNone
IN865865-8673+30 dBmNoneNone

For AS923 deployments common in Southeast Asia, the firmware must implement both duty cycle limiting and dwell time enforcement. The 400 ms maximum dwell time at SF10/125kHz limits payload sizes and effectively caps usable spreading factors. Devices requiring deep indoor penetration at SF12 must use the 500 kHz bandwidth option to stay within dwell time limits.

Integrating with Complementary IoT Protocols

LoRaWAN excels at long-range, low-data-rate applications but rarely operates in isolation. A comprehensive IoT architecture often combines LoRaWAN with complementary protocols. For local mesh connectivity within buildings or campuses, Zigbee 3.0 mesh networks provide reliable short-range communication with self-healing topology. For sub-GHz applications requiring Wi-Fi-like range but at lower power, Wi-Fi HaLow (802.11ah) bridges the gap between LoRaWAN's kilometer-range coverage and traditional Wi-Fi's throughput.

At the edge computing layer, gateways increasingly run lightweight application logic to reduce backhaul traffic and latency. The WebAssembly runtime on edge devices enables portable, sandboxed computation directly on gateway hardware, filtering and aggregating sensor data before forwarding to cloud infrastructure.

Network Capacity Planning and Optimization

Collision Probability Analysis

LoRaWAN's ALOHA-based access scheme means collision probability increases with network load. The probability of a successful transmission in pure ALOHA is:

P(success) = G * e^(-2G)

Where G = aggregate traffic load (Erlangs)

For G = 0.5 (maximum throughput):
  P(success) = 0.5 * e^(-1) ≈ 18.4%

Practical target: G < 0.1 per channel per SF
  P(success) = 0.1 * e^(-0.2) ≈ 8.2% channel utilization
  Collision rate: ~1.8%

To keep collision rates below 2%, each channel at each spreading factor should not exceed 10% utilization. With 8 channels and 6 spreading factors, the aggregate capacity is:

Capacity = 8 channels × 6 SFs × 0.10 utilization × (1/T_on_air)

For average 100ms airtime at SF8:
  Capacity ≈ 8 × 6 × 0.10 × (3600/0.1) = 172,800 frames/hour
  With 15-min interval: ~43,200 devices per gateway cluster

Gateway Densification Strategy

When network capacity is exhausted before coverage, gateway densification follows a hexagonal grid pattern. Each additional gateway reduces the average spreading factor of nearby devices through ADR, effectively increasing aggregate throughput non-linearly. Monitor these key performance indicators:

  • Packet Delivery Ratio (PDR): Target above 98% for critical monitoring applications
  • Average Spreading Factor: Lower values indicate efficient ADR utilization; target average SF below 9
  • Duplicate Frame Ratio: Between 1.5x-3.0x indicates healthy multi-gateway coverage
  • ADR Convergence Time: Time for new devices to reach optimal SF; should be under 48 hours
  • Join Accept Rate: OTAA join success rate; below 95% indicates gateway congestion during join windows

Security Hardening for Production Deployments

LoRaWAN 1.1 separates network and application security, but implementation details matter. Production deployments must secure the entire chain from device provisioning to cloud integration.

Hardware Security Module Integration

Store root keys (AppKey, NwkKey) in hardware security elements rather than firmware flash. The Microchip ATECC608B provides secure key storage with anti-tamper protection:

/* secure_element.c - ATECC608B key provisioning */
#include "cryptoauthlib.h"

#define APPKEY_SLOT   0
#define NWKKEY_SLOT   1

int se_derive_session_keys(const uint8_t *join_nonce,
                           const uint8_t *dev_nonce,
                           uint8_t *app_s_key,
                           uint8_t *nwk_s_key) {
    uint8_t input[16];
    ATCA_STATUS status;

    /* Derive AppSKey: AES-128(AppKey, 0x02|JoinNonce|NetID|DevNonce|pad) */
    memset(input, 0, sizeof(input));
    input[0] = 0x02;
    memcpy(&input[1], join_nonce, 3);
    /* ... fill remaining fields ... */

    status = atcab_aes_encrypt(APPKEY_SLOT, 0, input, app_s_key);
    if (status != ATCA_SUCCESS) return -1;

    /* Derive NwkSKey with 0x01 prefix */
    input[0] = 0x01;
    status = atcab_aes_encrypt(NWKKEY_SLOT, 0, input, nwk_s_key);

    return (status == ATCA_SUCCESS) ? 0 : -1;
}

Frequently Asked Questions

What is the maximum range of a LoRaWAN gateway in urban environments?

In dense urban environments, a single LoRaWAN gateway typically achieves 2-5 km range due to building obstructions and multipath interference. Rural and line-of-sight deployments can reach 10-15 km. Gateway placement at elevated positions with external antennas rated at 3-6 dBi significantly improves coverage. The link budget, factoring in path loss, antenna gains, and receiver sensitivity of -137 dBm at SF12, determines practical range.

How does the Adaptive Data Rate algorithm work in LoRaWAN?

The ADR algorithm dynamically adjusts spreading factor (SF7-SF12), transmission power, and channel selection based on received signal quality. The network server analyzes the last 20 uplink frame SNR values, calculates the margin above the demodulation floor, and sends ADR commands via downlink MAC frames. Devices with stable RF conditions use lower spreading factors for higher data rates.

What are the differences between LoRaWAN Class A, B, and C devices?

Class A devices open two receive windows only after each uplink, offering the lowest power consumption. Class B devices add scheduled ping slots synchronized via gateway beacons for predictable downlink latency. Class C devices keep their receiver continuously open, providing near-zero downlink latency but requiring mains power due to approximately 10-15 mA continuous receive current.

How many end devices can a single LoRaWAN gateway support?

A single 8-channel gateway comfortably handles 1,000-3,000 devices with typical sensor payloads of 10-20 bytes every 15 minutes under EU868 duty cycle constraints. Using ADR to distribute devices across spreading factors and channels maximizes capacity. Dense deployments benefit from multiple overlapping gateways for load balancing.

What security mechanisms does LoRaWAN 1.1 provide?

LoRaWAN 1.1 uses a dual-key architecture with separate Network Session Key and Application Session Key, ensuring end-to-end encryption. It includes a Join Server for key management, frame counter synchronization against replay attacks, and OTAA using AES-128 challenge-response with DevNonce anti-replay for fresh session key generation.