From 07e7e2d44bfd68abbe87f73a853b04d76b37ddf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= Date: Sat, 22 Nov 2025 02:06:44 +0100 Subject: [PATCH 01/10] companion: Suspend radio when hibernating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should significantly reduce power consumption in hibernation. Fixes: #1014 Signed-off-by: Jaroslav Škarvada Signed-off-by: Frieder Schrempf # generalize for all radios and UIs --- examples/companion_radio/ui-new/UITask.cpp | 1 + examples/companion_radio/ui-orig/UITask.cpp | 6 ++++-- src/helpers/radiolib/CustomSX1262Wrapper.h | 3 +++ src/helpers/radiolib/RadioLibWrappers.h | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 086f82599..d8d778c33 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -650,6 +650,7 @@ void UITask::shutdown(bool restart){ _board->reboot(); } else { _display->turnOff(); + radio_driver.powerOff(); _board->powerOff(); } } diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 045c955d3..89dda1160 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -292,10 +292,12 @@ void UITask::shutdown(bool restart){ #endif // PIN_BUZZER - if (restart) + if (restart) { _board->reboot(); - else + } else { + radio_driver.powerOff(); _board->powerOff(); + } } void UITask::loop() { diff --git a/src/helpers/radiolib/CustomSX1262Wrapper.h b/src/helpers/radiolib/CustomSX1262Wrapper.h index 119f6dced..1afee5e8b 100644 --- a/src/helpers/radiolib/CustomSX1262Wrapper.h +++ b/src/helpers/radiolib/CustomSX1262Wrapper.h @@ -19,4 +19,7 @@ class CustomSX1262Wrapper : public RadioLibWrapper { int sf = ((CustomSX1262 *)_radio)->spreadingFactor; return packetScoreInt(snr, sf, packet_len); } + virtual void powerOff() override { + ((CustomSX1262 *)_radio)->sleep(false); + } }; diff --git a/src/helpers/radiolib/RadioLibWrappers.h b/src/helpers/radiolib/RadioLibWrappers.h index 25cc53589..3c26d3727 100644 --- a/src/helpers/radiolib/RadioLibWrappers.h +++ b/src/helpers/radiolib/RadioLibWrappers.h @@ -21,6 +21,7 @@ class RadioLibWrapper : public mesh::Radio { RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; } void begin() override; + virtual void powerOff() { _radio->sleep(); } int recvRaw(uint8_t* bytes, int sz) override; uint32_t getEstAirtimeFor(int len_bytes) override; bool startSendRaw(const uint8_t* bytes, int len) override; From 0f565323a092fbf13354a1d908e9564694c0f113 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 19 Nov 2025 11:40:00 +0100 Subject: [PATCH 02/10] variants: WisMesh Tag: Enable DC/DC regulator According to the documentation and experiments on other boards using NRF52 + SX1262 this reduces the power consumption significantly. This assumes that the hardware actually has the inductor for the internal DC/DC regulator populated which is very likely. Even if not, it won't hurt. Signed-off-by: Frieder Schrempf --- variants/rak_wismesh_tag/RAKWismeshTagBoard.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variants/rak_wismesh_tag/RAKWismeshTagBoard.cpp b/variants/rak_wismesh_tag/RAKWismeshTagBoard.cpp index 68ce2fd8d..28f6f713d 100644 --- a/variants/rak_wismesh_tag/RAKWismeshTagBoard.cpp +++ b/variants/rak_wismesh_tag/RAKWismeshTagBoard.cpp @@ -21,6 +21,8 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { void RAKWismeshTagBoard::begin() { // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; + NRF_POWER->DCDCEN = 1; + pinMode(PIN_VBAT_READ, INPUT); pinMode(PIN_USER_BTN, INPUT_PULLUP); From b9b82fcf1bfa57ce4978b9e3e466343dc79e156f Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Thu, 20 Nov 2025 09:09:33 +0100 Subject: [PATCH 03/10] variants: WisMesh Tag: Enable status LED Use the blue LED as status LED. This prevents the blue LED from being always-on and draining the battery. Instead use it as status LED with blink patterns as other companion devices do. Signed-off-by: Frieder Schrempf --- variants/rak_wismesh_tag/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/rak_wismesh_tag/variant.h b/variants/rak_wismesh_tag/variant.h index b0e51efc8..3b8e079f4 100644 --- a/variants/rak_wismesh_tag/variant.h +++ b/variants/rak_wismesh_tag/variant.h @@ -66,7 +66,7 @@ #define LED_BLUE (36) #define LED_GREEN (35) -//#define PIN_STATUS_LED LED_BLUE +#define PIN_STATUS_LED LED_BLUE #define LED_BUILTIN LED_GREEN #define LED_PIN LED_GREEN #define LED_STATE_ON HIGH From 11f119a7fb7f868d276d495abd7c8755db234e08 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 19 Nov 2025 12:01:07 +0100 Subject: [PATCH 04/10] variants: XIAO NRF52: Enable DC/DC regulator This reduces the power consumption by approximately 25%. Signed-off-by: Frieder Schrempf --- variants/xiao_nrf52/XiaoNrf52Board.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/xiao_nrf52/XiaoNrf52Board.cpp b/variants/xiao_nrf52/XiaoNrf52Board.cpp index 03bb674ec..a709b1c38 100644 --- a/variants/xiao_nrf52/XiaoNrf52Board.cpp +++ b/variants/xiao_nrf52/XiaoNrf52Board.cpp @@ -23,6 +23,7 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { void XiaoNrf52Board::begin() { // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; + NRF_POWER->DCDCEN = 1; pinMode(PIN_VBAT, INPUT); pinMode(VBAT_ENABLE, OUTPUT); From c76d337a00e6db7ef110e25366bd9a9b8726f5cb Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 19 Nov 2025 17:25:05 +0100 Subject: [PATCH 05/10] variants: XIAO NRF52: Enable user button The Xiao nRF52840 combined with the Wio-SX1262 is often used for cheap and compact DIY companion nodes. The Wio actually has an onboard pushbutton that can be used as user button. Enable support for the button. Signed-off-by: Frieder Schrempf --- variants/xiao_nrf52/XiaoNrf52Board.cpp | 4 ++++ variants/xiao_nrf52/platformio.ini | 7 +++++++ variants/xiao_nrf52/target.cpp | 4 ++++ variants/xiao_nrf52/target.h | 5 +++++ variants/xiao_nrf52/variant.h | 2 +- 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/variants/xiao_nrf52/XiaoNrf52Board.cpp b/variants/xiao_nrf52/XiaoNrf52Board.cpp index a709b1c38..396880abc 100644 --- a/variants/xiao_nrf52/XiaoNrf52Board.cpp +++ b/variants/xiao_nrf52/XiaoNrf52Board.cpp @@ -29,6 +29,10 @@ void XiaoNrf52Board::begin() { pinMode(VBAT_ENABLE, OUTPUT); digitalWrite(VBAT_ENABLE, HIGH); +#ifdef PIN_USER_BTN + pinMode(PIN_USER_BTN, INPUT); +#endif + #if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL); #endif diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index 888e9493b..edbf6275e 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -26,10 +26,13 @@ build_flags = ${nrf52_base.build_flags} -D SX126X_RX_BOOSTED_GAIN=1 -D PIN_WIRE_SCL=D6 -D PIN_WIRE_SDA=D7 + -D PIN_USER_BTN=PIN_BUTTON1 + -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${nrf52_base.build_src_filter} + + +<../variants/xiao_nrf52> + + debug_tool = jlink upload_protocol = nrfutil lib_deps = ${nrf52_base.lib_deps} @@ -41,6 +44,7 @@ board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld board_upload.maximum_size = 708608 build_flags = ${Xiao_nrf52.build_flags} + -I examples/companion_radio/ui-orig -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 -D BLE_PIN_CODE=123456 @@ -52,6 +56,7 @@ build_flags = build_src_filter = ${Xiao_nrf52.build_src_filter} + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-orig/*.cpp> lib_deps = ${Xiao_nrf52.lib_deps} densaugeo/base64 @ ~1.4.0 @@ -62,6 +67,7 @@ board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld board_upload.maximum_size = 708608 build_flags = ${Xiao_nrf52.build_flags} + -I examples/companion_radio/ui-orig -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 -D QSPIFLASH=1 @@ -70,6 +76,7 @@ build_flags = build_src_filter = ${Xiao_nrf52.build_src_filter} + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-orig/*.cpp> lib_deps = ${Xiao_nrf52.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/xiao_nrf52/target.cpp b/variants/xiao_nrf52/target.cpp index 41142eb66..c9c02d215 100644 --- a/variants/xiao_nrf52/target.cpp +++ b/variants/xiao_nrf52/target.cpp @@ -2,6 +2,10 @@ #include "target.h" #include +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + XiaoNrf52Board board; RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index 86f546b8a..e1ea2a6b8 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -9,6 +9,11 @@ #include #include +#ifdef DISPLAY_CLASS + #include + extern DISPLAY_CLASS display; +#endif + extern XiaoNrf52Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; diff --git a/variants/xiao_nrf52/variant.h b/variants/xiao_nrf52/variant.h index c54f3c2fa..c888a8333 100644 --- a/variants/xiao_nrf52/variant.h +++ b/variants/xiao_nrf52/variant.h @@ -38,7 +38,7 @@ extern "C" #define LED_STATE_ON (1) // State when LED is litted // Buttons -#define PIN_BUTTON1 (PINS_COUNT) +#define PIN_BUTTON1 (0) // Digital PINs static const uint8_t D0 = 0 ; From 4a8dcb4906ba4452e6fc0e99898bb5cd67d4cad3 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Wed, 19 Nov 2025 17:26:15 +0100 Subject: [PATCH 06/10] variants: XIAO NRF52: Support power-off via user button Add the necessary code to properly power-off the Xiao + Wio companions. This way we can achieve around 15 microamps of power consumption in the off state. Signed-off-by: Frieder Schrempf --- variants/xiao_nrf52/XiaoNrf52Board.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/variants/xiao_nrf52/XiaoNrf52Board.h b/variants/xiao_nrf52/XiaoNrf52Board.h index b229507ab..f37660123 100644 --- a/variants/xiao_nrf52/XiaoNrf52Board.h +++ b/variants/xiao_nrf52/XiaoNrf52Board.h @@ -46,6 +46,24 @@ class XiaoNrf52Board : public mesh::MainBoard { NVIC_SystemReset(); } + void powerOff() override { + // set led on and wait for button release before poweroff + digitalWrite(PIN_LED, LOW); +#ifdef PIN_USER_BTN + while(digitalRead(PIN_USER_BTN) == LOW); +#endif + digitalWrite(LED_GREEN, HIGH); + digitalWrite(LED_BLUE, HIGH); + digitalWrite(PIN_LED, HIGH); + +#ifdef PIN_USER_BTN + // configure button press to wake up when in powered off state + nrf_gpio_cfg_sense_input(digitalPinToInterrupt(g_ADigitalPinMap[PIN_USER_BTN]), NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW); +#endif + + sd_power_system_off(); + } + bool startOTAUpdate(const char* id, char reply[]) override; }; From 048bd268a100bb1aad4dbfaff0a5d51cff242695 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Thu, 20 Nov 2025 10:58:14 +0100 Subject: [PATCH 07/10] companion: ui: Respect LED_STATE_ON for status LED The current logic only works for active high LEDs. Some boards need an active low level control and therefore they set LED_STATE_ON to 0. Take this into account and use the correct LED pattern for both cases. Signed-off-by: Frieder Schrempf --- examples/companion_radio/ui-new/UITask.cpp | 2 +- examples/companion_radio/ui-orig/UITask.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index d8d778c33..f12667c70 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -618,7 +618,7 @@ void UITask::userLedHandler() { led_state = 0; next_led_change = cur_time + LED_CYCLE_MILLIS - last_led_increment; } - digitalWrite(PIN_STATUS_LED, led_state); + digitalWrite(PIN_STATUS_LED, led_state == LED_STATE_ON); } #endif } diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 89dda1160..1fef8572e 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -269,7 +269,7 @@ void UITask::userLedHandler() { state = 0; next_change = cur_time + LED_CYCLE_MILLIS - last_increment; } - digitalWrite(PIN_STATUS_LED, state); + digitalWrite(PIN_STATUS_LED, state == LED_STATE_ON); } #endif } From 5235516dc7033f69d285eb91a86b49fce3378636 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Thu, 20 Nov 2025 10:59:37 +0100 Subject: [PATCH 08/10] variants: XIAO NRF52: Enable status LED Fix the active state of the LEDs (active low) and enable the status LED. Signed-off-by: Frieder Schrempf --- variants/xiao_nrf52/variant.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/variants/xiao_nrf52/variant.h b/variants/xiao_nrf52/variant.h index c888a8333..3f4d7afeb 100644 --- a/variants/xiao_nrf52/variant.h +++ b/variants/xiao_nrf52/variant.h @@ -34,8 +34,9 @@ extern "C" #define LED_RED (11) #define LED_GREEN (13) #define LED_BLUE (12) +#define PIN_STATUS_LED (LED_BLUE) -#define LED_STATE_ON (1) // State when LED is litted +#define LED_STATE_ON (0) // State when LED is on // Buttons #define PIN_BUTTON1 (0) From 32d622d96964881463c9f7bbdd5b301862078da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= Date: Sat, 22 Nov 2025 02:06:44 +0100 Subject: [PATCH 09/10] variants: Heltec T114: Disable LED and GPS when powering off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should reduce power consumption in hibernation. Signed-off-by: Jaroslav Škarvada --- variants/heltec_t114/T114Board.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/variants/heltec_t114/T114Board.h b/variants/heltec_t114/T114Board.h index 49d1ec373..0f7fc47fa 100644 --- a/variants/heltec_t114/T114Board.h +++ b/variants/heltec_t114/T114Board.h @@ -48,6 +48,13 @@ class T114Board : public mesh::MainBoard { } void powerOff() override { + #ifdef LED_PIN + digitalWrite(LED_PIN, HIGH); + #endif + #if ENV_INCLUDE_GPS == 1 + pinMode(GPS_EN, OUTPUT); + digitalWrite(GPS_EN, LOW); + #endif sd_power_system_off(); } From 7723a4cb34e5a8b380e378fb2c2170975dc85efe Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sat, 22 Nov 2025 10:31:47 +0100 Subject: [PATCH 10/10] variants: Heltec T114: Enable DC/DC regulator According to the documentation and experiments on other boards using NRF52 + SX1262 this reduces the power consumption significantly. Signed-off-by: Frieder Schrempf --- variants/heltec_t114/T114Board.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/heltec_t114/T114Board.cpp b/variants/heltec_t114/T114Board.cpp index f8d170b5d..f46a1a84b 100644 --- a/variants/heltec_t114/T114Board.cpp +++ b/variants/heltec_t114/T114Board.cpp @@ -21,6 +21,7 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { void T114Board::begin() { // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; + NRF_POWER->DCDCEN = 1; pinMode(PIN_VBAT_READ, INPUT);