ESP8266 deep-sleep met Espruino

Door Thijsmans op vrijdag 12 april 2019 20:30 - Reacties (7)
Categorie: -, Views: 1.509

In de meeste gevallen zal het geen punt zijn om een microprocessor te voeden vanaf het lichtnet. Maar soms beland je in de situatie dat een batterij de voorkeur geniet. Bijvoorbeeld omdat je geen stopcontact in de buurt hebt, of omdat je je afvraagt of Chinese buck-converters wel veilig zijn ;) Een ESP8266 vraagt echter best wat stroom, dus als je lukraak wat componenten aan elkaar hangt, gaat je batterij nog geen dag mee. In deze blog doe ik een boekje open over mijn batterij-gevoede ESP8266 met DHT22-sensor, die vele maanden meegaat dankzij de deep sleep mogelijkheden van de microprocessor. Voor de verandering draait mijn ESP8266 op Espruino :+

Achtereenvolgens zal ik ingaan op:
  • het stroomverbruik van de ESP8266;
  • de schakeling en behuizing van mijn project;
  • de benodigde javascript-code.
STROOMVERBRUIK

Espressif, de maker van de ESP8266, heeft het stroomverbruik van de ESP8266 ingeschat op (gemiddeld) circa 150 mA tijdens het verzenden van informatie en 50 mA tijdens het ontvangen. Ik ga ervan uit dat dit alleen het verbruik is van de radio, want als geen informatie wordt verzonden of ontvangen, verbruikt de ESP8266 nog altijd zo'n 60 tot 70 mA. Illustratief is onderstaande grafiek van Alex @ Cron.dk:

https://tweakers.net/ext/f/oqUEKq8r1HVmGVZCpsWfp3Ny/full.jpg


In de deep-sleep modus wordt alles uitgeschakeld, behalve de klok. Die telt een ingesteld aantal microsecondes terug naar 0, en als de tijd erop zit, trekt de klok aan GPIO16. Als je GPIO16 aan de reset-pin hangt, wordt de ESP dus gereset. In deep-sleep verbruikt de klok circa 20 uA. Jawel: uA: dat scheelt een factor 1.000 ten opzichte van mA. 20uA is dus 0,02mA.

Door het ontbreken van exacte meetapparatuur zal ik bij het stroomverbruik moeten aannemen dat bovenstaande cijfers juist zijn. Maar let op: deze getallen zijn alleen voor een "kale" ESP8266-microprocessor. Voor dit project wilde ik in de eerste instantie een Wemos D1-mini met DHT22-shield gebruiken. Ik had geen exacte meetapparatuur nodig om te bemerken dat dit een stroomslurper is die zich niet leent voor deep-sleep doeleinden: de on-board USB-naar-serieel chip (CH340) kan niet worden uitgeschakeld, en dat geldt ook voor de 5V-naar-3V spanningsregelaar. Dus ook in deep-sleep trekken deze onderdelen je batterij leeg.

Verder is bij het stroomverbruik van belang dat ook de DHT22-sensor niet op lucht werkt. Volgens de data-sheet verbruikt 'ie in stand-by gemiddeld 45 uA (van belang omdat de sensor na het inschakelen eerst even moet "settelen"!) en tijdens het meten (twee seconden lang) 1,25 mA. Dat valt (zeer) ruim binnen de grenzen van wat een GPIO-pin kan geven, en dat is mooi: de DHT22 kan gevoed worden vanuit de ESP8266 zelf. Direct voor en na de meting kan de sensor dus worden uitgeschakeld, terwijl de gemeten data wordt verzonden.

Tot slot verbruikt de spanningsdeler, die informatie geeft over de status van de batterij, ook "iets". Maar omdat de spanningsdeler een fractie van een seconde aanstaat, en ik geen informatie kan vinden over het typische verbruik ervan, ga ik daar even aan voorbij. De spanningsdeler zelf bestaat uit twee weerstanden (220 kOhm en 100 kOhm) en brengt de 3,3V voedingsspanning terug naar maximaal 1V (het maximum van de ADC-pin - de analoge input - van de ESP8266).

Een cyclus van vijftien minuten deep-sleep, en vervolgens opstarten, verbinden, meten en verzenden (waarbij het actieve deel 10 seconden duurt) levert het volgende (theoretische) verbruik op:

OnderdeelActieDuurVerbruik/sec.Verbruik totaal (mAs)
ESP8266Deep-sleep900 sec.20 uA18 mA
Basisverbruik10 sec.70 mA700 mA
Zenden1 sec.150 mA150 mA
Ontvangen1 sec.50 mA50 mA
DHT22Stand-by0,35 sec.45 uA0,016 mA
Meting2 sec.1,25mA2,5 mA
Totaal920,516 mA


Per complete cyclus van 910 seconden bedraagt het verbruik dus in theorie 920,5 mAs. Dit komt aardig overeen met wat mijn multimeter aangeeft: gedurende 10 seconden steeds tussen 75 en 85 mA. Al moet daarbij worden opgemerkt dat die slechts enkele metingen per seconden uitvoert, zodat pieken en dalen er gemakkelijk tussendoor glippen.

Aangezien er 86.400 seconden in een dag zitten, worden dagelijks zo'n 94 cycli doorlopen. Het dagelijks verbruik is dus 94 x 920,5 = 86.527 mAs. Een batterij van 2.000 mAh (milliampère-uur), of omgerekend 2.000 x 60 (minuten) x 60 (seconden) = 7.200.000 mAs (milliampère-seconden), levert vermogen voor 83,2 dagen, ofwel 12 weken of drie maanden. Neem je genoegen met twee metingen per uur, dan levert dezelfde batterij vermogen voor 159 dagen (22 weken of vijfenhalve maand). Met één meting per uur rek je het zelfs tot 326 dagen (46 weken, of ruim 11 maanden). Geschikte Lipo-batterijen hebben een spanning van 3,7V in plaats van de vereiste 3,3V (de ESP8266 kan dat prima aan), dus men zou verwachten dat de batterij nog iets langer meegaat - al heb ik niet de kennis daarover zinnige uitspraken te doen. Zo is het bijvoorbeeld ook denkbaar dat de batterij vanzelf lading verliest en dus in de praktijk zelfs minder lang meegaat dan op papier.

De praktijk onderschrijft de bovenstaande berekening. Mijn prototype gaf elke vijf minuten een meting door en draaide op een 800mAh batterij. Volgens bovenstaande berekening zou de batterij 11,37 dagen moeten meegaan. Dag 11 werd heelhuids gehaald. Bij het krieken van dag 12 nam de spanning af en toen de avond viel, stopten de metingen.

https://tweakers.net/ext/f/gZoXwRbTv9xHJPsK3rM9GamK/full.jpg

BEHUIZING EN SCHAKELING

Om de gebruikersacceptatietest te doorstaan, is het noodzakelijk dat mijn knutselprojecten niet te zeer in het oog springen. Daarom zocht en vond ik een fraaie wanddoos voor temperatuursensoren bij AliExpress:

https://tweakers.net/ext/f/pwFkmRNkGLkPNXy5IwiTAwFn/full.jpg

Voor € 2,07 is het een erg nette doos, waarbij het fijn is dat de schroefgaten op een standaard lasdoos passen. Hoewel de wanddoos niet erg ruim is, is er zeker genoeg ruimte om een batterij, ESP8266 (ESP12f) en DHT22-sensor en de vermelde spanningsdeler op een printplaatje te huisvesten.

Om de software later nog eens te kunnen updaten en componenten te kunnen toevoegen, heb ik header-pins toegevoegd en een switch om in flash-modus te booten. De ESP12f kent drie boot-modi: programma laden, flash-modus en SD-modus (?). Met dank aan deze instructable ben ik tot het volgende schema gekomen:

https://tweakers.net/ext/f/ggXRPjzfUtTJBeI9tqYlwSAs/full.jpg

En dat schema is als volgt op een stukje printplaat gekomen:

https://tweakers.net/ext/f/Has1Wjttn78CzdXdqwRLfx9R/medium.jpghttps://tweakers.net/ext/f/jgqFb5DxRGKI5PPUU3hD6p7w/medium.jpg


Op de eerste foto is te zien dat ik een connector heb gebruikt voor aansluiting van de print op de batterij. De USB-kabel erboven is een lader met een zelfde connector: als de batterij leeg is, kan ik 'm dus gewoon opladen aan een telefoonlader.

JAVASCRIPT-CODE

In mijn vorige blog legde ik uit hoe je de Espruino-firmware kunt flashen op jouw ESP8266. Heb je dat gedaan, dan kun je mijn project nabouwen met de onderstaande javascript-code. Omdat ik header-pins op de print heb gesoldeerd, kan ik gemakkelijk de TX-, RX-, VCC- en GND-pins in mijn ESP01-usb-serieel-adapter prikken en verbinden.

Enkele opmerkingen vooraf:
  • De wifi-instellingen moeten niet worden opgeslagen via wifi.save(), want dan zal de ESP direct na inschakelen verbinding maken. Dat willen we niet, omdat de verbinding dan onnodig lang open blijft;
  • De ESP zal met deze code een DHCP-lease vragen, en dat kost ook tijd. Ik heb overwogen een statisch IP-adres in te stellen met wifi.setIP(), maar in de docs staat: "You must be connected to an access point to be able to call this successfully". Tsja, wat is dan nog het punt...
  • Je kunt bij ESP8266.deepSleep() een argument meegeven, om te bepalen of de wifi-radio bij het resetten moet worden uitgeschakeld. Dat klinkt aantrekkelijk (want: stroombesparing), maar bij het inschakelen moet de radio opnieuw gecalibreerd worden, en dat kost tijd. Ik vraag mij daarom af of dit in dit scenario wel loont;
  • Er moeten enkele safe-guards worden ingebouwd, die voorkomen dat de ESP aan blijft bij een fout. De belangrijkste is dat de module in elk geval na 15 seconden wordt uitgeschakeld;
  • De workflow is: (1) DHT inschakelen en uitlezen, (2) bij een valide resultaat, de spanningsdeler inschakelen en het voltage uitlezen, (3) de MQTT-verbinding instellen, (4) verbinden met wifi en de MQTT-broker, (5) het bericht met de DHT-meting en voltage verzenden , (6) pas bij ontvangst van het bericht van de MQTT-broker terug naar deep-sleep (zodat de verbinding niet te vroeg wordt verbroken en de berichten niet aankomen).
Het javascript is als volgt:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  // Wifi-config
  var wifi = require("Wifi");
  var wifi_ssid = 'JOUW_SSID';
  var wifi_options = {
      password: 'JOUW_PASSWD',
    };

  // MQTT-config; zie voor alle config-options:
  // https://www.espruino.com/MQTT
  var mqtt_host  = "JOUW_BROKER_IP";
  var mqtt_topic = 'home/verdieping/kamer/dht';
  var mqtt_options = {
      username: undefined,
      password: undefined,
      client_id: 'esp-' + getSerial() + '-' + Math.ceil( Math.random()* 1000 ),
    };

  // GPIO-pins voor DHT-sensor
  var pin_dht_vcc  = 4;
  var pin_dht_data = 5;
  var dht;

  // Deep-sleep in microsecondes (900 = secondes)
  var deep_sleep_duration = 900 * 1000 * 1000;

  // GPIO-pins voor voltage-divider
  var pin_vdiv_r1 = 12;
  var pin_vdiv_r2 = 13;

  function enter_deep_sleep ()
  {
    wifi.disconnect();
    require("ESP8266").deepSleep( deep_sleep_duration );
  }

  E.on('init', function () {

    // Na het inschakelen even wachten om de sensor te 
    // laten stabiliseren, dus uitlezen in een timeout.
    digitalWrite( pin_dht_vcc, true );

    setTimeout( function () {
      dht = require("DHT22").connect( pin_dht_data );
      dht.read( function (r) {
        if( r.err ) 
          return enter_deep_sleep();
      
        // Voltage divider inschakelen, uitlezen en uitschakelen
        digitalWrite( pin_vdiv_r1, false );
        digitalWrite( pin_vdiv_r2, true );
        var batt_voltage = analogRead() * 3.3;
        digitalWrite( pin_vdiv_r2, false);
        
        // MQTT-object klaarmaken, maar nog niet verbinden
        mqtt = require("MQTT").create( mqtt_host, mqtt_options );
        
        // Als verbonden, dan direct bericht uitdoen
        mqtt.on('connected', function () {
          mqtt.subscribe(mqtt_topic);
          mqtt.publish( mqtt_topic, 
            JSON.stringify( { temp: r.temp, hum: r.rh, vcc: batt_voltage } ), 
            { retain: true } );
        });
     
        // Bericht ontvangen van broker, dan deep sleep
        mqtt.on('message', function (t, m) {
          digitalWrite( pin_dht_vcc, false );
          mqtt.disconnect();
          enter_deep_sleep();
        });
    
        // Meting gedaan, MQTT voorbereid, dus: 
        // verbinden of, bij fouten, deep sleep.
        wifi.connect( wifi_ssid, wifi_options, function (e) {
          if( e ) 
            return enter_deep_sleep();

          mqtt.connect();

          // Fail-safe: als na 15 seconden de sensor nog niet in 
          // deep sleep is gegaan, is de MQTT-broker ws onbereikbaar.
          // Dan terug naar deep sleep en wachten op volgende poging.
          setTimeout( function () {
            return enter_deep_sleep();
          }, 15000);
        });
      });
    }, 350);  
  });



Draait de ESP8266 deze code met succes? Dan kun je in Home Assistant MQTT-sensors aanmaken op de wijze die ik in een vorige blog beschreef.

Volgende: 's Werelds kleinste Home Assistant controller op ESP8266 en Espruino 24-03 's Werelds kleinste Home Assistant controller op ESP8266 en Espruino

Reacties


Door Tweakers user Raven, zaterdag 13 april 2019 09:45

Ik heb een tijdje terug eens gezocht naar ESP-01 i.c.m. DHT-sensor en deep sleep en kwam toen veel berichten tegen dat na een paar keer in deep sleep te zijn gegaan, dat de DHT-sensor geen waarden meer geeft. Liep jij daar toevallig ook tegenaan?

Door Tweakers user Thijsmans, zaterdag 13 april 2019 10:38

Nee. Ik heb allereerst wel eens een ESP01 in deep sleep kunnen krijgen, maar dat vergt wel echt precisie soldeerwerk. GPIO16 van de chip zit namelijk niet op een pin van de PCB. Nog een reden om geen ESP01 meer te gebruiken ;)

Wat betreft de DHT: ik kan me voorstellen dat als de ESP in deep sleep gaat, maar de DHT niet wordt uitgeschakeld, niet opnieuw kan worden "verbonden". Maar zoals ik hierboven beschreef, voed ik de DHT vanuit de ESP. Deep sleep betekent dus ook het uitschakelen van de DHT.

Door KirovAir, zaterdag 13 april 2019 11:17

Leuke blog!
Enige wat ik me afvraag is hoeveel overhead javascript heeft op dit soort microcontrollers, al helemaal in een energiezuinige omgeving.
Ik ga sowieso eens duiken in de ESP varianten, lijkt me een gaaf om mee te stoeien!

Door Tweakers user ProAce, zaterdag 13 april 2019 19:09

Om dit nog te verbeteren kun je eens kijken naar wat "professionelere" temperatuur sensoren. Zo heb ik goede ervaring met de SHT21 welke accurater,zuiniger en sneller uit te lezen is.

Daarnaast heeft een lithium accu erg last van een hoge zelf ontlading. Om het echt lang vol te houden wil je een zo laag mogelijke zelfontlading, goede keuzes daarvoor zijn alkaline (AA) of lithium-thionyl accu's. Deze zijn alleen niet oplaadbaar maar hebben een ontlading van 1% per jaar ten opzichte van een paar % per maand van de standaard lithium.

Door Slowdive, zaterdag 13 april 2019 21:46

Slim aangepakt! Je gebruikt in de code een broker om de json-data naar toe te sturen. Kun je een voorbeeld geven wat je daarvoor kunt gebruiken?

Door Tweakers user Thijsmans, zaterdag 13 april 2019 23:33

@ProAce: dank voor de tip, de SHT21 kende ik nog niet. Is nog goedkoper dan de DHT22 ook :)

@Slowdive: Home Assistant heeft een ingebouwde MQTT-broker (die niet erg stabiel lijkt te zijn), maar met hetzelfde gemak installeer je "gewoon" mosquitto (op een Pi: sudo apt-get install mosquitto). Ook een publieke MQTT-server is mogelijk (al valt dat af te raden vanwege de openbaarheid), bijvoorbeeld test.mosquitto.org of io.adafruit.com (account vereist).

Door Tweakers user CurlyMo, maandag 15 april 2019 09:27

Mijn setup is een DS18B20 + ESP01 + 2x AA. Dat draait in deep sleep met een update elke 10 minuten voor 2,5 maand. Dat vind ik nog iets te kort, dus in de zomermaanden maar naar de update elke 15 minuten. Dan moet 4 maanden wel lukken. Wel priegel solderen en de leds wegslopen :)

Reactie formulier
(verplicht)
(verplicht, maar wordt niet getoond)
(optioneel)