Giter Club home page Giter Club logo

pysunspec's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pysunspec's Issues

SMA sunny island: writing a value isn't working

Hi there,
I've the same issue as mentioned in the last comment of #9,
I'm writing 1 to reg 40375 (you have to choose the reg -1, so 40374) and get a "write ok".
But when reading it, it hasn't been changed. Pls. have a look:

modbus write 10.0.0.11 502 126 40374 1  
using MODBUS TCP
dev : 10.0.0.11 9600N81
addr: 126
op  : write
reg : 9DB6 (40374), data: 1
connecting...
Connecting to 10.0.0.11
[00][01][00][00][00][09][7E][10][9D][B6][00][01][02][00][01]
Waiting for a confirmation...
<00><01><00><00><00><06><7E><10><9D><B6><00><01>
write ok

isn't working, result is:

modbus read 10.0.0.11 502 126 40374
using MODBUS TCP
dev : 10.0.0.11 9600N81
addr: 126
op  : read
reg : 9DB6 (40374), num: 1
connecting...
Connecting to 10.0.0.11
reading with function code 0x03
[00][01][00][00][00][06][7E][03][9D][B6][00][01]
Waiting for a confirmation...
<00><01><00><00><00><05><7E><03><02><00><00>
reg 9DB6: 0000

Writing a 2 does the same, just 1 and 2 are allowed. Reading always shows 0, hmpf.
And the battery isn't loading.
SMA support answered: "We haven't any infos concerning that, sorry."
Fun, isn't it?

Thx a lot in advance for any hints!
smeop

Is handling of NaN values in scope of spec/library?

I‘ve noticed that SMA inverters use maximum unsigned values or minimum signed values in the respective data type number to indicate a NaN value. For example, model 101 single phase inverters will do so for phases B and C. This behaviour is documented by SMA.

Is this behaviour covered by the sunspec standard and this library? Couldn‘t find it in either code or specs I‘ve looked at?

Unknown point type uint64

Run the make_xls tool. Now it gets this error. This was working before.

Error loading model 00016 at C:\Python27\lib\site-packages\sunspec\core..\models\smdx\smdx_00016.xml: Unknown point type: uint64

Models: Fail if submodule not installed

Expected behaviour
A git clone should work out of the box or error / warn if dependencies are missing.

Actual behaviour
Git clone is installed correctly in develop mode. Module can be imported, client can be instantiated, but has the attributes client.model_1, client.model_111, ... instead of the expected client.common, client.inverter, ...

Steps to reproduce

git clone https://github.com/sunspec/pysunspec
pip install -e pysunspec

and then try an example such as https://pysunspec.readthedocs.io/en/latest/pysunspec.html#interacting-with-a-sunspec-device.

Suggested fix
Error out or warn the user / developer that the model definitions could not be found.

Notes
The README states that the clone should have --recursive for the git submodules, but that may be overlooked in development, customized or automated installations. This is to warn / fail early in case of an inconsistent and non-functioning installation.

No SMDX mapping

I have a couple of device types specifically 64113 and 64114 that don't have mappings in your release. How can I pull specific registers from them? I'd like to pull the whole block if possible.

I tried to do something like:
d.model_64113['40644']

That doesn't seem to work.

pysunspec for python 3.6

hi
i try to test the installation with Python3.6 using python -m unittest discover -v sunspec and get errors

Ran 40 tests in 0.046s
FAILED (errors=14)

Does pysunspec support Python3 already ?

Thanks

Interest in creating a base class for modbus.client classes

There are similar _methods in the ModbusClientRTU and ModbusClientDeviceTCP classes and so I thought I would do a comparison of the _read method to see if there's interest in creating something along the lines of a ModbusClientBase class. Below is a pseudo code draft of how such a class might look.

class ModbusClientBase:
    def _read(addr, count, op=FUNC_READ_HOLDING, trace_func=None, slave_id=None):
        resp = ''
        len_found = False
        except_code = None

        if slave_id is not None: #an RTU instance instead of TCP
            len_remaining = #RTU version
            req_structure = #RTU structure for the req struct command
            trace_func_structure = #RTU structure for the trace func inputs
        else: #TCP instance and not RTU instance
            len_remaining = #TCP version
            req_structure = #TCP structure for the req struct command
            trace_func_structure = #TCP structure for the trace func inputs
        
        req = struct.pack(req_structure, #Maybe a list containing the other TCP vs RTU specific arguments)

        if self.trace_func: #RTU has trace_func as an input and TCP has it attached to self. Should a uniform method be chosen?
            s = # This portion would need to be dynamically constructed based on TCP vs RTU
            for c in req:
                s += '%02X' % (ord(c))
            self.trace_func(s)


        # The TCP and RTU differ in their send methods and so binding a brief function in 
        # the above if statement to a variable `send` then call it here. For example, in 
        # the TCP case send = self.socket.sendall

        while len_remaining > 0:
            # Same idea here for a `receive` variable as the `send` variable listed above
            c = receive(len_remaining)
            len_read = len(c)
            if len_read > 0:
                resp += c
                len_remaining -= len_read
                if len_found is False and len(resp) >= #Dynamically set original len_remaining based on TCP vs RTU:
                    if not (ord(resp[#TCP VS RTU specific value]) & 0x80): #This statement
                        # appears in the while loop in the RTU version and outside the loop in 
                        # the TCP version
                else:
                    raise ModbusClientError('Response timeout')

        if trace_func:
            s = # This portion is RTU vs TCP specific and would need to be structured in the first 
                  # if statement
            for c in resp:
                s += '%02X' % (ord(c))
            trace_func(s)

        # There's a CRC check in RTU version but not TCP version. I am not familiar with CRC and so
        # I don't know if this is something that should be in both

        if except_code:
            raise ModbusClientException('Modbus exception %d' % (except_code))

        return resp[# This splice depends on RTU vs TCP and would need to be configured in the first if statement]

The ModbusClientRTU._read method can be found at here and the ModbusClientDeviceTCP._read method can be found here.

Pros:

  • Reduces code redundancy. If an error pops up it can be fixed for both TCP and RTU simultaneously

Cons:

  • Have to make variables have different meanings in the function based on the client type

Improving error reporting by masking less

Masking exceptions often makes it harder to understand and fix the problem, not easier. For example, running unit tests without having the models cloned (such as in #35 and others) results in this unhelpful message.

======================================================================
ERROR: test_client_device (sunspec.core.test.test_client.TestClientDevice)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/epc/t/612/pysunspec/sunspec/core/test/test_client.py", line 48, in test_client_device
    pathlist=self.pathlist)
  File "/epc/t/612/pysunspec/sunspec/core/device.py", line 175, in from_pics
    raise SunSpecError('Error loading PICS: %s' % str(e))
SunSpecError: Error loading PICS: Block index out of range: 1

That is masking a slightly better custom message which would have read:

Model file for model model 1 not found

which is masking the actually useful (and automatic) message:

[Errno 2] No such file or directory: '/epc/t/612/pysunspec/sunspec/core/../models/smdx/smdx_00001.xml'

Now certainly there are times that useful information can be added to a standard message. Above could be enhanced by a mention of the models subrepo and the search path feature so that a user/developer can look at the docs related to those topics.

In Python 3 you can simply raise ... from ... as below but I have not yet found a clean 2/3 compatible way to get a result like this.

altendky@tp:~$ cat rf.py
try:
    raise Exception('inner')
except Exception as e:
    raise Exception('outer') from e
altendky@tp:~$ python3 rf.py
Traceback (most recent call last):
  File "rf.py", line 2, in <module>
    raise Exception('inner')
Exception: inner

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "rf.py", line 4, in <module>
    raise Exception('outer') from e
Exception: outer

Regardless of chaining, is there any interest in discussing improving the clarity of the errors?

Outback AXS Port

I'm testing a Outback AXS Port with a FlexMax 60 Solar Charger. I have pysunspec setup on Ubuntu and have successfully connected to the AXS Port and inserted data from the FlexMax block (64112) into InfluxDB for Grafana. The problem i'm having is when i try to read the actual AXS Port block (64110), i'm getting a error on the read() saying either Connection Refused, Connection Reset By Peer, or Broken Pipe. I'm not understanding why this error is happening only when reading this particular block. Anybody have any ideas? I'm new to Python, just wondering what I could possibly be doing wrong.

Update instructions to use virtualenv, pip, and _not_ sudo

  • virtualenv allows isolation of installation of Python projects. This is basically the only way to install packages 'right'. --user hazards mixing library versions unexpectedly and installing into the system can corrupt entire installations in Linux.
  • pip should be called instead of calling setup.py directly so as to handle all dependencies at least. Also, don't use easy_install.
  • Do not use sudo to install. It's not consistent but lots of people have destroyed their python installations by doing this. The issue is that you end up mixing pip package management with the Linux system's package management and they don't necessarily cooperate well.

error running the pysunspec_test.py file

Receive following error on running the test file:

sudo python pysunspec_test.py
pySunSpec version: 1.0.8
Test device path: /usr/local/lib/python2.7/dist-packages/sunspec/core/test/devices

Traceback (most recent call last):
File "pysunspec_test.py", line 13, in
test.test_all()
File "/usr/local/lib/python2.7/dist-packages/sunspec/core/test/test_all.py", line 58, in test_all
(count_run, count_passed, count_failed) = module.test_all(pathlist, stop_on_failure)
File "/usr/local/lib/python2.7/dist-packages/sunspec/core/test/test_device.py", line 577, in test_all
if test(pathlist) is True:
File "/usr/local/lib/python2.7/dist-packages/sunspec/core/test/test_device.py", line 418, in test_device_from_pics
d1.from_pics(filename='pics_test_device_1.xml', pathlist=pathlist)
File "/usr/local/lib/python2.7/dist-packages/sunspec/core/device.py", line 127, in from_pics
raise SunSpecError('Error loading PICS: %s' % str(e))
sunspec.core.util.SunSpecError: Error loading PICS: Block index out of range: 1

What could be the reason ?

SMA Sunspec Control Model Not Compatible With pysunspec

Please feel free to remove this if you think it is not an issue or relevant and also correct me if I am wrong but I believe the pysunspec library is incompatible with SMA's sunspec implementation in the controls model (123).

SMA defines some of its control registers as "Parameter for PV system control" which are WO as opposed to sunspec's definition of RW.

This means that there is no point object created when a read() occurs for these registers, namely, Conn, WMaxLimPct, etc. Therefore the point member value_sf is never set even though there is a valid sf_point member which is of type ScaleFactor. This results in incorrect setting and reading of values as they are not scaled by the scale factor.

Note that:

  • m is SunSpecClientDevice object
  • controls is model 123
  • OutPFSet is defined by sunspec as RW and by SMA as WO

Example:

m.controls.OutPFSet = 1
print m.controls.OutPFSet
1
print m.controls.model.points['OutPFSet']
Point: id = OutPFSet impl= True addr = 40353 value_base = 1 sf_value = -4
print m.controls.model.points['OutPFSet'].value_getter()
1
m.controls.OutPFSet = 0.66
print m.controls.OutPFSet
0
print m.controls.model.points['OutPFSet']
Point: id = OutPFSet impl= True addr = 40353 value_base = 0 sf_value = -4
print m.controls.model.points['OutPFSet'].value_getter()
0
m.controls.OutPFSet = 6600
print m.controls.OutPFSet
6600
print m.controls.model.points['OutPFSet']
Point: id = OutPFSet impl= True addr = 40353 value_base = 6600 sf_value = -4
print m.controls.model.points['OutPFSet'].value_getter()
6600
print m.controls.model.points['OutPFSet'].value_sf
None
print m.controls.model.points['OutPFSet'].sf_point.value_base
-4

bug in sunspec/core/client.py

Found a bug in version 1.0.7, sunspec/core/client.py line 197:
raise SunSpecClientError('Error reading model %s' % model_type)
should be:
raise SunSpecClientError('Error reading model %s' % self.model_type)

Python 3 reads being converted to str

516287f
a3e7ede

if type(c) == bytes and sys.version_info > (3,):
    temp = ""
    for i in c:
        temp += chr(i)
    c = temp

It seems that if we switch the read bytes to str then they will never compare equal to the bytes (byte string) below. Why are we trying to work with str in py3 at all for generic incoming bytes? Sure, occasionally we'll want to decode some bytes to a string but not every byte and not with chr() normally.

if data[:4] == b'SunS':

(@jbm950, @bobfox)

The original symptom is:

Traceback (most recent call last):
  File "/home/altendky/st.pysunspec/Pysunspec_demo.py", line 188, in <module>
    sys.exit(main(sys.argv[1:]))
  File "/home/altendky/st.pysunspec/Pysunspec_demo.py", line 122, in main
    d = sunspec.core.client.SunSpecClientDevice(**client_args)
  File "/home/altendky/pysunspec/sunspec/core/client.py", line 775, in __init__
    self.device.scan(progress=scan_progress, delay=scan_delay)
  File "/home/altendky/pysunspec/sunspec/core/client.py", line 283, in scan
    raise SunSpecClientError(error)
sunspec.core.client.SunSpecClientError: Device responded - not SunSpec register map

Despite having gotten a response starting with SunS for base address 0.

Tagging format (an extra `.`?)

Shouldn't version tags be v1.0.8 not v.1.0.8? Ditto for v.1.0.7. Previous ones look correct. Noticed this when I was preparing a vcversioner pull request.

PICS: Block index out of range: 1

git cloned your repo
sudo python setup.py install

$ pysunspec_test.py 
pySunSpec version: 1.0.7
Test device path: /usr/local/lib/python2.7/dist-packages/sunspec/core/test/devices

Traceback (most recent call last):
  File "/usr/local/bin/pysunspec_test.py", line 13, in <module>
    test.test_all()
  File "/usr/local/lib/python2.7/dist-packages/sunspec/core/test/test_all.py", line 42, in test_all
    (count_run, count_passed, count_failed) = module.test_all(pathlist, stop_on_failure)
  File "/usr/local/lib/python2.7/dist-packages/sunspec/core/test/test_device.py", line 561, in test_all
    if test(pathlist) is True:
  File "/usr/local/lib/python2.7/dist-packages/sunspec/core/test/test_device.py", line 402, in test_device_from_pics
    d1.from_pics(filename='pics_test_device_1.xml', pathlist=pathlist)
  File "/usr/local/lib/python2.7/dist-packages/sunspec/core/device.py", line 111, in from_pics
    raise SunSpecError('Error loading PICS: %s' % str(e))
sunspec.core.util.SunSpecError: Error loading PICS: Block index out of range: 1

Checked the path shown:

$ ls /usr/local/lib/python2.7/dist-packages/sunspec/core/test/devices
mbmap_test_device_1_a.xml  mbmap_test_device_2.xml    mbmap_test_inverter_3.xml  pics_test_inverter_2.xml
mbmap_test_device_1_b.xml  mbmap_test_device_3.xml    pics_test_device_1.xml
mbmap_test_device_1_c.xml  mbmap_test_inverter_1.xml  pics_test_device_2.xml
mbmap_test_device_1.xml    mbmap_test_inverter_2.xml  pics_test_inverter_1.xml

What am I missing?

Reference to apt+pyserial seems out of place or unneeded.

Introduced in: 62ec0c6

https://github.com/sunspec/pysunspec/blame/9a7cd3a7072c89ef18673cb730ce28ee5d06e2ff/README.md#L72-L76

    on some systems (Debian based), you could be able to download it as a package (raspberry pi for ex.)

    ```
    $ sudo apt-get install python-serial
    ```

If this is really needed (envs are the way to go for development and are described below) then it belongs down in the dependencies section below. It's quite out of place where it is now.

Bug in python3 version of model_11

I found a bug the python 3 branch for model_11

The parsing of the MAC address should be different in py3.
In Python 3 the sock.recvfrom(...) call returns bytes while Python 2.7 recvfrom returns a string.
I couldn't find the line of code where sock.recvfrom(...) is called but this can be fixed in another way:

The function data_to_eui48 in core/util.py needs to be changed:

def data_to_eui48(data):
    return '%02X:%02X:%02X:%02X:%02X:%02X' % (ord(data[2]), ord(data[3]), ord(data[4]), ord(data[5]), ord(data[6]), ord(data[7]))

data is no longer of type str but of type bytes.

Therefore the line

data=data.decode('utf-8','backslashreplace') 

needs to be added.

A cleaner fix would be to search for all calls of sock.recvfrom(...) and change its output

pySunSpec Release 1.0.8 does not suport python3

I followed the instructions in the readme. It sends me to the latest release to download, unzip and install. I do that but use python3 instead of python for my commands. Then I try to run
python3 -m unittest discover -v sunspec Attached are my errors. It looks like python2 compatible code.
Help..

sunspec.log.gz

I also tried a git clone and a setup for python3 I get this:
charles:pysunspec$ sudo python3 setup.py install
r```
unning install
running build
running build_py
running build_scripts
running install_lib
byte-compiling /usr/local/lib/python3.6/dist-packages/sunspec/models/smdx/manifest.py to manifest.cpython-36.pyc
File "/usr/local/lib/python3.6/dist-packages/sunspec/models/smdx/manifest.py", line 89
except Exception, e:
^
SyntaxError: invalid syntax

running install_scripts
changing mode of /usr/local/bin/suns.py to 777
running install_egg_info
Removing /usr/local/lib/python3.6/dist-packages/pysunspec-2.0.0.egg-info
Writing /usr/local/lib/python3.6/dist-packages/pysunspec-2.0.0.egg-info

But the tests run to completion.

Ran 45 tests in 0.529s
- 

str_to_data() incorrectly adds length to point_data

The following function in sunspec/core/util.py is intended to convert a text string to bytes for writing to a device (i.e. via Modbus).

def str_to_data(s, slen=None):
    if slen is None:
        slen = len(s)
    if sys.version_info > (3,):
        s = bytes(s, 'latin-1')
    if slen < 16:
        s += b'\x00'
        slen += 1
    return struct.pack(str(slen) + 's', s)

The part I don't understand is:

    if slen < 16:
        s += b'\x00'
        slen += 1

if slen < 16:

Why is this here? It seems like all it does is add a null character if the string length is less than 16 bytes (or 8 Modbus registers). If you are unlucky enough to be writing an 8-register string, this causes an erroneous write of zero to the register immediately following the string. Indeed, this is how I discovered the bug.

Before I submit a pull request to delete these three lines of code, I'd like to understand what the intended purpose for adding the null byte is.

It seems like the only time you'd want to add a null byte would be to fill in the last word if the string had an odd number of characters. For this case, perhaps the check should be if slen % 2 == 1 instead of if slen < 16.

As far as I can tell, these to_data functions are only called with slen as an even number (i.e., point_len * 2), as in sunspec/core/client.py (on the last line in the code block below):

for block in self.blocks:
    for point in block.points_list:
        if point.dirty:
            point_addr = int(point.addr)
            point_len = int(point.point_type.len)
            point_data = point.point_type.to_data(point.value_base, (point_len * 2))

Travis only building PRs

As far as I can tell Travis isn't building for the master branch, only for PRs. It should build both.

Create wheel and publish on PyPi

I suspect that many users of this library will not be interested in Git and submodules etc. At least, those that want to distribute would find it a bit smoother if there were a wheel. There are always nuances but building a wheel is pretty much just venv/bin/python setup.py bdist_wheel.

I'll try to get a PR for this. We've already got Travis going and I think this is pure Python so we should be able to build a universal wheel there. Probably also use https://github.com/habnabit/vcversioner (I've used it for my own project).

SMDX 16,303,304,306 can't load model

Traceback (most recent call last):
File "C:\Users\jkn\Documents\GitHub\models\makeXLS.py", line 78, in
writeSmdxFile (xls, smdxFile)
File "C:\Users\jkn\Documents\GitHub\models\makeXLS.py", line 38, in writeSmdxFile
model = device.model_type_get(getModelId(smdxFile))
File "C:\Python27\lib\site-packages\sunspec\core\device.py", line 525, in model_type_get
raise SunSpecError('Error loading model %s at %s: %s' % (model_id, filename, str(e)))
sunspec.core.util.SunSpecError: Error loading model 00016 at C:\Python27\lib\site-packages\sunspec\core..\models\smdx\smdx_00016.xml: Unknown point type: uint64

client._get_property() 'name' undefined

Small bug in sunspec.core.client lines 370 ..

` def getitem(self, key):
return self._get_property(name)
# return self.dict.get(key, None)

def __setitem__(self, key, item):
    return self._set_property(name, item)
    # self.__dict__.set(key, item)`

I'm guessing the "key" argument was meant to be renamed "name"?

suns.py does not work on a solaredge inverter

Here is the traceback when I try to get sunspec data out of our solaredge inverter with the suns.py command:

$ suns.py -i 192.168.2.26 -a 1 -T 30

Timestamp: 2017-10-20T15:29:41Z
Traceback (most recent call last):
  File "/usr/bin/suns.py", line 88, in <module>
    sd.read()
  File "/usr/lib/python2.7/dist-packages/sunspec/core/client.py", line 477, in read
    self.device.read_points()
  File "/usr/lib/python2.7/dist-packages/sunspec/core/client.py", line 101, in read_points
    model.read_points()
  File "/usr/lib/python2.7/dist-packages/sunspec/core/client.py", line 246, in read_points
    raise SunSpecClientError(e)
sunspec.core.client.SunSpecClientError: Modbus read error: Connection error: [Errno 111] Connection refused

Note that the inverter modbus seems to work though as I'm able to retrieve data through a perl tcp modbus client:

$ perl mbtget -r3 -n 100 -a 40001 192.168.2.26
values:
  1 (ad 40001): 28243
  2 (ad 40002):     1
  3 (ad 40003):    65
  4 (ad 40004): 21359
  5 (ad 40005): 27745
  6 (ad 40006): 29253
  7 (ad 40007): 25703
  8 (ad 40008): 25888
  9 (ad 40009):     0
 10 (ad 40010):     0
 11 (ad 40011):     0
 12 (ad 40012):     0
 13 (ad 40013):     0
 14 (ad 40014):     0
 15 (ad 40015):     0
 16 (ad 40016):     0
 17 (ad 40017):     0
 18 (ad 40018):     0
 19 (ad 40019):     0
 20 (ad 40020): 21317
 21 (ad 40021): 13110
 22 (ad 40022): 14384
 23 (ad 40023):     0
 24 (ad 40024):     0
 25 (ad 40025):     0
 26 (ad 40026):     0
 27 (ad 40027):     0
 28 (ad 40028):     0
 29 (ad 40029):     0
 30 (ad 40030):     0
 31 (ad 40031):     0
 32 (ad 40032):     0
 33 (ad 40033):     0
 34 (ad 40034):     0
 35 (ad 40035):     0
 36 (ad 40036):     0
 37 (ad 40037):     0
 38 (ad 40038):     0
 39 (ad 40039):     0
 40 (ad 40040):     0
 41 (ad 40041):     0
 42 (ad 40042):     0
 43 (ad 40043):     0
 44 (ad 40044): 12336
 45 (ad 40045): 12339
 46 (ad 40046): 11826
 47 (ad 40047): 12337
 48 (ad 40048): 13824
 49 (ad 40049):     0
 50 (ad 40050):     0
 51 (ad 40051):     0
 52 (ad 40052): 14131
 53 (ad 40053): 12593
 54 (ad 40054): 12343
 55 (ad 40055): 13123
 56 (ad 40056):     0
 57 (ad 40057):     0
 58 (ad 40058):     0
 59 (ad 40059):     0
 60 (ad 40060):     0
 61 (ad 40061):     0
 62 (ad 40062):     0
 63 (ad 40063):     0
 64 (ad 40064):     0
 65 (ad 40065):     0
 66 (ad 40066):     0
 67 (ad 40067):     0
 68 (ad 40068):     2
 69 (ad 40069):   101
 70 (ad 40070):    50
 71 (ad 40071):   102
 72 (ad 40072):   102
 73 (ad 40073): 65535
 74 (ad 40074): 65535
 75 (ad 40075): 65534
 76 (ad 40076):  2374
 77 (ad 40077): 65535
 78 (ad 40078): 65535
 79 (ad 40079): 65535
 80 (ad 40080): 65535
 81 (ad 40081): 65535
 82 (ad 40082): 65535
 83 (ad 40083): 15959
 84 (ad 40084): 65534
 85 (ad 40085):  5012
 86 (ad 40086): 65534
 87 (ad 40087): 24435
 88 (ad 40088): 65534
 89 (ad 40089): 18503
 90 (ad 40090): 65534
 91 (ad 40091):  6531
 92 (ad 40092): 65534
 93 (ad 40093):    30
 94 (ad 40094):  7612
 95 (ad 40095):     0
 96 (ad 40096):  4280
 97 (ad 40097): 65532
 98 (ad 40098):  3785
 99 (ad 40099): 65535
100 (ad 40100): 16202

Any idea what is wrong with suns.py here?

point_class call in Model.load() is not keyworded

Just a simple issue that prevents me to reuse the code with a new class which inherits Point. I can make a pull request to correct it if possible.

At sunspec.core.device.Model.load, line 709:
now:

point = point_class(block, point_type, str(point_addr))

what I'ld like:

point = point_class(block=block, point_type=point_type, addr=str(point_addr))

adding a new vendor specific model

Hi,
Actually i would like to add a new Vendor specific Model to the smdx folder. As i understand an xml file needs to be created so that the pysunspec has access to this Vendor specific model. What i do not understand is the 'manifest.xml' in the smdx folder containing the md5 hash for all models.

Should an md5 hash be created for the new model, how can this be done.

Thanks for the help

Sunspec TCP on Outback device multiple reads fail with Errno 111

I'm trying to pull information out of a Outback AXS Port device.

d = client.SunSpecClientDevice(client.TCP, 0, None, None, None, None, ip_addr, 502, 2)
d.common.read()
print (d.common)
d.inverter.read()
print (d.inverter)

Output:

['common', 'model_64110', 'model_64120', 'inverter', 'model_64255', 'model_64113', 'model_64114']
Connection error: [Errno 111] Connection refused

The documentation isn't clear. What do I need to do? I've tried to close it and open a new connection. Fails there as well.

Unable to understand the way to get data from a sunspec device

Hi,
Sorry but after reading many times the Interacting with a sunspec device, I'm still unable to understand how to read values from a device. I'm able to get data from common and inverter with

l_d.common.SN

In my case, I'm trying to get the informations from the power limitation of an SMA device (inverter manager). I have the following device models:

['common', 'model_11', 'model_12', 'inverter', 'nameplate', 'settings', 'status', 'controls', 'storage', 'volt_var', 'freq_watt_param', 'reactive_current', 'watt_pf', 'volt_watt',
'mppt', 'lvrt', 'hvrt', 'base_met', 'mini_met']

after using this code:

l_d = client.SunSpecClientDevice(client.TCP, l_modbus_slave_address, ipaddr=l_ip_address, timeout=l_timeout)
l_d.inverter.read() # retreives latest inverter model contents
l_d.common.read()
self.__logger.info("--> ************* device models *************: %s" % (l_d.models))   

after that, I get followings when I do a:

self.__logger.info("-->inverter ************* reactive_current *************: %s" % (l_d.reactive_current)) 

=> => =>
inverter ************* reactive_current *************:
reactive_current (128):

How can I read the data of the 128 block? or storage? I still don't understand :-(

Thx !!

Can't speak to SMA Sunny Island device

I would like to use the pysunspec module to retrieve data from a SMA Sunny Island, but it does not seem to work. I get the following message when using the suns.py script:

$ suns.py -i 192.168.1.77
Error: Device responded - not SunSpec register map

So it says that the Sunny Island is not a SunSpec device, whereas the Sunny Island is supposed to speak the SunSpec modbus protocol, according to the SMA website: http://www.sma.de/en/products/battery-inverters/sunny-island-60h-80h.html#Downloads-206198

Any idea why it does not work?

Can't set value to rw field for SMA Sunny Island device

I can successfully read values from a SMA Sunny Island device, but I got the following error when I try to set a value in a rw field:

$ python
Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sunspec.core.client as client
>>> d = client.SunSpecClientDevice(client.TCP, 126, ipaddr='192.168.1.77')
>>> d.models
['common', 'model_11', 'model_12', 'inverter', 'nameplate', 'settings', 'status', 'controls', 'storage', 'volt_var', 'freq_watt_param', 'reactive_current', 'watt_pf', 'volt_watt', 'mppt']
>>> d.storage.WChaMax
>>> d.storage.read()
>>> d.storage.WChaMax
6000
>>> d.storage.WChaMax = 5900
>>> d.storage.write()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/bruno/.virtualenvs/pysunspec/local/lib/python2.7/site-packages/sunspec/core/client.py", line 303, in write
    self.model.write_points()
  File "/home/bruno/.virtualenvs/pysunspec/local/lib/python2.7/site-packages/sunspec/core/client.py", line 242, in write_points
    point.write()
  File "/home/bruno/.virtualenvs/pysunspec/local/lib/python2.7/site-packages/sunspec/core/client.py", line 259, in write
    self.block.model.device.write(int(self.addr), data)
  File "/home/bruno/.virtualenvs/pysunspec/local/lib/python2.7/site-packages/sunspec/core/client.py", line 80, in write
    raise SunSpecClientError('Modbus write error: %s' % str(e))
sunspec.core.client.SunSpecClientError: Modbus write error: Modbus exception: 1

According to SMA SunSpec documentation, WChaMax should be writable:

Modbus register number SunSpec-Name Description / Number code(s) Type Access
40372 WChaMax Setpoint for maximum active charging power. Reference value for WChaGra, WDisChaGra uint16 RW

I also tried with other rw fields, and I also got an error.

Any idea of what is wrong ?

Fronius Modbus Card returns empty objects

Been trying this library with an embedded device containing openWRT operating system. I could succesfully execute:

>>> import sunspec.core.client as client
>>> d = client.SunSpecClientDevice(client.RTU, 1, '/dev/ttyPORT1')

But when asking to print it all, I only get empty objects:

>>> print d

model_1 (1):

model_113 (113):

model_120 (120):

model_121 (121):

model_122 (122):

model_123 (123):

model_160 (160):

I have double checked that the device is in fact configured in Modbus RTU mode, 9600, 8N1. I have also checked that Fronius doesn't provide a different device id for sunspec-compatible readings.

Could you give a piece of advice on why this could happen?

Python 3 support

Is there any interest in a pull request providing both Python 2 and Python 3 support?

Tests are failing with an exception

Are the tests passing for other people? They fail with an exception for me. I'll work this out but figured it would be worth checking here.

/epc/t/313/pysunspec/venv/bin/python scripts/pysunspec_test.py
pySunSpec version: 1.0.7
Test device path: /epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/devices

Traceback (most recent call last):
  File "scripts/pysunspec_test.py", line 13, in <module>
    test.test_all()
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/test_all.py", line 58, in test_all
    (count_run, count_passed, count_failed) = module.test_all(pathlist, stop_on_failure)
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/test_device.py", line 577, in test_all
    if test(pathlist) is True:
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/test_device.py", line 418, in test_device_from_pics
    d1.from_pics(filename='pics_test_device_1.xml', pathlist=pathlist)
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/device.py", line 127, in from_pics
    raise SunSpecError('Error loading PICS: %s' % str(e))
sunspec.core.util.SunSpecError: Error loading PICS: Block index out of range: 1

Or, with an except removed to see the original trace:

/epc/t/313/pysunspec/venv/bin/python scripts/pysunspec_test.py
pySunSpec version: 1.0.7
Test device path: /epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/devices

Traceback (most recent call last):
  File "scripts/pysunspec_test.py", line 13, in <module>
    test.test_all()
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/test_all.py", line 58, in test_all
    (count_run, count_passed, count_failed) = module.test_all(pathlist, stop_on_failure)
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/test_device.py", line 577, in test_all
    if test(pathlist) is True:
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/test/test_device.py", line 418, in test_device_from_pics
    d1.from_pics(filename='pics_test_device_1.xml', pathlist=pathlist)
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/device.py", line 120, in from_pics
    model.from_pics(m)
  File "/epc/t/313/pysunspec/venv/lib/python2.7/site-packages/sunspec/core/device.py", line 481, in from_pics
    raise SunSpecError('Block index out of range: %s' % (str(block_index)))
sunspec.core.util.SunSpecError: Block index out of range: 1

Setup testing for all supported Python versions

I tend towards keeping up to date so the reference to 2.4 (replaced by 2.5 over a decade ago) in the readme is a bit scary. But, whatever versions we intend to support should be included in testing. It looks like Travis only provides 2.7 and 2.6 (in the py2 family) so we may need to do something special (install old versions from a ppa?) or add another testing platform to get coverage. tox may also be a good piece of the puzzle.

So, is the 2.4-2.7 reference in the readme the official list of what we need to support? Latest patch level on each? Obviously with interest in py3 versions in the future.

Tests are failing

When I try to run the tests on Linux (Debian) laptop, I get the following error:

$ pysunspec_test.py
pySunSpec version: 1.0.7
Test device path: /home/bruno/.virtualenvs/tmp-d3111b3cabc0fa7b/lib/python2.7/site-packages/sunspec/core/test/devices

Traceback (most recent call last):
  File "/home/bruno/.virtualenvs/tmp-d3111b3cabc0fa7b/bin/pysunspec_test.py", line 13, in <module>
    test.test_all()
  File "/home/bruno/.virtualenvs/tmp-d3111b3cabc0fa7b/local/lib/python2.7/site-packages/sunspec/core/test/test_all.py", line 42, in test_all
    (count_run, count_passed, count_failed) = module.test_all(pathlist, stop_on_failure)
  File "/home/bruno/.virtualenvs/tmp-d3111b3cabc0fa7b/lib/python2.7/site-packages/sunspec/core/test/test_device.py", line 561, in test_all
    if test(pathlist) is True:
  File "/home/bruno/.virtualenvs/tmp-d3111b3cabc0fa7b/lib/python2.7/site-packages/sunspec/core/test/test_device.py", line 402, in test_device_from_pics
    d1.from_pics(filename='pics_test_device_1.xml', pathlist=pathlist)
  File "/home/bruno/.virtualenvs/tmp-d3111b3cabc0fa7b/local/lib/python2.7/site-packages/sunspec/core/device.py", line 111, in from_pics
    raise SunSpecError('Error loading PICS: %s' % str(e))

pysunspec is not thread safe

I've built a simple web application based on pysunspec and bottle to be able to query sunspec data through http requests.
It works very well when I use a single-threaded server like Python wsgiref, but I noticed that when I use a multi-threaded server like cherrypy, the following errors start to occur:

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/bottle.py", line 862, in _handle
    return route.call(**args)
  File "/usr/lib/python2.7/dist-packages/bottle.py", line 1729, in wrapper
    rv = callback(*a, **ka)
  File "/usr/lib/python2.7/dist-packages/sunspecweb/server.py", line 13, in wrapper
    return func(*args,**kwargs)
  File "/usr/lib/python2.7/dist-packages/sunspecweb/server.py", line 125, in get_device_model
    m.read()
  File "/usr/lib/python2.7/dist-packages/sunspec/core/client.py", line 336, in read
    self.model.read_points()
  File "/usr/lib/python2.7/dist-packages/sunspec/core/client.py", line 197, in read_points
    data = self.device.read(self.addr, self.len)
  File "/usr/lib/python2.7/dist-packages/sunspec/core/client.py", line 82, in read
    return self.modbus_device.read(addr, count)
  File "/usr/lib/python2.7/dist-packages/sunspec/core/modbus/client.py", line 453, in read
    data = self._read(addr + read_offset, read_count, op=op)
  File "/usr/lib/python2.7/dist-packages/sunspec/core/modbus/client.py", line 407, in _read
    c = self.socket.recv(len_remaining)
AttributeError: 'NoneType' object has no attribute 'recv'

Is pysunspec supposed to be thread safe?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.