diy solar

diy solar

For those of you looking to monitor your ANT-BMS with Pi3 via Bluetooth.

Thank you, but I don't know what all that means and how to put it in a code :)

I have found some info of maybe "reverse-engineering" of the VBMS app and how it communicates with the BMS, if it's of any help, I'm not a coder:
https://github.com/FastDeath/VBMS/w...AzlmP-tSmURCAUn4wFb11SW8T9qkK7nVeStFZ_A9uX53Q
Holy shit! That's a great find! I've been trying to figure out how the checksum is calculated, and made very little progress, so this definitely helps a lot.
 
Unfortunately, the checksum method doesn't seem to work, or something else is required (maybe a secondary command with the "apply" address has to be sent, not sure), but thanks for the link.

I did take a look at the addresses for the temps, and looks like you can get battery sensor 1 and 2, balance temp, and "power" temp (which I assume covers both the charge and discharge mosfets)?

data = (Antw33.encode('hex') [92*2:92*2+2])
data=int(data,16)
print "Power Temp (top left): ",data

data = (Antw33.encode('hex') [94*2:94*2+2])
data=int(data,16)
print "Balance Temp: ",data

data = (Antw33.encode('hex') [96*2:96*2+2])
data=int(data,16)
print "Battery Temp Sensor 1: ",data

data = (Antw33.encode('hex') [98*2:98*2+2])
data=int(data,16)
print "Battery Temp Sensor 2: ",data

I confirmed the numbers above against the info on the LCD, the values are in celsius.
 
Thank you very much for the code for temps, yes the "top left" temperature is "MOS" and it covers both charge/discharge.
I have installed AL radiators on my BMS, so I can use more than the rated 50A charging current (seems that 70A is OK if MOS is cooled), also on discharge it gets pretty hot at 100-120A, even though it's rated for 300A discharge. Monitoring the MOS temperature in Grafana together with in/out amps in timegraph is awesome! Also the BMS is rated for 0.1A balancing current, but there is no problem even at 0.2A, if (again) cooling is good. There was software limitation to max. 0.2A balancing current in the Android apps I've used, maybe with this direct approach via RPi we can get beyond?
@pjones - you have PM about the checksum (for anyone wondering, it's information that has personal data).
 
...does anyone who know actually makes ANT BMS? It's not LLT, I think they make the JDK one.
@fhorst do you still have the link to the factory you sent me last summer? I can't find it.
I was in communication with someone at the factory for a while (2 ANT BMS mysteriously died)
 
@fhorst do you still have the link to the factory you sent me last summer? I can't find it.
I was in communication with someone at the factory for a while (2 ANT BMS mysteriously died)


I think they are the ones behind the BMS... The app for Android is called Mayi-BMS and there is a link to download it from their site, then you can side load it.
 
Has anyone tried to connect to an ANT BMS using an ESP32?

I haven't but I'd imagine if someone had the skills and effort, it might be possible, but maybe not worth the effort since almost any PI could work, and without Python, it might take some work to debug?
 
Holy shit! That's a great find! I've been trying to figure out how the checksum is calculated, and made very little progress, so this definitely helps a lot.

BTW, I can control the BMS now. The checksum is just the sum of the 3 bytes (address + data + data).

So.... sending it:

'A5A5FA0000FA' # Turn Off Charge MOSFET
'A5A5FA0001FB' # Turn On Charge MOSFET
'A5A5FE0000FE' # Reboot BMS
'A5A5F90000F9' # Turn Off DisCharge MOSFET
'A5A5F90001FA' # Turn On DisCharge MOSFET
'A5A5FC0000FC' # Toggles balancing

Adding this in case the future me forgets and has to google it. :)
 
Thank you very much for the code for temps, yes the "top left" temperature is "MOS" and it covers both charge/discharge.
I have installed AL radiators on my BMS, so I can use more than the rated 50A charging current (seems that 70A is OK if MOS is cooled), also on discharge it gets pretty hot at 100-120A, even though it's rated for 300A discharge. Monitoring the MOS temperature in Grafana together with in/out amps in timegraph is awesome! Also the BMS is rated for 0.1A balancing current, but there is no problem even at 0.2A, if (again) cooling is good. There was software limitation to max. 0.2A balancing current in the Android apps I've used, maybe with this direct approach via RPi we can get beyond?
@pjones - you have PM about the checksum (for anyone wondering, it's information that has personal data).
I'd love to see your cooling system on an ANTbms - currently one of the biggest limitations on my solar system is only charging at 50A and wasting solar power that could be used for charging. Raising to 70A would be perfect.
 
I'd love to see your cooling system on an ANTbms - currently one of the biggest limitations on my solar system is only charging at 50A and wasting solar power that could be used for charging. Raising to 70A would be perfect.
Me too. I've had 2 of these burn up.
1 charging mosfet just failed (the BMS had gone into short circuit protection and never worked again).
2nd one claims wires disconnected; I checked the soldering and all is good so who knows.
After that all is golden though so I have parts from the first 2 (sigh).
 
I haven't but I'd imagine if someone had the skills and effort, it might be possible, but maybe not worth the effort since almost any PI could work, and without Python, it might take some work to debug?
Thanks, I'll probably use my old Pi to get things rolling then *if* I get it all working I'll play with the esp32.
I'm not so much interested in cataloging the data as much as being able to send and receive commands to the BMS in an automated fashion and I dont want to buy a bunch of Pis for each battery.
 
Thanks, I'll probably use my old Pi to get things rolling then *if* I get it all working I'll play with the esp32.
I'm not so much interested in cataloging the data as much as being able to send and receive commands to the BMS in an automated fashion and I dont want to buy a bunch of Pis for each battery.

You don't have to have a Pi for each BMS, I am not sure what the limit is, but I have a Pi talking to 2 right now and I am sure rfcomm can do more than that.
 
You don't have to have a Pi for each BMS, I am not sure what the limit is, but I have a Pi talking to 2 right now and I am sure rfcomm can do more than that.
Yeah I know but these will be at different locations. a PI is really overkill for what I want to do (though cool for the project being discussed in this thread) :) I only need to do occasional reads and command issuance and ESP32's are like $3 here.
 
Can someone help me out with a simple logic in Node-RED with this code?
I need to sent a command (message) via MQTT in Node, if the battery charge goes below certain point, lets say <15%
Can someone explain me how to do this, I tried several methods via the "switch" function, but don't know how to "extract" the value of a specific column of the python code?

About the cooling I'm using, I will add photos soon, it's just a radiator with fins attached to the BMS plate. Also it's not only the temperature problem, the mosfets have physical current limitations also, so I'm really at risk with 70A
 
Hi all, Chad used parts of the code I wrote and posted in GitHub. https://github.com/juamiso/ANT_BMS

I have the ANT BMS running since July 2019 in combination with a Raspi 3B+ connected via Bluetooth. It is pretty robust I must say! Via the python control script the Raspi sends the data I want to log directly to an influxdb server (local network but running in another computer). And this other computer runs grafana and I can monitor from anywhere very useful stuff. See:

View attachment 28371
View attachment 28372
View attachment 28373
Hi im having som problems with my code. I want my system to work the same. sending data to a influx database.. is it possible you are willing to share your code?
 
Hi everyone,
i copied this script in to my system. I wanted to run this but there is a repeating error in the 113th line stating: error expected indented block.
I´m at my wits limit and can not find a solution. Maybe one of you can help me out here...
- if it is easier for anyone i am not native in english but in german so answer with whatever you prefer.
Thanks in advance

Python:
import sys
import time
import serial
import struct
from binascii import unhexlify
import requests as req
import bluetooth
from bluetooth import *
import sys
#if sys.version < '3':
#    input = raw_input
bd_addr = "AA:BB:CC:A1:23:45"
port = 1
#sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
#sock.connect((bd_addr, port))
#sock.close()
#time.sleep(1)
#Define RS485 serial port
ser = serial.Serial(
    port='/dev/rfcomm2',
    baudrate = 9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout = 1)
 
#while True :
test='DBDB00000000'
try:
 ser.write (test.decode('hex'))
except:
 ser.close()
time.sleep(3)
Antw33 = ser.read(140)
#SoC
data = (Antw33.encode('hex') [(74*2):(75*2)])
print data
try:
  resp = req.get(url+'SoC'+'?value='+str(int(data,16)))
except:
  pass
#Power
data = (Antw33.encode('hex') [(111*2):(114*2+2)])
try:
  if int(data,16)>2147483648:
    data=(-(2*2147483648)+int(data,16))
    print data
  else:
    data=int(data,16)
    print data
  resp = req.get(url+'BMS_pow'+'?value='+str(data))
except:
   pass
data=0
print data
print data
print data
print data
time.sleep(1)
#BMS current
data = (Antw33.encode('hex') [(70*2):(73*2+2)])
try:
   if int(data,16)>2147483648:
     data=(-(2*2147483648)+int(data,16))*0.1
     print data
   else:
     data = int(data,16)*0.1
     print data
   resp = req.get(url+'BMS_Current'+'?value='+str(data))
except:
   pass
#BMS V
data = (Antw33.encode('hex') [8:12])
data = struct.unpack('>H',unhexlify(data))[0]*0.1
print data
try:
   resp = req.get(url+'BMS_V'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.1))

except:
   pass
#Cell_avg
data = (Antw33.encode('hex') [(121*2):(122*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell_avg'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_min
data = (Antw33.encode('hex') [(119*2):(120*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell_min'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_max
data = (Antw33.encode('hex') [(116*2):(117*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell_max'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
 #Cell_1
data = (Antw33.encode('hex') [(6*2):(7*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell1'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_2
data = (Antw33.encode('hex') [(8*2):(9*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell2'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
 #Cell_3
data = (Antw33.encode('hex') [(10*2):(11*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell3'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
 #Cell_4
data = (Antw33.encode('hex') [(12*2):(13*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell4'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
 #Cell_5
data = (Antw33.encode('hex') [(14*2):(15*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell5'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_6
data = (Antw33.encode('hex') [(16*2):(17*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell6'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_7
data = (Antw33.encode('hex') [(18*2):(19*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell7'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_8
data = (Antw33.encode('hex') [(20*2):(21*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell8'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_9
data = (Antw33.encode('hex') [(22*2):(23*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell9'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_10
data = (Antw33.encode('hex') [(24*2):(25*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell10'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_11
data = (Antw33.encode('hex') [(26*2):(27*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell11'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_12
data = (Antw33.encode('hex') [(28*2):(29*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell12'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_13
data = (Antw33.encode('hex') [(30*2):(31*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell13'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_14
data = (Antw33.encode('hex') [(32*2):(33*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell14'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_15
data = (Antw33.encode('hex') [(34*2):(35*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell15'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
#Cell_16
data = (Antw33.encode('hex') [(36*2):(37*2+2)])
data = struct.unpack('>H',unhexlify(data))[0]*0.001
print data
try:
  resp = req.get(url+'cell16'+'?value='+str((struct.unpack('>H',unhexlify(data))[0])*0.001))
except:
  pass
 
ser.close()
 

Hi

I´m having problems.. bluetooth is paired and connected. bd_addr = "AA:BB:CC:A1:23:45"
when I run sudo python getbms-ant.py this come back....

sudo python getbms-ant.py
Traceback (most recent call last):
File "getbms-ant.py", line 41, in <module>
Antw33 = ser.read(140)
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 478, in read
raise portNotOpenError
serial.serialutil.SerialException: Attempting to use a port that is not open
 
serial.serialutil.SerialException: Attempting to use a port that is not open
Hi,

Does anybody have a solution for this problem? I managed to send the BMS data to MQTT and it works fine for a few minutes and then the script stops because of this error and most of the time I can't restart it (it always gives the same error)
 
Back
Top