Frankkkkk / python-pylontech

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

US2000: works perfectly. US2000C: no communication at all #23

Open df8oe opened 1 year ago

df8oe commented 1 year ago

As title says: has anyone successfully communicated with US2000C? When talking to US2000C I only get

File "/usr/lib/python3.10/site-packages/pylontech/pylontech.py", line 270, in get_values f = self.read_frame() File "/usr/lib/python3.10/site-packages/pylontech/pylontech.py", line 200, in read_frame f = self._decode_hw_frame(raw_frame=raw_frame) File "/usr/lib/python3.10/site-packages/pylontech/pylontech.py", line 181, in _decode_hw_frame assert got_frame_checksum == int(frame_chksum, 16) ValueError: invalid literal for int() with base 16: b'' Tested with two different setups (RPI, batteries) - same result...

df8oe commented 1 year ago

Additional question:

Can I disable anything so that everything which is received is displayed to check if hardware connection is working at all? The above error messages are identical if I call a serial port which does not exist. The adaptor is a CH340 one which works in a setup of US2000 (without C) perfectly.

maxx-ukoo commented 1 year ago

@df8oe Do you have real battery? Could you help with providing logs from battery? To check connection you can use terminal like HTerm and send RAW requests. If all ok - you will see RAW response. Could you help me with logs from real battery? I try to create pylontech emulator, this python script can communicate with my emulator but inverter just ask protocol version for batteries with address 52, 42, 32, 22, 12 and 02. I send responce but it looks like inverter didn't recognize responce.

52 => 7E 30 30 35 32 34 36 34 46 30 30 30 30 46 44 39 35 0D 42 => 7E 30 30 34 32 34 36 34 46 30 30 30 30 46 44 39 36 0D 32 => 7E 30 30 33 32 34 36 34 46 30 30 30 30 46 44 39 37 0D 22 => 7E 30 30 32 32 34 36 34 46 30 30 30 30 46 44 39 38 0D 12 => 7E 30 30 31 32 34 36 34 46 30 30 30 30 46 44 39 39 0D 02 => 7E 30 30 30 32 34 36 34 46 30 30 30 30 46 44 39 41 0D

This software do the same requests but with different addresses. I don't have real battery but accrding to pylontech specifications this software generate incorrect address.

df8oe commented 1 year ago

I do not have this battery by myself, but I do have access to a "real one". Can you please point me to a CLI version for raw requests? Software is running on a rpi3b+ without GUI - I am accessing via ssh.

maxx-ukoo commented 1 year ago

@df8oe in console you can do it with next step: open terminal on and execute stty -F /dev/ttyxxx 9600 cat /dev/ttyxxx

switch to another terminal and execute next commands line by line: echo -n -e '\x7E\x30\x30\x35\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x35\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x34\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x36\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x33\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x37\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x32\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x38\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x31\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x39\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x30\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x41\x0D' > /dev/ttyxxx

switch to terminal 1 and get result

Replace /dev/ttyxxx with real serial port

df8oe commented 1 year ago

Thanks. I will do this next time. The battery is owned by a friend and I must contact him to work on it. I will start this today hope his is not on holidays. I will keep you tracked because I am much interested in a solution to access the newer batteries. Thanks for your pointing me to a simple and fast testing environment.

eperdeme commented 1 year ago

@df8oe in console you can do it with next step: open terminal on and execute stty -F /dev/ttyxxx 9600 cat /dev/ttyxxx

switch to another terminal and execute next commands line by line: echo -n -e '\x7E\x30\x30\x35\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x35\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x34\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x36\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x33\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x37\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x32\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x38\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x31\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x39\x0D' > /dev/ttyxxx echo -n -e '\x7E\x30\x30\x30\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x41\x0D' > /dev/ttyxxx

switch to terminal 1 and get result

Replace /dev/ttyxxx with real serial port

Morning, I get no output on that command, but picocom works fine on the dev on 115200 for standard text. Guess I've enabled the admin console, no idea how to exit the admin console.

pylon>info 2 @ Device address : 2 Manufacturer : Pylon Device name : US3000C

etc

maxx-ukoo commented 1 year ago

@eperdeme for 115200 you should set right speed in stty -F /dev/ttyxxx 9600 command. Did you try with 9600 or 115200?

df8oe commented 1 year ago

I can confirm that there is absolutely no output if I send the echoes to the device. I have tried the above commands and I get no output at all on the US2000C. Then I have tried on my own system with US2000 (without 'C' which works perfectly with pylontech) and there is no output, too. I think there is an issue in the procedure. Because "cat" delivers only the output of the time I started it and then ends I have tried 'tail -f /dev/ttyUSBxxx' but no output, too.

eperdeme commented 1 year ago

My testing was invalid as I was using the wrong USB device as I have both USB1 - console(232) + USB0 - RS485 connected.I can't get any response on the 485 but to validate my cable I'll drag a windows laptop up and use another app.

df8oe commented 1 year ago

I used the correct device (in my case /dev/ttyUSB1) and the correct speed. pylontech works in this setup for US2000 (without 'C') perfectly, with US2000C it seems that pylontech gets no communication at all(??) Systems are running on RPI3B+ with Archlinux, pylontech is installed via pip.

df8oe commented 1 year ago

Any idea how to step forward? I have instantly access to an US2000C now.

Frankkkkk commented 1 year ago

Hi @df8oe , could you try and follow this step please ? Thanks !

df8oe commented 1 year ago

Inserting of the print(raw_frame) gives no other informations. There seems to be no communication at all. Dip switch (speed) is set to 115200 baud, I tried connecting RS485-USB-adaptor to both RJ45 (RS485 and CAN) because I have found informations on the web that RS485 connections of CAN work but not at RS485 plug, but no results at all. I think I must start at the absolute beginning:

petero-dk commented 1 year ago

Just to throw it in there because I made that mistake. The input of the RJ45 plug changed between the 2000 and 2000C, on the 2000C it supported RS485 on both pins 1,2 AND 7,8 on the 2000C it only supports on 7,8

From the 2000 Manual: image

From the 2000C Manual: image

And yes, it seems you are correct that the ports are now identical on the 2000C whereas on the 2000 they had different functionality

df8oe commented 1 year ago

Yes, I have noticed this. I have connected 7/8 to RS485 and 6 to GND. I tried both connections (CAN/RS485) but it looks like US2000C does not answer, maybe it does not accept the command at all. I am looking for debug this.

Marky0 commented 1 year ago

@df8oe did you manage to get any further with this ? I seem to have the same problem with US5000 and note that the wiring of the RJ45 pin port posted above is the same for US5000 and US2000C so likely the same problem.

When I follow @Frankkkkk step of printing the frame I always get back b'20024642E002FF' But I get the same even when I am not connected to the RS485 port of the battery, suggesting there is no connection. Just to be clear, I connect to the master battery B/RS485 port.

df8oe commented 1 year ago

I have not made any progress. Same here. I do have access to two friends US2000C connected via RS485-USB-adaptor to RPI. None of them answers to any commands. There is no difference if they are connected or not. Hardware is working fine: When I attach an US2000 everything works like a charm. I played around with communication speed without success.

Marky0 commented 1 year ago

Thanks @df8oe, @Frankkkkk any ideas ?

df8oe commented 1 year ago

I found informations under this link: https://www.photovoltaikforum.com/thread/172547-daten-von-pylontech-kompatiblem-akku-auslesen-rs485/ (post from Mattes33 12/29/2022) and will give it a try when I do have time...

strom-peter commented 1 year ago

Moin, I am able to communicate with the US2000C ... ... I send: echo -n -e '\x7E\x30\x30\x30\x32\x34\x36\x34\x46\x30\x30\x30\x30\x46\x44\x39\x41\x0D' > /dev/ttyUSB0 ...I got: stty -F /dev/ttyUSB0 115200 cat /dev/ttyUSB0 ~200246000000FDB2 so the HW is ok and the Address is starting with 02

>>> import pylontech >>> p = pylontech.Pylontech() _>>> print(p.get_values_single(2)) // get values from first US2000C send=b'~20024642E00202FD33\r' rec=b'~20024600C06E11020F0D040D040D030D040D040D040D040D040D040D030D030D040D040D030D03050B950B690B690B6A0B7E0000C337C03302C3500041E64E\r' Container: NumberOfModule = 2 NumberOfCells = 15 CellVoltages = ListContainer: 3.332 3.332 3.331 3.332 3.332 3.332 3.332 3.332 3.332 3.331 3.331 3.332 3.332 3.331 3.331 NumberOfTemperatures = 5 AverageBMSTemperature = 23.4 GroupedCellsTemperatures = ListContainer: 19.0 19.0 19.1 21.1 Current = 0.0 Voltage = 49.975 Power = 0.0 CycleNumber = 65 RemainingCapacity = 49.203 TotalCapacity = 50.0 TotalPower = 0.0 StateOfCharge = 0.98406

and

_>>> print(p.get_values_single(3)) // get values from second US2000C send=b'~20034642E00203FD31\r' rec=b'~20034600C06E11030F0D040D040D040D040D040D040D040D040D030D030D030D030D030D030D03050B950B6E0B6F0B6C0B820000C335BE4202C3500041E633\r'

Container: NumberOfModule = 3 NumberOfCells = 15 CellVoltages = ListContainer: 3.332 3.332 3.332 3.332 3.332 3.332 3.332 3.332 3.331 3.331 3.331 3.331 3.331 3.331 3.331 NumberOfTemperatures = 5 AverageBMSTemperature = 23.4 GroupedCellsTemperatures = ListContainer: 19.5 19.6 19.3 21.5 Current = 0.0 Voltage = 49.973 Power = 0.0 CycleNumber = 65 RemainingCapacity = 48.706 TotalCapacity = 50.0 TotalPower = 0.0 StateOfCharge = 0.9741200000000001

...so it is working, thanks to Frankkkkk

Marky0 commented 1 year ago

@strom-peter thanks !!!! You have found the solution. Pylontech.get_values() doesn't appear to work because the starting address is as you say 2. Once I got this error I hadn't tried any of the other commands doh !

So I record the full solution for three US5000 packs I have connected in parallel. (1) Use the USB to RS485 adaptor suggested by @Frankkkkk here, I bought mine from AliExpress (2) Make up a custom cable using the following wiring for the RJ45 connector

      RJ45 connector                    USB/RS422 adaptor         
      Pin 7 : Brown/White               D+ Pin A 
      Pin 8 : Brown                     D- Pin B

(3) Connect RJ45 connector to US5000 port B/RS485 on the master module (4) The following commands will generate the following response

p = Pylontech()
print(p.get_protocol_version())                #does not work - checksum error
print(p.get_manufacturer_info())               #does not work - checksum error
print(p.get_system_parameters())               #returns valid response !! 🥇 
print(p.get_management_info())                 #does not work - exception
print(p.get_module_serial_number())            #does not work - checksum error
print(p.get_values())                          #does not work - checksum error
print(p.get_values_single(1))                  #does not work - checksum error
print(p.get_values_single(2))                  #returns valid response !! 🥇 for Module 1
print(p.get_values_single(3))                  #returns valid response !! 🥇 for Module 2
print(p.get_values_single(4))                  #returns valid response !! 🥇 for Module 3
print(p.get_values_single(5))                  #does not work - checksum error - but I only have 3 modules ! 
df8oe commented 1 year ago

Nice solution @strom-peter I can confirm that the solution is working for US2000C, too. Nice idea. This is a perfect hotfix, but for a perfect solution we should investigate why the other queries get checksum errors. In my view the script should be able to identify if US2000 or 2000C (and compatible) is connected...

strom-peter commented 1 year ago

...or it is possible to use a parameter for select the address in the Function.

I think we got a checksum errors because there are no responds data.

print(p.get_protocol_version()) send= b'~2000464F0000FD9A\r' rec= b'' // no responds data Traceback (most recent call last): File "", line 1, in File "/python-pylontech-master/pylontech/pylontech.py", line 228, in get_protocol_version return self.read_frame() File "python-pylontech-master/pylontech/pylontech.py", line 201, in read_frame f = self._decode_hw_frame(raw_frame=raw_frame) File "/python-pylontech-master/pylontech/pylontech.py", line 182, in _decode_hw_frame assert got_frame_checksum == int(frame_chksum, 16) ValueError: invalid literal for int() with base 16: b''

Marky0 commented 1 year ago

@df8oe it appears that they do all work providing you force them to look at an address > 1, currently they default to 0. This requires an edit to the python function definitions to include an input for the module address, dev_id. I give an example for get_manufacturer_info, I am sure you can work out the rest.

def get_manufacturer_info(self, dev_id):
    self.send_cmd(dev_id, 0x51)
    f = self.read_frame()
    return self.manufacturer_info_fmt.parse(f.info)   

now get the manufacturer info with dev_id >=2

 print( get_manufacturer_info(2) )