Frankkkkk / python-pylontech

Python lib to talk to pylontech lithium batteries 🔋 (US2000, US3000, ...) using RS485
MIT License
67 stars 32 forks source link

Improve implementation of get_management_info function #20

Closed abelsson closed 1 year ago

abelsson commented 2 years ago

Hi!

I've hacked a bit further and I think the get_management_info message seem to work for me now, so we can see when the battery requests charging and when it allows charging / discharging - which could be used for inverter control.

Please let me know if you think this looks right or if there's any comments or concerns :)

Uksa007 commented 1 year ago

Trying to test this and I get the following error:

>>> print(p.get_management_info())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Pylontech.get_management_info() missing 1 required positional argument: 'dev_id'
rotorman commented 1 year ago

I played with get_management_info function on low-level with my US5000 and this is what I get: query: 7e | 32 30 | 30 32 | 34 36 | 39 32 | 45 30 30 32 | 30 32 | 46 44 32 45 | 0d reply: 7e | 32 30 | 30 32 | 34 36 | 30 30 | 42 30 31 34 | 30 32 | 44 30 30 32 | 41 46 43 38 | 30 30 30 30 | 46 43 45 30 | 34 30 | 46 39 33 46 | 0d

Reply analysis:

7e: SOI
32 30: VER 0x20
30 32: ADR 0x02
34 36: CID1 0x46 (const)
30 30: RTN = 0 = normal
42 30 31 34 = LENGTH = 0x14 = 20, Checksum 0x42
 INFO:
30 32: Command value 0x02
  Charge and discharge management value:
44 30 30 32: Charge voltage limit (uint16) 0xD002 = 53250 / 1000 = 53.25V
41 46 43 38: Discharge voltage limit (uint16) 0xAFC8 = 45000 / 1000 = 45.0V
30 30 30 30: Charge current limit (uint16) 0x0 = 0 / 10 = 0A
46 43 45 30: Discharge current limit (int16) 0xFCE0 = -800 / 10 = -80A
34 30: Charge, discharge status: 0x40, bit 7 - charge enable, bit 6 discharge enable, bit 5 charge immediately, bit 4 charge immediately, bit 3 full charge request
46 39 33 46: CHKSUM 0xF93F
0d: EOI
Frankkkkk commented 1 year ago

Sorry for the delay; thanks !

Uksa007 commented 1 year ago

@abelsson @Frankkkkk

So I'm getting the below, seems it is treating the ChargeVoltageLimit and DischargeVoltageLimit as signed integers, should be unsigned?

[11:13:51][I][main:178]: Start: Received new data
[11:13:51][I][uart_log:035]: <<< 7E:32:30:30:32:34:36:39:32:45:30:30:32:30:32:46:44:32:45:0D
[11:13:51][I][main:557]: Send Pylon charge, discharge management info
[11:13:51][I][main:588]: status byte hex: 40
[11:13:51][I][main:626]: charging_voltage D868
[11:13:51][I][uart_log:035]: >>> 7E:32:30:30:32:34:36:30:30:42:30:31:34:30:32:44:38:36:38:41:42:45:30:30:30:30:30:46:43:45:30:34:30:46:39:33:35:0D

>>> print(p.get_management_info(2))
b'\x02\xd8h\xab\xe0\x00\x00\xfc\xe0@'
10
Container:
    ChargeVoltageLimit = -10.136
    DischargeVoltageLimit = -21.536
    ChargeCurrentLimit = 0.0
    DischargeCurrentLimit = -80.0
    status = Container:
        ChargeEnable = False
        DischargeEnable = True
        ChargeImmediately2 = False
        ChargeImmediately1 = False
        FullChargeRequest = False
        ShouldCharge = False

edit: if I change to unsigned works as expected:

    management_info_fmt = construct.Struct(
        "ChargeVoltageLimit" / DivideBy1000(construct.Int16ub),
        "DischargeVoltageLimit" / DivideBy1000(construct.Int16ub),
abelsson commented 1 year ago

Right, yes it does appear that it should be unsigned - sorry! The protocol specification was unclear and it seems the data from my battery didn't show the signedness bug. Thanks for catching it!