Close
0%
0%

WiFi Logger

Simple ESP8266 based data logger, sending data to the cloud over WiFi

Similar projects worth following
To be able to evaluate the performance of my #LiFePO4wered/Solar1 solar power supply, I need to be able to collect a lot of run time data. I decided I needed something to automate this, hence this project.

Unlike most of my projects, this one isn't really intended to become a product, just something for me to use for my development work. Of course, you never know where it might end up. :) It looks to me like it may be useful for other people, so I'm documenting it here.

My requirements are:

  • Measure small differential voltage (up to 0.12V) across the #LiFePO4wered/Solar1 current sense resistor be able to determine charge current.
  • Measure #LiFePO4wered/Solar1 input (solar) voltage and output (battery) voltage.
  • Measure environmental conditions in the box that will be in the sun, exposed to the outdoor heat, cold, humidity. This will help me understand the environmental extremes the circuit and battery will be exposed to, whether the heater performance is good enough, what the pressure in the sealed box does, if moisture will be pulled into the box, etc.

I selected these components to get this done quickly:

  • ESP8266, need to find a good breakout board that is intended to run from 3V.
  • I will be developing the software in Javascript using the excellent Espruino project.
  • BME280 for environmental measurements.
  • ADS1115 for voltage / current measurements.
  • Some cloud system to dump data to, starting out with Initial State because they have an excellent waveform viewer that works much like a 'scope, not like most dumbed down panels intended for consumers. I also added a Losant as a second cloud service.

  • 1 × ESP8266
  • 1 × BME280
  • 1 × ADS1115

  • Source code!

    Patrick Van Oosterwijck09/09/2016 at 17:07 0 comments

    So here's the code for my WiFi Logger, using JavaScript with Espruino running on the ESP8266. I created Espruino modules to log to InitialState and Losant and pushed them upstream. Gordon merged my pull request but it seems the modules did not make it to the website yet (I don't know how often he regenerates it from Github). For now, you can find them in the EspruinoDocs repo.

    I made the code in such a way that you can choose which cloud service the data is sent to by setting the cloudService variable. I cleared my credentials from the code for obvious reasons, you'll need to get your own. :)

    var cloudService = 'initialstate';
    
    if (cloudService === 'initialstate') {
      initialState = require('InitialState');
    
      initialStateBucket = {
          bucketId: 'your bucket ID',
          accessId: 'your access ID'
      };
    }
    
    if (cloudService === 'losant') {
      var losantDeviceId = 'your device ID';
      var losantDeviceAuth = {
        key: 'your access key',
        secret: 'your access secret'
      };
    
      losant = require('Losant').setup(losantDeviceId, losantDeviceAuth);
    }
    
    
    I2C1.setup({scl: NodeMCU.D4, sda: NodeMCU.D3});
    
    var bme = require('BME280').connect(I2C1);
    var ads = require('ADS1X15').connect(I2C1);
    var wifi = require('Wifi');
    var esp = require('ESP8266');
    
    
    function getMedianEnvData(number, callback) {
      function sorter(a, b) { return 10e6 * (a - b); }
      var num = number;
      var temp = [];
      var press = [];
      var hum = [];
      var timer = setInterval(function () {
        bme.readRawData();
        temp.push(bme.calibration_T(bme.temp_raw) / 100.0);
        press.push(bme.calibration_P(bme.pres_raw) / 100.0);
        hum.push(bme.calibration_H(bme.hum_raw) / 1024.0);
        if (--num === 0) {
          clearInterval(timer);
          temp.sort(sorter);
          press.sort(sorter);
          hum.sort(sorter);
          callback({
            temperature: temp[number >> 1],
            pressure: press[number >> 1],
            humidity: hum[number >> 1]
          });
        }
      }, 1500);
    }
    
    function getChargerData(callback) {
      var data = {};
      ads.setGain(4096);
      ads.getADCVoltage(0, function (val) {
        data.inputVoltage = val * 208.2 / 8.2;
        ads.getADCVoltage(1, function (val) {
          data.batteryVoltage = val;
          ads.getADCVoltage(3, function (val) {
            data.outputVoltage = val;
            ads.getADCVoltage([2,3], function (val) {
              data.chargeCurrent = val / 0.27;
              callback(data);
            });
          });
        });
      });
    }
    
    var timeout = 20;
    
    function sendData(envdata, chargerdata) {
      if (wifi.getDetails().status !== 'connected') {
        timeout--;
        if (timeout === 0) {
          console.log('No WiFi connection');
          esp.deepSleep(60000000);
        } else {
          setTimeout(sendData, 1000, envdata, chargerdata);
        }
      } else {
        if (cloudService === 'initialstate') {
          initialState.sendEventsInsecure(initialStateBucket, envdata,
                                          chargerdata, function (err) {
            if (!err) console.log('Sent to InitialState');
            esp.deepSleep(60000000);
          });
        }
        if (cloudService === 'losant') {
          losant.updateDeviceData({
            temp: envdata.temperature,
            humidity: envdata.humidity,
            pressure: envdata.pressure,
            voltage_solar: chargerdata.inputVoltage,
            voltage_bat: chargerdata.batteryVoltage,
            current_charge: chargerdata.chargeCurrent
          }, function (err) {
            if (!err) console.log('Sent to Losant');
            esp.deepSleep(60000000);
          });
        }
      }
    }
    
    E.on('init', function() {
      getMedianEnvData(5, function (envdata) {
        console.log(envdata);
        getChargerData(function (chargerdata) {
          console.log(chargerdata);
          sendData(envdata, chargerdata);
        });
      });
    });
    Some of this stuff is of course very specific to my application, but it gives you the gist. After you load this code with the Espruino IDE, you need to type save() in the terminal to save it to flash. It makes use of the deep sleep timer to save power. For this to work, GPIO16 needs to be connected to the RESET pin. Every 60 seconds, the device will wake up, take readings, send them to the cloud and go back to sleep.

    I had issues with crappy readings from the BME280 that would cause a signal with significant spikes. That is the reason I implemented the filtering to get the median value. It's possible this is not necessary if everything is integrated on a nice board instead...

    Read more »

  • Environmental, voltages and current

    Patrick Van Oosterwijck09/08/2016 at 23:39 0 comments

    There is a convenient Espruino library for the ADS1115, it made it a snap to get to the point where all data I need are measured. This is my current prototype:

    I am writing Espruino libraries for logging to InitialState as well as Losant, making good progress with those and working on getting them upstream so anyone can just "require" them. Stay tuned, code is coming soon!

  • Environmental data logging to Initial State

    Patrick Van Oosterwijck08/29/2016 at 00:41 0 comments

    For initial prototyping I used a Chinese NodeMCU clone (LoLin) connected to a BME280 breakout board from AliExpress to try and get some environmental logging going.

    I had started to write a BME280 driver but then I noticed one already exists. Cool, less work for me!

    After writing a driver for Initial State, I got this log:

    Not bad for a start! You can see the temperature cycle from my air conditioning very well. You can also tell from the pressure that I'm at elevation (Longmont, CO).

    There are some weird "off" readings here and there. Not sure where they come from. It might be a supply issue, since everything is connected with long fly wires and powered from my laptop. I'm going to try multiple readings and taking the median to see if I can get rid of that.

    I realize this isn't much use without the source code, I'm going to try and straighten that out soon and get some code on Github.

View all 3 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates