Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modbus exception 2 with d.scan() on Model ID 714 SMA Sunny Tripower X 20 #89

Open
Friedemannn opened this issue Apr 15, 2024 · 13 comments

Comments

@Friedemannn
Copy link

Friedemannn commented Apr 15, 2024

Hi,
I'm trying to read out a SMA Tripower X Inverter.
During daytime I can read up to and including Model 712, but on Model 714 I'm getting following error:

ModbusClientException: Modbus exception 2: addr: 41161 count: 95

Code up to this point is:
import sunspec2.modbus.client as client
d = client.SunSpecModbusClientDeviceTCP(slave_id=126,ipaddr='172.23.58.22', ipport=502,trace_func=print)
d.scan()

According to the model_714.json and the PICS file supplied by SMA this adress corresponds to the Model ID and should be of size 1.

grafik
41161

As far as I understand pysunspec2 should do d.read(41161,1) and not d.read(41161,95). (Count corresponds to size/length?)

If I do .read() manually I'm getting the following results:
grafik
With d.read(41161,3) its the exception again: ModbusClientException: Modbus exception 2: addr: 41161 count: 3
If I do d.read(41162,1) its b'\x00]' which corresonds to [0,93].

This probably has something to do with Issue #36, but I don't fully understand whats happening. I've also run @bijwaard's sma-test.py and got this result:

41161: ID=234
41162: L=93
traceback ...
Modbus exception 2: addr: 41256 count: 1

Just to check if I understand whats happening:
With d.read(41161,1) I'm reading the first byte of 41161 which should be something like [0,714] but the Inverter responds with something wrong which trips up d.scan()? Edit: [2,202] is correct, it equal 2*256+202=714
With d.read(41161,2) I'm reading the first two bytes of 41161, which is 41161 and 41162? Edit: That is whats happening.
With d.read(41161,3) I'm trying to read 41163 which doesn't exist/isn't implemented. Because of that I'm getting the exception.
@bijwaard's sma-test.py somehow adds an offset with which one can somehow successfully read the whole model? Why is that?

To conclude, is this a problem with pysunspec2 or should I contact SMA? (Or with my implementation?)

(When I played around with it yesterday d.scan() didn't work during daytime but did work during nighttime. Without sun I've gotten the following result for 714:

{"ID": 714, "L": 18, "PrtAlrms": null, "NPrt": 0, "DCA": null, "DCW": null, "DCWhInj": null, "DCWhAbs": null, "DCA_SF": -1, "DCV_SF": 0, "DCW_SF": 1, "DCWH_SF": 0, "Tmp_SF": null}]}

But L should be 93? Anyhow, today I was not able to replicate it, the exception still pops up even without sun. Maybe because it has nothing to do with it?) Edit: Is replicable, see below.

@bijwaard
Copy link

Hi,
Hope someone can spot the error with your inverter, my inverter does not have your Model, so hard for me to test this. The checkWithOffsets() function in the script sma-test.py simply walks through the Models via modbus respecting their lengths. I noticed that the script is silently ignoring exceptions, you may want to change the exception handling to something like below, to see actual exceptions (you can choose to ignore them by not setting valid=False):

    except Exception as e:
      print("Problem reading register %s: %s"%(reg+1,str(e)))
      valid=False
      pass

Kind regards,
Dennis

@Friedemannn
Copy link
Author

Hi @bijwaard,

thank you for your reply!
I've added your code snippet like this:

def checkWithOffsets():
  valid=True
  reg=41161
  while valid:
    res1=d.read(reg,1)
    res1=16*res1[0]+res1[1]
    print("%d: ID=%s"%(reg,res1))
    try:
      res2=d.read(reg+1,1)
      res2=16*res2[0]+res2[1]
      print("%d: L=%s"%(reg+1,res2))
    except Exception as e:
      print("Problem reading register %s: %s"%(reg+1,str(e)))
      valid=False
      pass

    if res2==0:
      break
    reg=reg+2+res2

And got this output this afternoon:

41161: ID=234
41162: L=93
Traceback (most recent call last):
...
sunspec2.modbus.modbus.ModbusClientException: Modbus exception 2: addr: 41256 count: 1

and without sun a few minutes ago:

41161: ID=234
41162: L=18
41181: ID=4335
41182: L=0

So the additional code snippet doesn't make a difference during sunlight. (I've never tested sma-test.py wo sun.)
d.scan() and d.DERMeasureDC[0].get_dict(computed=True) is once again outputting this without sun:

{'ID': 714,
'L': 18,
'PrtAlrms': None,
'NPrt': 0,
'DCA': None,
'DCW': None,
'DCWhInj': None,
'DCWhAbs': None,
'DCA_SF': -1,
'DCV_SF': 0,
'DCW_SF': 1,
'DCWH_SF': 0,
'Tmp_SF': None}

With sun im getting the same exception today as the days before.

So it does indeed make a difference if the sun is shining or not. Maybe it just wasnt dark (long) enough yesterday in order for the second cpu in the inverter to be shut down.

What I'm wondering now is: Why does d.read(41161,3) and sma-test.py (with or wo sun) give different results for the Model ID on register 41161 than d.scan() without sunlight? 234 vs. 714

(And of course I'm still wondering why d.scan() isn't working while the sun is shining.)

I guess I'm gonna have to investigate what d,scan does in detail in the next few days.

@bijwaard
Copy link

Regarding sma_test: Since d.read() returns byte array insead of hexadecimal, so you'll need to multiply res1[0] and res2[0] with 256 instead of 16, this probably fixes the model number 234-32+512 and maybe also length 18-16+256.

Furthermore, I would suggest to enable trace logging, so sunspec/modbus experts can follow the complete modbus interaction of d.scan().

@Friedemannn
Copy link
Author

Friedemannn commented Apr 17, 2024

Thanks once again for the input.
So i guess the plot thickens, that something with d.scan() is going wrong(?).

Here is the output of d.scan() with trace logging.
scan_w_tracelogging.txt

How does one read this?

@bijwaard
Copy link

bijwaard commented Apr 17, 2024

The tracelog gives sunspec/modbus requests (>) and inverter responses (<) in hexademimal format. You may be able to spot the ID=714 (i.e. 0x02CA) of your model 7 lines from the end. Normally pysunspec2 interprets this for you using the JSON files;-)

Your trace seems to be when everything is ok, you can retry when the inverter is sleepy.
The outlier seems to be the length field of model 714 that sometimes gives L=18 with sma-test.py and d.scan(), and sometimes gives L=93 with sma-test.py while d.scan() fails. The sunspec table in your first message specifies the length to be L=93. The sizes in the JSON file are probably the number of bytes to read for certain attributes.

With the factor 256 explained above, sma-test.py will give ID=65535 (0xffff) for the last model with length L=0, i.e. for my inverter it closes with:

...
40555: ID=132
40556: L=64
40621: ID=160
40622: L=48
40671: ID=65535
40672: L=0

@Friedemannn
Copy link
Author

Friedemannn commented Apr 17, 2024

Thanks for the explanation, I think I'm slowly getting the hang of it.

The tracelog is during sunlight when L=93.
I'm not sure if everything is ok because when you look at the last 8 lines something strange happens:

> 0000000000067E03A0C90001 ->request Register: 41161 Count: 1 (Model ID)
< 0000000000057E030202CA ->response: 714 (uint16)
> 0000000000067E03A0CA0001 ->request Register: 41162 Count: 1 (Model Length)
< 0000000000057E0302005D ->response: 93 (uint16)
> 0000000000067E03A0CB0003 ->request Register: 41163 Count: 3 (PrtAlrms and should be size 2 not 3, PrTAlrms is marked as unimplemented)
< 0000000000097E0306FFFFFFFF0003 ->response: ? (should be bitfield32) (The inverter only responded with 97E0306 on the very first request)
> 0000000000067E03A0C9005F ->request Register: 41161 Count: 95 (Tries to read up to 41255 which should work because last address is 41244 with size 2 according to the table provided by SMA)
< 0000000000037E8302 ->response: Disconnect/modbus exception 2 (?)

If I look at the other requests and responses (tbh I only compared it to the first 13 lines (Edit: now until line 27)) in the tracelog, I'm noticting that:

On the first two models pysunspec individually reads Model ID and Length after that it reads the whole model (from first adress to last adress) at once with address [Model ID adress] and count: [Model length + 2] and then probably does the same thing with the next models. Edit: Not always on Model 701 for example it reads the last adress separately maybe because its a string with size 32?

With Model 714 it also reads PrtAlarms besides ID and Length. Which is weird because it seems kinda random and it should respond with None(?) because its unimplemented. And then the Inverter disconnects when pysunspec tries to read [Model ID adress] [Length + 2].

Edit2: I've tried to max out count on d.read(41161, count) And reached 22, which corresponds to 41182 which is Prt.1.ID. Everything above yields Modbus exception 2 (prbly, I tried until 30 to see if something changes if I read the whole IDStr).

So I guess the plot "de-thickens" that somethings going wrong with d.scan()? :D
And its probably the fault of the inverter?

Edit3: I just remembered that we have another Tripower X 20 Inverter, which currently has no panels connected to it. I've just run d.scan() on that one and it also responds with L=18 so its even more likely that it does make a difference if DC Power is supplied or not.

@bijwaard
Copy link

Can you try res2=d.read(41181,1) and d.read(41182,1)when you get L=93?
I wonder if you still get ID=0xffff and L=0 on these adresses, like after L=18. In that case your inverter sunspec may be wrong.

@Friedemannn
Copy link
Author

Friedemannn commented Apr 17, 2024

Here's the result:
grafik
If that is what you meant?

This still has the expected output but d.read(41183,8) has not: (I think this should result in None)
grafik

With the adress table for reference:
grafik

And here's the whole overview:
STP-X_STP_xx-50_Sunspec_Modbus_Model_PICS_Overview_V1.zip

Edit: I'm getting the same results with this tool. (But you have to shift every adress by 1.)
grafik

@bijwaard
Copy link

Yes, that is what I expected. The length given for model 714 by your inverter should probably always be 18 to correctly read the next model, which is the end of the chain with ID=0xffff and L=0.

It sometimes returns 93 as in the table of your first model. Do you have the rest of the table, e.g. what registers are supposed to be just before address 41181+93?

@Friedemannn
Copy link
Author

Friedemannn commented Apr 17, 2024

I don't think so, it should be 93, because during power production it should also display the data of the different DC ports.

You're maybe confusing the start adress of this model. 41161 is the Model ID. One before 41161+93 is 41253 which is Prt.3.DCSta. Right before 41181+93 there is nothing, because Model 714 is the last model and ends with adress 41255 which belongs to Prt.3.DCAlrm of size 2.

This is the complete table for 714 the complete xlsx is linked in my previous comment:

grafik
grafik
grafik

@bijwaard
Copy link

bijwaard commented Apr 18, 2024

summarizing, the next sunspec model read would start at:

  • register 41161+2+18=41181 at nighttime/no sun, which is: Prt.1.PrtTyp (supported), and gives 0xffff in your test to indicate undefined model
  • the next 2 bytes d.read(41182,1) gives 0 to indicate length 0 of undefined model, this is register Prt.1.ID (supported) with sun.
  • register 41161+2+93=41256 with sun, that is just beyond Prt.3.DCAlrm, since that is bitfield32 (2 register words). d.read(41256,1) should be 0xffff to make pysunspec2 happy
  • d.read(41257,1) with sun should give L=0 for to satisfy pysunspec2 to indicate 0 length of undefined next model.

Not sure if sunspec requires the last model to be 0xffff with 0 length, else this may be sunspec compliance issue of your inverter. Does SMA have a firmware update that fixes it? Else you could contact SMA about it.

In the meantime, pysunspec2 could be modified to ignore the read error of the last model of d.scan() and return everything read upto that point. On second thought, pysunspec2 may still remember the read models, in that case you could just put try/except around d.scan() call, and try pysunspec2 to get the model 714 contents.

@Friedemannn
Copy link
Author

Friedemannn commented Apr 18, 2024

Hi Dennis,

thank you for all your help.
Ig the issue is then that the inverter changes the Model Length correctly with sun/no sun but does'nt provide more adresses with sun.

I already updated the firmware to the newest version available. (03.06.15.R)
I've created a support request with SMA and will report back with news, if there are any.

Yeah, I'll prbly use try/except until it's fixed.

Until then, thank you again for the help and time invested.

@Kudrat9
Copy link
Contributor

Kudrat9 commented Apr 19, 2024

Hi Friedemannn, this seems like an issue with the inverter itself. The length of a model should be fixed (with or without DC power). Since you've created a support request with SMA, I hope they can help you out. We'll also try and reach out to them to get some input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants