diy solar

diy solar

Semi-DIY BMS: Active Balancer + Microcontroller

UPDATE ON BMS COMMS - While I wait for some parts to come in, I turned my attention to communications. Specifically, getting my MCU to communicate with my Growatt SPF-series inverters. This has been quite a learning experience, but I'm finally starting to make some progress. I've got the Inverter set to LI battery mode, with the protocol set to L-02 (the PylonTech protocol). Using a cheep logic analyzer, I've confirmed that the inverter is following the PylonTech RS232 communication protocol (see screenshot below). I'm using a MAX485-module for converting RS485 to/from UART. For testing/development, I'm just using a Arduino Nano clone.

I'm currently to the point where I'm sending the inverter one of the example strings provided in the PylonTech protocol. I'm sending it once per second, and it seems to keep the Inverter happy (no more fault error). I've also confirmed that the SOC value i'm sending it is what's now being displayed by the Inverter, which is a big success (for a rube like me, anyway).

Now I'm working on figuring out the CheckSum and InfoLength functions so I can start sending actual data to the inverter without checksum or length errors. Lots more to do to figure all this out.

I would greatly appreciate any help on this. If anyone has a similar setup (Growatt or MPP inverter that communicates with BMS over RS485), I'm happy to send you the details on this setup (cable specs, code, etc.) so we can collaborate on getting this all figured out.

Screen Shot 2021-03-29 at 10.52.40 AM.png
 
IIRC there's at least one thread of someone doing something similar and IIRC again he made a git repo. I recommend to use the search feature to try to find that thread (I don't have it on hand, sorry) ;)
 
IIRC there's at least one thread of someone doing something similar and IIRC again he made a git repo. I recommend to use the search feature to try to find that thread (I don't have it on hand, sorry) ;)

I managed to find an interesting thread about using an Arduino to 'hack' the RS-485 comms on Valance batteries, but in that case, the communication protocol was completely DIY. I'm really hoping that I can emulate the PylonTech RS232 protocol. I'm not finding any examples of that on the forums, but I might be missing it.

The part I'm really struggling with is all the conversions to/from ASCII to HEX to BINARY. And the CHKSUM use a 'modulus 35536' conversion while the Length CHKSUM uses a 'modulus 16' conversion (still struggling on how to apply those). I'm sure that someone with more coding experience could figure this all out in a matter of hours, if not minutes. I'm just starting from scratch, so its going to take me a while.
 
I think you wanted to say modulo: https://en.wikipedia.org/wiki/Modulo_operation ;)

And if I had to guess it's 65536 instead of 35536.

For the conversions part I can't say anything useful without more details from you (i.e. from what to what you want to convert?, for what purpose?, example?).
Yeah...you're right on all counts. Need to slow down a bit on these posts.

I've created a simple sketch that calculates the checksum values, which seem to match all the examples in the protocol. That's a relief. I'm pretty sure my sums will never exceed 65536, so I think i can probably ignore the modulo operation (for now, anyway).

The piece I'm struggling with is that the protocol provides all the example commands and responses in hex strings, with each 8-bit Hex value correspond an individual ASCII character. My checksum calculator gives me a hex string as well, but its a 4-digit Hex (eg, "FD35" or "E553"). I've highlighted the corresponding checksum values from two of the examples in the protocol. Is "FD35" the same - from a UART transmission perspective - as "0x46, 0x44, 0x33, 0x35"? Or do I need to somehow 'parse' FD35 and change it to 46 44 33 35 before transmission?

Sorry, realize that this is probably taught in 'coding 101' but sadly, I didn't take that one... No worries if you don't have time to teach me the basics. I'm sure I'll figure it out eventually!


Host Commands: 7E 32 30 30 31 34 36 34 32 45 30 30 32 30 31 46 44 33 35 0D

:Reply Data: 7E 32 30 30 31 34 36 30 30 43 30 36 45 31 31 30 31 30
46 30 44 34 35 30 44 34 34 30 44 34 35 30 44 34 34 30 44 34 35 30 44 34
34 30 44 33 45 30 44 34 35 30 44 34 41 30 44 34 41 30 44 34 42 30 44 34
41 30 44 34 41 30 44 34 41 30 44 34 41 30 35 30 42 43 33 30 42 43 33 30
42 43 33 30 42 43 44 30 42 43 44 30 30 30 30 43 37 32 35 42 46 36 38 30
32 43 33 35 30 30 30 30 32 45 35 35 33 0D
 
I don't recognize this method .... but it looks to me like it is 30 plus the hex to decimal value of the of each number.
F=16 , D=14, 5=5, 3=3
30 +16 = 46 30 + 14 = 34 30 + 5=35 30 + 3 = 33
 
I don't recognize this method .... but it looks to me like it is 30 plus the hex to decimal value of the of each number.
F=16 , D=14, 5=5, 3=3
30 +16 = 46 30 + 14 = 34 30 + 5=35 30 + 3 = 33
46, 44, 35, and 33 are the HEX equivalents of the ASCII characters F, D, 5, and 3 (which also correspond to the '30+' decimal equivalents, as you've pointed out). The protocol employs ASCII characters for pretty much all values. For example, the cell voltage values are provided as 30, 44, 34, 35, which is the the equivalent of 0D45, which can then be converted to the the decimal equivalent of 3397 mV. To do that, I'm taking the original hex numbers (30, 44, 34, 45), converting those to decimal values (48, 68, 52, 53) using the "HEX2DEC" excel function, then converting those to ASCII characters (0, D, 5, 3) using the "CHAR" function. Then I use the "HEX2DEC" function again to convert those values to a string of decimals (3, 3, 9, 7). Does not make any sense to me, but it works...in excel. I'm pretty sure I'm just confusing myself by trying to figure this all out in excel.
 
I've highlighted the corresponding checksum values from two of the examples in the protocol. Is "FD35" the same - from a UART transmission perspective - as "0x46, 0x44, 0x33, 0x35"? Or do I need to somehow 'parse' FD35 and change it to 46 44 33 35 before transmission?

You receive and send bytes. Those bytes can be displayed as ASCII characters or as any other thing you like. The question is what is the protocol spec? is it made for ASCII? or something else?

Ok, nevermind, you answered that later:

The protocol employs ASCII characters for pretty much all values.

But are you absolutely certain of this?


To do that, I'm taking the original hex numbers (30, 44, 34, 45), converting those to decimal values (48, 68, 52, 53) using the "HEX2DEC" excel function, then converting those to ASCII characters (0, D, 5, 3) using the "CHAR" function. Then I use the "HEX2DEC" function again to convert those values to a string of decimals (3, 3, 9, 7). Does not make any sense to me, but it works...in excel. I'm pretty sure I'm just confusing myself by trying to figure this all out in excel.

Oh god...

Also 0D53 isn't equal to 3397 but to 3411 so not sure what happens here.

Let's start from the start: what do you use on the PC to read the data from the RS485 adapter?
 
Sorry everyone. I really should have dug deeper into figuring this out before asking for any help. I realize that Excel is NOT the appropriate tool for this project, I'm just using it to try to learn how it works before jumping into the coding. And yes, once again, I put the wrong info into that response (0D45 (not 0D53) = 3397). Sorry for the confusion. I promise that will be the last time I respond using my phone!

From the protocol:

"The Basic data format SOI and EOI are explained and transferred in hexadecimal, the other items are explained in hexadecimal and transferred by hexadecimal-ASCII, each byte contains two ASCII e.g. CID2 4BH transfer 2byte: 34H the ASCII of ‘4’) and 42H(the ASCII of ‘B’)."

I'd share the full protocol, but I don't know that it's public information.

I'm using an Arduino Nano + MAX485 module for communicating with the inverter. At this point, I'm just using the serial monitor to view the string that the Inverter is sending. The 'command' strings I'm seeing from the inverter look just like the examples I posted above, and follow the format detailed in the protocol exactly. And all I'm sending to the inverter at this point is one of the example strings in the protocol. That seems to be enough to keep the inverter satisfied (ie, no faults or shutdowns).

I'm going to take a crack at creating a 'custom' response string to the inverter tomorrow. That will use the checksum calculator I put together. I'll let you know how that goes.

Thanks for all the help!
 
There are some existing checksum libraries for C which cover most common types.

You can have the serial.print() the frames as hex, ascii, binary. Putting them side by side in the output can be helpful. You may need to concatenate the bytes depending on how you are storing/receiving the data.

I like to comma delineate for easy transfer to excel or other software for sorting/analysis.

There are other serial terminal apps with better functionality than the IDE built in monitor.

There are also serial logging tools which can be configured to do lots of helpful stuff, but I haven't used any myself.
 
Last edited:
Ok, that explains a lot ;)

So, yes, excel is far from ideal for that job. Especially since with pretty much any programming language you would be able to do conversions much more easily (like no need to use decimal for example, you can convert from hex to ASCII directly) and same for the checksum. And you could read the serial port directly, no need to copy-paste with all the problems that brings.

So yea, I really recommend to do a proper program instead of using excel ;)
 
Last edited:
Update on BMS-Inverter Comms: I managed to make a few small steps forward today. I'm now able to calculate checksum values, so I'm able to change values in the response string and have those changes reflected on the inverter. I have to say, the the checksum value for the length calculation is a real bear (see below). I have no idea how I'm going to automate that process, as I have no clue how to get the MCU to 1) "divide [two bytes] to four ASCII bytes" for the analysis, 2) store the resulting 4-bit checksum value, and 3) amend the 12-bit length value with that 4-bit checksum. Once again, I'm sure i'll figure it out.

Next step is to figure out how to get the inverter to request charge/discharge management info. At this point, it just sends the same request for pack information over and over. I think I need to 'flag' a status change in that pack info to get it to request additional info.

Are all communication protocols this complicated?


Picture1.png
 
Are all communication protocols this complicated?

No, but to be honest this one is pretty simple. It just has some unecessary complications (main one being using ASCII instead of sending the value directly) but nothing really complex, just a PITA. Once you made a few basic functions to handle all that low level stuff you'll be able to concentrate on the higher level stuff ;)
 
Yeah, not a terribly complicated protocol. Just need to write a few functions to convert the raw bytes into the necessary variable values etc. Bit shifting and copying bytes directly into variables should be pretty straightforward. I am no expert but you are welcome to post up code for review.

It sounds like the inverter needs a specific frame/packet to trigger events. I have not reviewed the spec, so its just a guess. It may also just be a specific byte(s) in the frame which triggers the specific behavior.

Does the inverter docs specify if it actually checks the checksum? In several cases I have found the checksum is carried over for compatibility, but the receiving device doesn't always implement a check in its software.
 
Last edited:
It sounds like the inverter needs a specific frame/packet to trigger events. I have not reviewed the spec, so its just a guess. It may also just be a specific byte(s) in the frame which triggers the specific behavior.
The inverter is sending the 'get analog values' request. The protocol states that the response to that request includes the "INFOFLAG", which I'm assuming is the same as the "DATAFLAG", which is summarized in the table pasted below. In the response that I've been sending, I've got the flag set to 00010001, which I thought would prompt requests for additional data, but that doesn't seem to be happening (not that I've been able to detect, anyway). Need to play around with that a bit more I think.
Screen Shot 2021-03-30 at 8.40.31 PM.png

Does the inverter docs specify if it actually checks the checksum? In several cases I have found the checksum is carried over for compatibility, but the receiving device doesn't always implement a check in its software.
I don't have any inverter documents, so I'm flying blind on that side of things. I did confirm that without an accurate checksum, the inverter does fault out. That said, I haven't tried sending a response with an inaccurate length checksum value. I'll try that tomorrow. If it doesn't care about that one, would save me some work. Good suggestion.
 
Looking at the manual:

Communication Connection Please use supplied communication cable to connect to inverter and PC. Insert bundled CD into a computer and follow on-screen instruction to install the monitoring software. For the detailed software operation, please check user manual of software inside of CD.

The simplest is to get communications operational between a PC and inverter. You can then connect a "sniffer" to the data line to record communications. I've done this to obtain proprietary automotive communication.
 
Back
Top