sunspec / pysunspec

Python SunSpec Tools
MIT License
86 stars 50 forks source link

Python 3 reads being converted to str #60

Open altendky opened 5 years ago

altendky commented 5 years ago

https://github.com/sunspec/pysunspec/commit/516287f413036d53c95f913a0646abe6b7172767 https://github.com/sunspec/pysunspec/commit/a3e7edee6e558093a6a703ce4791a9e4678c1745

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.

https://github.com/sunspec/pysunspec/blob/5242ea9e4c687061cc0b8de4417b1943ed8f9264/sunspec/core/client.py#L229

(@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.

altendky commented 5 years ago

@bobfox, by my reading the master branch doesn't work with py3 right now. Do you know of anyone using it successfully with py3?

altendky commented 4 years ago

Anybody else? Does pysunspec master actually work for anyone talking to a device on Python 3? By my reading it can't. This leaves pysunspec working exclusively on Python 2.7 which is EOL already.

bobfox commented 4 years ago

I believe version 2.0.0 works with Python 3. I know of several who are using it in that context. I agree that the support could probably be improved/optimized but would prefer to do that in the next version that provides support for all of the proposed updates to SunSpec modeling. Does that seem reasonable? We would like to clear all the issues in the models repository and pysunspec repository and then do a 2.0.0 release.

altendky commented 4 years ago

There's no branch or tag so I guess f7c02e17a77401499ae7b09235a534f56e764dcd is v2.0.0? Or is it something after that commit?

From what I can tell that version will never be able to connect to a device in Python 3 because it checks 'SunS', a str, against b'SunS', a bytes, which are not equal due to their types. Can you offer any guidance as to what it is I am doing wrong? Perhaps other people using Python 3 just aren't connecting to devices over serial? I admittedly didn't try it over TCP today.

altendky@p1:/epc/repos/pysunspec$ git rev-parse HEAD
f7c02e17a77401499ae7b09235a534f56e764dcd
altendky@p1:/epc/repos/pysunspec$ git diff --cached
diff --git a/sunspec/core/client.py b/sunspec/core/client.py
index 3988b1f..c7b7caa 100755
--- a/sunspec/core/client.py
+++ b/sunspec/core/client.py
@@ -226,7 +226,11 @@ class ClientDevice(device.Device):
                 # print('trying base address %s' % (addr))
                 try:
                     data = self.read(addr, 3)
-                    if data[:4] == b'SunS':
+                    altendky_test = data[:4]
+                    altendky_reference = b'SunS'
+                    print(' - - altendky_test: {} {}'.format(type(altendky_test), repr(altendky_test)))
+                    print(' - - altendky_reference: {} {}'.format(type(altendky_reference), repr(altendky_reference)))
+                    if altendky_test == altendky_reference:
                         self.base_addr = addr
                         # print('device base address = %d' % self.base_addr)
                         break
diff --git a/x.py b/x.py
new file mode 100644
index 0000000..196c978
--- /dev/null
+++ b/x.py
@@ -0,0 +1,14 @@
+import sys
+
+import sunspec.core.client
+
+
+print(sys.version)
+
+device = sunspec.core.client.SunSpecClientDevice(
+    slave_id=1,
+    device_type=sunspec.core.client.RTU,
+    name='/dev/ttyUSB0',
+    baudrate=9600,
+    timeout=1,
+)
altendky@p1:/epc/repos/pysunspec$ venv2/bin/python x.py
2.7.17 (default, Dec  2 2019, 17:01:50) 
[GCC 9.2.1 20191008]
 - - altendky_test: <type 'str'> 'SunS'
 - - altendky_reference: <type 'str'> 'SunS'
altendky@p1:/epc/repos/pysunspec$ venv3/bin/python x.py
3.8.1 (default, Dec 27 2019, 18:45:57) 
[GCC 9.2.1 20191008]
 - - altendky_test: <class 'str'> 'SunS'
 - - altendky_reference: <class 'bytes'> b'SunS'
Traceback (most recent call last):
  File "x.py", line 8, in <module>
    device = sunspec.core.client.SunSpecClientDevice(
  File "/epc/repos/pysunspec/sunspec/core/client.py", line 779, in __init__
    self.device.scan(progress=scan_progress, delay=scan_delay)
  File "/epc/repos/pysunspec/sunspec/core/client.py", line 287, in scan
    raise SunSpecClientError(error)
sunspec.core.client.SunSpecClientError: Device responded - not SunSpec register map
RiccardoBa commented 4 years ago

Hi @bobfox, I have the same problems that has encountered @altendky. Are you sure that someone use succesfully the package with python 3? The connection fail istantaneously.