• Having fiddled a bit with Espruino on ESP8266 -see sister conversation Espruino on ESP8266 ESP-09 - 1 powerful cm2 - I gave this setup a shot for to play with. Final solution will most likely more go into LoRA then Wifi connection between sensors and collector / hub station, and the data will not be pulled but pushed by the sensor node. The browser / viewer wil still do a pull, but pull will not be from the (individual) sensor(s) but from the collector / hub station. For testing things though, the intervalled pull in the browser and use of local Wifi network felt just right.

    Initially I used the WebServer module... but with the setup as taken from the Espruino site - w/ inline stings and anonymous function, it stopped work after abut 8..12 pulls, and it did not reconnect. I was a bit disappointed... and lacking the energy to work myself through the WebServer module. Since I served pages before using just the http module and RYO request handler function, I did that again, as you see in the code. Additionally, I converted the http response composing to ES6 Template Strings. Then I gave the WebServer module another chance - with the inline stuff 'externalized', and now it works too... at least longer than before.

    The implementation uses two (2) http requests:

    1. One for the base page. It is loaded once, frames the data -in an iframe - and allows pausing and resuming the data pull.
    2. One for the data pull. The data pull is just pulling a terse document into the base page as iframe.

    Some trick makes the data available to the main page for further processing/rendering/etc. That I have access to the iframe document and data with .innerHTML on the node with id data, you can see in the debug window of the browser screenshot showing parts of Web page and Espruino Web IDE console. I can even JSON parse the string and get a nice object to work with.

    The iframe's document (DOM) makes itself accessible to the base / main / control page by setting itself as a iframeDocument property of the top window. Initially I used a direct setting like top.iframeDocument = document; as the script in the iframe document. Now I check for the presence of the top.setIframeDocument() function / method and use that. Using a setter function provides easy hook into the event of new data for what ever (post) processing / rendering by the application. Instead of iframe, ajax / xhr call would do as well... but is way more code with no added benefits....

    Using iframe to avoid ajax and make data pull as lightweight as possible was not the only reason: initially I did serve the top, framing page with file://...`` protocol, because I was not sure if I would have enough space in the ESP-09 for all the dhtml code... but it worked itself nicely out... still about half of the variables free... ;-) ...as you can see from stats:

    Connecting to wifi...
    Connected to wifi.
    `--- wifi.getIP(): ---`
    {
      "ip": "192.168.0.119",
      "netmask": "255.255.255.0",
      "gw": "192.168.0.1",
      "mac": "18:fe:34:9c:15:3b"
     }
    `--- process.env: ---`
    {
      "VERSION": "2v00",
      "GIT_COMMIT": "ff35517",
      "BOARD": "ESP8266_BOARD",
      "FLASH": 0, "RAM": 81920,
      "SERIAL": "18fe349c-153b",
      "CONSOLE": "Serial1",
      "MODULES": "Flash,Storage,heatshrink,net,dgram,http­,NetworkJS,Wifi,ESP8266,TelnetServer,cry­pto,neopixel",
      "EXPTR": 1073643636 }
    `--- process.memory: ---`
    { "free": 980, "usage": 720, "total": 1700, "history": 689,
      "gc": 5, "gctime": 1.625 }
    

    The last visual attachment shows a 404 - page not found - http error... just to verify that my 404 in the RYO WebServer does what it's supposed to to.

    Here is the complete code - with static and dynamic Web resources at the end:

    // E09SoilTest1And2.js
    // (c)20181028 allObjects
    
    var lg = false; // logging to console
    var webServerId = "1"; // "1"=module     | "2"=RYO
                           // fails in a bit | keeps going
    
    function log() { if (lg) console.log.apply(console,arguments); }
    
    var wifiCreds = require("wifiCreds");
    var sid = "StaEastRow3";
    
    var wifi = require("Wifi");
    
    function initWifi(cb) {
      log("Connecting to wifi...");
      wifi.connect(wifiCreds.ssid
          , {password:wifiCreds.pw}, function(err) {
        if (err) {
          log('error during connect:',err);
          wifi.disconnect();
        } else {
          log('Connected to wifi.');
          wifi.stopAP();
          log(wifi.getIP());
          log(process.env);
          log(process.memory());
          // wifi.save();
          setTimeout(cb,1000);
        }
      });
    }
    
    var webServer, WebServer;
    
    function initWebServer1() {
      WebServer = require("WebServer");
      webServer = new WebServer(
        { port: 80
        , default_type:  'text/plain'
        , default_index: 'index.html'
        , memory:
          { 'info.html': { 'content': info_html, 'type': 'text/html' }
          , 'info.txt':  { 'content': 'Hello World!' }
          , 'info.njs':  { 'content': info_njs } // content from function return
          }
        });
      webServer.on('start', function (WebServer) {
        // log('WebServer listening on port ' + WebServer.port);
      });
      webServer.on('request', function (request, response, parsedUrl, WebServer) {
        // log('WebServer requested', parsedUrl);
      });
      webServer.on('error', function (error, WebServer) {
        // log('WebServer error', error);
      });
      webServer.createServer();
    }
    
    
    var webServer2created, webServer2listening, httpMod;
    
    function onPageRequest(req, res) {
      var urlObj = url.parse(req.url, true), resObj;
      log(urlObj);
      switch (urlObj.pathname) {
        case "/info.html": res.writeHead(200, {'Content-Type': 'text/html'});
                           res.end(info_html); break;
        case "/info.njs" : resObj = info_njs();
                           res.writeHead(200, {'Content-Type': resObj.type });
                           res.end(resObj.content); break;
        default:           res.writeHead(404, {'Content-Type': 'text/html'});
                           res.end("");
      }
    }
    
    function initWebServer2() {
      httpMod = require("http");
      webServer2created = httpMod.createServer(onPageRequest);
      webServer2listening = webServer2created.listen(80);
    }
    
    var iidM, recM = { sid:sid, mid:0, tim:0, lite:0, temp:0, moist: 0};
    var i2cM, sclM = D13, sdaM = D12; // sw I2C
    
    function initSensorM() {
      i2cM = new I2C();
      i2cM.setup({scl:sclM, sda:sdaM});
    }
    
    function getLite(){ //takes ~3 sec. to acquire
      i2cM.writeTo(0x20,0x03);
      setTimeout(function(){
        i2cM.writeTo(0x20,0x04);
        var d = i2cM.readFrom(0x20,2);
        recM.lite = d[0]*256 + d[1];
      },3000);
    }
    function getTemp(){
      i2cM.writeTo(0x20,0x05);
      var d = i2cM.readFrom(0x20,2);
      recM.temp = d[0]*256 + d[1];
    }
    function getMoist(){
      i2cM.writeTo(0x20,0x00);
      var d = i2cM.readFrom(0x20,2);
      recM.moist = d[0]*256 + d[1];
    }
    
    function getMSensorVals() {  // done at ~:
      i2cM.writeTo(0x20,0x06);   // H+00[s] reset the sensor
      recM.mid++; recM.tim = Math.floor(getTime());
      setTimeout(getLite ,1000); // H+04
      setTimeout(getTemp ,6000); // H+06
      setTimeout(getMoist,8000); // H+08
    }
    
    function cycle() {
      getMSensorVals();
      setTimeout(function(){
          log(recM);
        },9000);
    }
      
    function startSensing() {
      initSensorM();
      cycle();
      iidM = setInterval(cycle,10000);
    }
    
    function onInit() {
      initWifi(function(){
        if (webServerId == "1") {
          initWebServer1();
        } else {
          initWebServer2();
        }
        startSensing();
      });
    }
    
    // static and dynamic Web resources:
    
    var info_html = `
    <html>
    <!-- info.html -->
    <head>
    <title>Info</title>
    <script>
    var baseUrl = ""; // "http://192.168.0.119";
    var reloadInt = 15; // reload interval in seconds
    var tid, cnt = 0, paused = true;
    function wait(remaining) {
      tid = null;
      if (remaining > 0) {
        document.getElementById("countDown").inn­erHTML
          = "" + cnt + ". Reloading in " + remaining + " seconds";
        tid = setTimeout(wait,1000,remaining - 1);
      } else {
        if (paused) {
          pause();
        } else {
          cnt++
          document.getElementById("countDown").inn­erHTML
            = "" + cnt + ". Loading...";
          document.getElementById("data").src = baseUrl+"/info.njs";
          wait(reloadInt);
        }
      }
    }
    function pause() {
      if (tid) { clearInterval(tid); tid = false; }
      paused = true;
      document.getElementById("pauseChkBox").c­hecked = true;
      document.getElementById("countDown").inn­erHTML = "Paused";
    }
    function resume() {
      paused = false;
      document.getElementById("pauseChkBox").c­hecked = false;
      wait(0);
    }
    function setIframeDocument(iframeDocument) {
      top.iframeDocument = iframeDocument;
      // ...and some other code using it
    }
    </script>
    </head>
    <body onload="wait(0);">
    <h3>Info</h3>
    <div><p>
      <input id="pauseChkBox" type="checkbox"
        onclick="if (this.checked) { pause(); } else { resume(); }" 
        > Pause
    </p></div>
    <div><p><span id="countDown"></span><p></div>
    <div><iframe id="data" style="width:100%;"></iframe></div>
    </body>
    </html>
    `;
    
    function info_njs() {
      return {'type': 'text/html', 'content': `
    <html><body><div id="info">${JSON.stringify(recM)}</div>
    <script>if (top.setIframeDocument) top.setIframeDocument(document);
    </script></body></html>
    ` };
    }
    
    setTimeout(onInit,1000); // to be removed for save()
    

    3 Attachments

    • ESP09WS1.png
    • E09EChirp.jpg
    • Nice404PageNotFound.png
About

Avatar for allObjects @allObjects started