hoylabs / OpenDTU-OnBattery

Software for ESP32 to talk to Hoymiles/TSUN/Solenso Inverters, VE.Direct devices, battery management systems, and related peripherals
GNU General Public License v2.0
301 stars 63 forks source link

feature: add support for pytes batteries #1088

Closed AndreasBoehm closed 2 months ago

AndreasBoehm commented 3 months ago

With this PR we can get all data from Pytes V5 and Pytes 48100R batteries via CAN.

The protocol is based on BYDs CAN protocol and I used a Raspberry Pi with a CAN-HAT and VenusOS to read, modify and replay the CAN messages to reverse engineer the CAN protocol.

CAN protocol documentation can be found here: https://github.com/AndreasBoehm/PytesCANProtocol

Features

Screenshots

Screenshot 2024-07-07 at 17 53 44

Screenshot 2024-07-09 at 18 18 40

VenusOS

image image image image image image

quantenquark commented 3 months ago

Hi Andreas,

thanks a lot for your support! I assume that the new pytes V5 family runs the same CAN protocol than previous battery versions. I need to digg into it to understand how to transfer the code to my todays test environement first.

73 Achim

AndreasBoehm commented 3 months ago

Hi Andreas,

thanks a lot for your support! I assume that the new pytes V5 family runs the same CAN protocol than previous battery versions. I need to digg into it to understand how to transfer the code to my todays test environement first.

73 Achim

Based on the CAN messages that got posted here (https://github.com/helgeerbe/OpenDTU-OnBattery/discussions/541#discussioncomment-9771146) the CAN protocol of previous battery versions should be the same.

To install the test build you can grab the matching file for your openDTU from here and install it as an OTA update.

quantenquark commented 3 months ago

I have installed the FW /pr1088-202407071130 but it looks to me as it did not work out: Screenshot 2024-07-07 174610 Screenshot 2024-07-07 173913 Screenshot 2024-07-07 173609

Maybe Pytes eBox48100R is again different to V5? Any ideas?

AndreasBoehm commented 3 months ago

@quantenquark Can you confirm that you selected Pytes instead of Pylontech in the battery settings on your openDTU? Screenshot 2024-07-07 at 17 53 44

quantenquark commented 3 months ago

Oops, force of habit. Config loaded but not changed...

Done: Screenshot 2024-07-07 180506

AndreasBoehm commented 3 months ago

@quantenquark Nice to see that it works now!

Did you remove the serial number from the screenshot or is the parsing of the CAN message not working?

As you are using two battery modules i would be very interest in how the can messages look for a setup like this. Could you by any chance record the can messages and post them here or send them to me somehow?

quantenquark commented 3 months ago

Hi Andreas, great work! Sorry for the inconvenience caused.

No, serials are not shown in the log either:

19:01:57.853 > [Pytes] totalCapacity: 198 Ah 19:01:57.903 > [Pytes] snPart1: 19:01:58.008 > [Pytes] snPart2: 19:01:58.547 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 0.000000 dischargeCurrentLimit: 100.000000 dischargeVoltageLimit: 44.500000 19:01:58.602 > [Pytes] soc: 100 soh: 100 19:01:58.651 > [Pytes] voltage: 56.669998 current: 1.000000 temperature: 20.000000 19:01:59.004 > [Pytes] Alarms: 0 0 0 0 0 0 0 0 0 0 19:01:59.059 > [Pytes] Warnings: 0 0 0 0 0 0 0 0 0 0 19:01:59.106 > [Pytes] Manufacturer: PYTES 19:01:59.276 > [Pytes] fwversion: v105.0 availableCapacity: 198 Ah 19:01:59.324 > [Pytes] moduleCountOnline: 2 moduleCountBlockingCharge: 0 moduleCountBlockingDischarge: 0 moduleCountOffline: 0 19:01:59.377 > [Pytes] lowestCellMilliVolt: 3529 highestCellMilliVolt: 3555 minimumCellTemperature: 20.000000 maximumCellTemperature: 20.000000 19:01:59.480 > [Pytes] cellMinVoltageName: 0000 19:01:59.529 > [Pytes] cellMaxVoltageName: 0000 19:01:59.579 > [Pytes] cellMinTemperatureName: 0000 19:01:59.684 > [Pytes] cellMaxTemperatureName: 0000

Will check how to get access to the CAN messages directly.

AndreasBoehm commented 3 months ago

I just pushed a new commit that will print all CAN messages to the console. Thats the easiest option to get those messages for now.

The new build should be available here in a couple of minutes: https://github.com/helgeerbe/OpenDTU-OnBattery/actions/runs/9829084807

They will look like this example

19:26:08.078 > [Pytes] Received CAN message: 0x305 - 00 00 00 00 00 00 00 00 
19:26:08.098 > [Pytes] Received CAN message: 0x307 - 12 34 56 78 56 49 43 00 
quantenquark commented 3 months ago

Voila! Hope this gives any answer ;-) 20240707_CAN info.txt

AndreasBoehm commented 3 months ago

Voila! Hope this gives any answer ;-) 20240707_CAN info.txt

Thanks for your help! I pushed a new commit that will ignore empty serial numbers. Besides that the CAN messages look the same for the V5 and the 48100R.

EDIT: The 48100R is missing the message for 'charged energy' and 'discharged energy'. Will take care of removing this information if its not available.

AndreasBoehm commented 3 months ago

Latest builds can be found here: https://github.com/helgeerbe/OpenDTU-OnBattery/actions/runs/9834350042?pr=1088

quantenquark commented 3 months ago

20240708_CAN info.txt Hi Andreas, looks like all your changes have been adopted:

Screenshot 2024-07-08 092406

schlimmchen commented 3 months ago

@AndreasBoehm @quantenquark Please check if my changes to the web UI work as intended: The labels for the cells with the extreme values should now be printed verbatim, i.e., without the web UI trying to translate them. Check out the freshly built firmware.

@AndreasBoehm Do you agree with https://github.com/helgeerbe/OpenDTU-OnBattery/pull/1088/commits/59e7679bc9c7f268bf5c176caed67287b491f3ed ? I think it is perfectly fine (and a good idea) to dump messages while verbose logging is enabled. I do this for the JK BMS as well. Also the VE.Direct controllers do that.

AndreasBoehm commented 3 months ago

@AndreasBoehm @quantenquark Please check if my changes to the web UI work as intended: The labels for the cells with the extreme values should now be printed verbatim, i.e., without the web UI trying to translate them. Check out the freshly built firmware.

Looks and works good. Thanks for your help. Screenshot 2024-07-09 at 18 18 40

@AndreasBoehm Do you agree with 59e7679 ? I think it is perfectly fine (and a good idea) to dump messages while verbose logging is enabled. I do this for the JK BMS as well. Also the VE.Direct controllers do that.

Good idea, makes sense to actually be verbose.

schlimmchen commented 3 months ago

Looks and works good.

:+1:

Thanks for your help.

You are very welcome.

I assume this is ready to merge, then? There is already positive feedback by a third party.

schlimmchen commented 3 months ago

I scrolled through the list of changes once more and noticed that the implementations to convert the serial CAN data to internal data types was strangely complicated. Can you please double-check that I did not mess up? New Firmware

AndreasBoehm commented 3 months ago

@schlimmchen Everything works as expected with the latest build from this PR. Sorry, I just copied what was there and modified it for the other int types, not used to work with low-level code like this.

schlimmchen commented 2 months ago

Sorry, I just copied what was there and modified it for the other int types, not used to work with low-level code like this.

Not an issue.

Thank you very much for this contribution! Well done :rocket:

ranma commented 2 months ago

Oh, nice. I just set up a Pytes ESS48-2U-L battery with OpenDTU (with the battery configured for Pylontech CAN messages using setprt PYLON on the console) the other day, I should try it it native mode next time I'm visiting my mom. :)

PYTES>info
@
Device address      : 1
Manufacturer        : PYTES
Device name         : E-BOX-4850P-C
Board version       : SQBMSV15
Main Soft version   : SPBMS15SPH2203V1.5.33.C8
Iterate version     : SPBMS15SPH2203V1.5.33.C8.T4
Soft  version       : V1.5
Boot  version       : V1.14
Comm version        : V2.0
Release Date        : 23-12-15
[...]
Board SRAM Size     : 96KB
Board FLASH Size    : 256KB
Specification       : 48V/50AH
Cell Number         : 15
Max Dischg Curr     : -60000mA
Max Charge Curr     : 52000mA
Console Port rate   : 115200
Command completed successfully
[...]
PYTES>login config
@
Command completed successfully
$$
PYTES_config>setprt PYLON
@
Command completed successfully
$$
PYTES_config>logout
@
Command completed successfully
$$
PYTES>
ranma commented 2 months ago

FWIW I have CAN traces for the following messages from the ESS48-2U-L:

    201  Identifier: 854 (0x356)
    317  Identifier: 864 (0x360)
    168  Identifier: 885 (0x375)
   4721  Identifier: 889 (0x379)
    308  Identifier: 896 (0x380)

e.g.:

194166-194209 CAN: Fields: Identifier: 854 (0x356)
194210-194213 CAN: Fields: Remote transmission request: data frame
194214-194217 CAN: Fields: Identifier extension bit: standard frame
194218-194221 CAN: Fields: Reserved bit 0: 0
194222-194241 CAN: Fields: Data length code: 6
194242-194273 CAN: Fields: Data byte 0: 0x49
194274-194305 CAN: Fields: Data byte 1: 0x13
194306-194341 CAN: Fields: Data byte 2: 0x00
194342-194381 CAN: Fields: Data byte 3: 0x00
194382-194413 CAN: Fields: Data byte 4: 0xd2
194414-194449 CAN: Fields: Data byte 5: 0x00
194450-194509 CAN: Fields: CRC-15 sequence: 0x6dd9
194510-194513 CAN: Fields: CRC delimiter: 1
194514-194517 CAN: Fields: ACK slot: NACK
194518-194521 CAN: Fields: ACK delimiter: 0
194522-194549 CAN: Fields: End of frame

-> Voltage 49.37, current 0.0, temperature 21.0

314857-314860 CAN: Fields: Start of frame
314861-314904 CAN: Fields: Identifier: 864 (0x360)
314909-314912 CAN: Fields: Remote transmission request: data frame
314913-314916 CAN: Fields: Identifier extension bit: standard frame
314917-314920 CAN: Fields: Reserved bit 0: 0
314921-314940 CAN: Fields: Data length code: 1
314941-314976 CAN: Fields: Data byte 0: 0x00
314977-315036 CAN: Fields: CRC-15 sequence: 0x355e
315037-315040 CAN: Fields: CRC delimiter: 1
315041-315044 CAN: Fields: ACK slot: NACK
315045-315048 CAN: Fields: ACK delimiter: 0
315049-315076 CAN: Fields: End of frame 

Unknown message? I don't see any handling for this in PytesCanReceiver.cpp.

436074-436077 CAN: Fields: Start of frame
436078-436121 CAN: Fields: Identifier: 885 (0x375)
436122-436125 CAN: Fields: Remote transmission request: data frame
436126-436129 CAN: Fields: Identifier extension bit: standard frame
436130-436133 CAN: Fields: Reserved bit 0: 0
436134-436149 CAN: Fields: Data length code: 8
436150-436185 CAN: Fields: Data byte 0: 0x30
436186-436221 CAN: Fields: Data byte 1: 0x30
436222-436257 CAN: Fields: Data byte 2: 0x30
436258-436293 CAN: Fields: Data byte 3: 0x30
436294-436333 CAN: Fields: Data byte 4: 0x00
436334-436369 CAN: Fields: Data byte 5: 0x00
436374-436409 CAN: Fields: Data byte 6: 0x00
436410-436449 CAN: Fields: Data byte 7: 0x00
436450-436509 CAN: Fields: CRC-15 sequence: 0x0c7b
436510-436513 CAN: Fields: CRC delimiter: 1
436514-436517 CAN: Fields: ACK slot: NACK
436518-436521 CAN: Fields: ACK delimiter: 0
436522-436549 CAN: Fields: End of frame

-> highest voltage on cell 0?

556542-556545 CAN: Fields: Start of frame
556546-556589 CAN: Fields: Identifier: 889 (0x379)
556590-556593 CAN: Fields: Remote transmission request: data frame
556594-556597 CAN: Fields: Identifier extension bit: standard frame
556598-556601 CAN: Fields: Reserved bit 0: 0
556602-556621 CAN: Fields: Data length code: 2
556622-556653 CAN: Fields: Data byte 0: 0x32
556654-556689 CAN: Fields: Data byte 1: 0x00
556690-556749 CAN: Fields: CRC-15 sequence: 0x485b
556750-556753 CAN: Fields: CRC delimiter: 1
556754-556757 CAN: Fields: ACK slot: NACK
556758-556761 CAN: Fields: ACK delimiter: 0
556762-556789 CAN: Fields: End of frame 

-> BatterySize 50Ah

AndreasBoehm commented 2 months ago

FWIW I have CAN traces for the following messages from the ESS48-2U-L:

    201  Identifier: 854 (0x356)
    317  Identifier: 864 (0x360)
    168  Identifier: 885 (0x375)
   4721  Identifier: 889 (0x379)
    308  Identifier: 896 (0x380)

Are those all message that you got? A lot of messages are missing, look here to see what a V5 or 48100 provides.

314857-314860 CAN: Fields: Start of frame
314861-314904 CAN: Fields: Identifier: 864 (0x360)
314909-314912 CAN: Fields: Remote transmission request: data frame
314913-314916 CAN: Fields: Identifier extension bit: standard frame
314917-314920 CAN: Fields: Reserved bit 0: 0
314921-314940 CAN: Fields: Data length code: 1
314941-314976 CAN: Fields: Data byte 0: 0x00
314977-315036 CAN: Fields: CRC-15 sequence: 0x355e
315037-315040 CAN: Fields: CRC delimiter: 1
315041-315044 CAN: Fields: ACK slot: NACK
315045-315048 CAN: Fields: ACK delimiter: 0
315049-315076 CAN: Fields: End of frame 

Unknown message? I don't see any handling for this in PytesCanReceiver.cpp.

Its always 0x00.

436074-436077 CAN: Fields: Start of frame
436078-436121 CAN: Fields: Identifier: 885 (0x375)
436122-436125 CAN: Fields: Remote transmission request: data frame
436126-436129 CAN: Fields: Identifier extension bit: standard frame
436130-436133 CAN: Fields: Reserved bit 0: 0
436134-436149 CAN: Fields: Data length code: 8
436150-436185 CAN: Fields: Data byte 0: 0x30
436186-436221 CAN: Fields: Data byte 1: 0x30
436222-436257 CAN: Fields: Data byte 2: 0x30
436258-436293 CAN: Fields: Data byte 3: 0x30
436294-436333 CAN: Fields: Data byte 4: 0x00
436334-436369 CAN: Fields: Data byte 5: 0x00
436374-436409 CAN: Fields: Data byte 6: 0x00
436410-436449 CAN: Fields: Data byte 7: 0x00
436450-436509 CAN: Fields: CRC-15 sequence: 0x0c7b
436510-436513 CAN: Fields: CRC delimiter: 1
436514-436517 CAN: Fields: ACK slot: NACK
436518-436521 CAN: Fields: ACK delimiter: 0
436522-436549 CAN: Fields: End of frame

-> highest voltage on cell 0?

yes, on cell 0000. They start at 0 instead of 1. But because you are missing a lot of other messages i would not bet that this delivers anything meaningful right now.

quantenquark commented 2 months ago

@AndreasBoehm @quantenquark Please check if my changes to the web UI work as intended: The labels for the cells with the extreme values should now be printed verbatim, i.e., without the web UI trying to translate them. Check out the freshly built firmware.

Looks and works good. Thanks for your help. Screenshot 2024-07-09 at 18 18 40

@AndreasBoehm Do you agree with 59e7679 ? I think it is perfectly fine (and a good idea) to dump messages while verbose logging is enabled. I do this for the JK BMS as well. Also the VE.Direct controllers do that.

Good idea, makes sense to actually be verbose.

Voila, here we go :-) Looks fine to me, additional info attached: PR#1080_20240711_CAN info.txt PR#1008_20240711_1423

Both batteries are always full at this time, will see error messages from autumn to spring only ;-)

ranma commented 2 months ago

FWIW I have CAN traces for the following messages from the ESS48-2U-L:

    201  Identifier: 854 (0x356)
    317  Identifier: 864 (0x360)
    168  Identifier: 885 (0x375)
   4721  Identifier: 889 (0x379)
    308  Identifier: 896 (0x380)

Are those all message that you got? A lot of messages are missing, look here to see what a V5 or 48100 provides.

For now, yes. I didn't capture for very long and there was nothing on the bus to ACK the messages, so lots of repeats.

For capturing I used pulseview with a cheap fx2lafw-compatible 24MHz logic analyzer connected to the "OpenDTU Fusion CAN/Iso Shield Beta".

github-actions[bot] commented 1 month ago

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new discussion or issue for related concerns.