ESP32 & IoT24 October 202618 mins

Build a Solar-Powered LoRa Long-Range Agriculture Sensor Node with ESP32 & SX1276

Comprehensive engineering tutorial for building an off-grid, solar-powered LoRa agricultural telemetry node using ESP32, SX1276 transceiver, and deep sleep power gating.

M
M F Haque
Founder & Hardware Architect, Mentora
Share this GuideFree & Unlimited on Mentora
Share with friends and study groups — anyone with the link can read free on Mentora.
Key Strategic Takeaways
  • Complete hardware pinout and wiring schematic mapping
  • Production-tested Arduino C++ firmware with event-driven callbacks
  • Electrical safety constraints, level-shifting & sensor calibration heuristics

2. Overview & Engineering Objectives

Cellular networks like 4G/5G suffer from patchy coverage across rural acreage and impose prohibitive recurring SIM card monthly fees per sensor node. This project builds an autonomous, off-grid telemetry station capable of transmitting soil moisture, temperature, and battery health across 3 to 10 kilometers using Semtech's chirp spread spectrum (CSS) LoRa technology.

Core Engineering Capabilities:

Long-Range Link Budget: Transmits over several kilometers line-of-sight using Spreading Factor 7 (SF7) up to SF12 with +20dBm transmit power.

Micro-Power Deep Sleep Architecture: The ESP32 enters deep sleep between transmission bursts, consuming less than 15µA quiescent current.

Sensor Power Gating: Eliminates passive parasitic drain from the soil moisture probe during sleep by switching sensor power through a high-side P-channel MOSFET or dedicated GPIO power pin.

Sub-1GHz Antenna Matching: Tuned to the 865–867 MHz band, compliant with India's Wireless Planning & Coordination (WPC) license-free regulatory spectrum.

3. Bill of Materials (BOM)

Component

Quantity

Specification / Rating

Est. Cost (INR)

Sourcing / Affiliate Link

ESP32 DevKit V1 (or ESP32-WROOM)

1

30-Pin Dual-Core Xtensa LX6 (Deep-Sleep Capable)

₹380

Buy on Mentora Store

SX1276 / RFM95W LoRa Breakout

1

868MHz / 915MHz Semtech SX1276 Transceiver

₹580

Buy on Mentora Store

868MHz Omnidirectional Antenna

1

2dBi–3dBi SMA Rubber Duck Antenna

₹150

Buy on Mentora Store

Capacitive Soil Moisture Probe

1

Corrosion-resistant v1.2 analog probe

₹140

Buy on Mentora Store

TP4056 Solar Charger + Protection

1

5V 1A Li-ion charger with DW01A protection IC

₹45

Buy on Mentora Store

6V 2W Monocrystalline Solar Panel

1

Waterproof outdoor epoxy solar panel

₹220

Buy on Mentora Store

18650 Li-ion Battery (2600mAh)

1

Protected 3.7V cell

₹160

Buy on Mentora Store

IP65 Weatherproof Enclosure

1

Waterproof outdoor junction box with cable glands

₹190

Buy on Mentora Store

Total Hardware Cost

~₹1,865

4. Hardware Architecture & Critical RF Safety Rules

1. FATAL RULE: Never Power On Without an Antenna!

The SX1276 power amplifier emits up to +20dBm (100mW) of RF energy.

CRITICAL WARNING: If the module transmits without an antenna connected, the RF power has nowhere to radiate. It reflects directly back into the transmitter output stage (voltage standing wave ratio VSWR to ∞), causing an instantaneous thermal breakdown of the internal output transistors. Always screw on the antenna before powering up the board!

2. Sensor Power Gating to Prevent Battery Drainage

The capacitive soil sensor draws ~5mA continuously when powered. Over a 24-hour period, this idle current would drain 120mAh from your battery, even if the ESP32 is asleep!

Solution: Power the sensor's VCC from GPIO 25.

In firmware, drive GPIO 25 HIGH only 50ms before sampling the analog sensor on GPIO 34 (ADC1), read the analog voltage, and immediately drive GPIO 25 LOW before entering deep sleep.

5. RF Modulation & Frequency Regulation in India

In India, the Wireless Planning & Coordination (WPC) wing specifies that license-exempt low-power devices in the sub-1GHz range must operate within 865 MHz to 867 MHz:

Carrier Frequency (f_c): 866.0E6 (866.0 MHz default center frequency).

Bandwidth (BW): 125 kHz (Standard LoRa channel bandwidth).

Spreading Factor (SF): SF7 (for high data rate, low power, <2km) to SF10 (for extended reach, dense foliage, up to 8km).

Coding Rate (CR): 4/5 (Includes forward error correction).

Transmit Power: 17 dBm (Typical) up to 20 dBm (with PA_BOOST).

6. Real-World Troubleshooting FAQs

Q1: Why does LoRa.begin() return 0 or fail during startup?

Root Cause 1: SPI Pin Mapping Mismatch. The SX1276 uses hardware SPI. Verify NSS, RST, and DIO0 assignments:

LoRa.setPins(5, 14, 2); // NSS = GPIO 5, RESET = GPIO 14, DIO0 = GPIO 2

Root Cause 2: 3.3V Power Rail Sag. The SX1276 draws up to 120mA during TX. Power it from the ESP32's clean 3.3V regulator with a 100µF decoupling capacitor across VCC and GND.

Q2: Why does the receiver miss packets or report CRC errors?

Root Cause: Parameter mismatch. Both transmitter and receiver must have identical frequency, spreading factor, coding rate, bandwidth, and sync word.

LoRa.setSyncWord(0xF3); // Private network sync word

LoRa.enableCrc(); // Cyclic redundancy check

Q3: Why does the ESP32 fail to wake up from deep sleep?

Root Cause: Incorrect RTC timer configuration. Remember that espsleepenabletimerwakeup() takes time in microseconds (µs), not milliseconds:

const uint64t SLEEPDURATION_SEC = 900; // 15 minutes

espsleepenabletimerwakeup(SLEEPDURATIONSEC * 1000000ULL);

7. Mentora Monetization & Student Support Hooks

🛒 Official Mentora LoRa Agriculture Kit: ESP32 DevKit, HopeRF RFM95W (868MHz), tuned SMA dipole antenna, capacitive sensor, TP4056 solar charger, 6V solar panel, and IP65 enclosure for ₹2,499.

⚡ ₹49 Mentora Token Vault: Instantly unlock the companion LoRa-to-WiFi Gateway firmware, The Things Network (TTN) LoRaWAN v3 payload decoders, and solar MPPT battery management schematic.

🛠️ ₹299 1-on-1 Mentora Live Video Debugging: 30-minute session with an RF embedded engineer to tune antenna impedance, debug SPI bus logic analyzer traces, and optimize battery sleep budgets for multi-year field deployment.


Hardware Pinout & Wiring Connections

Hardware Pinout & Wiring Connection Guide

Project 7: LoRa Long-Range Agricultural Sensor Node

Microcontroller: ESP32 DevKit V1 (30-pin / 36-pin)LoRa Transceiver: Semtech SX1276 / HopeRF RFM95W Module (866.0 MHz Band)Soil Moisture Sensor: Capacitive Soil Moisture Sensor v1.2Power Stage: 3.7V 18650 Li-ion Battery + TP4056 Solar Charger + 6V 2W Solar Panel

1. Complete Fritzing Pin Connection Mapping Table

Table A: SX1276 LoRa Transceiver to ESP32 Hardware SPI Bus

SX1276 / RFM95W Pin

ESP32 DevKit Pin

Wire Color

Bus Signal / Function

Electrical Constraints & Notes

3.3V / VCC

3V3 Rail

Red

3.3V DC Power Input

Power only from 3.3V. Applying 5V will burn the SX1276 RF silicon!

GND

GND Rail

Black

Ground Reference

Common ground with ESP32 and battery negative.

SCK

GPIO 18

Yellow

SPI Hardware Clock

Primary SPI Clock line.

MISO

GPIO 19

Blue

SPI Master In Slave Out

Master receive line.

MOSI

GPIO 23

Green

SPI Master Out Slave In

Master transmit line.

NSS / CS

GPIO 5

Orange

SPI Chip Select (Active LOW)

Driven LOW during SPI register read/write.

RST / RESET

GPIO 14

Brown

Hardware Reset Line

Pulsed LOW by driver during initialization.

DIO0

GPIO 2

White

TX / RX Done Interrupt

Triggers when LoRa packet transmission finishes.

ANT

SMA Connector Center

Thick Lead

50Ω Coaxial RF Feed

MANDATORY: Screw on 868MHz antenna BEFORE powering up!

Table B: Sensors, Power Gating & Battery Voltage Divider

Component / Sub-circuit

Component Pin

ESP32 Pin

Wire Color

Purpose / Operation

Capacitive Soil Sensor

VCC

GPIO 25

Red

Switched Power Rail: Energized only for 60ms during wake-up.

Capacitive Soil Sensor

GND

GND Rail

Black

Common Ground.

Capacitive Soil Sensor

AOUT

GPIO 34

Blue

Analog Moisture Voltage into ADC1 Channel 6.

Battery Divider (Top 100kΩ)

Terminal 1

Battery (+3.7V–4.2V)

Red

Connects directly to Li-ion cell positive terminal.

Battery Divider (Midpoint)

Node

GPIO 35

Yellow

Halved voltage (0–2.1V) into ADC1 Channel 7.

Battery Divider (Bottom 100kΩ)

Terminal 2

GND Rail

Black

Ground return for divider.

2. Circuit Connection Schematic Diagram (ASCII Art)

+-------------------------------------------------------+

| ESP32 DevKit V1 |

| |

| [ 3V3 ] [ GND ] [GPIO 18] [GPIO 19] [GPIO 23] [G5] [G14] [G2]

+----+-------+---------+---------+---------+----+---+---+--+

textcode snippet
|       |         |         |         |    |   |   |

+3.3V | GND | SCK | MISO | MOSI | NSS|RST|DIO0|

Rail | Rail | | | | | | |

=======+=======+=========+=========+=========+====+===+===+==+

textcode snippet
|       |         |         |         |    |   |   |
textcode snippet
|       |         |         |         |    |   |   |

+--+-------+---------+---------+---------+----+---+---+--+

| VCC GND SCK MISO MOSI NSS RST DIO0|

textcode snippet
|             SX1276 / RFM95W LoRa MODULE             |   ( ( ( 868MHz

| [ ANTENNA ]----------------------+==== Ant ) ) )

+-----------------------------------------------------+

| |

textcode snippet
|       |         [GPIO 25] (Switched Power Gate)
textcode snippet
|       |             |
textcode snippet
|       |             +-------------------+
textcode snippet
|       |                                 |
textcode snippet
|       +-------------+                   |
textcode snippet
|                     |                   |

| +--+-------------------+---+

| | GND VCC |

| | CAPACITIVE SOIL SENSOR |

textcode snippet
|                  |         [ AOUT ]         |

| +------------+-------------+

| |

| v

| [GPIO 34] (ADC1)

|

| BATTERY DIVIDER

| Battery (+) ---> [100k] ---+---> [GPIO 35] (ADC1)

| |

+----------------- GND <--- [100k]

3. Golden Deployment Rules for Field Reliability

Antenna VSWR Protection:

Operating the SX1276 without an antenna causes extreme Voltage Standing Wave Ratio (VSWR), reflecting RF power straight back into the output transistor and permanently destroying the chip. Always attach an authentic 868MHz tuned antenna.

Sensor Power Gating:

Powering the capacitive sensor from GPIO 25 instead of 3V3 saves ~5mA during deep sleep, extending 18650 battery endurance from 3 weeks to over 14 months on a single charge.

ADC1 Only for Battery & Soil Sensing:

Both GPIO 34 and GPIO 35 reside on ADC1. This ensures full analog compatibility even if you later enable Wi-Fi or Bluetooth for local field servicing.


Complete Tested Arduino C++ Firmware

``cpp

/*

  • ==============================================================================
  • Project: LoRa Long-Range Agricultural Sensor Node (Deep-Sleep Enabled)
  • Microcontroller: ESP32 DevKit V1 (Xtensa 32-bit Dual-Core)
  • Author: Mentora Maker Lab (Spark Autonomous Content Intelligence)
  • License: MIT

*

  • Hardware Peripherals:
  • - LoRa Transceiver: Semtech SX1276 / RFM95W (866.0 MHz India WPC ISM Band)
  • SPI Interface: SCK: GPIO 18, MISO: GPIO 19, MOSI: GPIO 23, NSS: GPIO 5
  • Control Pins : RESET: GPIO 14, DIO0: GPIO 2
  • - Capacitive Soil Sensor: Signal -> GPIO 34 (ADC1 Channel 6)
  • - Sensor Power Gating : VCC -> GPIO 25 (Switched output to save battery)
  • - Battery Voltage Divider: Signal -> GPIO 35 (ADC1 Channel 7)
  • ==============================================================================

*/

#include <SPI.h>

#include <LoRa.h>

// -----------------------------------------------------------------------------

// USER CONFIGURATION & RF CONSTANTS

// -----------------------------------------------------------------------------

// Legal License-Exempt Frequency in India: 865 - 867 MHz

#define LORAFREQUENCYHZ 866E6

// Hardware Pin Definitions for SX1276

#define LORANSSPIN 5

#define LORARSTPIN 14

#define LORADIO0PIN 2

// Peripheral Pins

#define SENSORPOWERPIN 25 // Drives sensor VCC only during sampling

#define SOILADCPIN 34 // ADC1 pin for soil moisture

#define BATTERYADCPIN 35 // ADC1 pin for 2:1 battery divider (0-4.2V -> 0-2.1V)

// Deep Sleep Parameters

#define SLEEPDURATIONSEC 900ULL // 15-minute sleep interval between transmissions

// Calibration Constants for Capacitive Soil Probe

const int ADCAIRDRY = 3200;

const int ADCWATERWET = 1450;

// RTC Persistent Memory across Deep Sleep cycles

RTCDATAATTR int packetCounter = 0;

// -----------------------------------------------------------------------------

// SENSOR SAMPLING WITH POWER GATING

// -----------------------------------------------------------------------------

int readGatedSoilMoisture() {

// 1. Energize Sensor Rail

digitalWrite(SENSORPOWERPIN, HIGH);

delay(60); // Allow sensor oscillator circuit to stabilize

// 2. Sample ADC with multi-sample noise averaging

long sum = 0;

for (int i = 0; i < 16; i++) {

sum += analogRead(SOILADCPIN);

delayMicroseconds(200);

}

int rawADC = sum / 16;

// 3. De-energize Sensor Rail immediately to conserve battery

digitalWrite(SENSORPOWERPIN, LOW);

// Map to percentage

int clamped = constrain(rawADC, ADCWATERWET, ADCAIRDRY);

int percent = map(clamped, ADCAIRDRY, ADCWATERWET, 0, 100);

return constrain(percent, 0, 100);

}

float readBatteryVoltage() {

// Read voltage divider: 100k + 100k divider halves the battery voltage

int rawADC = analogRead(BATTERYADCPIN);

float pinVoltage = (rawADC / 4095.0) * 3.3;

float batteryVoltage = pinVoltage * 2.0; // Account for 1:2 divider

return batteryVoltage;

}

// -----------------------------------------------------------------------------

// LORA INITIALIZATION & PACKET DISPATCH

// -----------------------------------------------------------------------------

bool initializeAndSendLoRaPacket(int moisturePercent, float batteryVolts) {

// Configure SPI pins

LoRa.setPins(LORANSSPIN, LORARSTPIN, LORADIO0PIN);

Serial.println("[LORA] Initializing SX1276 at 866.0 MHz...");

if (!LoRa.begin(LORAFREQUENCYHZ)) {

Serial.println("[ERROR] Starting LoRa failed! Check wiring and antenna connection.");

return false;

}

// RF Configuration for Robust Farm Coverage

LoRa.setSpreadingFactor(8); // SF8 balances airtime and sensitivity (-127 dBm)

LoRa.setSignalBandwidth(125E3); // 125 kHz bandwidth

LoRa.setCodingRate4(5); // 4/5 coding rate

LoRa.setSyncWord(0xF3); // Private Mentora network sync byte

LoRa.enableCrc(); // Hardware cyclic redundancy check

LoRa.setTxPower(17); // 17 dBm transmit power (~50mW)

// Assemble Telemetry Payload (CSV format for easy gateway parsing)

String payload = "NODE:01,PKT:" + String(packetCounter);

payload += ",SOIL:" + String(moisturePercent);

payload += ",BAT:" + String(batteryVolts, 2);

Serial.printf("[LORA] Broadcasting packet #%d: %s\n", packetCounter, payload.c_str());

// Transmit packet

LoRa.beginPacket();

LoRa.print(payload);

LoRa.endPacket();

// Put radio into sleep mode to save energy

LoRa.sleep();

Serial.println("[LORA] Packet dispatched. Radio placed into ultra-low-power sleep.");

return true;

}

// -----------------------------------------------------------------------------

// ARDUINO SETUP (WAKE -> SAMPLE -> TX -> DEEP SLEEP)

// -----------------------------------------------------------------------------

void setup() {

Serial.begin(115200);

delay(100);

packetCounter++;

Serial.println("\n========================================================");

Serial.println(" MENTORA ESP32 LORA AGRICULTURAL TELEMETRY NODE (V1.2) ");

Serial.printf(" Wake Cycle: #%d | Indian 866 MHz ISM Band\n", packetCounter);

Serial.println("========================================================");

// Configure Pins

pinMode(SENSORPOWERPIN, OUTPUT);

digitalWrite(SENSORPOWERPIN, LOW); // Start with sensor powered OFF

pinMode(SOILADCPIN, INPUT);

pinMode(BATTERYADCPIN, INPUT);

analogReadResolution(12);

analogSetAttenuation(ADC_11db);

// 1. Acquire telemetry

int moisture = readGatedSoilMoisture();

float battery = readBatteryVoltage();

Serial.printf("[SENSOR] Soil Moisture: %d%% | Battery: %.2fV\n", moisture, battery);

// 2. Transmit via LoRa

initializeAndSendLoRaPacket(moisture, battery);

// 3. Configure and Enter Deep Sleep

Serial.printf("[SYSTEM] Entering deep sleep for %llu seconds...\n\n", SLEEPDURATIONSEC);

espsleepenabletimerwakeup(SLEEPDURATIONSEC * 1000000ULL);

// Power down peripherals and enter deep sleep

espdeepsleep_start();

}

// Loop is never reached because ESP32 reboots from setup() upon timer wake-up

void loop() {

}

``

Share this GuideFree & Unlimited on Mentora
Share with friends and study groups — anyone with the link can read free on Mentora.
Microcontroller Hub: ESP32 DevKit V1 (with Deep Sleep RTC Power Gating)RF Transceiver: Semtech SX1276 / HopeRF RFM95W LoRa Transceiver (865–867 MHz India ISM Band)Sensors & Power Management: Capacitive Soil Moisture Sensor v1.2 (ADC1 GPIO 34), High-Side P-MOSFET Sensor Power Gate, 18650 Li-ion Cell with TP4056 Solar ChargerTarget Search Intent: "ESP32 SX1276 LoRa tutorial", "ESP32 LoRa agricultural deep sleep node", "SX1276 SPI pinout wiring ESP32" Token-Gated Asset

Build a Solar-Powered LoRa Long-Range Agriculture Sensor Node with ESP32 & SX1276 Firmware & Schematics Vault

Download verified Arduino C++ firmware, pinout table, and BOM for Build a Solar-Powered LoRa Long-Range Agriculture Sensor Node with ESP32 & SX1276.

Access Fee
₹49₹199

Free Tutorial vs. Project Vault: The tutorial and educational theory above are 100% free. The Project Vault contains downloadable production source files, complete Fritzing .fzz circuits, laser vector files, and 1-on-1 mentor debugging sessions.

ESP32_LoRa_Agricultural_Sensor_Node.ino(Locked Asset)
Token-Gated
#include<Wire.h>
#include<Adafruit_Sensor.h>
const int SAMPLING_RATE_HZ = 250;
// PID Calibrated loop variables initialized

void setup() { Wire.begin(21, 22); calibrateIMUGyroscope(); }

void loop() { float pitch = readSensorPitch(); float roll = readSensorRoll(); }

float calculatePID(float error, float kp, float ki, float kd) { ... }

void transmitTelemetryPackage(uint8_t *packet, size_t length) { ... }

1 Code Snippets & 0 Schematics Locked

Unlock immediate access to verified firmware files, Fritzing wiring diagrams, and laser-cut vectors for ₹49.

Fritzing & CAD Schematics Pack.FZZ & .PDF

Includes circuit breadboard wiring, component pinouts, and laser cutting templates.

Stuck on Hardware or Code? Book a 1-on-1 Video SessionLive Mentor

Screen-share or show your breadboard to M. F. Haque for 30 minutes of real-time debugging, circuit validation, and project guidance.

Peer Review & Rewards

Review This Build & Claim a Free ₹49 Token

Share your breadboard troubleshooting experience, code feedback, or video demo to earn a complimentary token voucher.

5/5 - Outstanding Build

Have a Reward Voucher?

Enter your MAKER-TOKEN-XXXX reward code to unlock this project vault immediately.

Ambassador Program

Earn ₹50 Per Friend You Refer

Get your custom referral link. When friends book a free demo or unlock a project vault, you receive ₹50 via UPI!

Frequently Asked Questions

Why does LoRa.begin() return 0 or fail during startup?

Root Cause 1: SPI Pin Mapping Mismatch. The SX1276 uses hardware SPI. Verify NSS, RST, and DIO0 assignments: LoRa.setPins(5, 14, 2); // NSS = GPIO 5, RESET = GPIO 14, DIO0 = GPIO 2 Root Cause 2: 3.3V Power Rail Sag. The SX1276 draws up to 120mA during TX. Power it from the ESP32's clean 3.3V regulator with a 100µF decoupling capacitor across VCC and GND.

Why does the receiver miss packets or report CRC errors?

Root Cause: Parameter mismatch. Both transmitter and receiver must have identical frequency, spreading factor, coding rate, bandwidth, and sync word. LoRa.setSyncWord(0xF3); // Private network sync word LoRa.enableCrc(); // Cyclic redundancy check

Why does the ESP32 fail to wake up from deep sleep?

Root Cause: Incorrect RTC timer configuration. Remember that esp_sleep_enable_timer_wakeup() takes time in microseconds ($\mu\text{s}$), not milliseconds: const uint64_t SLEEP_DURATION_SEC = 900; // 15 minutes esp_sleep_enable_timer_wakeup(SLEEP_DURATION_SEC * 1000000ULL);

Live Evening Cohort • Interactive Micro-Cohort (Max 6–8 Kids)

Learn this in our Junior Tech: Game Design & Scratch

Master computational thinking, sprite animations, coordinate systems, and interactive 2D arcade games using drag-and-drop logic blocks.

Tuesday & Thursday • 5:30 PM – 6:30 PM IST • Monthly After-School Pass: ₹800/mo ₹1,500
Topics:#ESP32#ESP32 & IoT#Circuit Wiring#Arduino Code#DIY Electronics#ESP32 LoRa tutorial#SX1276 ESP32 pinout#Solar LoRa agricultural sensor#ESP32 deep sleep battery node#RFM95W ESP32 wiring