Qrome / printer-monitor

OctoPrint 3D Printer Monitor using Wemos D1 Mini ESP8266
MIT License
474 stars 164 forks source link

Adding battery shield for full wireless use #31

Open FireDemon007 opened 6 years ago

FireDemon007 commented 6 years ago

Adding a battery shield for full Wireless use is without a doubt possible. But I'm wondering if you could read the battery level through one of the analog pins every so often and display it on the display?

NeoRame commented 5 years ago

That would be nice!

Oxmaster commented 5 years ago

I'd love to see a battery indicator next to the RSSI graph. You just need to add 220k resistor (allowing to measure up to 5.4V to be on a safe side) in series with the battery to ADC pin to have 440k/100k voltage divider (D1 has 220k/100k divider by default on ADC pin, so you can measure 3v3).

I'm working on botching the sketch to make little battery display charge of battery, will probably share the code tomorrow. For some reason I can't upload code to my D1 after uploading this project (port unable to be opened) so will try tomorrow.

Oxmaster commented 5 years ago

So I finished writing the botch, and did some testing on battery life. Without this mod, the monitor lived for about 24 hours of idling (RPi connected, not printing) on 2000mAh battery, so it shouldn't be shorter than this with this mod.

Add this to your printermonitor.ino at line 1012 (after the function void drawRssi(OLEDDisplay *display) and add drawBattery(display); to void drawRssi(OLEDDisplay *display) function after line 1010 (before the end of the function). So whenever the RSSI graph is updated, so is the battery status. I suggest you calibrate your resistors, as it could vary quite a lot depending on the tolerance of the resistor itself.

As I said this is a quick botch, it could use options to add sleep to prolong the battery life etc. and I didn't do any real testing, as I'm in the process of designing case for 2×18650, 128×64 OLED, D1 mini and TP4056 or battery shield module.

void drawBattery(OLEDDisplay *display){
    /* Battery botch by Oxmaster
    * ------------------------------------------------
    * add this snippet to printermonitor.ino
    * right after void drawRssi(OLEDDisplay *display)
    * and drawBattery(display); at the end of
    * drawRssi function (above this one)
    * whenever the RSSI graph is updated, so is this
    *-------------------------------------------------
    * When using D1 battery shield:
    *
    * The shield has integrated 130k resistor, just
    * bridge J2 connector on the back
    * change voltageDividerRatio to 4.5
    * and batteryVoltageRange = {3.1, 4.15}
    *-------------------------------------------------
    * When using TP4056
    *
    * Add 220k resistor inline with the battery
    * Battery -> 220k resistor -> ADC0
    * change voltageDividerRatio to 5.1
    * and batteryVoltageRange = {2.5, 4.15}
    *-------------------------------------------------
    *
    * to get better accuracy, calibrate the voltageDividerRatio
    */

    // constants -------------------------------------------------------

    // 1 bit equals x volts
    const float bitPerVolt = 0.0009765625;

    // voltage divider ratio (use to calibrate your divider)
    // use different arduino sketch to get this value
    const float voltageDividerRatio = 5.1;
    //const float voltageDividerRatio = 4.5;

    // min and max voltage that the battery will achieve
    // used to calculate percentage of charge

    // per TP5400 datasheet (D1 battery shield)
    //const float batteryVoltageRange[2] = {3.1, 4.15};

    // per TP4056 datasheet
    const float batteryVoltageRange[2] = {2.5, 4.15};

    // vars ------------------------------------------------------------
    // !! do not change !!

    const uint8_t dataPoints = 5;
    static uint8_t dataIndex = 0;
    static int8_t dataReadings[dataPoints] = {0, 0, 0, 0, 0};
    static int16_t dataTotal = 0;
    int8_t average = 0;

    // calculations ----------------------------------------------------
    uint16_t adcOutput = analogRead(A0);

    // calculate voltage
    float batteryVoltage = (float)adcOutput * bitPerVolt * voltageDividerRatio;

    // convert voltage to percentage (map function)
    // int16 because the value could go above 128, overflowing int8
    int16_t batteryChargePercentage = (batteryVoltage - batteryVoltageRange[0]) * 100 / (batteryVoltageRange[1] - batteryVoltageRange[0]);

    // constrain the value in case of anomaly
    batteryChargePercentage = constrain(batteryChargePercentage, 0, 100);

    // using running average, calculate the charge percentage
    dataTotal -= dataReadings[dataIndex];
    dataReadings[dataIndex] = batteryChargePercentage;
    dataTotal += dataReadings[dataIndex];
    dataIndex ++;

    if (dataIndex >= dataPoints)
        dataIndex = 0;

    average = dataTotal / dataPoints;

    // debug
    /*
    Serial.print("ADC: ");
    Serial.println(adcOutput);
    Serial.print("VOLT: ");
    Serial.println(batteryVoltage);
    Serial.print("PERCENT: ");
    Serial.println(batteryChargePercentage);  
    Serial.print("PERCENT AVG: ");
    Serial.println(average);
    */

    // draw the battery outline
    display -> drawRect(104, 49, 7, 15);

    // fill the battery, 5 steps
    // 0, 25, 50, 75, 100%

    if (average <= 0){
        // 0%

    } else if (average > 0){
        // 25%
        display -> drawRect(106, 60, 3, 2);

        if (average >= 25){
            // 50%
            display -> drawRect(106, 57, 3, 2);

            if (average >= 50){
                // 75%
                display -> drawRect(106, 54, 3, 2);

                if (average >= 75){
                    // 100%
                    display -> drawRect(106, 51, 3, 2);

                }
            }
        }
    }
}

This is how it looks: 0percent 100percent

File that you can just replace: printermonitor.zip

NeoRame commented 5 years ago

To expand the battery live, you may can take a look to my night mode ( I started a pull request) with the darker display the battery life expand around 50-100% longer in my tests

Oxmaster commented 5 years ago

When I will have time (if) I will try to understand how the web interface works and try to implement it "properly" with settings etc. Unless someone more knowledgeable is up to the task.

NeoRame commented 5 years ago

Next week when I’m home I’ll take a look and try to add this function to my monitor. Maybe I need a schematic where I put the resistors...

Oxmaster commented 5 years ago

On Sunday I will try to upload the schematic and a sketch to help calibrate the divider, maybe earlier, don't know as I have a lot of work this week.

Oxmaster commented 5 years ago

Again, I didn't test it too much, just verified that it works for me.

https://github.com/Oxmaster/VoltageDividerCalibration