jbuehl / solaredge

SolarEdge inverter logging data capture
GNU General Public License v3.0
288 stars 60 forks source link

semonitor won't open serial port if symlink #154

Closed Millox closed 1 year ago

Millox commented 4 years ago

Hi.

I changed my udev setup today to accommodate for the multiple rs485 to usb-dongles that I use on my raspberry pi. Unfortunately semonitor does not allow the use of symlinked devices as argument -a.

Jul 24 14:10:41 saldaea semonitor[16408]: /dev/solaredge0 is not a valid serial device
Jul 24 14:10:41 saldaea semonitor[16408]: Input device types 2 and 4 are only valid for a serial device

It works if using /dev/ttyUSB1 instead. Links point to the respective character device correctly

lrwxrwxrwx  1 root root           7 Jul 24 01:53 solaredge0 -> ttyUSB0
lrwxrwxrwx  1 root root           7 Jul 24 01:53 solaredge1 -> ttyUSB1
tobylorenz commented 3 years ago

+1 for this feature request.

I call semonitor that way: ./semonitor.py -d stdout -m -s $SN -t 4 -vvvv $(readlink -f /dev/solaredge0) instead of ./semonitor.py -d stdout -m -s $SN -t 4 -vvvv /dev/solaredge0

oliv3r commented 1 year ago

@tobylorenz, @Millox I tried to resolve this, but it's not so trivial. PySerial doesn't like symlinks.

I tried this patch, which didn't do what I would have expected:

Author: Olliver Schinagl <oliver@schinagl.nl>
Date:   Tue Jun 20 13:08:20 2023 +0200

    resolve symlinks for serial ports

    It is not uncommon to setup smart symlinks for hotpluggable/USB
    adapters, so they always have a known name. PySerial however seems to
    refuse to follow symlinks

    Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>

diff --git a/se/env.py b/se/env.py
index bd00a3e..4319e06 100644
--- a/se/env.py
+++ b/se/env.py
@@ -117,7 +117,7 @@ def getArgs():
     elif args.datasource != "stdin":
         # figure out the list of valid serial ports on this server
         # this is either a list of tuples or ListPortInfo objects
-        serial_ports = serial.tools.list_ports.comports()
+        serial_ports = serial.tools.list_ports.comports(include_links=True)
         serial_port_names = map(lambda p: p.device if isinstance(p,
                                 serial.tools.list_ports_common.ListPortInfo) else p[0], serial_ports)
         serialDevice = args.datasource in serial_port_names
diff --git a/se/files.py b/se/files.py
index f41e6ee..18d7288 100644
--- a/se/files.py
+++ b/se/files.py
@@ -7,6 +7,8 @@ import select
 import logging
 import se.logutils

+from pathlib import Path
+
 logger = logging.getLogger(__name__)
 socketTimeout = 120.0

@@ -52,7 +54,7 @@ def openDataSocket(ports):

 # open serial device
 def openSerial(inFileName, baudRate):
-    return serial.Serial(inFileName, baudrate=baudRate)
+    return serial.Serial(Path(inFileName).resolve(), baudrate=baudRate)

 def openInFile(inFileName):
     if inFileName == "stdin":

So instead, use my dockerize feature #180 and map the serial port within docker (--device /dev/solaredge0:/dev/ttyUSB0).

@jbuehl @ericbuehl I think we can best close this issue, as this is not the fault of semonitor ...

tobylorenz commented 1 year ago

The solution with ./semonitor.py -d stdout -m -s $SN -t 4 -vvvv $(readlink -f /dev/solaredge0) works well for me.

So I don't insist on having a fix in semonitor.py to bypass a problem in Python Serial ;-)

oliv3r commented 1 year ago

The solution with ./semonitor.py -d stdout -m -s $SN -t 4 -vvvv $(readlink -f /dev/solaredge0) works well for me.

So I don't insist on having a fix in semonitor.py to bypass a problem in Python Serial ;-)

Ah, yes, you are resolving the symlink before offering it :) This will work, until the symlink changes, which requires a restart of semonitor. Being able to use an actual symlink, means that if the symlink changes (via udev) there is some chance it could fix itself. But these are all very edgy edge-cases!

I couldn't use this solution myself, because I'd have to put this in my docker compose file, which can't be done, because compose won't execute the subshell. But remapping it in docker works good enough (tm) (still suffering from the same issues as I mentioned above of course).