RisalDash RisalDash

Project · LoRa · Long range

Kilometres of radio, no internet at all

Wi-Fi dies at the fence. A $4 LoRa module keeps talking for kilometres — farm sensors, a mountain cabin, a boat at anchor — with no gateway, no SIM card and no monthly fee. This build links two ESP32s point-to-point and puts RSSI, SNR and a live traffic log on each node's own dashboard, so you can see the link quality as you walk away.

ProjectLoRaSX1278RadioESP32
ESP32 LoRa point-to-point project: SX1278, RSSI and SNR live, no internet

The wiring — plain SPI plus two control pins

The SX1278 is an SPI device: SCK/MISO/MOSI shared, its own NSS chip-select, a RST line and DIO0 as the “packet ready” interrupt. One physical rule outranks everything: never transmit without the antenna — the PA can die in seconds.

LoRa SX1278 module wired to an ESP32 over SPI with NSS, RST and DIO0
SX1278 on the ESP32's VSPI. Built in BoardLab.

The protocol — a beacon, not a stack

P2P LoRa needs no LoRaWAN stack. Each node beacons ID:counter; anything heard that isn't your own ID is the peer. Hardware CRC silently drops corrupt packets, and a 10-second timeout drives the “peer online” LED:

#define NODE_ID 'A'             // flash 'A' on one board, 'B' on the other
#define FREQ 433E6              // match your module + region!

LoRa.setPins(LORA_NSS, LORA_RST, LORA_DIO0);
if (!LoRa.begin(FREQ)) { evlog->print("LoRa init FAILED"); return; }
LoRa.enableCrc();               // drop corrupt packets in hardware

// Beacon "A:123" every couple of seconds:
LoRa.beginPacket();
LoRa.print(String((char)NODE_ID) + ":" + String(++txNo));
LoRa.endPacket();
int sz = LoRa.parsePacket();
if (sz) {
  String msg;
  while (LoRa.available()) msg += (char)LoRa.read();
  if (msg.length() && msg[0] != NODE_ID) {      // anything not ours = the peer
    recv += 1;
    rssi = LoRa.packetRssi();                   // link strength, dBm
    snr  = LoRa.packetSnr();                    // quality above the noise floor
    if (evlog) evlog->print(msg + "  " + String((int)rssi) + " dBm");
  }
}
online = millis() - lastHear < 10000;           // peer-online LED

Flash the shipped sketch (examples/06_Projects/LoRaLink, library: sandeepmistry/LoRa) on two boards — NODE_ID 'A' and 'B' — and each serves its own dashboard AP. ⚠ Set FREQ to your region: 433 MHz (Asia/EU ISM), 868 MHz (EU), 915 MHz (US).

Reading RSSI and SNR

ReadingRangeMeaning
RSSI −40…−90 dBmstrongplenty of margin
RSSI −90…−110 dBmworkingnormal long-range territory
RSSI −110…−125 dBmedgeLoRa still decodes below the noise floor — watch SNR
SNR > 0 dBcleansignal above noise
SNR 0…−15 dBmagic zoneonly LoRa survives here

Range levers: a higher spreading factor (SF7→SF12) buys kilometres at the cost of airtime; lower bandwidth helps too. For a battery node, pair with deep sleep — beacon, sleep, repeat. How LoRa compares to ESP-NOW, Zigbee and the rest: the wireless-protocols guide; mesh on top of LoRa: Meshtastic.

Two boards, two antennas — and a link you can watch by the dBm.