I have a question about the procedure doDeepSleep in sleep.cpp
If the parameter msecToWake is not equal to portMAX_DELAY, then the ESP32 should restart automatically after this timeout. Where and how is this used in the firmware without Shutdown(Forever)?
I wanted to realize a timer for shutdown after e.g. 5 minutes and wakeup after 8 minutes in firmware 2.3.6. When calling doDeepSleep(517000,false) you can see in the log that the ESP32 wants to shut down for 517 seconds, but it boots again directly with “Booted, wake cause 3 (boot count 2)reset_reason=ext1 RTC_CNTL”. I used a TLORA_2_1_1P6 device for testing.
Could it be that doDeepSleep with msecToWake has a bug here? The RTC also loses the time after the reset.
I enforce sdtS=517 seconds shutdown timer in Power.cpp by calling powerFSM.trigger(EVENT_SHUTDOWN);
—Log—
INFO | 00:51:23 641 [PowerFSM] Turning off screen
DEBUG | 00:51:23 641 [Power] Battery{PTS}: usbPower=1, isCharging=1, batMv=4401, batPct=100, cfgOBS=1891, cfgSDS=86405, cfgLS=86326, uptS=641, rtcHS=3083, sdtS=517
DEBUG | 00:51:23 641 [Power] Enter state: SHUTDOWN
INFO | 00:51:23 641 [Power] Shutting down
INFO | 00:51:23 641 [Power] Entering deep sleep for 517 seconds
INFO | 00:51:23 641 [Power] Disable bluetooth until reboot
INFO | 00:51:23 641 [Power] Saving /prefs/db.proto
INFO | 00:51:24 642 [Power] Saving /prefs/config.proto
INFO | 00:51:24 642 [Power] Saving /prefs/module.proto
INFO | 00:51:25 643 [Power] Saving /prefs/channels.proto
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13192
load:0x40080400,len:3028
entry 0x400805e4
E (71) esp_core_dump_flash: No core dump &â–’ŃĄŃĄâ–’â–’â–’found!
E (71) esp_core_dump_flash: No core dump partition found!
[ 12][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
â–’â–’@INFO | ??:??:?? 0
//\ E S H T /\ S T / C
------- 00:51 ------
INFO | ??:??:?? 0 Booted, wake cause 3 (boot count 2), reset_reason=ext1 RTC_CNTL
DEBUG | ??:??:?? 0 Disabling any holds on RTC IO pads
DEBUG | ??:??:?? 0 Filesystem files (495616/1048576 Bytes):
DEBUG | ??:??:?? 0 /prefs/channels.proto (100 Bytes)
DEBUG | ??:??:?? 0 /prefs/config.proto (92 Bytes)
DEBUG | ??:??:?? 0 /prefs/db.proto (630 Bytes)
DEBUG | ??:??:?? 0 /prefs/module.proto (106 Bytes)
DEBUG | ??:??:?? 0 /static/.gitkeep (0 Bytes)
DEBUG | ??:??:?? 0 /static/Logo_Black.svg.gz (602 Bytes)
DEBUG | ??:??:?? 0 /static/Logo_White.svg.gz (610 Bytes)
DEBUG | ??:??:?? 0 /static/apple-touch-icon.png.gz (3164 Bytes)
DEBUG | ??:??:?? 0 /static/favicon.ico.gz (2270 Bytes)
DEBUG | ??:??:?? 0 /static/icon.svg.gz (852 Bytes)
DEBUG | ??:??:?? 0 /static/index-BMhLjTmL.css.gz (16270 Bytes)
DEBUG | ??:??:?? 0 /static/index-Bt2MYVVB.js.gz (203021 Bytes)
DEBUG | ??:??:?? 0 /static/index-CGqDWSD_.js.gz (348 Bytes)
DEBUG | ??:??:?? 0 /static/index.html.gz (548 Bytes)
DEBUG | ??:??:?? 0 /static/maplibre-gl-BXZZhNda.js.gz (210451 Bytes)
DEBUG | ??:??:?? 0 /static/robots.txt.gz (42 Bytes)
DEBUG | ??:??:?? 0 /static/site.webmanifest.gz (197 Bytes)
[ 507][I][esp32-hal-i2c.c:75] i2cInit(): Initialising I2C Master: sda=21 scl=22 freq=100000
DEBUG | ??:??:?? 0 Using analog input 35 for battery level
INFO | ??:??:?? 0 ADCmod: ADC characterization based on reference voltage stored in eFuse
INFO | ??:??:?? 0 Scanning for i2c devices…
[ 535][W][Wire.cpp:301] begin(): Bus already started in Master Mode.
DEBUG | ??:??:?? 0 Scanning for i2c devices on port 1
DEBUG | ??:??:?? 0 I2C device found at address 0x3c
INFO | ??:??:?? 0 ssd1306 display found
INFO | ??:??:?? 0 ssd1306 display found
DEBUG | ??:??:?? 0 0x7 subtype probed in 2 tries
INFO | ??:??:?? 0 1 I2C devices found
DEBUG | ??:??:?? 0 acc_info = 0
INFO | ??:??:?? 0 Meshtastic hwvendor=3, swver=2.3.6
DEBUG | ??:??:?? 0 Setting random seed 2789740177
DEBUG | ??:??:?? 0 Total heap: 197780
DEBUG | ??:??:?? 0 Free heap: 163244
DEBUG | ??:??:?? 0 Total PSRAM: 0
DEBUG | ??:??:?? 0 Free PSRAM: 0
DEBUG | ??:??:?? 0 NVS: UsedEntries 70, FreeEntries 560, AllEntries 630, NameSpaces 3
DEBUG | ??:??:?? 0 Setup Preferences in Flash Storage
DEBUG | ??:??:?? 0 Number of Device Reboots: 17
DEBUG | ??:??:?? 0 OTA firmware version 0.2.1.ceca52c
INFO | ??:??:?? 0 Initializing NodeDB
INFO | ??:??:?? 0 Loading /prefs/db.proto
INFO | ??:??:?? 0 Loaded /prefs/db.proto successfully
INFO | ??:??:?? 0 Loaded saved devicestate version 22, with nodecount: 4
INFO | ??:??:?? 0 Loading /prefs/config.proto
INFO | ??:??:?? 0 Loaded /prefs/config.proto successfully
INFO | ??:??:?? 0 Loaded saved config version 22
INFO | ??:??:?? 0 Loading /prefs/module.proto
INFO | ??:??:?? 0 Loaded /prefs/module.proto successfully
INFO | ??:??:?? 0 Loaded saved moduleConfig version 22
INFO | ??:??:?? 0 Loading /prefs/channels.proto
INFO | ??:??:?? 0 Loaded /prefs/channels.proto successfully
INFO | ??:??:?? 0 Loaded saved channelFile version 22
[ 834][E][vfs_api.cpp:105] open(): /littlefs/oem/oem.proto does not exist, no permits for creation
INFO | ??:??:?? 0 File /oem/oem.proto not found
DEBUG | ??:??:?? 0 cleanupMeshDB purged 0 entries
DEBUG | ??:??:?? 0 Using nodenum 0x6d00f2f8
DEBUG | ??:??:?? 0 Number of Device Reboots: 17
DEBUG | ??:??:?? 0 Expanding short PSK #1
INFO | ??:??:?? 0 Wanted region 3, using EU_868
INFO | ??:??:?? 0 Saving /prefs/db.proto
DEBUG | ??:??:?? 1 Using GPIO12 for button
DEBUG | ??:??:?? 1 SPI.begin(SCK=5, MISO=19, MOSI=27, NSS=18)
DEBUG | ??:??:?? 1 Set Timezone to GMT0
DEBUG | ??:??:?? 1 Read RTC time as 1714438286
DEBUG | ??:??:?? 1 NeighborInfoModule is disabled
INFO | ??:??:?? 1 External Notification Module Disabled
INFO | ??:??:?? 1 Turning on screen
DEBUG | ??:??:?? 1 Module wants a UI Frame
DEBUG | ??:??:?? 1 RF95Interface(cs=18, irq=26, rst=23, busy=33)
INFO | ??:??:?? 1 Starting meshradio init…
DEBUG | ??:??:?? 1 (bw=250, sf=11, cr=4/5) packet symLen=8 ms, payloadSize=0, time 231 ms
DEBUG | ??:??:?? 1 (bw=250, sf=11, cr=4/5) packet symLen=8 ms, payloadSize=253, time 2115 ms
INFO | ??:??:?? 1 Radio freq=869.525, config.lora.frequency_offset=0.000
INFO | ??:??:?? 1 Set radio: region=EU_868, name=LongFast, config=0, ch=0, power=27
INFO | ??:??:?? 1 Radio myRegion->freqStart → myRegion->freqEnd: 869.400024 → 869.650024 (0.250000 mhz)
INFO | ??:??:?? 1 Radio myRegion->numChannels: 1 x 250.000kHz
INFO | ??:??:?? 1 Radio channel_num: 1
INFO | ??:??:?? 1 Radio frequency: 869.525024
INFO | ??:??:?? 1 Slot time: 42 msec
INFO | ??:??:?? 1 Set radio: final power level=20
INFO | ??:??:?? 1 RF95 init result -16
INFO | ??:??:?? 1 Frequency set to 869.525024
INFO | ??:??:?? 1 Bandwidth set to 250.000000
INFO | ??:??:?? 1 Power output set to 20
WARN | ??:??:?? 1 Failed to find RF95 radio
INFO | ??:??:?? 1 Not using WIFI
ERROR | ??:??:?? 1 NOTE! Recording critical error 3 at src/main.cpp:921
INFO | ??:??:?? 1 PowerFSM iniâ–’â–’M â–’power=1
DEBUG | ??:??:?? 1 Enter state: BOOT
[ 1222][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 320 / 4 = 80 Mhz, APB: 80000000 Hz
DEBUG | ??:??:?? 1 [Power] Battery{PTS}: usbPower=0, isCharging=0, batMv=3100, batPct=0, cfgOBS=1891, cfgSDS=86405, cfgLS=86326, uptS=1, rtcHS=0, sdtS=0
For your understanding: I would like to implement very low-power routers with ESP32, which always set up a mesh for 5 minutes on the hour. This reduces the power consumption to less than 100mAh per day. These routers are used for forwarding sensors, for example, which also only transmit on the hour.
My proof of concept uses the time from NTP, GPS or other nodes.
—Power.cpp mod—
// --- snippet
#include "gps/RTC.h"
uint32_t pts_shutdowntime_sec;
// ---
void Power::shutdown()
{
LOG_INFO("Shutting down\n");
#if defined(ARCH_NRF52) || defined(ARCH_ESP32)
#ifdef PIN_LED1
ledOff(PIN_LED1);
#endif
#ifdef PIN_LED2
ledOff(PIN_LED2);
#endif
#ifdef PIN_LED3
ledOff(PIN_LED3);
#endif
//>>> power timer switch
// doDeepSleep(DELAY_FOREVER, false);
if (pts_shutdowntime_sec > 0) {
doDeepSleep(pts_shutdowntime_sec*1000, false);
} else {
doDeepSleep(DELAY_FOREVER, false);
}
//<<<
#endif
}
// ---
void Power::readPowerStatus()
{
if (batteryLevel) {
// ---
// Notify any status instances that are observing us
const PowerStatus powerStatus2 = PowerStatus(
hasBattery ? OptTrue : OptFalse, batteryLevel->isVbusIn() || NRF_USB == OptTrue ? OptTrue : OptFalse,
batteryLevel->isCharging() || NRF_USB == OptTrue ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
//>>> power timer switch
// LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
// powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
//
// --- magic values to setup power timer switch ---
// config.power.on_battery_shutdown_after_secs = 1791 # timer switch enabled (cfg % 10 == 1 enabled >= 90% on)
// config.power.sds_secs = 86405 # 5min per hour (cfg % 100 == 5)
// config.power.ls_secs = 86326 # 15min=5+2x5 every 6hour (cfg % 100 - % 10)
// config
uint8_t pts_cfg_mode = (config.power.on_battery_shutdown_after_secs % 10); // power timer switch mode
bool pts_cfg_enabled = (pts_cfg_mode >= 1); // power timer switch enabled
uint8_t pts_cfg_alwayson_pct = (config.power.on_battery_shutdown_after_secs % 100) - pts_cfg_mode; // percentage
uint32_t pts_cfg_short_uptimer_sec = (config.power.sds_secs % 100) * 60; // uptime short and long
uint8_t pts_cfg_long_interval = (config.power.ls_secs % 10); // interval hours for long uptime
uint8_t pts_cfg_long_multipier = ((config.power.ls_secs % 100)-pts_cfg_long_interval)/10; // multiplier
uint32_t pts_cfg_long_uptimer_sec = pts_cfg_short_uptimer_sec + pts_cfg_short_uptimer_sec * pts_cfg_long_multipier;
// time
uint32_t pts_dev_uptime_sec = millis()/1000; // time since lastest restart
bool pts_rtc_exists = (getRTCQuality() >= 2); // real time (2:other node, 3:ntp, 4:gps)
uint32_t pts_rtc_sec = getValidTime(RTCQuality::RTCQualityDevice); // seconds since 1970..2036
uint32_t pts_rtc_sec_day = (pts_rtc_sec % SEC_PER_DAY); // seconds since midnight
uint32_t pts_rtc_sec_hour = (pts_rtc_sec_day % SEC_PER_HOUR); // seconds since hour
uint32_t pts_rtc_hour = (pts_rtc_sec_day / SEC_PER_HOUR); // current hour
// timer switch
pts_shutdowntime_sec = 0; // shutdown if needed
if (pts_cfg_enabled) { // power timer switch enabled
if (pts_rtc_exists) { // real time clock exists
if ((pts_rtc_hour % pts_cfg_long_interval) == 0) { // long intervals
if (pts_rtc_sec_hour > pts_cfg_long_uptimer_sec ) { // timeout after long-uptime
pts_shutdowntime_sec = SEC_PER_HOUR - pts_rtc_sec_hour; // restart next hour
}
} else { // long intervals
if (pts_rtc_sec_hour > pts_cfg_short_uptimer_sec ) { // timeout after short-uptime
pts_shutdowntime_sec = SEC_PER_HOUR - pts_rtc_sec_hour; // restart next hour
}
}
} else {
if (pts_dev_uptime_sec > pts_cfg_short_uptimer_sec ) { // timeout after short-uptime
pts_shutdowntime_sec = SEC_PER_HOUR - pts_dev_uptime_sec; // restart next hour
}
}
if (powerStatus2.getBatteryChargePercent() > pts_cfg_alwayson_pct){ // fully charged
if (powerStatus2.getHasUSB() == false) { // not usb powered
pts_shutdowntime_sec = 0; // don't shutdown
}
}
}
// DEBUG | ??:??:?? 161 [Power] Battery{PTS}: usbPower=1, isCharging=1, batMv=4650, batPct=100, cfgOBS=1891, cfgSDS=86405, cfgLS=86326, uptS=161, rtcHS=0, telS=0, sdtS=0
// DEBUG | 00:09:06 241 [Power] Battery{PTS}: usbPower=1, isCharging=1, batMv=4606, batPct=100, cfgOBS=1891, cfgSDS=86405, cfgLS=86326, uptS=241, rtcHS=546, telS=0, sdtS=0
LOG_DEBUG("Battery{PTS}: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d, cfgOBS=%d, cfgSDS=%d, cfgLS=%d, uptS=%d, rtcHS=%d, sdtS=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent(),
config.power.on_battery_shutdown_after_secs, config.power.sds_secs, config.power.ls_secs,
pts_dev_uptime_sec, pts_rtc_sec_hour, pts_shutdowntime_sec) ;
if (pts_shutdowntime_sec > 0) { // timeout
powerFSM.trigger(EVENT_SHUTDOWN); // shutdown
}
//<<<
newStatus.notifyObservers(&powerStatus2);
// ---
}