Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e30b611
To support PowerSaving for all ESP32-based repeaters and NRF52-based …
IoTThinks Jan 9, 2026
ea42140
To add flag RADIO_SX1276 to support PowerSaving for SX1276. SX1276 us…
IoTThinks Jan 9, 2026
07b0c72
To expose LoRa pins at platformio.ini instead of header files
IoTThinks Jan 9, 2026
67a4398
To implement power saving for NRF52 using System-Idle On
IoTThinks Jan 13, 2026
f988eb3
To implement light sleep for ESP32 without changing setFlag
IoTThinks Jan 14, 2026
a7a6bd2
To support PowerSaving for all ESP32-based repeaters and NRF52-based …
IoTThinks Jan 9, 2026
36a9ee9
To add flag RADIO_SX1276 to support PowerSaving for SX1276. SX1276 us…
IoTThinks Jan 9, 2026
5476c35
To expose LoRa pins at platformio.ini instead of header files
IoTThinks Jan 9, 2026
d4b3115
To implement power saving for NRF52 using System-Idle On
IoTThinks Jan 13, 2026
69e02df
To implement light sleep for ESP32 without changing setFlag
IoTThinks Jan 14, 2026
b4a699a
Merge branch 'MCdev-PowerSaving-for-all-ESP32-NRF52-repeaters' of htt…
IoTThinks Jan 17, 2026
b460cc2
Added missing OFFLINE_QUEUE_SIZE
IoTThinks Jan 17, 2026
7086e8e
Cleanup and fix typo for enterLightSleep in ESP32Board.h
IoTThinks Jan 17, 2026
9763785
Removed unused library for NRF52Board.cpp
IoTThinks Jan 17, 2026
0477d50
Supported sleep for NRF52 with SX127x
IoTThinks Jan 17, 2026
89f97a3
Cleanup comments
IoTThinks Jan 17, 2026
b5036a8
Added getIRQGpio and safeToSleep. Merged enterLightSleep to sleep.
IoTThinks Jan 17, 2026
26339a7
Fixed to poll wakeupPin correctly
IoTThinks Jan 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/MeshCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class MainBoard {
virtual void onAfterTransmit() { }
virtual void reboot() = 0;
virtual void powerOff() { /* no op */ }
virtual uint32_t getIRQGpio() { return -1; } // DIO0 for SX127x and DIO1 for SX126x/LR11xx
virtual bool safeToSleep() { return false; }
virtual void sleep(uint32_t secs) { /* no op */ }
virtual uint32_t getGpio() { return 0; }
virtual void setGpio(uint32_t values) {}
Expand Down
63 changes: 48 additions & 15 deletions src/helpers/ESP32Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,62 @@ class ESP32Board : public mesh::MainBoard {
return raw / 4;
}

void enterLightSleep(uint32_t secs) {
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(P_LORA_DIO_1) // Supported ESP32 variants
if (rtc_gpio_is_valid_gpio((gpio_num_t)P_LORA_DIO_1)) { // Only enter sleep mode if P_LORA_DIO_1 is RTC pin
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
esp_sleep_enable_ext1_wakeup((1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet
uint32_t getIRQGpio() {
#if defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276
return P_LORA_DIO_0;
#elif defined(P_LORA_DIO_1) // SX1262
return P_LORA_DIO_1;
#else
return -1; // Not found
#endif
}

bool safeToSleep() {
// Check for RX status
gpio_num_t wakeupPin=(gpio_num_t) getIRQGpio();
if(digitalRead(wakeupPin) == HIGH) {
return false;
}

if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs
}
// Check for WiFi status to see if there is active OTA
wifi_mode_t mode;
esp_err_t err = esp_wifi_get_mode(&mode);

esp_light_sleep_start(); // CPU enters light sleep
if (err == ESP_OK) { // WiFi is on
return false;
}
#endif

// Safe to sleep
return true;
}

void sleep(uint32_t secs) override {
// To check for WiFi status to see if there is active OTA
wifi_mode_t mode;
esp_err_t err = esp_wifi_get_mode(&mode);
// Skip if not safe to sleep
if(!safeToSleep()) {
return;
}

if (err != ESP_OK) { // WiFi is off ~ No active OTA, safe to go to sleep
enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet
// Configure GPIO wakeup
gpio_num_t wakeupPin=(gpio_num_t) getIRQGpio();
esp_sleep_enable_gpio_wakeup();
gpio_wakeup_enable((gpio_num_t) wakeupPin, GPIO_INTR_HIGH_LEVEL); // Wake up when receiving a LoRa packet

// Configure timer wakeup
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000ULL); // Wake up periodically to do scheduled jobs
}

// Disable CPU interrupt servicing
noInterrupts();

// MCU enters light sleep
esp_light_sleep_start();

// Avoid ISR flood during wakeup due to HIGH LEVEL interrupt
gpio_set_intr_type(wakeupPin, GPIO_INTR_POSEDGE);

// Enable CPU interrupt servicing
interrupts();
}

uint8_t getStartupReason() const override { return startup_reason; }
Expand Down
74 changes: 74 additions & 0 deletions src/helpers/NRF52Board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,78 @@ bool NRF52BoardOTA::startOTAUpdate(const char *id, char reply[]) {

return true;
}

uint32_t NRF52Board::getIRQGpio() {
#if defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276
return P_LORA_DIO_0;
#elif defined(P_LORA_DIO_1) // SX1262
return P_LORA_DIO_1;
#else
return -1; // Not connected
#endif
}

bool NRF52Board::safeToSleep() {
// Check for RX status
uint32_t wakeupPin = getIRQGpio();
if (digitalRead(wakeupPin) == HIGH) {
return false;
}

// Check if the BLE is powered and looking for/connected to a phone
uint8_t sd_enabled;
sd_softdevice_is_enabled(&sd_enabled); // Set sd_enabled to 1 if the BLE stack is active.

if (sd_enabled) { // BLE is on
return false;
}

// Safe to sleep
return true;
}

void NRF52Board::sleep(uint32_t secs) {
// Skip if not safe to sleep
if (!safeToSleep()) {
return;
}

// Configure GPIO wakeup
uint32_t wakeupPin = getIRQGpio();

// Mark the start of the sleep
uint32_t startTime = millis();
uint32_t timeoutMs = secs * 1000;

// Create event when wakeup pin is high
nrf_gpio_cfg_sense_input(wakeupPin, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);

while (true) {
// Wakeup timer
if ((millis() - startTime) >= timeoutMs) {
break;
}

// Clear stale events
__SEV();
__WFE();

// Disable ISR servicing
noInterrupts();

if (digitalRead(wakeupPin) == HIGH) {
interrupts();
break;
}

// Attempt to sleep, wakeup on any events
__WFE();

// Enable ISR servicing
interrupts();
}

// Disable sense on wakeup pin
nrf_gpio_cfg_input(wakeupPin, NRF_GPIO_PIN_PULLDOWN);
}
#endif
3 changes: 3 additions & 0 deletions src/helpers/NRF52Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class NRF52Board : public mesh::MainBoard {
virtual uint8_t getStartupReason() const override { return startup_reason; }
virtual float getMCUTemperature() override;
virtual void reboot() override { NVIC_SystemReset(); }
virtual uint32_t getIRQGpio() override;
virtual bool safeToSleep() override;
virtual void sleep(uint32_t secs) override;
};

/*
Expand Down
8 changes: 0 additions & 8 deletions src/helpers/esp32/TBeamBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,6 @@
// uint32_t P_LORA_BUSY = 0; //shared, so define at run
// uint32_t P_LORA_DIO_2 = 0; //SX1276 only, so define at run

#define P_LORA_DIO_0 26
#define P_LORA_DIO_1 33
#define P_LORA_NSS 18
#define P_LORA_RESET 23
#define P_LORA_SCLK 5
#define P_LORA_MISO 19
#define P_LORA_MOSI 27

// #define PIN_GPS_RX 34
// #define PIN_GPS_TX 12

Expand Down
12 changes: 0 additions & 12 deletions variants/heltec_mesh_solar/MeshSolarBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,6 @@
#include "meshSolarApp.h"
#endif

// LoRa radio module pins for Heltec T114
#define P_LORA_DIO_1 20
#define P_LORA_NSS 24
#define P_LORA_RESET 25
#define P_LORA_BUSY 17
#define P_LORA_SCLK 19
#define P_LORA_MISO 23
#define P_LORA_MOSI 22

#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 1.8

class MeshSolarBoard : public NRF52BoardOTA {
public:
MeshSolarBoard() : NRF52BoardOTA("MESH_SOLAR_OTA") {}
Expand Down
9 changes: 9 additions & 0 deletions variants/heltec_mesh_solar/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ build_flags = ${nrf52_base.build_flags}
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
-I variants/heltec_mesh_solar
-D HELTEC_MESH_SOLAR
-D P_LORA_DIO_1=20
-D P_LORA_NSS=24
-D P_LORA_RESET=25
-D P_LORA_BUSY=17
-D P_LORA_SCLK=19
-D P_LORA_MISO=23
-D P_LORA_MOSI=22
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
Expand Down
7 changes: 4 additions & 3 deletions variants/heltec_v2/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ build_flags =
-D HELTEC_LORA_V2
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D P_LORA_DIO_1=26
-D RADIO_SX1276
-D P_LORA_DIO_0=26
-D P_LORA_DIO_1=35
-D P_LORA_NSS=18
-D P_LORA_RESET=RADIOLIB_NC
-D P_LORA_BUSY=RADIOLIB_NC
-D P_LORA_RESET=14
-D P_LORA_SCLK=5
-D P_LORA_MISO=19
-D P_LORA_MOSI=27
Expand Down
4 changes: 2 additions & 2 deletions variants/heltec_v2/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ HeltecV2Board board;

#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1);
#endif

WRAPPER_CLASS radio_driver(radio, board);
Expand Down
1 change: 1 addition & 0 deletions variants/lilygo_t3s3_sx1276/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ build_flags =
-D PIN_OLED_RESET=21
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D RADIO_SX1276
-D SX127X_CURRENT_LIMIT=120
-D SX176X_RXEN=21
-D SX176X_TXEN=10
Expand Down
7 changes: 7 additions & 0 deletions variants/lilygo_tbeam_SX1262/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_SX1262
-D TBEAM_SX1262
-D P_LORA_DIO_0=26
-D P_LORA_DIO_1=33
-D P_LORA_NSS=18
-D P_LORA_RESET=23
-D P_LORA_SCLK=5
-D P_LORA_MISO=19
-D P_LORA_MOSI=27
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
Expand Down
8 changes: 8 additions & 0 deletions variants/lilygo_tbeam_SX1276/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_SX1276
-D TBEAM_SX1276
-D P_LORA_DIO_0=26
-D P_LORA_DIO_1=33
-D P_LORA_NSS=18
-D P_LORA_RESET=23
-D P_LORA_SCLK=5
-D P_LORA_MISO=19
-D P_LORA_MOSI=27
-D SX127X_CURRENT_LIMIT=120
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D RADIO_SX1276
-D DISPLAY_CLASS=SSD1306Display
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=4
Expand Down
7 changes: 7 additions & 0 deletions variants/lilygo_tbeam_supreme_SX1262/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_supreme_SX1262
-D TBEAM_SUPREME_SX1262
-D P_LORA_DIO_0=26
-D P_LORA_DIO_1=33
-D P_LORA_NSS=18
-D P_LORA_RESET=23
-D P_LORA_SCLK=5
-D P_LORA_MISO=19
-D P_LORA_MOSI=27
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D RADIO_CLASS=CustomSX1262
Expand Down
1 change: 1 addition & 0 deletions variants/lilygo_tlora_v2_1/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ build_flags =
-D DISPLAY_CLASS=SSD1306Display
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D RADIO_SX1276
-D SX127X_CURRENT_LIMIT=120
-D LORA_TX_POWER=20
build_src_filter = ${esp32_base.build_src_filter}
Expand Down
13 changes: 0 additions & 13 deletions variants/promicro/PromicroBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,6 @@
#include <Arduino.h>
#include <helpers/NRF52Board.h>

#define P_LORA_NSS 13 //P1.13 45
#define P_LORA_DIO_1 11 //P0.10 10
#define P_LORA_RESET 10 //P0.09 9
#define P_LORA_BUSY 16 //P0.29 29
#define P_LORA_MISO 15 //P0.02 2
#define P_LORA_SCLK 12 //P1.11 43
#define P_LORA_MOSI 14 //P1.15 47
#define SX126X_POWER_EN 21 //P0.13 13
#define SX126X_RXEN 2 //P0.17
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE (1.8f)

#define PIN_VBAT_READ 17
#define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking

Expand Down
12 changes: 12 additions & 0 deletions variants/promicro/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ board = promicro_nrf52840
build_flags = ${nrf52_base.build_flags}
-I variants/promicro
-D PROMICRO
-D P_LORA_NSS=13
-D P_LORA_DIO_1=11
-D P_LORA_RESET=10
-D P_LORA_BUSY=16
-D P_LORA_MISO=15
-D P_LORA_SCLK=12
-D P_LORA_MOSI=14
-D SX126X_POWER_EN=21
-D SX126X_RXEN=2
-D SX126X_TXEN=RADIOLIB_NC
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8f
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
Expand Down
10 changes: 0 additions & 10 deletions variants/rak4631/RAK4631Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@
#include <Arduino.h>
#include <helpers/NRF52Board.h>

// LoRa radio module pins for RAK4631
#define P_LORA_DIO_1 47
#define P_LORA_NSS 42
#define P_LORA_RESET RADIOLIB_NC // 38
#define P_LORA_BUSY 46
#define P_LORA_SCLK 43
#define P_LORA_MISO 45
#define P_LORA_MOSI 44
#define SX126X_POWER_EN 37

//#define PIN_GPS_SDA 13 //GPS SDA pin (output option)
//#define PIN_GPS_SCL 14 //GPS SCL pin (output option)
//#define PIN_GPS_TX 16 //GPS TX pin
Expand Down
8 changes: 8 additions & 0 deletions variants/rak4631/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ build_flags = ${nrf52_base.build_flags}
-I variants/rak4631
-D RAK_4631
-D RAK_BOARD
-D P_LORA_DIO_1=47
-D P_LORA_NSS=42
-D P_LORA_RESET=38
-D P_LORA_BUSY=46
-D P_LORA_SCLK=43
-D P_LORA_MISO=45
-D P_LORA_MOSI=44
-D SX126X_POWER_EN=37
-D PIN_BOARD_SCL=14
-D PIN_BOARD_SDA=13
-D PIN_GPS_TX=PIN_SERIAL1_RX
Expand Down