Successfully implemented an ultra-low power LoRa remote control system using ESP32-S3 with SX1262 radio, achieving months of battery operation through optimized deep sleep and duty cycle reception.
Key Achievement: 175 µA average current consumption with 13-19 months battery life on a 3000 mAh LiPo battery.
- Development Board: EoRa Pi ESP32-S3 (SX1262 LoRa 915MHz)
- Power Consumption: ~175 µA average (measured with Nordic Power Profiler Kit II)
- Battery Life: 13-19 months on 3000 mAh LiPo
- Custom wake-up circuit using a 74HC04N DIP package of six inverters (two used); for clean unity gain and signal routing
- Ebyte EoRa-S3-900TB (EoRa PI) - Pair of transceivers for your country's ISM frequency band
- 3000 mAh LiPo Battery - JST-2 1.25 SH Series connector
- Development Environment - Arduino IDE 2.3.6
- Compiled with 2.0.17 Board Manager
- Choose Board - "ESP32S3 Development Module"
- KY-002S bistable MOSFET switch - Enables remote load switching
- 74HC04N DIP package of Six inverters (two used) - For unity gain buffering and clean wake signal routing (GPIO33 → RTC_GPIO16)
-
Install Dependencies
- Install RadioLib library in Arduino IDE
- Download this repository and open desired sketch
- Compiled using ESP32 Board Manager 2.0.17
-
Basic Setup
- Transmitter: Uses "EoRa PI" board only (no additional wiring needed)
- Receiver: See wiring schematic for component connections
-
Upload & Test
- Flash
EoRa_PI_WOR_Transmitter.ino
to transmitter board - Flash
EoRa_PI_WOR_Receiver.ino
to receiver board - Power on both units and test basic communication
- Flash
- Average Current: 175 µA (ESP32-S3 deep sleep + SX1262 duty cycle)
- Battery Configuration: 3000 mAh LiPo with JST-2 1.25 SH connector
- Measured with: Nordic Power Profiler Kit II (NPPK II)
Scenario | Duration | Notes |
---|---|---|
Theoretical Maximum | ~1.96 years (714 days) | Ideal conditions |
Realistic Estimate | ~19.2 months (586 days) | 82% usable capacity |
Practical Limit | ~13.5 months | Accounting for self-discharge |
- ESP32-S3 Deep Sleep: Ultra-low consumption when idle
- LoRa Duty Cycle:
radio.startReceiveDutyCycleAuto()
minimizes radio power - Wake-on-Radio Protocol: Two-stage packet system for reliable operation; single transmission
- Smart RTC_GPIO Routing: SX1262 DIO1 → GPIO33 → 74HC04N (input A1, Y1 output connected to A2 input, y2 output) → RTC_GPIO16 → ESP32 RTC_GPIO external0 Wake up.
// Optimized LoRa parameters for duty cycle operation
Frequency: 915.0 MHz
Bandwidth: 125.0 kHz
Spreading Factor: 7
Coding Rate: 4/7
TX Power: 14 dBm
Preamble: 512 symbols (critical for duty cycle timing)
Sync Word: RADIOLIB_SX126X_SYNC_WORD_PRIVATE
Implemented a two-packet protocol for reliable one-transmission operation:
- WOR (Wake-On-Radio) packet → Wakes ESP32 → Initializes duty cycle mode
- Payload packet → Received by duty cycle radio → Executes command immediately
// Server side - dual transmission
sendWakePacket(); // Wake the receiver
delay(500); // Brief pause
sendCommandPacket(); // Actual command execution
- Command: "1, + timestamp"
- Keep Alive: Only one command (turn ON)
- Dead Man's Switch: Automatic timeout shutdown (2-minute safety)
- Timestamp: NTP-based time from transmitter
- Web request received → Preamble message switches radio to Duty Cycle mode
- ESP32-S3 awakens from deep sleep
- Transmitter sends "1,timestamp" packet
- Receiver processes command → Resets 2-minute safety timer
- No packet received → Timer expires → Switch turns OFF automatically
The transmitter uses WiFiManager (by tzapu) for easy network setup without hardcoding credentials:
-
Initial Setup Mode
- Power on the transmitter device
- Device creates WiFi access point:
EoRa-PI-Setup
- Connect to this network from your phone/computer
- Open web browser and navigate to:
192.168.4.1
-
Configure Your Network
- Select your home WiFi network from the list
- Enter your WiFi password
- Device will connect and display the assigned IP address
-
Remote Control Operation
- Note the IP address displayed (e.g.,
192.168.1.100
) - Open web browser on any device connected to your network
- Navigate to:
[YOUR_IP_ADDRESS]/relay
- Example:
192.168.1.100/relay
- This sends the LoRa WOR (Wake-On-Radio) packet followed by command packet to the receiver
- Note the IP address displayed (e.g.,
- Simple HTTP endpoint: Just add
/relay
to your device's IP address - Instant transmission: Sends wake packet + command packet sequence
- No complex interface: Single-click operation for remote control
- Successfully converted from SX126x-Arduino library, example "DeepSleep.ino" to RadioLib, "EoRa_PI_Foundation_Receiver.ino"
- Preserved duty cycle reception capabilities
- Clean String-based packet reading implementation
void goToSleep(void) {
Serial.println("=== PREPARING FOR DEEP SLEEP ===");
Serial.printf("DIO1 pin state before sleep: %d\n", digitalRead(RADIO_DIO1_PIN));
Serial.printf("Wake pin (GPIO16) state before sleep: %d\n", digitalRead(WAKE_PIN));
// Set up the radio for duty cycle receiving
radio.startReceiveDutyCycleAuto();
Serial.println("Configuring RTC GPIO and deep sleep wake-up...");
// Configure GPIO16 for RTC wake-up - using internal pull-down
rtc_gpio_pulldown_en(WAKE_PIN); // Internal pull-down on GPIO16
// Setup deep sleep with wakeup by GPIO16 - RISING edge (buffered DIO1 signal)
esp_sleep_enable_ext0_wakeup(WAKE_PIN, RISING);
// Turn off LED before sleep
digitalWrite(BOARD_LED, LED_OFF);
Serial.println("✅ Going to deep sleep now...");
Serial.println("Wake-up sources: DIO1 pin reroute");
Serial.flush(); // Make sure all serial data is sent before sleep
SPI.end();
// Finally set ESP32 into sleep
esp_deep_sleep_start();
}
-
Average current: 175µA
-
Sleep current: 25.38µA
-
Active current: 11,000µA (11mA)
-
Duty cycle ≈ (175 - 25.38) / (11,000 - 25.38) ≈ 1.36%
-
Achieving a very low ~1.4% duty cycle, which is excellent for battery life.
-
Interrupt-driven system is working well:
-
98.6% of time in deep sleep (25.38µA)
-
1.4% of time active receiving (11mA)
-
Clean transitions with no lingering current
- Deep Sleep: ~23 µA, Average current ~175 µA (ESP32-S3) + duty cycle radio consumption
- Active Time: <5% duty cycle during command execution
- Wake-up Time: <2 seconds
- Command Processing: Immediate response
- Return to Sleep: Automatic after task completion
- 100% packet reception success rate
- Consistent wake-up and command execution
- Sub-second response time from transmission to action
- Remote equipment control in field deployments (months of operation)
- Battery-powered IoT sensor networks
- Agricultural automation systems
- Emergency/backup communication systems
- Environmental monitoring with long-term deployment
- Camera activation systems (original use case)
- Local logging: Store sensor data on SD card or flash memory
- Cloud integration: Optional by request; POST INA226 data to Google Sheets via Apps Script
- Power monitoring: Track current consumption and battery health
- Multi-node networks: Scale to multiple sensor/control points
- GPIO Routing Critical: RTC_GPIO access essential for deep sleep wake-up
- Parameter Matching: TX/RX LoRa parameters must match exactly
- Duty Cycle Timing: Longer preambles (512 symbols) crucial for reliable reception
- RadioLib Integration: String-based packet reading provides clean implementation
- Two-Stage Protocol: Wake-On-Radio approach solves timing challenges elegantly
- Power Measurement: NPPK II essential for validating ultra-low power performance
- Complete Pin Mapping Guide:
/Docs/Complete Ebyte EoRa-S3-900TB Pin Mapping Guide.pdf
- Power Waveforms:
/Docs/Deep Sleep Waveforms (Latest Nordic PPK2 Observations)/
- User Manual:
/Docs/EoRa_PI_UserManual_EN_v1.1.pdf
- Power Reference:
/Docs/ESP32-S3 Power Consumption Reference Guides.pdf
- Connector: JST-2 1.25 SH Series
- Power Off Consumption: ~5 µA (battery only, no USB)
- Sleep Mode Consumption: ~25 µA (all peripherals in sleep mode)
- Max Charging Current: 500mA
This project was developed with testing and guidance from:
- William Lucid – Founder & Developer
- OpenAI ChatGPT – Engineering Assistant & Debugging Partner
- Claude – Lead programmer & Debugger, Battery Analysis, "EoRa_PI_WOR_Receiver.ino"
- Copilot, "DIO1 re-routing" and Gemini – Support and Contributions to coding
- Community testers and contributors
We welcome contributions! Here's how to help:
- 🐛 Found a bug? Open an issue with details and steps to reproduce
- 💡 Have an idea? Submit a feature request or start a discussion
- 🔧 Want to code? Fork the repo and submit a pull request
- 📚 Documentation: Help improve examples, guides, or troubleshooting
MIT License – see LICENSE
for details.
Successfully achieved the goal of creating a production-ready, ultra-low power LoRa remote control system. The combination of ESP32-S3 deep sleep, SX1262 duty cycle reception, and smart protocol design delivers months of battery operation with reliable command execution.
Hardware: EoRa Pi ESP32-S3 + SX1262
Software: Arduino IDE, RadioLib, ESP-IDF framework
Power: Battery-optimized for 13-19 month field deployment
Range: LoRa 915MHz with excellent rural coverage
73's de AB9NQ thanks for stopping by!
What started as a simple Wyze Cam switch evolved into a flexible, ultra-low-power LoRa + ESP32-S3 foundation achieving sub-200µA operation.