Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

SX1278 LoRa (Ra-02) with NodeMCU ESP8266 — wiring and code

Wire a 433 MHz SX1278 / Ra-02 LoRa module to a NodeMCU ESP8266 on HSPI with NSS off the D8 boot pin, and send and receive packets.

Arduino C++Verified — core esp8266 3.1.2, LoRa 0.8.0, 3 Nov 2026Compile-only

Community draft — report a mistake

LoRa sends small packets over kilometres on very little power, which makes it popular for farm sensors, tank levels and village-scale monitoring where Wi-Fi doesn’t reach. The cheap module in Indian shops is the Ra-02 (SX1278).

On the NodeMCU, SCK/MISO/MOSI go to D5/D6/D7 (hardware SPI). The ESP8266-specific choices are the other three: NSS on D2 to keep the D8 boot pin clear, RST on D0, and DIO0 on D1 because D0 can’t do interrupts.

Wiring

NodeMCU ESP8266Only the pins used are shown · 3.3 V logicSX1278 LoRa module (Ra-02, 433 MHz)GND3V3D0D1D2D5D6D73.3VGNDNSSSCKMOSIMISORSTDIO0
Also needed: 433 MHz antenna (spring or 17 cm wire) — never transmit without one.
Every connection
NodeMCU ESP8266SX1278 LoRa module (Ra-02, 433 MHz)WireNotes
3V33.3VredAbout 120 mA while transmitting — within the NodeMCU regulator’s budget, but nothing else heavy on 3V3.
GNDGNDblack
D5SCKyellowD5 = GPIO14, hardware SPI clock.
D6MISOgreenD6 = GPIO12.
D7MOSIblueD7 = GPIO13.
D2NSSpurpleChip select on D2 instead of D8, so the module can’t hold GPIO15 high at boot.
D0RSTwhiteRST only needs a plain output — a good use for D0.
D1DIO0orangeD1 = GPIO5, interrupt-capable (D0 is not).

3.3 V only (1.8–3.7 V) part, 3.3 V board. The SX1278 is a 3.3 V part and its pins are not 5 V tolerant. ESP32 and Pico connect directly. With an Uno or Nano, level-shift NSS, SCK, MOSI and RST, and power the module from a 3.3 V regulator that can supply about 120 mA while transmitting.

Board quirks

  • Frequency, honestly: the SX1278 / Ra-02 is a 433 MHz chip; it can’t reach India’s LoRa band of 865–867 MHz (used by LoRaWAN “IN865” gateways). For that you need an SX1276/RFM95 868 MHz module. The sketch uses 433.92 MHz, inside the 433.05–434.79 MHz short-range band, at low power (10 dBm) — check the current WPC rules before deploying anything.
  • The SPI bus (D5/D6/D7) is fixed in hardware, but chip select is just a GPIO. Most ESP8266 LoRa examples put NSS on D8 (GPIO15); that works only if nothing pulls it high at reset. Moving NSS to D2 removes the risk and leaves D8 alone.
  • D0 (GPIO16) has no interrupt, so it can’t be DIO0. It is fine for RST, which the library only pulses at begin().
  • The module is 3.3 V-only and connects directly — no level shifting on the ESP8266. Never feed its 3.3V pin from VIN.
  • LoRa.endPacket() blocks for the packet’s airtime (around 200 ms at SF9). That is fine, but higher spreading factors (SF11–12) block for over a second; keep Wi-Fi work out of the same moment or use endPacket(true) for async sending.

Code

lora-sx1278-nodemcu.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// SX1278 (Ra-02, 433 MHz) LoRa module on a NodeMCU (ESP8266) — sends a counter and prints
// anything it hears. Load the same sketch on a second board to test a link.
// 3.3V → 3V3, GND → GND, SCK → D5, MISO → D6, MOSI → D7, NSS → D2, RST → D0, DIO0 → D1.
// NSS is on D2, not D8: D8 (GPIO15) must stay LOW at boot and is better left alone.
#include <SPI.h>
#include <LoRa.h>

const uint8_t LORA_NSS = D2;   // GPIO4
const uint8_t LORA_RST = D0;   // GPIO16 — a plain output is all RST needs
const uint8_t LORA_DIO0 = D1;  // GPIO5 — interrupt-capable (D0 is not)
// 433.92 MHz keeps a 125 kHz channel inside the 433.05–434.79 MHz band. Keep power low.
const long FREQ = 433920000;

unsigned long lastSend = 0;
uint32_t counter = 0;

void setup() {
  Serial.begin(115200);
  Serial.println();
  LoRa.setPins(LORA_NSS, LORA_RST, LORA_DIO0);
  if (!LoRa.begin(FREQ)) {
    Serial.println("LoRa init failed - check wiring and 3.3 V power");
    while (true) delay(1000);
  }
  LoRa.setTxPower(10);  // 10 dBm, the low end
  LoRa.setSpreadingFactor(9);
  Serial.println("LoRa ready on 433.92 MHz");
}

void loop() {
  int size = LoRa.parsePacket();
  if (size) {
    String msg;
    while (LoRa.available()) msg += (char)LoRa.read();
    Serial.printf("Received '%s'  RSSI %d dBm  SNR %.1f dB\n", msg.c_str(), LoRa.packetRssi(), LoRa.packetSnr());
  }
  if (millis() - lastSend > 5000UL + random(0, 1000)) {  // jitter so two boards don't keep colliding
    lastSend = millis();
    LoRa.beginPacket();
    LoRa.print("hello ");
    LoRa.print(counter);
    LoRa.endPacket();  // blocks for the airtime (~0.2 s at SF9)
    Serial.printf("Sent hello %u\n", counter++);
  }
}

Library: LoRa (Sandeep Mistry) — compiled with LoRa 0.8.0.

Expected serial output

Serial Monitor · 115200Output
LoRa ready on 433.92 MHz
Sent hello 0
Received 'hello 3'  RSSI -71 dBm  SNR 9.5 dB
Sent hello 1

Common errors

“LoRa init failed”

Usually NSS or RST on the wrong pin, or MISO/MOSI swapped. Check NSS is on D2 and RST on D0 as in LoRa.setPins(), and that 3.3V is connected.

Board won’t boot after wiring the module

NSS (or another wire) is on D8 and holds GPIO15 high at reset. Move it to D2 — see boot mode (1,6).

Both boards send but neither receives

Settings must match exactly: frequency, spreading factor and bandwidth. Flash the same sketch on both, and fit antennas.

↑↓ to move · Enter to open