A "reverse engineering" of the BYD Battery-Box Premium LVS CAN protocol when used with Victron/Venus OS. See the source code for a full working implementation.
The following information has been discovered between a BYD Battery-Box Premium LVS B019 / v1.23 and a Victron Venus OS v3.00. Battery-Box consist of 2 batteries in 1 tower (48V, 2* 78Ah).
CAN protocol is set to 500kBit/s (no FD). All frames are sent with 8 bytes length (zero padded).
When emulating a BYD battery it seems to be sufficient to just periodically send the following frames with a 900ms
and 1000ms
delay:
- 0x35E, ManufacturerInfo
- 0x382, ProductInfo
- 0x35F, BatteryInfo
- 0x35A, AlarmsWarnings
- 0x35B, EventsUnused
- 0x351, Dvcc
- 0x355, StateInfo
- 0x356, BatteryStats
- 0x360, Unknown0
- 0x372, BankInfo
- 0x373, CellInfo
- 0x374, CellVoltMinId
- 0x375, CellVoltMaxId
- 0x376, CellTempMinId
- 0x377, CellTempMaxId
- 0x378, History
- 0x379, BatterySize
Things to note:
- Frames sent from Victron seem to be ignorable. We can just start sending the frames at any time.
- I did not check if the order of the frames is important. The above sequence seems to work.
- If frames are not sent completeley or properly, Venus OS tends to recognise the sender as "Pylontech" or "CAN bus BMS".
- If frames are not sent frequently enough, Venus OS interprets the sender as being disconnected (offering to remove the device).
- "Redetect battery" in Venus OS seems to send some frames to the "battery". It seems to be sufficient to just keep on sending the above frames (no other sequence needed).
- All information has been dumped on a Raspberry 4 with Venus OS v3.00 (as written above) and a RS485 CAN HAT with
candump
. - Emulation of the battery has been done from an Espressif ESP32 (and S2, S3) with a TJA1050/1 transceiver.
- (not really BYD related) Extended frames (with 29bit identifiier) seem to get ignored by Venus OS. So, in theory, it would be possible to connect a Venus OS to different CAN devices / batteries and have a single device aggregate the messages from each battery into a BYD message and send that to Venus OS.
Id | Hex | Ascii | Description |
---|---|---|---|
305 | 00 00 00 00 00 00 00 00 | ........ | ? it seems when no battery present: 305 and 307 are sent rapdily |
306 | 00 00 00 00 00 00 00 00 | ........ | ? it seems when battery is present: 305, 306 and 307 are sent periodically |
307 | 12 34 56 78 56 49 43 00 | .4VxVIC. | ? it seems when no battery present: 305 and 307 are sent rapdily |
Id | Hex | Ascii | Description |
---|---|---|---|
350 | not seen | ||
351 | 48 02 00 05 00 05 AE 01 | H....... | Dvcc: CVL, CCL, DCL, DVL |
[00:01] "48 02" (V*10, DeciVolt) 58.4V CVL | |||
[02:03] "00 05" (A/10, DeciAmp) 128.0A CCL | |||
[04:05] "00 05" (A/10, DeciAmp) 128.0A DCL | |||
[06:07] "AE 01" (V*10, DeciVolt) 43.0V DVL | |||
352 | not seen | ||
353 | not seen | ||
354 | not seen | ||
355 | 43 00 64 00 00 00 00 00 | C.d..... | StateInfo: State of Charge, State of Health |
[00:01] "43 00" (%) 67% SoC | |||
[02:03] "64 00" (%) 100% SoH | |||
[04:05] always null, ??? | |||
[06:07] always null, ??? | |||
356 | BE 14 F9 FF 8C 00 00 00 | ........ | BatteryStats: Voltage, Amps, Temperature |
[00:01] "BE 14" (mV, MilliVolt) 53.1V current voltage | |||
[02:03] "F9 FF" (A/10, DeciAmp, signed) -0.7A consumed Amps; "-" discharge / "+" charge | |||
[04:05] "8C 00" (°C/10, Deci, signed) 14.0°C battery temperature | |||
[06:07] always found to be null, definitely not Watts | |||
357 | not seen | ||
358 | not seen | ||
359 | not seen | ||
35A | AA AA AA AA AA AA AA AA | ........ | Alarms and Warnings, bit field, 'AA' means OK |
10 .. .. .. .. .. .. .. | ........ | [00] "10" Low battery voltage: Alarm | |
.. .. .. .. 10 .. .. .. | ........ | [04] "10" Low battery voltage: Warning | |
04 .. .. .. .. .. .. .. | ........ | [00] "04" High battery voltage : Alarm | |
.. .. .. .. 04 .. .. .. | ........ | [04] "04" High battery voltage : Warning | |
.. .. 01 .. .. .. .. .. | ........ | [02] "01" High charge current: Alarm | |
.. .. .. .. .. .. 01 .. | ........ | [06] "01" High charge current: Warning | |
.. 40 .. .. .. .. .. .. | ........ | [01] "40" High discharge current: Alarm | |
.. .. .. .. .. 40 .. .. | ........ | [05] "40" High discharge current: Warning | |
.. 01 .. .. .. .. .. .. | ........ | [01] "01" Low temperature: Alarm | |
.. .. .. .. .. 01 .. .. | ........ | [05] "01" Low temperature: Warning | |
40 .. .. .. .. .. .. .. | ........ | [00] "40" High temperature: Alarm | |
.. .. .. .. 40 .. .. .. | ........ | [04] "40" High temperature: Warning | |
.. 10 .. .. .. .. .. .. | ........ | [01] "10" Low charge temperature: Alarm | |
.. .. .. .. .. 10 .. .. | ........ | [05] "10" Low charge temperature: Warning | |
.. 04 .. .. .. .. .. .. | ........ | [01] "04" High charge temperature: Alarm | |
.. .. .. .. .. 04 .. .. | ........ | [05] "04" High charge temperature: Warning | |
.. .. 40 .. .. .. .. .. | ........ | [02] "40" Internal failure: Alarm | |
.. .. .. .. .. .. 40 .. | ........ | [06] "40" Internal failure: Warning | |
.. .. .. 01 .. .. .. .. | ........ | [03] "01" Cell imbalance: Alarm | |
.. .. .. .. .. .. .. 01 | ........ | [07] "01" Cell imbalance: Warning | |
35B | 00 00 00 00 00 00 00 00 | ........ | ??? always found to be null, aka Events |
35C | not seen | ||
35D | not seen | ||
35E | 42 59 44 00 00 00 00 00 | BYD..... | ManufacturerInfo |
[00:02] "BYD" (string) "BYD" manufacturer identification | |||
[04:07] always found to be null | |||
35F | 4C 69 01 17 69 00 00 00 | Li..i... | BatteryInfo: Product/Firmware version, Ah available |
[00:01] "4C 69" product code, always seen that value | |||
[02:03] "01 17" v1.17 firmware version | |||
[04:05] "69 00" (Ah) 105Ah capacity available | |||
[06:07] ??? always found to be null, might be hardware version according to MrConstantin84 | |||
360 | 00 00 00 00 00 00 00 00 | ........ | ??? always found to be null |
361 | not seen | ||
362 | not seen | ||
363 | not seen | ||
364 | not seen | ||
365 | not seen | ||
366 | not seen | ||
367 | not seen | ||
368 | not seen | ||
369 | not seen | ||
36A | not seen | ||
36B | not seen | ||
36C | not seen | ||
36D | not seen | ||
36E | not seen | ||
36F | not seen | ||
370 | not seen | ||
371 | not seen | ||
372 | 02 00 00 00 00 00 00 00 | ........ | BankInfo |
........ | 2 batteries online, 0 batteries offline | ||
02 00 .. .. .. .. .. .. | ........ | [00:01] "02 00" batteries online | |
........ | [02:03] "00 00" ???, seems to be ignored by Venus OS, see below | ||
........ | [04:05] "00 00" ???, seems to be ignored by Venus OS, see below | ||
.. .. .. .. .. .. 01 00 | ........ | [06:07] "01 00" batteries offline | |
........ | BYD system sent these frames upon first power up: | ||
02 00 02 00 01 00 00 00 | ........ | Frame 01 | |
02 00 00 00 00 00 00 00 | ........ | Frame 02 + consecutive frames | |
........ | according to MrConstantin84 might be: | ||
........ | [02:03] "00 00" block charge | ||
........ | [04:05] "00 00" block discharge | ||
373 | EA 0C 01 0D 1F 01 22 01 | ......". | CellInfo: Cell Voltage and Temperature |
[00:01] "EA 0C" (mV) 3.306V Lowest Cell Voltage, see 374 | |||
[02:03] "01 0D" (mV) 3.329V Highest Cell Voltage, see 375 | |||
[04:05] "1F 01" (K) 287K, 14°C Minimum Cell Temperature, see 376 | |||
[06:07] "22 01" (K) 290K/17°C Maximum Cell Temperature, see 377 | |||
374 | 32 00 00 00 00 00 00 00 | 2....... | Battery/Cell name (string) with "Lowest Cell Voltage", see 373 |
375 | 32 00 00 00 00 00 00 00 | 2....... | Battery/Cell name (string) with "Highest Cell Voltage", see 373 |
376 | 32 00 00 00 00 00 00 00 | 2....... | Battery/Cell name (string) with "Minimum Cell Temperature", see 373 |
377 | 31 00 00 00 00 00 00 00 | 1....... | Battery/Cell name (string) with "Maximum Cell Temperature", see 373 |
378 | 40 08 00 00 2B 07 00 00 | @...+... | History: Charged / Discharged Energy |
[00:03] "40 08 00 00" (kWh/10, HectoWattHour) 211.2kWh Charged Energy | |||
[04:07] "2B 07 00 00" (kWh/10, HectoWattHour) 183.5kWh Discharged Energy | |||
379 | 9C 00 00 00 00 00 00 00 | ........ | BatterySize: Installed Ah |
[00:01] "9C 00" (Ah) 156Ah | |||
[02:07] ??? always found to be null | |||
37A | not seen | ||
37B | not seen | ||
37C | not seen | ||
37D | not seen | ||
37E | not seen | ||
37F | not seen | ||
380 | not seen | ||
381 | not seen | ||
382 | 50 52 45 4D 49 55 4D 00 | PREMIUM. | Product identification |
[00:06] "PREMIUM" (string) product identification | |||
[07] always found to be null | |||
383 | not seen | ||
384 | not seen | ||
385 | not seen | ||
386 | not seen | ||
387 | not seen | ||
388 | not seen | ||
389 | not seen | ||
38A | not seen | ||
38B | not seen | ||
38C | not seen | ||
38D | not seen | ||
38E | not seen | ||
38F | not seen |
- Nr of modules blocking charge/discharge (not clear if supported)
After I finished documenting the protocol, I stumbled across a document about the SMA CAN protocol "Technical Information: Connecting Batteries with external Battery Management System to SUNNY ISLAND 6.0H-11" ("SMA CAN protocol.pdf"). Here is a table with some of their CAN ids - which seem to be similar to BYD.
HiResSOC 0x355 [04:07] and Events 0x35B do not seem to be supported on BYD.