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
// 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);
}