diy solar

diy solar

Anyone working with the Overkill Solar Arduino lib?

[UPDATE]
I'm concluding that this is a voltage diff issue between the uarts and I am purchasing some line level / logic level converters to experiment with. For example...

 
Yes I have found 3.3v to 5V on the same bidirectional data lines works only some of the time...and then sometimes not on the same line.
You can use two BS180 fets to to translate the 3.3v Esp MU data to BMS direction to convert up to +5V and the BMS 5V might not need to be converted down to 3.3V for BMS to ESP data direction. Something like this circuit might work. Good Luck
Just saw your reply. Thank you!
 
By the way, your thread reminded me of this thread, some info in it that might help.


Sorry can't provide exact reason why it's not working, but I have experienced issues with 3.3v and 5v mixing in logic stuff in the past

this article helped me with logic level-fu https://learn.sparkfun.com/tutorials/logic-levels/all

1632259077924.png
 
Unfortunately, I cannot seem to get the serial connection to the bms to work. I'm sure I'm doing something wrong.

You bet. Attached is the fixed (I think) bms.cpp lib from the repo and my sketch inside overkill_sandbox.zip. The sketch is just dumping debug output right now. The photos and pinout are attached too.

I have not used the Vraw from the bms's port because it's 13v and also because I'm powering the board with the usb connection. You can see the gnd, rx and tx connected. I am using uart2. That is gpio17 for tx and gpio16 for rx. The blue wire is ground.
I could be mistaken, but do you have the TX and RX pins flipped?

On the BMS,
"TX" seems to mean "Tx From BMS -> World"
"RX" seems to mean "Rx From World -> BMS"

GPIO17 is TX for microcontroller to BMS, so that should go to "RX" on BMS right?
GPIO16 is RX for microcontroller from BMS, so that should go to "TX" on BMS right?

These little things catch me all the time with arduino land, so the deliberation is out of hope maybe the leads are switched out of unclear nomenclature perhaps? Pinout data from BMS Manual:
1632268379581.png

Good luck with the ongoing project (y)
 
By the way, your thread reminded me of this thread, some info in it that might help.


Sorry can't provide exact reason why it's not working, but I have experienced issues with 3.3v and 5v mixing in logic stuff in the past

this article helped me with logic level-fu https://learn.sparkfun.com/tutorials/logic-levels/all

View attachment 65739
nice. That does help
 
I could be mistaken, but do you have the TX and RX pins flipped?

On the BMS,
"TX" seems to mean "Tx From BMS -> World"
"RX" seems to mean "Rx From World -> BMS"

GPIO17 is TX for microcontroller to BMS, so that should go to "RX" on BMS right?
GPIO16 is RX for microcontroller from BMS, so that should go to "TX" on BMS right?

These little things catch me all the time with arduino land, so the deliberation is out of hope maybe the leads are switched out of unclear nomenclature perhaps? Pinout data from BMS Manual:
View attachment 65757

Good luck with the ongoing project (y)
Correct on this esp32s' uart2:
gpio17 is tx and goes to rx on the bms
gpio16 is rx and goes to tx on the bms

They were not swapped. Though I checked them probably a 1/2 dozen times.
 
Last edited:
Darn, figured to check, thank you

I'm trying to wire up a SAMD21 microcontroller (adafruit qtpy) to interface with my 4S JBD BMS. Using a 5V regulator to power it from VDD rail on BMS harness (in my case it's like 9V because i'm using a 4S BMS as a 3S BMS)

Will share if I can get any data out of it.
 
Ok, I thought I was clever and that the BMS would continually emit data packets. So I only wired up the Microcontroller RX from BMS wire.

This is all so the bluetooth dongle would remain usable alongside the microcontroller.

However, the SAMD21 microcontroller is indeed reading serial data only while Xiaoxiang app is connected to bluetooth dongle.

JBD-SP04S020-L4S-120A-B-U-K⸮⸮w⸮JBD-SP04S020-L4S-120A-B-U-K⸮⸮w⸮⸮c⸮*A

from very basic serial passthrough debug thing:

void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { if (Serial1.available()) { Serial.write(Serial1.read()); } }

So now I get to wire up the TX to BMS and think about what I will do about the bluetooth dongle. Probably leave it unplugged so that there is no problem of crosstalk between bluetooth dongle and microcontroller, leading to corrupted instructions to BMS. To use bluetooth dongle, I would need to disable the microcontroller or somehow put it into a state that prevents it from sending anything TX to BMS.

edit: ok, I pasta'd the overkill_sandbox printing lines to do some Serial Debugging(tm) and got some partially populated data structures. probably because it can't ask for any data. only observe what is being printed as a result of the bluetooth dongle being connected and mobile xiaoxiang app in foreground streaming data.
Voltage: 9.680 volts Current:0.0 amps {name:,voltage:9.68,current:0.00,voltageDiff: inf,soc:50,cFet:1,dFet:1,lowestCell:0.00,highestCell: inf

what i got so far.
 
Last edited:
Ok, I thought I was clever and that the BMS would continually emit data packets. So I only wired up the Microcontroller RX from BMS wire.

This is all so the bluetooth dongle would remain usable alongside the microcontroller.

However, the SAMD21 microcontroller is indeed reading serial data only while Xiaoxiang app is connected to bluetooth dongle.

JBD-SP04S020-L4S-120A-B-U-K⸮⸮w⸮JBD-SP04S020-L4S-120A-B-U-K⸮⸮w⸮⸮c⸮*A

from very basic serial passthrough debug thing:

void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { if (Serial1.available()) { Serial.write(Serial1.read()); } }

So now I get to wire up the TX to BMS and think about what I will do about the bluetooth dongle. Probably leave it unplugged so that there is no problem of crosstalk between bluetooth dongle and microcontroller, leading to corrupted instructions to BMS. To use bluetooth dongle, I would need to disable the microcontroller or somehow put it into a state that prevents it from sending anything TX to BMS.

edit: ok, I pasta'd the overkill_sandbox printing lines to do some Serial Debugging(tm) and got some partially populated data structures. probably because it can't ask for any data. only observe what is being printed as a result of the bluetooth dongle being connected and mobile xiaoxiang app in foreground streaming data.
Voltage: 9.680 volts Current:0.0 amps {name:,voltage:9.68,current:0.00,voltageDiff: inf,soc:50,cFet:1,dFet:1,lowestCell:0.00,highestCell: inf

what i got so far.
If you haven't already, check out the readme for furtrader's lib. You have to request the data from the bms.
 
Thank you! I'll solder in the TX wire and see what happens! lol hope these headway cells don't explode.
 
There's another user who is pulling data from an Outback Skybox and using a cloud-based app to generate a nice UI. Combining this with that would be a win, I think.

Also, I think I read the ESP32s are very sensitive to >3.3v level inputs. I.e., they can wreck the input. One discussion here:
 
Cool, it works, mostly...

1632278506593.png
pololu 5v regulator on left, SAMD21 microcontroller on right. no resistors, just wires connecting stuff. no bluetooth dongle attached.

Voltage: 9.650 volts Current:-0.5 amps {name:JBD-SP04S020-L4S-120A-B-U-K,voltage:9.65,current:-0.53,voltageDiff: inf,soc:50,cFet:1,dFet:1,lowestCell:0.00,highestCell: inf

1632278299770.png

edit: the cell voltage reading works now. had to reduce N in a line of code from 16 to 3 because I don't have 16 cells. have 3.

Voltage: 9.610 volts Current:-0.5 amps {name:JBD-SP04S020-L4S-120A-B-U-K,voltage:9.61,current:-0.53,voltageDiff:0.01,soc:49,cFet:1,dFet:1,lowestCell:3.20,highestCell:3.21

woohoo.

here's the entire code
C++:
#include "bms.h"
#define NUM_CELLS 3
OverkillSolarBms bms = OverkillSolarBms();
uint32_t last_update;

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
  while (!Serial) {  // Wait for the debug serial port to initialize
  }
  while (!Serial1) {  // Wait for the BMS serial port to initialize
  }
  last_update = millis();
  bms.begin(&Serial1);
}

void loop() {
  bms.main_task();

  // print status every 2.5 seconds
  if (millis() - last_update >= 2500) {
    // Get voltage
    float voltage = bms.get_voltage();
    Serial.print("Voltage: ");
    Serial.print(voltage, 3);
    Serial.println(" volts");
    // Get current
    float current = bms.get_current();
    Serial.print("Current:" );
    Serial.print(current, 1);
    Serial.println(" amps");
    // Get voltage diff
    float lowest = 99;
    float highest = 0;
    float v = 0;
    for (int i = 0; i < NUM_CELLS; i++) {
      v = bms.get_cell_voltage(i);
      if (v < lowest) {
        lowest = v;
      }
      if (v > highest) {
        highest = v;
      }
    }
    float voltageDiff = highest - lowest;
    // Get state of charge
    uint8_t soc = bms.get_state_of_charge();
    //  Get charge fet status
    bool cFet = bms.get_charge_mosfet_status() ? "on" : "off";
    // Get discharge fet status
    bool dFet = bms.get_discharge_mosfet_status() ? "on" : "off";
    //     // Get flags
    ProtectionStatus flags = bms.get_protection_status();
    String flagString = "{";
    flagString += (String)"single_cell_overvoltage_protection" + ":" + flags.single_cell_overvoltage_protection;
    flagString += (String)",single_cell_undervoltage_protection" + ":" + flags.single_cell_undervoltage_protection;
    flagString += (String)",whole_pack_overvoltage_protection" + ":" + flags.whole_pack_overvoltage_protection;
    flagString += (String)",whole_pack_undervoltage_protection" + ":" + flags.whole_pack_undervoltage_protection;
    flagString += (String)",charging_over_temperature_protection" + ":" + flags.charging_over_temperature_protection;
    flagString += (String)",charging_low_temperature_protection" + ":" + flags.charging_low_temperature_protection;
    flagString += (String)",discharge_over_temperature_protection" + ":" + flags.discharge_over_temperature_protection;
    flagString += (String)",discharge_low_temperature_protection" + ":" + flags.discharge_low_temperature_protection;
    flagString += (String)",charging_overcurrent_protection" + ":" + flags.charging_overcurrent_protection;
    flagString += (String)",discharge_overcurrent_protection" + ":" + flags.discharge_overcurrent_protection;
    flagString += (String)",short_circuit_protection" + ":" + flags.short_circuit_protection;
    flagString += (String)",front_end_detection_ic_error" + ":" + flags.front_end_detection_ic_error;
    flagString += (String)",software_lock_mos" + ":" + flags.software_lock_mos;
    flagString += "}";
    // Get bms name
    String name = bms.get_bms_name();
    // Build the json we'll send
    String jsonStr = "{";
    jsonStr += "name:" + (String)name;
    jsonStr += ",voltage:" + (String)voltage;
    jsonStr += ",current:" + (String)current;
    jsonStr += ",voltageDiff:" + (String)voltageDiff;
    jsonStr += ",soc:" + (String)soc;
    jsonStr += ",cFet:" + (String)cFet;
    jsonStr += ",dFet:" + (String)dFet;
    jsonStr += ",lowestCell:" + (String)lowest;
    jsonStr += ",highestCell:" + (String)highest;

    //    Serial.print(flagString);
    Serial.print(jsonStr);
    Serial.println();

    last_update = millis();
  }
}

if someone wants to adapt this, please be sure to change the part for (int i = 0; i < 3; i++) { to be the number of cells you have instead of 3.

change NUM_CELLS at top to be the number of cells you have.
 
Last edited:
There's another user who is pulling data from an Outback Skybox and using a cloud-based app to generate a nice UI. Combining this with that would be a win, I think.

Also, I think I read the ESP32s are very sensitive to >3.3v level inputs. I.e., they can wreck the input. One discussion here:
I read the same thing... but, after I connected it to the tx and rx of the bms. ?

...I plan to do a other esp32 to esp32 serial test to be sure it still works.
 
Cool, it works, mostly...

View attachment 65778
pololu 5v regulator on left, SAMD21 microcontroller on right. no resistors, just wires connecting stuff. no bluetooth dongle attached.

Voltage: 9.650 volts Current:-0.5 amps {name:JBD-SP04S020-L4S-120A-B-U-K,voltage:9.65,current:-0.53,voltageDiff: inf,soc:50,cFet:1,dFet:1,lowestCell:0.00,highestCell: inf

View attachment 65769

edit: the cell voltage reading works now. had to reduce N in a line of code from 16 to 3 because I don't have 16 cells. have 3.

Voltage: 9.610 volts Current:-0.5 amps {name:JBD-SP04S020-L4S-120A-B-U-K,voltage:9.61,current:-0.53,voltageDiff:0.01,soc:49,cFet:1,dFet:1,lowestCell:3.20,highestCell:3.21

woohoo.

here's the entire code
C++:
#include "bms.h"
OverkillSolarBms bms = OverkillSolarBms();
uint32_t last_update;

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
  while (!Serial) {  // Wait for the debug serial port to initialize
  }
  while (!Serial1) {  // Wait for the BMS serial port to initialize
  }
  last_update = millis();
  bms.begin(&Serial1);
}

void loop() {
  bms.main_task();

  // print status every 2.5 seconds
  if (millis() - last_update >= 2500) {
    // Get voltage
    float voltage = bms.get_voltage();
    Serial.print("Voltage: ");
    Serial.print(voltage, 3);
    Serial.println(" volts");
    // Get current
    float current = bms.get_current();
    Serial.print("Current:" );
    Serial.print(current, 1);
    Serial.println(" amps");
    // Get voltage diff
    float lowest = 99;
    float highest = 0;
    float v = 0;
    for (int i = 0; i < 3; i++) {
      v = bms.get_cell_voltage(i);
      if (v < lowest) {
        lowest = v;
      }
      if (v > highest) {
        highest = v;
      }
    }
    float voltageDiff = highest - lowest;
    // Get state of charge
    uint8_t soc = bms.get_state_of_charge();
    //  Get charge fet status
    bool cFet = bms.get_charge_mosfet_status() ? "on" : "off";
    // Get discharge fet status
    bool dFet = bms.get_discharge_mosfet_status() ? "on" : "off";
    //     // Get flags
    ProtectionStatus flags = bms.get_protection_status();
    String flagString = "{";
    flagString += (String)"single_cell_overvoltage_protection" + ":" + flags.single_cell_overvoltage_protection;
    flagString += (String)",single_cell_undervoltage_protection" + ":" + flags.single_cell_undervoltage_protection;
    flagString += (String)",whole_pack_overvoltage_protection" + ":" + flags.whole_pack_overvoltage_protection;
    flagString += (String)",whole_pack_undervoltage_protection" + ":" + flags.whole_pack_undervoltage_protection;
    flagString += (String)",charging_over_temperature_protection" + ":" + flags.charging_over_temperature_protection;
    flagString += (String)",charging_low_temperature_protection" + ":" + flags.charging_low_temperature_protection;
    flagString += (String)",discharge_over_temperature_protection" + ":" + flags.discharge_over_temperature_protection;
    flagString += (String)",discharge_low_temperature_protection" + ":" + flags.discharge_low_temperature_protection;
    flagString += (String)",charging_overcurrent_protection" + ":" + flags.charging_overcurrent_protection;
    flagString += (String)",discharge_overcurrent_protection" + ":" + flags.discharge_overcurrent_protection;
    flagString += (String)",short_circuit_protection" + ":" + flags.short_circuit_protection;
    flagString += (String)",front_end_detection_ic_error" + ":" + flags.front_end_detection_ic_error;
    flagString += (String)",software_lock_mos" + ":" + flags.software_lock_mos;
    flagString += "}";
    // Get bms name
    String name = bms.get_bms_name();
    // Build the json we'll send
    String jsonStr = "{";
    jsonStr += "name:" + (String)name;
    jsonStr += ",voltage:" + (String)voltage;
    jsonStr += ",current:" + (String)current;
    jsonStr += ",voltageDiff:" + (String)voltageDiff;
    jsonStr += ",soc:" + (String)soc;
    jsonStr += ",cFet:" + (String)cFet;
    jsonStr += ",dFet:" + (String)dFet;
    jsonStr += ",lowestCell:" + (String)lowest;
    jsonStr += ",highestCell:" + (String)highest;

    //    Serial.print(flagString);
    Serial.print(jsonStr);
    Serial.println();

    last_update = millis();
  }
}

if someone wants to adapt this, please be sure to change the part for (int i = 0; i < 3; i++) { to be the number of cells you have instead of 3.
Right on!
 
Cool, it works, mostly...

View attachment 65778
pololu 5v regulator on left, SAMD21 microcontroller on right. no resistors, just wires connecting stuff. no bluetooth dongle attached.

Voltage: 9.650 volts Current:-0.5 amps {name:JBD-SP04S020-L4S-120A-B-U-K,voltage:9.65,current:-0.53,voltageDiff: inf,soc:50,cFet:1,dFet:1,lowestCell:0.00,highestCell: inf

View attachment 65769

edit: the cell voltage reading works now. had to reduce N in a line of code from 16 to 3 because I don't have 16 cells. have 3.

Voltage: 9.610 volts Current:-0.5 amps {name:JBD-SP04S020-L4S-120A-B-U-K,voltage:9.61,current:-0.53,voltageDiff:0.01,soc:49,cFet:1,dFet:1,lowestCell:3.20,highestCell:3.21

woohoo.

here's the entire code
C++:
#include "bms.h"
OverkillSolarBms bms = OverkillSolarBms();
uint32_t last_update;

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
  while (!Serial) {  // Wait for the debug serial port to initialize
  }
  while (!Serial1) {  // Wait for the BMS serial port to initialize
  }
  last_update = millis();
  bms.begin(&Serial1);
}

void loop() {
  bms.main_task();

  // print status every 2.5 seconds
  if (millis() - last_update >= 2500) {
    // Get voltage
    float voltage = bms.get_voltage();
    Serial.print("Voltage: ");
    Serial.print(voltage, 3);
    Serial.println(" volts");
    // Get current
    float current = bms.get_current();
    Serial.print("Current:" );
    Serial.print(current, 1);
    Serial.println(" amps");
    // Get voltage diff
    float lowest = 99;
    float highest = 0;
    float v = 0;
    for (int i = 0; i < 3; i++) {
      v = bms.get_cell_voltage(i);
      if (v < lowest) {
        lowest = v;
      }
      if (v > highest) {
        highest = v;
      }
    }
    float voltageDiff = highest - lowest;
    // Get state of charge
    uint8_t soc = bms.get_state_of_charge();
    //  Get charge fet status
    bool cFet = bms.get_charge_mosfet_status() ? "on" : "off";
    // Get discharge fet status
    bool dFet = bms.get_discharge_mosfet_status() ? "on" : "off";
    //     // Get flags
    ProtectionStatus flags = bms.get_protection_status();
    String flagString = "{";
    flagString += (String)"single_cell_overvoltage_protection" + ":" + flags.single_cell_overvoltage_protection;
    flagString += (String)",single_cell_undervoltage_protection" + ":" + flags.single_cell_undervoltage_protection;
    flagString += (String)",whole_pack_overvoltage_protection" + ":" + flags.whole_pack_overvoltage_protection;
    flagString += (String)",whole_pack_undervoltage_protection" + ":" + flags.whole_pack_undervoltage_protection;
    flagString += (String)",charging_over_temperature_protection" + ":" + flags.charging_over_temperature_protection;
    flagString += (String)",charging_low_temperature_protection" + ":" + flags.charging_low_temperature_protection;
    flagString += (String)",discharge_over_temperature_protection" + ":" + flags.discharge_over_temperature_protection;
    flagString += (String)",discharge_low_temperature_protection" + ":" + flags.discharge_low_temperature_protection;
    flagString += (String)",charging_overcurrent_protection" + ":" + flags.charging_overcurrent_protection;
    flagString += (String)",discharge_overcurrent_protection" + ":" + flags.discharge_overcurrent_protection;
    flagString += (String)",short_circuit_protection" + ":" + flags.short_circuit_protection;
    flagString += (String)",front_end_detection_ic_error" + ":" + flags.front_end_detection_ic_error;
    flagString += (String)",software_lock_mos" + ":" + flags.software_lock_mos;
    flagString += "}";
    // Get bms name
    String name = bms.get_bms_name();
    // Build the json we'll send
    String jsonStr = "{";
    jsonStr += "name:" + (String)name;
    jsonStr += ",voltage:" + (String)voltage;
    jsonStr += ",current:" + (String)current;
    jsonStr += ",voltageDiff:" + (String)voltageDiff;
    jsonStr += ",soc:" + (String)soc;
    jsonStr += ",cFet:" + (String)cFet;
    jsonStr += ",dFet:" + (String)dFet;
    jsonStr += ",lowestCell:" + (String)lowest;
    jsonStr += ",highestCell:" + (String)highest;

    //    Serial.print(flagString);
    Serial.print(jsonStr);
    Serial.println();

    last_update = millis();
  }
}

if someone wants to adapt this, please be sure to change the part for (int i = 0; i < 3; i++) { to be the number of cells you have instead of 3.
Very nice. Thanks for providing the code. Suggestion: parameterize the number of cells:
#define NUM_CELLS 16
at the top after the include
 
Are those round silver dudes under the bms your battery cell's terminals? They're awful close to the bms case.
?they are close but it is mounted in a way that they cannot say hello to each other and have an angry pixie duel haha

1632341835732.jpeg

double sided tape to prevent lateral slippage and strapped down for normal use with legendary gaffer tape, multiple rounds to prevent unravel. a real janky hack job ? but held right before i disassembled earlier this month to take photos of the mosfets under the thermal pads. i want to 3d print some joinery and have some sheets laser cut to make it more proper one day..
 
Last edited:
Back
Top