sunspec / pysunspec2

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

How to use numbered models? #51

Closed bijwaard closed 1 year ago

bijwaard commented 3 years ago

Dear all, It is unclear to me how I can read/use the model parts, since for SMA (I'm using v1.0.5) there are no names like "common" attached to the models like in the repository Readme examples. It only has numbered items like 1:, 11:, .. How can I use such a model? 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'

Originally posted by @bijwaard in https://github.com/sunspec/pysunspec2/issues/36#issuecomment-943147929

Some further tinkering:

>>> d.models[1]
[<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7f4851ed7f10>]
>>> d.models[1].read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'read'
>>> d.models[1][0].read()
>>> d.models[1][1].read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> print(d.models[1][0])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/dennis/compiling/SST/pysunspec2/sunspec2/device.py", line 458, in __str__
    return self.disp()
  File "/home/dennis/compiling/SST/pysunspec2/sunspec2/device.py", line 467, in disp
    s = '%s%s%s:\n' % (indent, self.gdef[mdef.NAME], index)
TypeError: 'NoneType' object is not subscriptable
bijwaard commented 3 years ago

Looks like the model can be retrieved as follows, however most of the functions and attributes don't seem to give an answer on my SMA Inverter:

 >>> m=d.models[11][0]
 >>> m.[TAB KEY]
m.access_regions  m`.gdef            m.gname           m.mid             m.model_len       m.set_dict(
m.add_error(      m.get_dict(       m.group_class(    m.model           m.offset          m.set_json(
m.device          m.get_json(       m.groups          m.model_addr      m.points          m.set_mb(
m.disp(           m.get_mb(         m.index           m.model_def       m.points_len      m.write(
m.error_info      m.get_text(       m.len             m.model_id        m.read(           m.write_points(
 >>> m.groups
OrderedDict()
 >>> m.points
OrderedDict()
 >>> m.device
<sunspec2.modbus.client.SunSpecModbusClientDeviceTCP object at 0x7f7577ba1520>
 >>> m.get_json()
'{}'
 >>> m.gname
 >>> m.index
 >>> m.model
<sunspec2.modbus.client.SunSpecModbusClientModel object at 0x7f7576166760>
 >>> m.model_id
11
 >>> m.points_len
0
 >>> m.model_len
13
 >>> m.len
13
 >>> m.access_regions
[]
 >>> m.access_regions
[]
 >>> m.error_info
'Model definition not found for model 11\n'
 >>> m.mid
'5364e491-86f2-4e2c-a8ba-d8e7edef6bcb_1'
 >>> m.read()
 >>>

Still not sure how to use the model effectively.

Kind regards, Dennis

shelcrow commented 3 years ago

Are you installing through PIP or through cloning the repo?

If you are cloning the repo you have to add the --recursive tag to get the models along with the repo, otherwise the models will be missing:

git clone https://github.com/sunspec/pysunspec2.git --recursive

Another way to check if the models are missing is to see if the models directory under sunspec2 is empty.

bijwaard commented 3 years ago

I initially cloned the repo without recursive, didn't know this was necessary as it is not specified in the psunspec2 README.rst, my models folder is indeed empty. I proceeded installing through PIP. Now the model names do show up, thanks! I understand now that the read() method does not directly show anything, it just populates the model with the most recent values. The model seems to be correctly populated now, great!

>>> import sunspec2.modbus.client as client
>>> d = client.SunSpecModbusClientDeviceTCP(slave_id=126, ipaddr='192.168.0.125', ipport=502)
>>> d.scan()
>>> for i in d.models:
...     if type(i)==str: print(d.models[i][0].gname)
... 
common
model_11
model_12
inverter
nameplate
settings
status
controls
storage
volt_var
freq_watt_param
reactive_current
watt_pf
volt_watt
mppt
>>> m=d.common[0]
>>> m.gname
'common'
>>> m.read()
>>> m.get_json()
'{"ID": 1, "L": 66, "Mn": "SMA", "Md": "Solar Inverter", "Opt": "9098", "Vr": "39191300", "SN": "305131922", "DA": null, "Pad": 32768}'
>>> m=d.inverter[0]
>>> m.read()
>>> m.get_json()
'{"ID": 103, "L": 50, "A": 5, "AphA": 2, "AphB": 2, "AphC": 2, "A_SF": -1, "PPVphAB": null, "PPVphBC": null, "PPVphCA": null, "PhVphA": 2396, "PhVphB": 2385, "PhVphC": 2398, "V_SF": -1, "W": 11, "W_SF": 1, "Hz": 5001, "Hz_SF": -2, "VA": 13, "VA_SF": 1, "VAr": -7, "VAr_SF": 1, "PF": null, "PF_SF": -3, "WH": 1567066, "WH_SF": 1, "DCA": null, "DCA_SF": null, "DCV": null, "DCV_SF": null, "DCW": null, "DCW_SF": 1, "TmpCab": 30, "TmpSnk": null, "TmpTrns": null, "TmpOt": null, "Tmp_SF": 0, "St": 4, "StVnd": null, "Evt1": 0, "Evt2": null, "EvtVnd1": null, "EvtVnd2": null, "EvtVnd3": null, "EvtVnd4": null}'
bijwaard commented 3 years ago

For new users it may help to mention both installation methods (PIP as well as git clone) in the README.rst. And specifically mention the need for recursive cloning. When people forgot to clone recursively, they may be able to do this later with git submodule update --init --recursive