The problem with calling ESP.deepSleep(xx) inside loop() is that watchdog is already activated there, and then a reset occurs during the sleep state.
To fix this, I used the software's own ESP.restart() reset technique after having written a signature to a "not init" variable, as follows:
Variable area:
uint16_t SleepSign __attribute__((section(".noinit"))); // Hot reset / deep sleep signature.
Then, at the beginning of setup() we write the code that tests the content of that uninitialized variable, and if it contains the signature, ESP.deepSleep(xx) is called. In my case I use ESP.deepSleep(0) because I intend for the device to reboot only on a new boot:
void setup()
{
if (SleepSign == 0xdd11) ESP.deepSleep(0);
Rest of the initialization:
...
Inside loop():
...
if ((millis() - timeconnect) > 300*1000) {
SleepSign = 0xdd11; // deep sleep at restart
ESP.restart();
}
...
This system is tested and works correctly, reducing consumption to the minimum specified by espressif. I previously tried to block watch before exiting setup(), but it didn't work, of course:
*((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF
Obviously, if we are interested in using a timed deepSleep, and have the device do anything before going back to sleep, we can assign several values to the SleepSign variable to control the restart, also resetting its value before calling ESP.deepSleep(0):
void setup()
{
if (SleepSign == 0xdd11) {
SleepSign = 0xffff;
ESP.deepSleep(xx);
}
Rest of the initialization:
...
{ if (SleepSign == 0xdd11) { SleepSign = 0xffff; ESP.deepSleep(xx); } Rest of the initialization: ...
The only drawback I find is that the esp will perform a reset before going to sleep, but I don't think that matters much.