Very DeepSleep and energy saving on ESP8266 – Part 1: Basics

Intro: For the seasoned ESP user I might be over explaining things here, but apparently some people struggle with basic things around deepsleep, hence my perhaps somewhat overly long explanation.

For battery fed projects, low energy consumption is a must.
The ESP8266 can help with that, using DeepSleep.

Earlier I published a rather simple DeepSleep program, combined with MQTT, but from an energy conserving point of view  there are more things in setting up DeepSleep that can make a difference. There are also couple of other things to take into consideration.

The ideas here are not new. I have gotten some inspiration from Erik Bakke’s OppoverBakke site, even though there was a mistake in his code snippets.

I will just describe what I did to bring my ESP8266 to minimal energy consumption.

1. Pick the proper ESP8266 board.
You want your ESP board as lean as possible. No other power hungry other components such as FTDI chip or LEDs. This basically excludes most modules such as Wemos D1 mini or NodeMCU and only leaves the bare chips such as ESP-03, ESP-04 and ESP12 on a carrier board. The ESP12 is the easiest though as the ESP-03 and ESP-04 for instance do not have the GPIO16 or RST pin broken out to a side connector, but to a pad on the PCB. The ESP M2 and ESP M3 can be used too as they have gpio16 broken out
The ESP8266-01 would be perfect after you remove the LED, but it does not have the DO/GPIO16 pin broken out. If you have young eyes and a steady hand you can try to solder a wire on the GPIO16 pin.

2. Pick the right voltage regulator.
If you are using 2×1.5V AA cells (unlikely) or LiFePO4 battery (3.6V) you could get by without a regulator, but if for instance you are using 3×1.2V NiCd-s or a 3.7V Lipo (that can go up as high as 4.2Volt), you are going to need a regulator. You dont want a regulator that needs a big input voltage in order to maintain 3.3Volt, so you will need a Low drop regulator, a so called ‘LDO’
Possible candidates are:

Type Quiescent current Drop Voltage Max Input Voltage Max Output Package
Torex XC6206 1μA ‎ 160mV@100mA 6Volt 200mA SOT23-3, SOT89,USP-6B
Torex XC6204 70μA* ‎ 200mV@100mA 10Volt 300mA** SOT23-3, SOT89,USP-6B
Analog Devices LTC3525-3.3 7μA ‎ Step up converter ‎ 6Volt ‎ 60mA at 3.3V from a 1V Input, or 140mA at 3.3V from a 1.8V Input‎  
Holtek HT7333 4μA 90mV@40mA 12V 250mA SOT89,TO92
Holtek HT7833 4μA 360mV@500mA 8.5V 500mA SOT89,TO92
ME6211 40μA* 100mV@100mA 6.5V 300-500mA SOT23, SOT89
SPX3819M5 90μA* 340mV@full load 16V 800mA SOT23-5, SOIC8, DFN8
Microchip MCP1700 1.6μA 178 mV@ 250 mA 6V 250mA SOT23, SOT89, TO92
Microchip MCP1825 120μA 210mV@ 500 mA 6V 500mA SOT23, SOT89, TO92
Microchip MCP1826 0.1-220μA 250mV@ 1000 mA 6.5V 1000mA SOT23, SOT89, TO92
LT-1763 30μA 300mV 20V 500mA S8
TPS783xx 500nA 130-175mV 6V 150mA SOT5
TLF80511TFV33 38μA 100mV@100mA 45V 400mA PG-TO252-3
MCP1825S33 0.1μA 210mV@500mA 6V 500mA SOT223-5, DDPAK-5. TO220-5
TC1262-3v3AB 70-130μA 650mV@500mA 6V 500mA TO220-5
LM2937IMPX-3.3/NOPB 2mA 600mV 26(60 peak) 500ma To220,DPAK,SOT223

*) The SPX3819 also has an enable pin that needs to be pulled HIGH for it to work. In standby mode  its current draw is practically zero. Ditto for the ME6211 A &H types, these have a standby current of 0.1μA. Ditto for the XC6204, that has a standby current of 0.1μA. This will be used in a yet to appear chapter 7 in this series.
**) only the E-H types. Otherwise 150mA

The problem here is that many of the LDO’s that have a very low quiescent current, also have an output current that is on the edge of what the ESP8266 needs at startup.

The MCP1700 as well as the HT7333 are often advised,but they are really at the verge of what an ESP8266 needs in current using WiFi. If the 90mV drop of the HT7333 is important for your project then consider adding a beefy capacitor.

In all honesty I would advise AGAINST using any regulator giving less than 300mA.

Apparently it is possible to use two HT7333 chips in parallel. The HT7833 seems a pretty good choice. It typically needs a 1uF elco on the input and a 2.2uF elco on the output to be stable. A higher value is ofcourse a good idea.

The ME6211 is often used on the Wemos D1 mini board (which does not mean it is the best choice for low-drop/low Iq). Same goes for the SPX3819M5 on the Lolin NodeMCU.

The LM2937IMPX is a bit of a questionable advice as it has  a rather high quiescent current and relatively large voltage drop, but it  can handle fairly high input  voltage….for the rare case that would be needed in a Low Power setup, but for that very rare situation, i am going to leave it there.

3. Pick the right internet connection
Often we pick a DHCP connection by default. A DHCP connection usually  takes longer to establish than a static IP connection. It is therefore best to chose for the latter. With the ESP it is simply a matter of providing the following details (mind you, the IPnrs are just an example)

//We will use static ip
IPAddress ip(192, 168, 1, 35);// 
IPAddress dns(192.168.1.1);
IPAddress gateway(192, 168, 1, 1); //
IPAddress subnet(255, 255, 255, 0); // this one is pretty standard

and then make the connection with

WiFi.config( ip, dns, gateway, subnet );
WiFi.begin( WLAN_SSID, WLAN_PASSWD );

That is not the only thing we can do making the connection. We can try circumvent some oddities that the ESP8266 shows in connecting to the WiFi network:

the ESP8266 persists the network connection information to flash, and then reads it back when it next starts the WiFi function. It does this every time, and it takes at least 1.2 seconds (source Erik Bakke).

The chip does this even when you pass connection information to WiFi.begin(), like:

WiFi.begin( WLAN_SSID, WLAN_PASSWD );

This will actually load the connection information from flash, ignore it and use the values you specify instead, connect to the WiFi and then finally write your values back to flash.

We can disable that with the command WiFi.persistent( false )

There is more we can do to save time though. The Wifi.begin(SSID,PASSWORD) command does a scan for the proper network amongst the ones advertised. It is possible to supply a WiFi channel number and a BSSID to the WiFi.begin() command that takes away the need for a scan.
The ESP does not know the channel number or BSSID, so we need to read that info from the first connection, store it, and submit it at the next connection.
For that we need to replace the Wifi.begin(); statement with a piece of code that retrieves and manages the necessary information.
Fortunately there is such code available, and as I saw it in various places, I would not know  who to credit for it.
We begin with defining a structure:

A structure aka. struct is a way to group variables together, possibly of different types. One can have several instances of a declared structure. The variables within a structure are called members.

We define the following structure:

struct {
  uint32_t crc32;   // 4 bytes
  uint8_t channel;  // 1 byte,   5 in total
  uint8_t ap_mac[6];// 6 bytes, 11 in total
  uint8_t padding;  // 1 byte,  12 in total
} rtcData;

We use a CRC checksum to see if the data we use perhaps got corrupted. We use 1 bte for the channel and 6 bytes for the Accespoint information.
We add one superfluous byte to come to a multiple of 4. (here is more about storing data in rtc memory).

Then on connecting we make a few checks:

        1. is the CRC data correct? If not, make a normal connection.
        2. if after 100 tries it is not working, we reset the WiFi and go make a normal connection
        3. If  after 600 tries still no connection, we put the ESP8266 to sleep and will try later again.

We do need a routine to do the CRC-check, but that’s easily done.
Once we made the WiFi connection, we can connect to where we need to go: an MQTT broker or make an HTTP request for instance.

4. Make sure you do not connect to WiFi before you have to.
Making the connection at the right moment is important though. You do not want to waste energy on your 2.4 GHz signal when you are still reading sensors. As it is, the ESP8266   already has its radio on by default.
So the first thing we need to do upon wake up, is to switch off the radio.
We do that like this:

void setup() {   // disable WiFi, coming from DeepSleep, as we do not need it right away
  WiFi.mode( WIFI_OFF );
  WiFi.forceSleepBegin();
  delay( 1 );

Only once we have done that, we let the program do what it must, like reading sensors, and only then do we start thinking about making the  WiFi connection. Ofcourse we first need to switch the modem/radio on and we do that with:

//Switch Radio back On
WiFi.forceSleepWake();
delay( 1 );

That brings us almost to the end of what we need to do, software wise:
We Switch off the radio, read the sensors, switch on the radio, try make a quick connection and if necessary a regular connection, we then connected to where we want to go (Thingspeak,  MQTTbroker, whatever)and then it is finally time to put the ESP8266 into DeepSleep.

5.Putting the ESP8266 into deepsleep
The simplest form of a DeepSleep program is to do the stuff you need to do  (read yr sensors,make connections) and then call:
ESP.deepSleep(SLEEPTIME)
There is however more that we can do. remember that I said that on wake up the radio is on by default? Well we can give the ESP8266 a wake up instruction so it knows what to do when waking up. We can already tell the ESP8266 that it should NOT switch on the radio by default. We do this with:

ESP.deepSleep(SLEEPTIME, WAKE_RF_DISABLED);

I know that in an earlier step we started with switching the radio off and strictly speaking that step would no longer be necessary once we use the wake up instruction, but I left it in anyway, just to make sure/for illustration. You could opt to leave it out though.
Truthfully there is a bit more superfluous code. e.g. it is not really necessary to switch off the WiFi immediately before DeepSleep.

Only one thing remains now: How long will we put the ESP8266 to sleep?

That ofcourse is a very personal decision, but lets see how long we CAN put the ESP to sleep.

The max deepsleep USED to be max 71 minutes. That was simply because the system_deep_sleep parameter was defined as an unsigned 32 bit integer. The max value of a 32bit unsigned integer is 0xFFFFFFFF, that is 71 min in usecs.
Since the 2.4.1 core, it is a 64 byte unsigned integer. That comes to 18446744073709551615 us or 5,124,095,576 hrs or about half a million year. Nobody wants to wait that long, so expressif seem to have capped that to about 3.5 hrs

This capped number is defined in the ESP.deepSleep(Max) parameter. So when I defined my deepsleep call as ESP.deepSleep(ESP.deepSleepMax(),WAKE_RF_DISABLED );, my ESP went to sleep for 3hrs and 9 min. I noticed though that this cycle tended to get shorter over time. Also if you define a specific period, e.g. 1 hour, with 3.6e9 (=3.6×109) then you will find that that might not be exactly an hour. in my case it was about 58 min.

Testing on a Wemos D1 mini. Connect RST pin with a jumper tp pin D0, as shown here

You will find a DeepSleep program as described above, here. The only thing you need to add other than your web credentials is some code to read your sensors and some code to send your data to where you want to store it (e.g. Thingspeak or yr own webserver, or a broker). I will be adding such code in several follow up articles.
Upload the code and AFTER your upload, connect D0/gpio16 to the RST pin.

6. Think about your sensors
Your sensors use power as well, even when your ESP8266 is sleeping. Perhaps there is a sensor that does the same as another sensor, but uses less power. Consider feeding yr sensors from a gpio pin that you switch LOW when the sensor is not used. Keep in mind that some sensors need a warm up or settling time.  If you do that, ALWAYS make sure your sensor does not draw more than an ESP8266 pin can deliver (12mA), but chances are that if it does, it isn’t one that you should feed from a battery anyway. If you really have to or want to, you can opt for a FET to switch on the sensor. A very popular ‘sensor’ in battery fed projects is measuring the battery voltage. As the ADC of the ESP8266 only goes up to 1 Volt, some form of resistor voltage divider is necessary. This means a constant drain on the battery, so it is best to chose high values for the divider. If you use a 420k divider, you would be constantly draining 10uA on a full battery. That may not seem much, but it is also what your entire ESP8266 uses in deepsleep. If you are using a pFET for HighSide switching of a voltage divider measuring your battery you will encounter the problem that a full LiPo battery may carry 4.2Volt. It will be nearly impossible to close the pFET with only 3.3V on its Gate. Johan Westlund found a solution for that.

If you are not using a power regulator, for instance when you are using 2×1.5Volt batteries, then it is better to use the internal measurement of the Vcc. Do that with:

ADC_MODE(ADC_VCC);
float vccVolt = ESP.getVcc()/1024.0F;

Another possibility is to switch off the voltage divider with a p-FET.The idea is to only put current to the voltage divider when it is needed. We can do that with a circuit like this:
batterijmeten

Through a “HIGH” on the input of the circuit, the BC547 will conduct and pull the gate of the p-FET down. The P-FET will open and allow  voltage to be on the voltage divider. After the measurement, the input should be pulled “LOW” which will block any current to go through the voltage divider. As it is, the  (3.3-0.6)/1000=2.4mA, ONLY when the pin is pulled HIGH. It is possible to increase the  base resistor: the current going through the collector will be roughly 3.3/10.000=33uA. with an hFE of roughly 100, the current through the base would only need to be 0.33uA, so most likely a 68k base resistor would still be OK. The FET needs to be a type with a low RDSon and a Vgs of around -2-3 Volt (remember the Vgs(th) is when the Fet starts to conduct, still not up to full power). The values chosen for the resistors are pretty ‘safe’. Yet they also will consume power. It is  possible to use a higher value. Make the 10k a 100k and you could make the 1k even a 1Mohm, provided the transistor has a decent hFE. The downside of using a 100k gate resistor is that the switch off time takes a bit longer (think ms). A suitable P-FET might be the NDX2301, that is a surface mount though. It has a Vgs  of 1.8 Volt. It will not even need the transistor driver in front of it.
nx2301

Another possibility is to give the sensors their own voltage regulator, that can be switched off by the ESP8266. The SPX3819 is a suitable one. Connect a GPIO pin to the ENABLE pin of the regulator.  A HIGH (<= 0.25V) will switch it on, a LOW will switch it off. Make sure that the voltage regulator has a lower quiescent current than the peripherals you are switching with it (the SPX3819  has a quiescent current of 90uA, max 16V input, a voltage drop of 340mV and a max current of 800mA). Something similar can be done with the ME6211 (40uA quiescent current).

spx3819

High-side switching can also be obtained by a PNP transistor, like so:

highside-b

According to some older expressif documentation the status of the gpio pins is maintained in DeepSleep but can only drive 2uA. It is a bit unclear though in the updated version, saying the state of the pins on DeepSleep is no longer defined (table 1-1), though it seems to then contradict itself (page 5/9).
When I measured myself. I always found the same status of my pins during deepsleep, regardless whether they were HIGH or LOW before deepsleep. Status was as follows:

  • D0 0V
  • D1 0V
  • D2 0V
  • D3 1V68
  • D4 3v3
  • D5 3v3
  • D6 3v3
  • D7 3v3
  • D8 3v3

Ofcourse from some pins this is to be expected (D0,D3,D4) but I had expected D8 (GPIO15) to be LOW.

The results teach us though that if you want to feed a sensor with HighSide switching through a a p-FET or PNP transistor, you’d better use pins D4-D7 to close it during deepsleep.

Some sensors –like the BME280– can be programmed to go to sleep in between measurements. For the BME280 this is the ‘Forced Mode’ if you then have a 1/min reading (Bosch calls this the ‘weather monitoring state’) the power consumption is 0.16uA. Using forced mode is also a good way to prevent/limit internal warming up of the chip, which would give skewed readings.

An ADC like the PCF8591 has a relatively low current use in ‘standbye’ as Vin equal to Vss or Vdd, which is not well possible in situ. (Chapter 14.1, Table 8).

The ubiquitous DHT11 has an operating current: 0.3mA (measuring) and 60uA (standby), as 60uA is still rather high, cutting off the power would be better. In that case however the DHT11 needs a 1 sec warming up period. The HTU21D is a better choice with a 0.14uA sleep current.

7. Do you need to send your values?
Rather than sending every measurement when made, you could opt to store results in RTC/SPIFFS memory and only send them say once a day,  or you could decide that if a new measurement result is say within 5% of the previous reading, there is no need to send it. If you are weary of RAM wear, you could add some FRAM, e.g. the MB85RS64V (8k, Operating current 1.5 mA. Standby current 10 μA) or MB85RC256V (32K, Operating current 200μA. Standby current 27uA) (library). (The 8k uses SPI, the 32k uses I2C).

8. Choose your batteries wisely
Once you get to uA levels, self discharge of the batteries becomes an important competing factor.
Nick Gammon states the following self discharge for a number of batteries:

Type Capacity mAH Discharge %/month Self discharge (uA)
CR1212 (3V) 18 1 0.250
CR1620 (3V) 68 1 0.950
CR2032 (3V) 210 1 3
NiCD AAA (1.2V) 350 20 98
NiMH AAA (1.2V) 900 30 375
NiCd AA (1.2V) 1000 20 270
Alkaline AAA (1.5V) 1250 2 35
NiMH AA (1.2V) 2400 30 1000
Alkaline AA (1.5V) 2890 2 80
Li-Ion (3.7V) 4400 10 600

The LiFePO4 (Lithium Iron Phosphate) is worth considering as it’s max voltage is 3.6Volt and it’s nominal voltage 3.2Volt with a very flat discharge curve. One could opt to use these without a voltage regulator.

TIt is also possible to use a Lithium Thionyl Chloride battery without a voltage regulator. These batteries give 3.6 Volt…which is really at the top spec for  the ESP8266. These non-rechargeable batteries generally have a very long life, with about 1% self-discharge per year. Keep in mind that in cold temperatures their internal resistance will increase  significantly, so they need to be buffered when used in cold temperatures or your ESP8266 may crash when it needs power to connect to WiFi. You cannot do this with say 3×1.2 NiCd cells in series, as they may  be well over 1.2 volt when fully charged and you could end up feeding 4,35 Volts to your ESP8266, which it really does not like. You could use a Lithium Thionyl Chloride battery with a voltage regulator, just to be safe, as long as you pick one with a voltage drop of less than 300mV

Further reduction of Power
The Expressif documentation mentions 8 further ways to reduce power (chapter 4.5) that I have not tried myself and to be honest I have seen some back and forth on the various fora about it not working, about it being fixed and about it still not working.

Connecting D0/GPIO16 to RST
In order for the wake up pulse to work, D0 needs to be connected to RST. The drawback of that is that you need to remove that link when you want to reflash the ESP8266. some people advise connecting the pins via a resistor. That has mixed results though. A better way is to use a Skottky diode -e.g a 1N5819– with the cathode to pin gpio16/D0 and the anode to the RST pin.

In a follow up article, I will publish some code that uses this deepsleep framework to read a sensor and send it to a database.

Part 1 -DeepSleep General
Part 2 -DeepSleep HTTP publishing
Part 3 -DeepSleep MQTT Publishing
Part 4 -DeepSleep MQTT Subscribing
Part 5 -Deepsleep ESP-NOW
Part 6 – Power Down

41 thoughts on “Very DeepSleep and energy saving on ESP8266 – Part 1: Basics”

  1. I have issues with compiling the sketch you provided, errors like (error: ‘calculateCRC32’ was not declared in this scope) with platformIO. Which libraries should I use for mqtt, crc32.

    1. The code in this article only uses the library. ESP8266WiFi
      That comes with the esp8266 core and does not need separate install when using arduino IDE. I do not know platformIO well enough to know how it works there.
      The error you get though doesnt point to a library issue but looks like perhaps there is a misdeclaration coz of typo or something check yr lines 121-139

  2. Pingback: Wemos | Pearltrees
  3. First, I have to say that your 5 parts series of article is by far the best I found about this topic (sensors, MQTT and deepsleep).

    Despite using fix ip/gateway/dns/mask, my wifi connection still seems to take a rough 3.8 seconds to establish itself. In your articles you stated several time to first read data, then establish wifi connection to send the readings.
    I was wondering, have you ever tried establishing wifi asynchronously (Like presented in the article from ramdomnerd – https://randomnerdtutorials.com/esp8266-nodemcu-mqtt-publish-bme680-arduino/) in order to read (and warm up) the sensors while the wifi connection is establishing itself ? This way we should have sensors data available right when the wifi is ready to send them.

    Do you have any opinion about this solution ?

    1. Christophe tnx for your kind words. My experience with asynchronous connections is mainly with setting op a webserver. I know the article you are referring to and tbh i did not really see the advantage of the asynchronous connection in that case.
      The reason i read data first is because setting op the wifi connection takes most energy thus you want that to be as brief as possible but ofcourse one can do it after the wifi connection has been established. 3.8 secs still seems a bit long though. Not sure anymore how long my connection took but i think it was shorter. What sensors are you using?

      1. I thought asynchronous connections could be used to do some reading of sensors while the WiFi was establishing itself. But I found an easier solution giving me the same result. I am now reading my sensors between WiFi.begin() and WiFi.status() == WL_CONNECTED as you can see below:

        WiFi.begin(ssid, password, ap_channel, ap_mac, true);

        // Read sensors
        int moisture = read_moisture();
        float voltage = read_voltage();

        // Wait to be connected
        while (WiFi.status() != WL_CONNECTED) {
        delay(50);
        }
        connecting_time = millis() – connecting_time;

        I found out that this has no influence on my connecting time. I found out as well that I can read one more sensor before WiFi.status() is returning WL_CONNECTED. This does not reduce the amount of time I am connected to WiFi but I reduce the amount of time the ESP is ON all together. It just spend less time in the while loop.

        My connecting time is 1054 ms. And sensors reading is around 200 ms. If I read the sensors before, the full time ON is 1054ms + 200ms (for this part of the program, I don’t include MQTT publishing, etc..), but the way I am doing now, it takes only 1054ms including the reading. So I am glad with the solution.

        When I started, the connecting time was 5376 ms. Then I applied your first trick of using static IP, gateway, DNS and mask and it sent down to 3819 ms. Then I applied your next trick of using router mac address and channel and I went down to 1054ms. So thanks to you my project will last much longer on the same battery. One note though, when the channel changes, it then takes more than 18 seconds to detect that it needs to do a WiFi.begin() without the channel information. This seriously kills to gains. So I removed the auto-channel on my router to avoid this issue.

        I was thinking as well that asynchronous connection could sort out the delay after the MQTT publish. Right now I have a delay(200) after my publish to give time to the ESP to send my message before it switches off. If I put a too short delay I never get the message on the receiving end. It I put a too long one, I waste time and energy. So I was thinking using onMqttPublish to know when the message is safely sent. In my opinion, this would be more clean than trying to guess a delay (which perhaps can vary based on MQTT server load for example) like I am doing now.

        Regarding the sensors, for now, I am just doing two analog readings. 1 – humidity sensor, 2 – battery voltage through a voltage divider.

        Next step is to implement your smart BJT/MOSFET cut off for the divider. Could you please tell me what you mean by “low Rdson” ? I mean what is “low” for you? 😉 I have selected the NDP6020P or the FQP47P06 for now (I still need to order them). Do you have a better suggestion ?

        Thanks again for your excellent series or article on this topic.

      2. I am happy it helped you.
        A ‘low’ RDSon is a bit relative. If you only use it to switch on a sensor that has a mA consumption then i would say anything <0.1 ohm would be fine. I think the FQP should be fine. Thank you for your kind words

  4. Hi!
    Your article was very helpful for me. I wish I have found it earlier 😀 It has crucial information for me – concerning the lack of ESP-01 GPIO and a good table to compare LDOs.
    I just want to mention one thing. So far I couldn’t make WiFi work after deep sleep if it was called with “WAKE_RF_DISABLED”.
    More on issue:https://github.com/esp8266/Arduino/issues/3072

      1. He proposed to do special deep sleep with RF_DEFAULT? I didn’t try this – it seems strange and inconvenient.
        I tried ForceSleepBegin/ForceSleepWake after waking from RF_DISABLED. It works, but must be applied right at the beginning of the sketch. It is inconvenient too 🙂 I need time to ponder – whether I want to switch WiFi on or not 😀
        For now I use your first method – switching off wifi at the beginning of the sketch and switching it on back again if it is needed. I don’t know how much I lose in mAh but I’m trying to do a water leakage sensor and want to keep its code as simple as possible.
        One more thing – I have rather stable but different ADC readings when I use RF_DISABLED and RF_DEFAULT with wifi “manually” switched off. I use ADC to measure battery’s voltage.
        I use one Li-ion battery to power NodeMCU so I do not have a “proper” power supply, but my multimeter doesn’t see significant voltage drops. In my setup ADC gives 930 points when RF_DISABLED and 860 points in manual mode.
        It is about 350mV difference near 4150mV.
        At first I thought that battery had been discharged so fast (85% -> 45% drop) with RF_DEFAULT.

      2. Tnx for your feedback. To be honest the ‘solution’ presented there remained a it vague.
        The ADC issue you describe seems not unknown. Check the comments of ‘amrisayed’ in this link https://github.com/esp8266/Arduino/issues/1660 perhaps that provides a solution for you. Would love to hear if it does

  5. Thanks for the project, very informative. Please tell me where to enter the channel and MAC address?

    1. Sergey,sorry for the confusion: you do not need to enter the channel and ap_mac. What happens is that when you first make a WiFi connection, the program checks if the stored rtcdata is valid (line 55). On first connection it isn’t valid (line 59), so a regular connection is made (line 61). Subsequently (line 98) the program retrieves the necessary acces point data (including the channel and ap_mac (the latter also known as BSSID)) from the existing connection info, and stores that in the rtcdata structure. On the next time (after sleep) a connection is made, the program again checks the rtcdata structure (line 55) and now finds it valid (as the program stored it the previous time) and a faster connection is made (line 57).

      If forwhatever reason (bad connection) no wifi connection can be made (line 80), after checking 600 times, the program goes back to sleep
      Hope that is clear
      https://gitlab.com/diy_bloke/verydeepsleep/blob/master/VeryDeepSleep.ino

  6. Thanks for the clarification! I have a server with username and password. Did I change the line from
    //if (client.connect(ClientId.c_str()))
    //if your MQTT server is protected with a password, use the next line instead of the revious
    //if (client.connect(ClientId.c_str()),mqtt_user,mqtt_password))
    of
    //if (client.connect(ClientId.c_str()))
    // if your MQTT server is protected with a password, use the next line instead of the revious
    if (client.connect(ClientId.c_str(),”***”, “***”))
    correctly?

  7. Thanks a lot for the clarification. Everything worked! I’m trying to convert DShT to DS, so far it doesn’t work. Could you help me?

  8. I figured out the ds, please check if I did everything right?
    //——–DS18B20——
    float temp=0;
    #include
    #include
    #define ONE_WIRE_BUS 2 // This is the ESP8266 pin to which the sensors are connected
    #define PIN_POWER_DS 0
    OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with DS18B20
    DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature
    ——————————
    void setup() {
    sensors.begin(); // My changes.
    Serial.begin(115200);
    ——————————-
    pinMode (PIN_POWER_DS, OUTPUT); // My changes.
    digitalWrite(PIN_POWER_DS, HIGH); // My changes.
    // Try to read WiFi settings from RTC memory
    bool rtcValid = false;
    ——————————–
    void sendMQTTmessage()
    {
    if (!client.connected()) {
    reconnect();
    }
    sensors.requestTemperatures(); // My changes.
    client.publish(“home/sleep/tele/batt”, String(batt / 1023.0F).c_str(), false);
    client.publish(“home/sleep/tele/temp”, String(sensors.getTempCByIndex(0)).c_str(),false); // My changes.
    sensor when wifi off
    digitalWrite(PIN_POWER_DS, LOW); // Turn off the power to the sensor
    /* Close MQTT client cleanly */
    client.disconnect();
    ———————————
    //if (client.connect(ClientId.c_str()))
    // if your MQTT server is protected with a password, use the next line instead of the revious
    if (client.connect(ClientId.c_str(),”sss”, “1234”))

    1. Sergey, the DS18B20 part seems ok, but as i am not sure what you exactly want the program to do it is hard for me to check if it does everything you want. You seem to have removed all deepsleep info but still do a check on the rtc memory. Also you devoting a pin to feed the ds18b20 suggests you want the device to go to sleep, but you using print statements suggests it will remain attached to a cable

  9. I cited only those places where I corrected the code under DS. Here is the complete code.
    /*************************************************
    Template for static IP,MQTT &DeepSleep
    Read out a DHT11
    https://arduinodiy.wordpress.com/2020/01/23/very-deep-sleep-part-3-mqtt/
    *************************************************/
    long SLEEPTIME = 300e6; //5min
    const char* WLAN_SSID = “TP-Link_Mobil”;
    const char* WLAN_PASSWD = “*******”;

    #include
    #include “PubSubClient.h”

    // We make a structure to store connection information
    // The ESP8266 RTC memory is arranged into blocks of 4 bytes. The access methods read and write 4 bytes at a time,
    // so the RTC data structure should be padded to a 4-byte multiple.
    struct {
    uint32_t crc32; // 4 bytes
    uint8_t channel; // 1 byte, 5 in total
    uint8_t ap_mac[6];// 6 bytes, 11 in total
    uint8_t padding; // 1 byte, 12 in total
    } rtcData;

    IPAddress ip(192, 168, 1, 80); // pick your own IP outside the DHCP range of your router
    IPAddress gateway(192, 168, 1, 1); //watch out, these are comma’s not dots
    IPAddress subnet(255, 255, 255, 0);
    IPAddress dns(192, 168, 1, 1);
    #define chanal 2 //канал wifi
    byte macAP[6] = {0xE4, 0xC3, 0x2A, 0x6C, 0xAB, 0x5A}; //mac
    //———voor pubsub
    WiFiClient espClient;
    PubSubClient client(espClient);
    //———Other——
    String naam = (__FILE__); // filenaam
    unsigned int batt;
    ADC_MODE(ADC_VCC); // vcc uitlezen.
    //——–DS18B20——
    float temp=0;
    #include
    #include
    #define ONE_WIRE_BUS 2 // This is the ESP8266 pin to which the sensors are connected
    #define PIN_POWER_DS 0
    OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with DS18B20
    DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature

    void setup() {
    sensors.begin();
    Serial.begin(115200);
    // we disable WiFi, coming from DeepSleep, as we do not need it right away
    WiFi.mode( WIFI_OFF );
    WiFi.forceSleepBegin();
    delay( 1 );
    Serial.println(“wifi uit”);
    pinMode (PIN_POWER_DS, OUTPUT);
    digitalWrite(PIN_POWER_DS, HIGH);
    // Try to read WiFi settings from RTC memory
    bool rtcValid = false;
    if ( ESP.rtcUserMemoryRead( 0, (uint32_t*)&rtcData, sizeof( rtcData ) ) ) {
    // Calculate the CRC of what we just read from RTC memory, but skip the first 4 bytes as that’s the checksum itself.
    uint32_t crc = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) – 4 );
    if ( crc == rtcData.crc32 ) {
    rtcValid = true;
    }
    }
    //now do stuff
    Serial.println(“do stuff”);
    //strip naam
    //strip path van filenaam
    byte p1 = naam.lastIndexOf(‘\\’);
    byte p2 = naam.lastIndexOf(‘.’);
    naam = naam.substring(p1 + 1, p2);
    batt = ESP.getVcc()-350;
    //Serial.print(“Sketch name “);
    //Serial.println(naam);
    Serial.print(“Battery Voltage “);
    Serial.println(batt/1023.0F);

    // Start connection WiFi
    //Switch Radio back On
    WiFi.forceSleepWake();
    delay( 1 );

    // Disable the WiFi persistence. The ESP8266 will not load and save WiFi settings unnecessarily in the flash memory.
    WiFi.persistent( false );
    Serial.println(“Start WiFi”);
    // Bring up the WiFi connection
    WiFi.mode( WIFI_STA );
    WiFi.config( ip, dns, gateway, subnet );
    //———–Now we replace the normally used “WiFi.begin();” with a precedure using connection data stored by us
    if ( rtcValid ) {
    // The RTC data was good, make a quick connection
    WiFi.begin( WLAN_SSID, WLAN_PASSWD, rtcData.channel, rtcData.ap_mac, true );
    }
    else {
    // The RTC data was not valid, so make a regular connection
    WiFi.begin( WLAN_SSID, WLAN_PASSWD );
    }
    //WiFi.begin( WLAN_SSID, WLAN_PASSWD );

    //——now wait for connection
    int retries = 0;
    int wifiStatus = WiFi.status();
    while ( wifiStatus != WL_CONNECTED ) {
    retries++;
    if ( retries == 100 ) {
    // Quick connect is not working, reset WiFi and try regular connection
    WiFi.disconnect();
    delay( 10 );
    WiFi.forceSleepBegin();
    delay( 10 );
    WiFi.forceSleepWake();
    delay( 10 );
    WiFi.begin( WLAN_SSID, WLAN_PASSWD );
    }
    if ( retries == 600 ) {
    // Giving up after 30 seconds and going back to sleep
    WiFi.disconnect( true );
    delay( 1 );
    WiFi.mode( WIFI_OFF );
    ESP.deepSleep( SLEEPTIME, WAKE_RF_DISABLED );
    return; // Not expecting this to be called, the previous call will never return.
    }
    delay( 50 );
    wifiStatus = WiFi.status();
    }
    //———

    Serial.println(” WiFi connected”);
    Serial.println(“IP address: “);
    Serial.println(WiFi.localIP());

    //—–
    // Write current connection info back to RTC
    rtcData.channel = WiFi.channel();
    memcpy( rtcData.ap_mac, WiFi.BSSID(), 6 ); // Copy 6 bytes of BSSID (AP’s MAC address)
    rtcData.crc32 = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) – 4 );
    ESP.rtcUserMemoryWrite( 0, (uint32_t*)&rtcData, sizeof( rtcData ) );

    //———As we are connected to WiFi, begin MQTT connection
    client.setServer(“192.168.1.101”, 1883); //your MQTT server’s IP.Mind you, these are separated by dots again
    //client.setCallback(callback);
    //——-Here is where you send data
    Serial.println(“Start Sending data”);
    sendMQTTmessage();
    //——————
    /* Close WiFi connection */
    //client.stop();
    //—-and go to back to sleep
    Serial.println(“Go back to sleep”);
    WiFi.disconnect( true );
    delay( 1 );

    // WAKE_RF_DISABLED to keep the WiFi radio disabled when we wake up
    ESP.deepSleep( SLEEPTIME, WAKE_RF_DISABLED );
    }
    void loop() {

    }
    void sendMQTTmessage()
    {
    if (!client.connected()) {
    reconnect();
    }
    sensors.requestTemperatures(); // от датчика получаем значение температуры
    //delay(1000);
    // client.publish(“home/sleep/tele/naam”, naam.c_str(), false);
    client.publish(“home/sleep/tele/batt”, String(batt / 1023.0F).c_str(), false);
    client.publish(“home/sleep/tele/temp”, String(sensors.getTempCByIndex(0)).c_str(),false);//alternatively: read the sensor when wifi off
    //client.publish(“sleep/sleep/tele/humid”,String(dht.readHumidity()).c_str(),false);
    digitalWrite(PIN_POWER_DS, LOW); // отключаем питание датчика
    /* Close MQTT client cleanly */
    client.disconnect();
    }
    void reconnect() {
    while (!client.connected())
    {
    String ClientId = “ESP8266″;
    ClientId += String(random(0xffff), HEX);
    //if (client.connect(ClientId.c_str()))
    // if your MQTT server is protected with a password, use the next line instead of the revious
    if (client.connect(ClientId.c_str(),”sss”, “1234”))
    {
    Serial.print(“Connected”);
    client.publish(“home/hok/stat/connection”, “OK”);
    } else {
    Serial.print(“failed, rc= “);
    Serial.print(client.state());
    delay(1000);
    }
    }
    }
    // the CRC routine
    uint32_t calculateCRC32( const uint8_t *data, size_t length ) {
    uint32_t crc = 0xffffffff;
    while ( length– ) {
    uint8_t c = *data++;
    for ( uint32_t i = 0x80; i > 0; i >>= 1 ) {
    bool bit = crc & 0x80000000;
    if ( c & i ) {
    bit = !bit;
    }
    crc <<= 1;
    if ( bit ) {
    crc ^= 0x04c11db7;
    }
    }
    }
    return crc;
    }

      1. Yes, it works. I would like you to check everything correctly and all the lines are in place? Because I’m not sure of myself.

      2. Well if it works everything is in place. I have given an MQTT example and indeed the only thing you needed to do is to replace the dht code with DS18B20 code, which you did.

  10. I can’t send to sleep if the battery voltage is below the set value (for example, 2.8v). Could you help me?

    1. Everything worked out, I added the lines
      VCC = ESP.getVcc();
      if (VCC < 2900)
      ESP.deepSleep(86400e6); // sleep for a day with low nutrition
      Thanks for the code. Now the autonomous sensor will be protected from battery discharge in the absence of wifi and from low battery discharge.

      1. Yes, already at work. MQTT local server on ESP-01S, ours is with you 🙂 autonomous temperature sensor. And all this data is taken by a clock thermometer on the MAX7219.

  11. Thanks for the article and information it was extremely useful. I’ve currently got it set to 30 second intervals and working with a LiPo battery attached to my ESP8266 which down voltages to 3.3V and this is connected to the 3.3V input pin of my ESP8266 NodeMCU. I have observed some very odd behaviour though with the DH11 temperature readings. The value is oddly reporting a negative value e.g. -11.5 and this then on future wake up this changes to the correct temperature value. When I inspect the historical data over the course of a day the readings constantly fluctuate between this -11.5 and the correct current temperature. Is this something you have observed? I’m wondering if the ESP is getting enough voltage especially if a DH11 sensor is also attached to it?

    1. Hi James. I am happy you found the article usefull. The DHT11 is the sensor we all love to hate, but in your case the voltage might very well be the issue. The DHT11 has a supply voltage range ge of 3.3-5.5 volt, which is right on the edge of what the ESP can deliver. If any i would advise to use say a HTU21D. But if you stick with the DHT11, a capacitor may help. However, that may influence your energy use a bit

      1. Ok I’m now running it via USB with a 5V supply and the readings are showing the same behaviour going from 11 to 21. I know from previous other DH11 examples I haven’t experienced this problem so will investigate further and try another sensor .

      2. I take it you are still feeding the DHT11 from the 3v3 pin of the esp? Or are you feeding the DHT with 5 volt?. Would be interested to see results of your future experiments

      3. Still at the lower edge of the required DHT voltage. Try a 100uF cap over it’s supply line just to see if that makes a difference

      4. Ok I don’t have one of those capacitors to hand but will give it a go thanks. Out of curiosity I went back to my first DHT11 script with connects via MqTT to OpenHAB. I have run this for half hour and it continuously loops with real time readings and values are stable and able to see if graphed out ok – no rapid dip in temperature. I had this running on a 5V supply into the ESP but then moved it to a 3.3V battery supply. Power is supplied to a 3.3V pin on the ESP. Checking OpenHAB again and the reading is still consistent so it appears the ESP and DHT11 sensor is getting sufficient power. Could the deep sleep code and it not getting a temperature reading in time on wake up be a possible issue?

      5. Well, that did cross my mind. The DHT11 is rather slow. Just for testing purposes you could take a reading, wait a second and take one again and see what that does.
        Mqtt and openHAB? An old love from me. I really like openHAB just found the raspberry pi unreliable for it. Still plan to install it on a miniboard

  12. OK I swapped the sensor out with another one and introduced a delay. it seems to be now working even with a 3.3V supply from a LiPo battery. Happy Days!! Thanks again!!

  13. btw. Try OpenHab again with the latest version and a Pi 4 as I’ve been running mine at home for 2 years now. It has failed once due to a dodgy SD card but aside from that its been excellent. I now write-protect the Boot partition in case of corruption. My setup does involves various Z wave sensors and i’ve made some pretty good progress with it if you ever needed any help in giving it another shot.

    1. Apologies for my late reply. I have been thinking about protecting the sd card as much as possible. With the current prices and a ailability of the raspberry, it might be better to use a mini mother board that can directly use a harddisk. So i may try that. Currently though i am trying to see whats possible with firebase. I do have a weak spot for openhab though. But should i find it necessary i will surely take you up on yr kind offer

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.