Battery Monitoring

Circuit-wise, identical to the AD Blackbox (but only for the sake of demonstrating the fuel gauge):

Code-wise, we have one additional library to import, along with some additional calls to poll the battery charge controller. This is also a great example of how a Photon talks to digital sensors using the I2C protocol. The battery charge controller can be seen as a sensor, for the battery.

Also, refer to this Sparkfun article for more details: https://learn.sparkfun.com/tutorials/photon-battery-shield-hookup-guide#using-the-max17043-lipo-fuel-gauge


Libraries Used


Code

  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
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
// This #include statement was automatically added by the Particle IDE.
#include <SparkFunMAX17043.h>

// how long between each log update? feel free to change this value,
// but this must not be anything less than 1000 milliseconds!
#define INTERVAL_BETWEEN_LOGS 5000

// initialise the timer
Timer dataTimer(INTERVAL_BETWEEN_LOGS, doDataUpdate);

// Battery monitoring
float voltage = 0; // Variable to keep track of LiPo voltage
float soc = 0;     // Variable to keep track of LiPo state-of-charge (SOC)
bool alert; // Variable to keep track of whether alert has been triggered


// code in this setup function runs just once, when Photon is powered up or reset
void setup() {
    Serial.begin(9600);         // Open a connection via the Serial port / USB cable – useful for debugging
    delay(5000);                // Common practice to allow board to 'settle' after connecting online

    dataTimer.start();

    pinMode(D0, INPUT_PULLDOWN); // tell the Photon we're using D0 as an INPUT (pulldown resistor enabled)
    pinMode(D1, INPUT_PULLDOWN); // tell the Photon we're using D1 as an INPUT (pulldown resistor enabled)

    // if you're adding more digital pins as INPUT, add lines similar to the above accordingly.

    // note: analogue pins do not need to be initialised as they are INPUTs by default

    // BATTERY GAUGE CODE STARTS HERE:
    // -------------------------------
    // To read the values from a browser, go to:
    // http://api.particle.io/v1/devices/{DEVICE_ID}/{VARIABLE}?access_token={ACCESS_TOKEN}
    // Set up Particle variables (voltage, soc, and alert):
    Particle.variable("voltage", voltage);
    Particle.variable("soc", soc);
    Particle.variable("alert", alert);

    // Set up the MAX17043 LiPo fuel gauge:
    lipo.begin(); // Initialize the MAX17043 LiPo fuel gauge

    // Quick start restarts the MAX17043 in hopes of getting a more accurate
    // guess for the SOC.
    lipo.quickStart();

    // We can set an interrupt to alert when the battery SoC gets too low.
    // We can alert at anywhere between 1% - 32%:
    lipo.setThreshold(20); // Set alert threshold to 20%.

}

// code in this loop function runs forever, until you cut power!
// for the A/D blackbox, there is nothing to do in here because data updates are handled by our timer
void loop() {

}

// doDataUpdate runs every interval set in INTERVAL_BETWEEN_LOGS
void doDataUpdate() {
    // IMPORTANT: to prevent server overload, the Particle cloud can only accept
    // update rates of once per second, with the option to 'burst' 4 updates in a
    // second (but then you'll get blocked for the next 4 seconds). 'Ration' your
    // INTERVAL_BETWEEN_LOGS and the number of readings you are publishing; in our
    // default example, we are frugally using just 1 publish, by concatenating
    // all the data we want into a single publish statement

    // first we save what we want to read into temporary variables first.
    // feel free to add/remove these lines as you see fit in your application:

    bool D0State = digitalRead(D0); // read a digital true/false state from D0
    bool D1State = digitalRead(D1); // read a digital true/false state from D1

    int A0State = analogRead(A0); // read an analogue range (0-4095) from A0
    int A1State = analogRead(A1); // read an analogue range (0-4095) from A0

    // now we form the concatenated string to put them all together. This String
    // must NOT exceed 255 characters!
    String output = "D0:" + String(D0State) + ",D1:" + String(D1State) +
                  ",A0:" + String(A0State) + ",A1:" + String(A1State);

    // prints this out the Serial port (coolterm) for us HUMANS to verify and
    // debug; comment the next line if you don't want to see it in Coolterm
    Serial.println(output);

    // finally, send it out (and have sensored.mdit.space receive it):
    Particle.publish("sensorData", output);

    // BATTERY MONITORING
    // lipo.getVoltage() returns a voltage value (e.g. 3.93)
    voltage = lipo.getVoltage();
    // lipo.getSOC() returns the estimated state of charge (e.g. 79%)
    soc = lipo.getSOC();
    // lipo.getAlert() returns a 0 or 1 (0=alert not triggered)
    alert = lipo.getAlert();

    String battStat = "V:" + String(voltage) + ",SOC:" + String(soc) + ",ALERT:" + alert;
    Particle.publish("battStat", battStat);
}