sunspec / pysunspec2

SunSpec Python library for interfacing with SunSpec devices.
Apache License 2.0
57 stars 22 forks source link

Modbus exception with d.scan() on SMA inverter #36

Closed bijwaard closed 3 years ago

bijwaard commented 3 years ago

Dear developers, I get a Modbus exception with v1.0.4 (both via pip3 install as well as from master branch) when trying to scan() an SMA inverter (STP-5000TL-20 via Ubuntu 20.04.02 LTS), see below: $ python3 Python 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information.

import sunspec2.modbus.client as client d = client.SunSpecModbusClientDeviceTCP(slave_id=126, ipaddr='192.168.0.125', ipport=502) d.scan() Traceback (most recent call last): File "", line 1, in File "/home/dennis/.local/lib/python3.8/site-packages/sunspec2/modbus/client.py", line 262, in scan model.read() File "/home/dennis/.local/lib/python3.8/site-packages/sunspec2/modbus/client.py", line 85, in read data = self.model.device.read(self.model.model_addr + self.offset, self.len) File "/home/dennis/.local/lib/python3.8/site-packages/sunspec2/modbus/client.py", line 317, in read return self.client.read(addr, count, op) File "/home/dennis/.local/lib/python3.8/site-packages/sunspec2/modbus/modbus.py", line 584, in read data = self._read(addr + read_offset, read_count, op=op) File "/home/dennis/.local/lib/python3.8/site-packages/sunspec2/modbus/modbus.py", line 545, in _read raise ModbusClientException('Modbus exception %d: addr: %s count: %s' % (except_code, addr, count)) sunspec2.modbus.modbus.ModbusClientException: Modbus exception 2: addr: 40085 count: 98

Any idea how to solve this?

I modified the exception, to also show len(resp)=9 and resp[TCP_HDR_LEN+1]=0x83, the output is below, and I hope this helps to analyse the issue:

  File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/modbus.py", line 545, in _read
    raise ModbusClientException('Modbus exception %d: addr: %s count: %s, len(resp)=%d, resp[TCP_HDR_LEN+1]=0x%x' % (except_code, addr, count, len(resp), resp[TCP_HDR_LEN + 1]))
sunspec2.modbus.modbus.ModbusClientException: Modbus exception 2: addr: 40085 count: 98, len(resp)=9, resp[TCP_HDR_LEN+1]=0x83

Kind regards, Dennis

bijwaard commented 3 years ago

Hi,

I looked in the SMA SunSpec document and couldn't find register 40085, and model ID is listed on address 40086 with value 12. In the PICS., it shows Point "ID" on address 40085 for model 12 with Value 12.

I figured out how to the use tracefunc, and get the following result when I enable it with a simple print function:

d = client.SunSpecModbusClientDeviceTCP(slave_id=126, ipaddr='192.168.0.125', ipport=502,trace_func=print)

When only reading the first 11 int16s from register 40085 everything goes well:

d.read(40085,11) 0000000000067E039C95000B < 0000000000197E0316000C0062000000000000000000010000000500010000 b'\x00\x0c\x00b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x01\x00\x00'

When reading one more byte, I trigger the issue:

d.read(40085,12) 0000000000067E039C95000C < 0000000000037E8302 Traceback (most recent call last): File "", line 1, in File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/client.py", line 317, in read return self.client.read(addr, count, op) File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/modbus.py", line 584, in read data = self._read(addr + read_offset, read_count, op=op) File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/modbus.py", line 545, in _read raise ModbusClientException('Modbus exception %d: addr: %s count: %s, len(resp)=%d, resp[TCP_HDR_LEN+1]=0x%x' % (except_code, addr, count, len(resp), resp[TCP_HDR_LEN + 1])) sunspec2.modbus.modbus.ModbusClientException: Modbus exception 2: addr: 40085 count: 12, len(resp)=9, resp[TCP_HDR_LEN+1]=0x83

When reading one int16 of register 40085, I get the expected 12 (0xc) back:

d.read(40085,1) 0000000000067E039C950001 < 0000000000057E0302000C b'\x00\x0c'

Reading register 40086, gives back 0xb, which looks like an invalid length, since length 98 is expected:

d.read(40086,1) 0000000000067E039C960001 < 0000000000057E03020062 b'\x00b

When doing the complete scan with a progress function it breaks during the scan of model 12, I get:

def progressPrint(*args,kwargs): ... print( "XXX"+" ".join(map(str,args))+"XXX", kwargs) ... return True d.scan(progress=progressPrint) 0000000000067E0300000003 < 0000000000097E0306FFFFFFFFFFFF 0000000000067E039C400003 < 0000000000097E030653756E530001 0000000000067E039C430001 < 0000000000057E03020042 XXXScanning model 1XXX 0000000000067E039C420042 < 0000000000877E038400010042534D410000000000000000000000000000000000000000000000000000000000536F6C617220496E76657274657200000000000000000000000000000000000039303938000000000000000000000000333931393133303000000000000000003330353133313932320000000000000000000000000000000000000000000000 0000000000067E039C860001 < 0000000000057E0302000B 0000000000067E039C870001 < 0000000000057E0302000D XXXScanning model 11XXX 0000000000067E039C86000D < 00000000001D7E031A000B000D00640003000100000040AD9FD6920000000000000000 0000000000067E039C950001 < 0000000000057E0302000C 0000000000067E039C960001 < 0000000000057E03020062 XXXScanning model 12XXX 0000000000067E039C950062 < 0000000000037E8302 Traceback (most recent call last): File "", line 1, in File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/client.py", line 262, in scan model.read() File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/client.py", line 85, in read data = self.model.device.read(self.model.model_addr + self.offset, self.len) File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/client.py", line 317, in read return self.client.read(addr, count, op) File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/modbus.py", line 584, in read data = self._read(addr + read_offset, read_count, op=op) File "/home/dennis/compiling/SST/pysunspec2/sunspec2/modbus/modbus.py", line 545, in _read raise ModbusClientException('Modbus exception %d: addr: %s count: %s, len(resp)=%d, resp[TCP_HDR_LEN+1]=0x%x' % (except_code, addr, count, len(resp), resp[TCP_HDR_LEN + 1])) sunspec2.modbus.modbus.ModbusClientException: Modbus exception 2: addr: 40085 count: 98, len(resp)=9, resp[TCP_HDR_LEN+1]=0x83

jayatsandia commented 3 years ago

This SMA device is likely not pySunSpec2-compliant. You'll have to use the original pysunspec python library because it is not backward compatible. There were major revisions to the structure of the datatypes when SunSpec moved to pysunspec2. Try: https://github.com/sunspec/pysunspec

bobfox commented 3 years ago

We will look at this in more detail but wanted to clarify the comment from @jayatsandia. pysunspec2 should be compatible with all SunSpec compliant devices and is backward compatible with all SunSpec standard model definitions and implementations. We recommend that you replace pysunspec with pysunspec2 for SunSpec device interaction. Support for pysunpec is very limited. The scripting syntax when interacting with devices is a little different in pysunspec2 than pysunspec so minor adjustments may be needed to scripts moving from pysunspec to pysunspec2.

SunSpec has updated the modeling and model definitions but still supports all existing model definitions.

jayatsandia commented 3 years ago

My mistake. I misunderstood the following statement in the pySunSpec2 README: "The Python objects used for interacting with devices have some differences from version 1 and it is not backward compatible with version 1. This version of pySunSpec must be used with devices implementing the 7xx series of information models as they use updated modeling concepts."

bobfox commented 3 years ago

No worries, good to clarify.

bijwaard commented 3 years ago

Hi again, I created a simple Python program sma-test.py.txt to test the addresses and length fields for the different models and this appears to work fine for my SMA inverter:

Here is the output for the offset test:

$ ./sma-test.py 40002: ID=1 40003: L=66 40070: ID=11 40071: L=13 40085: ID=12 40086: L=98 40185: ID=103 40186: L=50 40237: ID=120 40238: L=26 40265: ID=121 40266: L=30 40297: ID=122 40298: L=44 40343: ID=123 40344: L=24 40369: ID=124 40370: L=24 40395: ID=126 40396: L=64 40461: ID=127 40462: L=10 40473: ID=128 40474: L=14 40489: ID=131 40490: L=64 40555: ID=132 40556: L=64 40621: ID=160 40622: L=48 40671: ID=4335 40672: L=0

Kind regards, Dennis

Epyon01P commented 3 years ago

Can confirm this issue also happens on SMA SB 4000 TL, SB 1500, SB2000 TL and SB Storage 2500. So probably communication wih all SMA devices is affected. Communication works fine when using the old pysunspec library.

moorboss commented 3 years ago

Can confirm this issue also happens on SMA SB 4000 TL, SB 1500, SB2000 TL and SB Storage 2500. So probably communication wih all SMA devices is affected. Communication works fine when using the old pysunspec library.

It looks like I have the same problem with my SMA SB 3000TL-21 How can you use the old pysunspec library? Which file(s) do you need for that?

shelcrow commented 3 years ago

@bijwaard There was an issue with models reads being two registers short that we fixed in the latest release. Can you update pysunspec2 and try again?

bijwaard commented 3 years ago

Dear shelcrow, After updating the repo, and installing the new version, I don't get the exception anymore, see below. Great! It is however unclear to me how I can read/use the model, since there are no names like "common" attached to the models like in the Readme, only numbered items like 1:, 11:, .. Kind regards, Dennis

Python 3.8.10 (default, Sep 28 2021, 16:10:42) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sunspec2.modbus.client as client
>>> d = client.SunSpecModbusClientDeviceTCP(slave_id=126, ipaddr='192.168.0.125', ipport=502)
>>> d.scan()
>>> d.models
{1: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63dcafe50>], 
11: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63dcafc10>], 
12: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63dcafa60>], 
103: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63ddc50d0>], 
120: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63ddc5e80>], 
121: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63ddadb50>], 
122: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86490>], 
123: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86820>], 
124: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86880>], 
126: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86520>], 
127: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da864f0>], 
128: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86b80>], 
131: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86460>], 
132: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da86430>], 
160: [<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7fc63da342e0>]}
>>> d.common[0].read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/dennis/compiling/SST/pysunspec2/sunspec2/device.py", line 713, in __getattr__
    raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, attr))
AttributeError: 'SunSpecModbusClientDeviceTCP' object has no attribute 'common'
>>> d.common[1].read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/dennis/compiling/SST/pysunspec2/sunspec2/device.py", line 713, in __getattr__
    raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, attr))
AttributeError: 'SunSpecModbusClientDeviceTCP' object has no attribute 'common'
bijwaard commented 3 years ago

When will the new 1.0.5 release be available through pip install? It still gives me v1.0.4...

$ pip3 install pysunspec2
Collecting pysunspec2
  Using cached pysunspec2-1.0.4-py3-none-any.whl (251 kB)
Installing collected packages: pysunspec2
Successfully installed pysunspec2-1.0.4
$ pip3 uninstall pysunspec2
Found existing installation: pysunspec2 1.0.4
Uninstalling pysunspec2-1.0.4:
  Would remove:
    /home/dennis/.local/lib/python3.8/site-packages/pysunspec2-1.0.4.dist-info/*
    /home/dennis/.local/lib/python3.8/site-packages/sunspec2/*
Proceed (y/n)? y
  Successfully uninstalled pysunspec2-1.0.4

dennis@turbo:~/work/pysunspec2 $ sudo python3 setup.py install
/usr/lib/python3.8/distutils/dist.py:274: UserWarning: Unknown distribution option: 'python_requires'
  warnings.warn(msg)
/usr/lib/python3.8/distutils/dist.py:274: UserWarning: Unknown distribution option: 'extras_require'
  warnings.warn(msg)
...
running install_egg_info
Writing /usr/local/lib/python3.8/dist-packages/pysunspec2-1.0.5.egg-info
shelcrow commented 3 years ago

1.0.5 is now on PyPI. Please give it a try and let me know if you are still running into issues.