This website uses cookies to ensure you get the best experience on our website.
Introducing Solar Samba: The Innovative ESP32-Based LiFePo4 Battery Charger for Efficient Solar Energy Management

As Solar Samba continued its dance, it couldn't help but ponder over the readings on its digital display. "Ah, 12.5V," it thought, "the sun's been generous today." But as the clouds gathered, Solar Samba's display dimmed, mirroring the sky. "11.9V... time for me to shine!" it declared, springing into action.

With every dip in voltage, Solar Samba's resolve grew stronger. "I won't let the darkness win," it mused, as the display flickered with the rhythm of its charge. As night fell, Solar Samba's display became a beacon of hope, its numbers dancing in the dark, ensuring the battery bank stayed alive.

But Solar Samba knew its limits. When load shedding struck, its display read a somber "No Grid Power." It sighed, "Time for Plan C to take the stage." As the generator roared to life, Solar Samba whispered, "Rest now, my batteries, for tomorrow, we dance again."

Through every challenge, Solar Samba's digital display was its window to the world, a reflection of its thoughts and a guide for its next move. In the dance of light and darkness, it was more than just a charger; it was a thinker, a guardian, and a true solar samba dancer.

//So, for a voltage divider with a ratio of 11.0, you could use a 24.8kΩ resistor for R1 and a 2.48kΩ resistor for R2. 

These are not standard resistor values, so you might use the closest standard values, which are 24kΩ for R1 and 2.4kΩ for R2.

This will give you a slightly different ratio, but it should be close enough for most purposes. 

Always double-check the actual output voltage of your voltage divider with a multimeter to ensure it's safe for your microcontroller.


Battery+ (14.6V) ----[R1 (24kΩ)]----+----[R2 (2.4kΩ)]---- GND

                                    |

                                    +---- Output (to ESP32 analog pin, max 3.3V)

//

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#include "BluetoothSerial.h"

#include <WiFi.h>

#include <WiFiClient.h>

#include <ThingSpeak.h>


#define SCREEN_WIDTH 128 // OLED display width, in pixels

#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


const int currentSensorPin = 34; // Pin connected to the ACS712 output (ADC1)

const int voltageSensorPin = 35; // Pin connected to the voltage divider output (ADC1)

const int chargeControlPin = 32;  // Pin connected to the gate of the MOSFET


const float voltageDividerRatio = 11.0; // Ratio of the voltage divider (R2/(R1+R2))

const float currentSensorSensitivity = 0.066; // Sensitivity of the ACS712 30A sensor in V/A


const float maxChargingCurrent = 30.0; // Maximum charging current in A

const float nightModeChargingCurrent = 15.0; // Maximum charging current in night mode

const float maxChargingVoltage = 14.6; // Maximum charging voltage for LiFePo4 battery

const float floatVoltage = 13.6; // Float voltage for LiFePo4 battery

const float minBatteryVoltage = 11.0; // Minimum voltage for 0% SOC

const float activationVoltage = 12.0; // Voltage threshold for activating charging


const unsigned long slowStartDuration = 5000; // Duration of the slow start in milliseconds

unsigned long slowStartTime = 0; // Timestamp when the slow start begins

bool slowStartActive = false; // Flag to indicate if slow start is active


bool nightMode = false; // Flag to indicate if night mode is active

bool chargingEnabled = false; // Flag to indicate if charging is enabled

bool chargeControl = true; // Flag to control charging based on Bluetooth command


BluetoothSerial SerialBT; // Bluetooth Serial object


// WiFi credentials

const char* ssid = "YOUR_SSID";

const char* password = "YOUR_PASSWORD";


// ThingSpeak credentials

unsigned long channelID = XXXXXX;

const char* writeAPIKey = "XXXXXXXXXXXXX";


WiFiClient client;


void setup() {

  Serial.begin(115200);

  SerialBT.begin("ESP32_Charger"); // Bluetooth device name

  pinMode(chargeControlPin, OUTPUT);

  ledcSetup(0, 5000, 8); // Channel 0, 5 kHz frequency, 8-bit resolution

  ledcAttachPin(chargeControlPin, 0); // Attach chargeControlPin to channel 0

  

  // Initialize the OLED display

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

    Serial.println(F("SSD1306 allocation failed"));

    for(;;);

  }

  display.clearDisplay();

  display.setTextSize(1);

  display.setTextColor(SSD1306_WHITE);


  // Connect to WiFi

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }

  Serial.println("WiFi connected");


  // Initialize ThingSpeak

  ThingSpeak.begin(client);

}


void loop() {

  // Check for Bluetooth serial input

  if (SerialBT.available()) {

    char receivedChar = SerialBT.read();

    if (receivedChar == '1') {

      nightMode = true;

    } else if (receivedChar == '0') {

      nightMode = false;

    } else if (receivedChar == '2') {

      chargeControl = false; // Stop charging

    }

  }


  float batteryVoltage = readBatteryVoltage();

  float chargingCurrent = readChargingCurrent();

  int batterySOC = calculateSOC(batteryVoltage);


  // Check if the battery voltage is below the activation threshold and charging is controlled

  chargingEnabled = (batteryVoltage <= activationVoltage) && chargeControl;


  // Send data to ThingSpeak

  ThingSpeak.setField(1, batteryVoltage);

  ThingSpeak.setField(2, chargingCurrent);

  ThingSpeak.setField(3, batterySOC);

  ThingSpeak.setField(4, nightMode ? 1 : 0);

  ThingSpeak.writeFields(channelID, writeAPIKey);


  // Display battery voltage, charging current, SOC, and night mode status on OLED

  display.clearDisplay();

  display.setCursor(0,0);

  display.print("Voltage: ");

  display.print(batteryVoltage);

  display.println(" V");

  display.print("Current: ");

  if (chargingCurrent < 0.09) {

    display.print("0 A");

  } else {

    display.print(chargingCurrent);

    display.println(" A");

  }

  display.print("SOC: ");

  display.print(batterySOC);

  display.println("%");

  display.print("Night Mode: ");

  display.println(nightMode ? "ON" : "OFF");

  display.print("Charging: ");

  display.println(chargingEnabled ? "ON" : "OFF");

  display.display();


  float currentLimit = nightMode ? nightModeChargingCurrent : maxChargingCurrent;


  if (chargingEnabled && batteryVoltage < maxChargingVoltage) {

    // Constant current mode

    if (!slowStartActive) {

      slowStartActive = true;

      slowStartTime = millis();

    }

    if (chargingCurrent < currentLimit) {

      if (millis() - slowStartTime < slowStartDuration) {

        // Slow start phase

        int dutyCycle = map(millis() - slowStartTime, 0, slowStartDuration, 0, 255);

        ledcWrite(0, dutyCycle);

      } else {

        // Normal charging phase

        ledcWrite(0, 255);

      }

    } else {

      ledcWrite(0, 0); // Maintain charging current

    }

  } else if (chargingEnabled && batteryVoltage >= maxChargingVoltage && batteryVoltage < floatVoltage) {

    // Constant voltage mode

    slowStartActive = false;

    ledcWrite(0, 127); // Adjust PWM to maintain voltage

  } else {

    // Float mode or charging disabled

    slowStartActive = false;

    ledcWrite(0, 0); // Stop charging

  }


  delay(1000);

}


float readBatteryVoltage() {

  int sensorValue = analogRead(voltageSensorPin);

  return sensorValue * (3.3 / 4095.0) * voltageDividerRatio;

}


float readChargingCurrent() {

  int sensorValue = analogRead(currentSensorPin);

  float voltage = sensorValue * (3.3 / 4095.0);

  return (voltage - 2.5) / currentSensorSensitivity; // Adjust for sensor offset

}


int calculateSOC(float voltage) {

  float soc = (voltage - minBatteryVoltage) / (maxChargingVoltage - minBatteryVoltage) * 100;

  return constrain((int)soc, 0, 100); // Ensure SOC is within 0-100%

}

Leave a Reply

Your email address will not be published. Required fields are marked *


Math Captcha
17 + = 22