0

I'm trying to create a battery & solar-powered ESP32 for future use with sensors. It connects to Wifi, MQTT, publishes some readings and status messages and goes back to sleep. From time to time (it can happen after a few sleep cycles and sometimes after a few hundred cycles), I get 2 unexplained behaviours: 1) fails to connect to MQTT at boot, 2) fails to sleep.

Sometimes those behaviours happen simultaneously.

Is there a known issue with deepsleep and MQTT (using PubSubClient)? Most deepsleep examples I see online, all code is outside the loop() section - is it mandatory to be like that?

I don't share code, since it is more a general question.

Guy

EDIT1

  1. most of callback was commented out, leaving only printing the incoming message.

  2. LED was attached to a GPIO, generating a blink on loop() - when sleep succeeds - it goes off, when it fails, it stays on. This test shows that when this "error" happens, code actually stop running, but does not enter deep sleep (power-wise).

5
  • skip the call to MQTT publish to see if the device still fails to sleep .... skip the call by doing a calculation such as if (a+1 == 2) {, not by commenting the line, because commenting the line would cause the compiler to generate different code ........ do the same with the sleep code
    – jsotola
    Jul 11, 2020 at 18:37
  • @jsotola just to understand - a+1 should create a logic state that wont enter the if loop to void publish ? and the other part to the esp_deep_sleep_start(); ? I dont understand why so... by the way- see edit 1/
    – guyd
    Jul 11, 2020 at 19:14
  • if you use a comment mark // to prevent the MQTT publish command from running, then the compiler will produce different code that may not have the sleep problem .... using an if statement makes sure that the compiler does not skip un-executed code ..... do the same kind of a test for the sleep code to see if it is affecting the MQTT code ...... do the tests separately
    – jsotola
    Jul 11, 2020 at 19:40
  • @jsotola - I understood the reason why to do this, I asked only for the sleep part. by the way - the publish workaround did not work, even not when I increased MQTT_MAX_PACKET_SIZE to 512 to be sure
    – guyd
    Jul 11, 2020 at 19:47
  • @jsotola for the second check ( "masking" sleep phase ) - all went as expected. In order to cause "reboots" a ESP.restart() every 30 sec was added to loop()
    – guyd
    Jul 12, 2020 at 6:19

2 Answers 2

1

Is there a known issue with deepsleep and MQTT ?

No. There may be a specific problem with the specific library you are using, but the concept of there being an issue with MQTT in general is nonsense.

Most deepsleep example I see online, all code is outside loop()section - is it mandatory to be like that ?

No, that's just being structured and tidy with your code. Whether code is in loop or in functions that are called by loop makes no difference. It can be a lot easier to manage your code if you structure it in functions rather than dumping it all in loop.

3
  • I don't know about the nonsense, but s similar question was asked in github.com/knolleary/pubsubclient/issues/634 ( same behviour, but case is still open... )
    – guyd
    Jul 11, 2020 at 16:02
  • MQTT is just a protocol. The concept of it having a problem makes no logical sense. If there is a problem that is related to using MQTT then it's a problem with pubsubclient not MQTT.
    – Majenko
    Jul 11, 2020 at 16:04
  • OK, I agree, I ment to pubsubClient
    – guyd
    Jul 11, 2020 at 16:15
2

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:
  ...

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.