Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RS485 protocol #2

Open
mvdklip opened this issue Nov 28, 2022 · 41 comments
Open

RS485 protocol #2

mvdklip opened this issue Nov 28, 2022 · 41 comments
Labels
question Further information is requested

Comments

@mvdklip
Copy link

mvdklip commented Nov 28, 2022

I am trying to communicate with the BMS in a battery over RS485 but do not know the protocol details. I tried to load the aia file on Kodular to find out but I get errors loading the blocks when I do this. Can you tell me how to communicate with the BMS? Is there a list of messages / bytes and their meanings?

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 3, 2022

Hi mvdklip, can you be more detailed about the issues you have ? . Do you build the interface ? the RS485 module plus the BT module ? At basic level the protocol is 9600bps 8n1 and with the interface connected by the RS845 side to the bike and the BT module linked to any android phone, for example, open a program like "serial terminal bluetooth 1.40 " app and you start to see all the trafic of the bike bus. Make the interface conect to your android phone and open and conect to the Bluetooth module with the "Serial Terminal Bluetooth" and let me know what characters scroll in your screen. ML

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 3, 2022

Note: if you connect only to the battery there are no RS485 out from the BMS until receive a control word from bike or charger, if you woul like to see any answer from battery alone, connect to the SuSoDev interface and hit "enter" from "serial terminal bluetooth" linked with the BT of the interface. You would see anwer of
5 HEX chars. Hope this helps, too.

@mvdklip
Copy link
Author

mvdklip commented Dec 8, 2022

Hi Xmanu12, thanks for your answer. My issue is not really with the tool but that I can't find anywhere what has been found out about the RS485 internals using this tool. I guess by now the tool has been used to identify what messages can be send to the BMS (for example) and what answers it will supply. I only have a battery for now so I'm mostly interested in this communication. To put it simple: I want to ask the BMS about the current SoC and/or SoH.

I already have some sort of serial communication working at 9600 8n1. When I sent the BMS the following message:

0x01 0x03 0x00 0x00 0x00 0x01 0x84 0x0A

It responds with:

01 03 00 00 F1 D8

This is very similar to modbus but not quite the same. Maybe it's cdbus or something proprietary. Anything you can share on how to decipher the packets would help. Thanks.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 10, 2022

Hi Matthijs, well, internals of the RS485 messages was directly implements and decodes in the app, never have time to write any document about my findings this is the reason to publish the source of the version 04 aia. Here you can find. Anyway I take time to write some guide to you regarding the battery messages you have interest.
basic_RS485.docx
Unfortunately SoH is not currently located, but have some ideas to look for, if you have experience with Java decoding.
Let me know if the document attached is clear.

@mvdklip
Copy link
Author

mvdklip commented Dec 12, 2022

Thanks! If I understand correctly that document tells me what messages the TC and TCMAX chargers send and what answer they get. Is the answer documented the one from the BMS?

The message seems to have the same length as I discovered (modbus like) which is 8 bytes long and ends with a 2-byte modbus CRC. Not sure why it starts with C5 5C but maybe these are just magic bytes? :-)

It seems 5A is the id of charger and AA might be the id of the answering device in this case. So then the format would be:

<magic> <magic> <source> <destination> <length> <data> <checksum> <checksum>

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 12, 2022

Hi Matthijs, yes the documented answer is from the BMS. Too much assumtions, not sure if the format you write is correct. For example, b6 6b start appear in other messages of the bus, but comming from the ECU. For sure the end of the messages is always 0d, and is not part of the checksum, it only have 1 byte lenght, for sure. And regarding 8 bytes long, my observations resumed as <Header><Header><Source><Destination><Length><Data><Checksum><End> the 80% of the messages is 10 bytes data, 9% is 14 Byte data, 1% is 1 Byte data, 1% is 2 Byte data, more or less, so not really modbus, if you like " far family". ;-)

@mvdklip
Copy link
Author

mvdklip commented Dec 12, 2022

Ah yes, missed that "end" 0d. Weird because I have observed that my modbus like messages have to be ended in a two byte modbus CRC so maybe the BMS understands two different kinds of messages? Wednessday I'll be back in the workshop and will try sending one of your example messages.

Question: how do you calculate the 1 byte checksum?

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 13, 2022

Hi Matthjis,
-- Question: how do you calculate the 1 byte checksum?
At this moment, as we only read from the bus of the Bike, dont need to calculate the Checksum, only ignore it and believe that all the messages are correct.

@mvdklip
Copy link
Author

mvdklip commented Dec 14, 2022

Already found it. It's a simple XOR of the data bytes starting with the length byte.

01 97 => 96
01 9a => 9b
0a 42 4b 1e 00 00 0d 00 41 00 00 => 51

Which makes the packet format:

<header> <header> <source> <destination> <data-length> <data-bytes> ... <data-xor> <end>

Also found a small error in your doc, I believe. The "charging or not" is in byte 10 for me, not in byte 7. Byte 9 went from 0 to 1 after doing a full charge to 100% and the charging stopped. Might have a meaning.

@mvdklip
Copy link
Author

mvdklip commented Dec 14, 2022

I have just checked all (single-byte) requests and I get different responses from the battery for requests 9A and 9C:

c5 5c 5a aa 01 9a 9b 0d => b6 6b aa 5a 02 00 02 00 0d
c5 5c 5a aa 01 9c 9d 0d => b6 6b aa 5a 10 41 54 36 30 34 33 32 32 30 32 32 34 30 37 31 31 07 0d

Ofcourse I do not know the meaning of this yet, but I saw you had 9A in your document for the TCMAX charger. Do you know the meaning of 9A?

@mvdklip
Copy link
Author

mvdklip commented Dec 14, 2022

I also tried all source and destination addresses. Interestingly enough the BMS sends the following:

  • Source 5A, dest AA => response from AA to 5A
  • Source 5A, dest 5A => response from AA to 5A
  • Source A0, dest AA => response from AA to A0

This makes me think that 5A=Charger, AA=BMS and A0 might be ECU. It's kind of silly that the BMS also responds to a request from charger to charger but this might be a bug.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 15, 2022

Hi Matthjis, Great !! all your new findings. Congratulations for the Checksum generation, I test few other messages bus and is correct, its a Xor sum, this is great news because now we are ready to "create" messages and build for example an other brand of Smart BMS like ANT or DALY and make a translator to answer like a SS BMS. Great !!

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 15, 2022

-- Also found a small error in your doc, I believe. The "charging or not" is in byte 10 for me, not in byte 7. Byte 9 went from 0 to 1 after doing a full charge to 100% and the charging stopped. Might have a meaning. --

Maybe you are right, let me confirm with my battery if bytes change as you observed.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 15, 2022

c5 5c 5a aa 01 9a 9b 0d => b6 6b aa 5a 02 00 02 00 0d
c5 5c 5a aa 01 9c 9d 0d => b6 6b aa 5a 10 41 54 36 30 34 33 32 32 30 32 32 34 30 37 31 31 07 0d

For me, 00 02 data for the first message is an "incompatible charger"
The other message, is strange, first of all, is not "standard" all the good relevant messages have a data lenght of 0a, this however is 10H, so 16 Bytes, mmmm.
Let me know, what is yout battery model ? know the LiPo serial strings number ? and model of your Bilke and Charger ?

--Do you know the meaning of 9A?
At this moment, for me 9A is the code for a 72V 10A original SS charger for TCMax. So a BMS of 72V nominal with 20 LiPo serial strings will accept and answer correctly when receive a c5 5c 5a aa 01 9A 9b 0d, other codes than 9A are refused and the BMS dont answer about his status. ( But charge if the Voltage of the charger is between the minimun and the maximum allowed by BMS )

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 15, 2022

--This makes me think that 5A=Charger, AA=BMS and A0 might be ECU. It's kind of silly that the BMS also responds to a request from charger to charger but this might be a bug.--
Yes, maybe they newer think in two chargers in the same bus ;-)) Looks like BMS accept all messages from 5A because is only for the BMS interest. Or a bug, really.

@mvdklip
Copy link
Author

mvdklip commented Dec 16, 2022

I don't have a bike, only a battery and the charger is not original. I get what you mean about 97 and 9A now. It's a simple way to avoid hooking up the wrong charger. Nice.

The battery I have is a 17S li-ion 60V43Ah model.

I think the 9C response might be a more in-depth status report of the BMS and/or battery but I'm not sure.

Also I'm wondering whether there are also more 'config' like operations possible because the current messages are more 'status' like. I would be especially interested in configuring the AA address for each battery because I would eventually like to hook up multiple batteries to the same RS485 bus and query their status individually. That's not possible now because all batteries will respond at the same time.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 19, 2022

Hi Matthijs,
Please note a mistake I write in previous post, now corrected. -- At this moment, for me 9A is the code for a 72V 10A original SS charger for TCMax. So a BMS of 72V nominal with 20 LiPo serial strings will accept and answer correctly when receive a c5 5c 5a aa 01 9A 9b 0d, other codes than 9A are refused and the BMS dont answer about his status. ( But charge if the Voltage of the charger is between the minimun and the maximum allowed by BMS ) --
So this is the real situation verify by multiple users of the Bike, they can use other aftermarket Chargers ( with the correct 60V or 72V with limit to 12A max ) and the BMS allowed to charge, without RS485 comunication

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 19, 2022

Thanks for let me know your setup.
Is strange that your battery dont answer the espected b6 6b aa 5a 0a 42 xx xx xx xx xx xx xx xx xx xx 0d. If is a 60V nominal battery is probably from a TC or TS model, so c5 5c 5a aa 01 97 96 0d is the correct message for this BMS, have you tried to send 3 o 4 times at once the c5 5c 5a aa 01 97 96 0d ?

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 19, 2022

--I think the 9C response might be a more in-depth status report of the BMS and/or battery but I'm not sure. --
Yes , seems to me the same.

-- Also I'm wondering whether there are also more 'config' like operations possible because the current messages are more 'status' like. I would be especially interested in configuring the AA address for each battery because I would eventually like to hook up multiple batteries to the same RS485 bus and query their status individually. That's not possible now because all batteries will respond at the same time. --

Uff, hard work. Looks like the address is hard coded in the BMS, instead we discover a command message that allowed to change this default address. The other solution is put an arduino in each battery with an "IN" RS485 and an "OUT" RS485 that only allow pass messages to his bind battery. For example if you send c5 5c 5a AB 01 97 96 0d an Arduino listening only for c5 5c 5a AB translate to his battery as c5 5c 5a AA .... and all his answers type b6 6b aa 5a... will be translated as b6 6b AB 5a....to the BUS.
An idea...

@mvdklip
Copy link
Author

mvdklip commented Dec 21, 2022

Byte 9 seems to be some sort of error state of the BMS. I have observed values 0 (no error), 1, 2 and 4. I think I after a charge means the (aftermarket) charger didn't stop at 100% and the BMS stopped it. Value 2 seems to happen when I connect 2 batteries two eachother. The batteries should balance eachother out in that case but it seems the BMS doesn't allow it. Probably because the current is uncontrolled. I have seen >200A flowing very shortly between two batteries. Error 2 happens on the battery receiving the charge so it might mean something as "too high charge current". Value 4 I'm investigating right now because I have one battery stuck in this state.

@mvdklip
Copy link
Author

mvdklip commented Dec 21, 2022

Okay. I think I got it:

  • 1: Charging forcefully stopped by BMS
  • 2: Too high charge current
  • 4: Too high discharge current

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 21, 2022

So finally you have a good response of type b6 6b aa 5a 0a xx xx xx xx xx xx xx xx xx xx xx 0d message ? in your battery ?

Interesting the finding you have observed for byte 9, never see this in my dumps of RS485 messages (normal as a SS Bike never have two batterys in parallel) Is consistent with the observed by users, BMS discharge is unlimited ( well limited by LiPo cell chemical and the Mosfets in BMS really) and BMS charge is limited to 12A max. This is the reason we dont have regenerative charge in the SS bikes, Motor+ECU can generate power in a downhill, but BMS dont accept this overcurrent charge and during few seconds we have a charge error light in odometer display

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 21, 2022

I suspect that you know very well what are you doing regarding put two LiPo batteries pack in parallel, as you know is not a good idea and is nearly imposible that both live together without degrading or suffer his cells.

@mvdklip
Copy link
Author

mvdklip commented Dec 22, 2022

So finally you have a good response of type b6 6b aa 5a 0a xx xx xx xx xx xx xx xx xx xx xx 0d message ? in your battery ?

Yes, my batteries respond to the 97 request. As you explained this seems to be the correct request (or charger identifier) for my type of battery. I think this battery is meant for the CPx, so not TC or TCMAX. TC and CPx are 60V (17S), TCMAX is 72V (20S).

@mvdklip
Copy link
Author

mvdklip commented Dec 22, 2022

I suspect that you know very well what are you doing regarding put two LiPo batteries pack in parallel, as you know is not a good idea and is nearly imposible that both live together without degrading or suffer his cells.

Well, there shouldn't be any problem putting lithium batteries in parallel. Why do you think so? I am top balancing them before connecting them together now so that I avoid the problems with too high charge or discharge currents.

@mvdklip
Copy link
Author

mvdklip commented Dec 22, 2022

Have you looked at the position of "charging or not" by the way? For me byte 7 stays 0 while charging. It's byte 10 which goes to 1 during charge and to 4 during discharge.

@mvdklip
Copy link
Author

mvdklip commented Dec 22, 2022

I also found out that the (16 byte) response to request 9C is actually largely in ASCII text. It returns the serial number of the battery. AT....

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 22, 2022

So finally you have a good response of type b6 6b aa 5a 0a xx xx xx xx xx xx xx xx xx xx xx 0d message ? in your battery ?

Yes, my batteries respond to the 97 request. As you explained this seems to be the correct request (or charger identifier) for my type of battery. I think this battery is meant for the CPx, so not TC or TCMAX. TC and CPx are 60V (17S), TCMAX is 72V (20S).

Great if you have a good answer. So we can update our basic understand of this RS485 protocol with the addition of CPx charger as type 97 . He ask c5 5c 5a aa 01 97 96 0d, then.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 22, 2022

Well, there shouldn't be any problem putting lithium batteries in parallel. Why do you think so?

( Note. Battery Pack, not battery cells) Uff this an extended topic in few forums and war flames discussions. Im not an expert in Batteries but the resume is; there are few key factors in the characteristics of a LiPo cell that with time and charges and discharges alter his properties. This depend also from chemical, internals metals etc. so first point to have a good LiPo package is all cells same Manufacturer, same model, same internal resistence, and a good BMS with active balancing for the Serial strings at lest, and if possible for the parallel cells, too. Later in the real life with temperature changes, discharges more or less deep, standby days-weeks, and charging cycles you will degrading the cells. Is nearly imposible you have another battery pack with the same life so you will have two different batery packs internally and if you connect in parallel, both find the equilibrium flowing current from the more Volts to the less. But in Charge or Discharge mode the differences in the cells of each packs cause an internal current flows that is not 1/2 for each pack. At large time you accelerate the degradation of both packages much more than if you use in serial or "in time" So for example, EV Bikes with two battery packs have a switch box that use one battery until drop to a 20% SoC, then swith to the other, and for charging, swith to the other when reaches 100% SoC.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 22, 2022

Have you looked at the position of "charging or not" by the way? For me byte 7 stays 0 while charging. It's byte 10 which goes to 1 during charge and to 4 during discharge.

Unfortunately dont have the TC of my son here, Im waiting he comes from last week, maybe this weekend I can "hack" his bike.

@Xmanu12
Copy link
Owner

Xmanu12 commented Dec 22, 2022

I also found out that the (16 byte) response to request 9C is actually largely in ASCII text. It returns the serial number of the battery. AT....

Yes, I think the same, let me check this weekend this answer in my TC battery, too.
Have you check with the serial number print in the lateral label of your battery ? Will be great if has coincidence, but maybe one S/N is SS battery stock and the 16 bytes answer is S/N of the BMS manufacturer.

@mvdklip
Copy link
Author

mvdklip commented Dec 29, 2022

I have checked the serial and it's definitely the same as returned by 9C.

@mvdklip
Copy link
Author

mvdklip commented Dec 29, 2022

For me, 00 02 data for the first message is an "incompatible charger"

It seems you have to check the message length to find out what kind of response is being returned.

  • Len 2 = error
  • Len 10 = status
  • Len 16 = serial

How do you know that 00 02 means "incompatible charger"? It seems logical but I'm asking because I want to be able to decode other errors as well.

@mvdklip
Copy link
Author

mvdklip commented Dec 29, 2022

Also have you ever seen other messages than the ones starting with C5 5C (read request) and B6 6B (read response)? I am still searching for a message to write configuration. Also I would really like a more detailed status. The current one with Amps in whole numbers is not precise enough. It must be possible to get better info from the BMS.

@mvdklip
Copy link
Author

mvdklip commented Dec 29, 2022

I have also resumed poking around with the "modbus like" messages. I found a lot of messages the BMS is actually responding too with a valid (modbus) crc16 but I don't understand it fully yet. Some of the responses I get:

  • 01 03 00 00 f1 d8 : probably means "No data available".
  • 60 0f 00 20 2f ff: doesn't look like modbus but crc is valid.
  • 01 10 00 00 01 00 c1 99 : looks like modbus but means that write to multiple registers succeeded.

All tried this with function 03 - read holding registers. I've actually found some requests which makes the BMS crash/reboot as well. :-P

@Xmanu12 Xmanu12 added the question Further information is requested label Apr 5, 2023
@stprograms
Copy link

Hi guys!
First of all, thank you very very much for your awesome work here 🥇

Since SuperSoco decided to shutdown the SuperSoco cloud portal for connecting to the bike last year, I am now on the way to build my own tracking device to also fetch the current SoC. Thanks to your work, I am now able to fetch all the data I require from the bike through the RS485 interface.

At the moment, I have only started theoretically and made some prove of concept, but I will start with the actual project in the next days.

For the prove of concept, I have written a terminal application that extracts and parses the "telegrams" from the bus and shows them on the console (either in hex or already parsed). It logs the binary data to files, which can then be reread again. You can find it on github - SuperSoco485Monitor

I directly used a RS485 to serial converter in my case, but I guess if you connect the Bluetooth hardware to a laptop, it should also create a serial port and then you could also use the monitor with this hardware.

Maybe what it also interesting for you, I have collected and summarized all your findings regarding the structure, content of the telegrams and checksum generation, in the readme file there. The information is based on this "thread" and the content of the kodular project.

Maybe this helps in further reverse engineering the RS485 data :-)

Best regards from Austria

@Xmanu12
Copy link
Owner

Xmanu12 commented Jun 7, 2023 via email

@stprograms
Copy link

Hi Manuel,

I'm happy that you find it useful too :-)
I just struggled over some questions though, where maybe you are able to help me out. Did you find out the unit and data type for the electric current fields and the speed?

For example I get 0x0BE5 for the "discharging" current of the BMS while driving (just a snapshot value here), but I don't know if that is somehow coded as a float or int and if it needs to be interpreted as Amps or milliamps. Similar with the speed returned by the ECU. Would be great if you could help me out here to extend the documentation further.

Best regards,
Andreas

@mvdklip
Copy link
Author

mvdklip commented Aug 21, 2023

Hi Andreas,

Question was not directed to me but I am interested where you got this (word) value. I only know of the byte sized "current" field which is not precise at all. Copy of actual code I use:

return {
    'Voltage'   : self.getByte(m[0:]),
    'SoC'       : self.getByte(m[1:]),
    'Temp'      : self.getByte(m[2:], signed=True),
    'Current'   : self.getByte(m[3:], signed=True),
    'Cycles'    : self.getWord(m[4:]),
    'Unknown1'  : self.getByte(m[6:]),
    'Unknown2'  : self.getByte(m[7:]),
    'VBreaker'  : self.getByte(m[8:]), # 1 = bms stopped charge, 2 = too high charge current, 4 = too high discharge current
    'Activity'  : self.getByte(m[9:]), # 1 = charging, 4 = discharging
}

@stprograms
Copy link

stprograms commented Aug 21, 2023

Hi Matthijs,

Thank you very much for the quick reply!
That helps me a lot. I assume that the Current has the unit Amps, correct?
I will also correct the documentation and code in the Monitoring application later on.

The problem is when you try to collect information from different sources, you eventually end up with a knot in your head and mix things up ^_^. That's why I'm trying to collect all data in the SuperSoco485Monitor repository, so we all get a reference.

I checked again and the two byte current field I meant is in a message of the ECU, not the BMS. I got this information from the v0.4 project file.

Best regards,
Andreas

@valy84
Copy link

valy84 commented Aug 1, 2024

Hello, I am using an esp32 and have no problem sending bms and ecu data to the display. However I can't manage to make the display use any GPS data I'm sending. The goal here is for me to send the time to the display. I don't have a gps module so no real way for me to analyze the GSM packages. The display doesn't seem to request anything from BA . Does anyone have a clue on how to deliver the gsm packages?
C5 5C BA AA 0E 4C 0F 1D 1 10 12 0 0 0 3 1 0E 0 2D 72 0D
This seems to be a valid request someone posted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants