Callback help

Posted on
  • Hi, I'm writing some code for my Pico with an ESP8266 which sends temperature and humidity sensor readings to a Google Form (like this tutorial).

    I'm using a DHT11 sensor like this...

    var dht = require("DHT11").connect(C11);
    dht.read(function (a) {Temp = a.temp.toString();Humidity = a.rh.toString();});
    

    Then next I send the Temp and Humidity to Google like this...

    sendForm(Temp, Humidity);
    

    but the sensor hasn't finished reading yet, it's to soon to send the data. I can use setTimeout to wait a couple of seconds before sending, that works, but I'm thinking I need learn how to use a callback but I can't work out how to write it.

  • How about changing your existing callback:

    dht.read(function (a) {Temp = a.temp.toString();Humidity = a.rh.toString();});
    

    to:

    dht.read(function (a) {
      Temp = a.temp.toString();
      Humidity = a.rh.toString();
      sendForm(Temp, Humidity);
    });
    

    So now you send the form as soon as you have the information ready?

  • Great, thanks Gordon

  • Hi, I'm trying to add a BH1750 sensor to measure light intensity but now when I send the form, after one succesfull send, I get errors...

    _____                 _
    |   __|___ ___ ___ _ _|_|___ ___
    |   __|_ -| . |  _| | | |   | . |
    |_____|___|  _|_| |___|_|_|_|___|
              |_| http://espruino.com
     1v91 Copyright 2016 G.Williams
    >
    =undefined
    Saving key
    Saving cert
    Saving ca
    Done!
    >save()
    =undefined
    Erasing Flash.....
    Writing............................
    Compressed 81600 bytes to 26255
    Checking...
    Done!
    Running onInit()...
    Connecting to WiFi
    192.168.1.68
    Connecting to Google
    Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    Performing the SSL/TLS handshake...
    >Verifying peer X.509 certificate...
    Connected to Google
    Google connection closed, 65577 bytes received
    process.memory();
    ={ "free": 3919, "usage": 1181, "total": 5100, "history": 1,
      "stackEndAddress": 536958444, "flash_start": 134217728, "flash_binary_end": 378496, "flash_code_start": 134234112, "flash_length": 393216 }
    Connecting to Google
    Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    ERROR: Failed! mbedtls_ssl_setup: Not enough memory
    ERROR: Unable to create socket
    Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    ERROR: Failed! mbedtls_ssl_setup: Not enough memory
    ERROR: Unable to create socket
    >process.memory();
    ={ "free": 3868, "usage": 1232, "total": 5100, "history": 1,
      "stackEndAddress": 536958444, "flash_start": 134217728, "flash_binary_end": 378496, "flash_code_start": 134234112, "flash_length": 393216 }
    

    but it seems like there is enough memory. I don't understand what I've done wrong.

    function onInit() {
    
      I2C3.setup({sda:B4,scl:A8});
      var bh=require("BH1750").connect(I2C3);
      bh.start(3);
      
      var dht = require("DHT11").connect(B5);
      
      clearInterval();
      // initialise the ESP8266, after a delay
      setTimeout(function() {
        
        Serial1.setup(115200, { rx: B7, tx : B6 });
        wifi = require("ESP8266WiFi_0v25").connect(Serial1, function(err) {  
          if (err) throw err;
          console.log("Connecting to WiFi");
          wifi.connect("xxxx", "xxxx", function(err) {
            if (err) throw err;
            wifi.getIP(function(e,ip) {
              LED2.set();
              console.log(ip);
              setInterval(function() {
                dht.read(function (a) {
                  sendForm(a.temp.toString(), a.rh.toString(), Math.round(bh.read()).toString());
                });
              }, 60000); // once a minute
            });
          });
        });
      }, 2000); 
    }
    
  • I'd try breaking sendForm() and bh.read() out of the dht.read() callback. Not sure if that will help, but it might relieve some memory shortage. Untested code:

    // global vars up near the top
    var lastTemp = "";
    var lastHumidity = "";
    var lastLight = "";
    
    function sendSensorData(){
       sendForm(lastTemp, lastHumidity, lastLight);
    }
    
    // ........
    // further down, in place of your setInterval() section
    
    setInterval(function() {
      lastLight = Math.round(bh.read()).toString();
      dht.read(function (a) {
        lastTemp = a.temp.toString();
        lastHumidity = a.rh.toString();
    
        // let's give Espruino an opportunity to do housekeeping
        // before sending our form
        setTimeout(sendSensorData, 5000);
      });
    }, 60000); // once a minute
    
    
    
    
  • Thanks @oesterle, it worked a treat.

  • Wow. OK, then! Sorta cool when you code something up, and it runs on someone else's hardware the first time. Cheers, @countxerox.

  • Hi, I let the program run for 25 hrs, sending to google every 2 minutes but when I look at google for the responses only 417 responses have been logged. It didn't crash but after the first few successful sends it either has the memory error, handshake failed or it works.

    >Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    Performing the SSL/TLS handshake...
    Verifying peer X.509 certificate...
    it works
    >Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    ERROR: Failed! mbedtls_ssl_setup: Not enough memory
    ERROR: Unable to create socket
    Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    ERROR: Failed! mbedtls_ssl_setup: Not enough memory
    ERROR: Unable to create socket
    >Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    Performing the SSL/TLS handshake...
    ERROR: Failed! mbedtls_ssl_handshake returned -0x4290
    >Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    Performing the SSL/TLS handshake...
    ERROR: Failed! mbedtls_ssl_handshake returned -0x4290
    >process.memory();
    ={ "free": 3920, "usage": 1180, "total": 5100, "history": 1,
      "stackEndAddress": 536958120, "flash_start": 134217728, "flash_binary_end": 377416, "flash_code_start": 134234112, "flash_length": 393216 }
    >Connecting with TLS...
    Loading the CA root certificate...
    Loading the Client certificate...
    Loading the Client Key...
    Performing the SSL/TLS handshake...
    Verifying peer X.509 certificate...
    it works
    

    Is there something wrong with my code again?

    function onInit() {
      USB.setConsole(1);
      var lastTemp = "";
      var lastHumidity = "";
      var lastLight = "";
      var lastmeasure ="";
      
      I2C3.setup({sda:B4,scl:A8});
      var bh=require("BH1750").connect(I2C3);
    
      var dht = require("DHT11").connect(B5);
      
      clearInterval();
      
      setTimeout(function() {   
        Serial1.setup(115200, { rx: B7, tx : B6 });
        wifi = require("ESP8266WiFi_0v25").connect(Serial1, function(err) {  
          if (err) throw err;
          wifi.connect("xxx", "xxx", function(err) {
            if (err) throw err;
              LED2.set();
              setInterval(function() {
                dht.read(function (a) {
                  lastTemp = a.temp.toString();
                  lastHumidity = a.rh.toString();
                });
                bh.start(3,1);
                lastLight = Math.round(bh.read()).toString();
      
                var n=0,i=100;
                while (i--) n+=analogRead(A7);
                lastmeasure = (100-Math.round(n)).toString();
      
                setTimeout(function() {
                  sendForm(lastTemp, lastHumidity, lastLight, lastmeasure);
                }, 5000);
              }, 120000); // once every 2min
          });
        });
      }, 2000); 
    }
    
  • Right now, everything lives inside onInit(). Can you reorganize your code into separate task-focused functions? That may relieve memory issues, and also make your code more reusable on other projects.

    I'd try to make onInit() focused on just the setup you need to do on power on.

    You also have a long-lived nest of multiple callback functions. I'd pull the connection and sending out into a separate function that's called every 2 minutes. In that function, I'd also turn off Wi-Fi when done sending. This is good practice for IoT sensors that you intend to battery power, also.

    Finally, you'll still probably have rare occasions where connection or sending fails, but these should be less frequent.

  • Thanks for that advice @oesterle. I've had a go and I think it's improved but I can't close the wifi connection. wifi.disconnect() isn't recognised.

    Serial1.setup(115200, { rx: B7, tx : B6 });
    
    I2C3.setup({sda:B4,scl:A8});
    var bh=require("BH1750").connect(I2C3);
    
    var dht = require("DHT11").connect(B5);
    
    function read_sensors(callback) {
      var n=0,i=100;
      while (i--) n+=analogRead(A7);
      bh.start(3);
      light_intensity = Math.round(bh.read()).toString();
      soil_moisture = (100-Math.round(n)).toString();
      dht.read(function (a) { 
        temp = a.temp.toString();
        humidity = a.rh.toString();
        callback (light_intensity, soil_moisture, temp, humidity);
      });
    }
    
    function send(l,m,t,h) {
      wifi = require("ESP8266WiFi_0v25").connect(Serial1, function(err) {  
        if (err) throw err;
        wifi.connect("Xxx", "xxx", function(err) {
          if (err) throw err;
          LED2.set();
          sendForm(l,m,t,h);
        });
      });
    }
    
    function onInit() {
      USB.setConsole(1);
      clearInterval();
      setInterval(function() {
        read_sensors(send);
      },30000);
    }
    
  • That code looks a lot cleaner, @countxerox!

    Thanks for that advice @oesterle. I've had a go and I think it's improved but I can't close the wifi connection. wifi.disconnect() isn't recognized.

    Well, at least it's perfectly OK to call wifi.connect() even when already connected according to the docs. And, your callback is called.

    I wonder why wifi.disconnect() isn't working? @Gordon, any idea?

  • There actually isn't a disconnect function in the ESP8266_WiFi driver - there's just what is mentioned here: http://www.espruino.com/ESP8266#reference

    If you want to disconnect to save power, I'd recommend that you actually bring the CH_PD wire out from the ESP8266 and connect it to Espruino - you can then totally power the chip down, which should be a lot more efficient than just telling it to disconnect from WiFi.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Callback help

Posted by Avatar for countxerox @countxerox

Actions