'pySerial PermissionError(13, 'Access denied', None, 5)

I wanted to create a manager for the frige and therefor I wanted to use a EAN Scanner to scan the items. So far I wrote myself a EANScanner class in order to read the EANs from the serial port and everything was fine. But now I wanted to continue on my desktop and ran into strange problems (at least strange for me) I always get a PermissionError(13, 'Access denied', None, 5) when I try to connect to the comport of the scanner. Once I uninstall the device in devicemanager and restart I can connect to the comport of the scanner as long as I do not unplug it and plug it back in, then I need to do the procedure again... This is pretty annoying because I also wanted to have the ability to reconnect for my class if the scanner is unplugged and plugged back in.

here is the python file of the EANScanner class (hope that is not that kind of a mess for you, I am open to any advice)

from time import sleep
from threading import Thread, Event
from queue import Queue
import logging

from serial import Serial, SerialException
import serial.tools.list_ports as list_ports


logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


class DuplicateFilter(object):
    def __init__(self):
        self.msgs = set()

    def filter(self, record):
        rv = record.msg not in self.msgs
        self.msgs.add(record.msg)
        return rv


dup_filter = DuplicateFilter()
logger.addFilter(dup_filter)

formatter = logging.Formatter('%(asctime)s: %(levelname)s: %(name)s.%(funcName)s: %(message)s\n')

file_handler = logging.FileHandler('broker.log')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)

stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)

logger.addHandler(file_handler)
# logger.addHandler(stream_handler)


class EANScanner(Thread):
    """
    Listener for serial EAN Scanner

    This class is capable to open a serial port based on a vendors and product id of the scanner
    device. It implements so that it is not blocking any other functionality due to listening to
    the comport.
    Received messages are stored to the backlog fifo queue in order to guarantee a thread safe
    access to the data and keep their order.

    Args:
            vid: vendors id of the scanner.
            pid: product id of the scanner.
            line_terminator: terminator the scanner uses for messages.
            name (str, optional): name for the thread. Defaults to 'scanner'.
    """
    __slots__ = ['vid', 'pid', 'line_terminator', 'backlog', '_device', '_stop_event', '_connected']

    def __init__(self, vid, pid, line_terminator, name='scanner'):
        self.vid = vid
        self.pid = pid
        self.line_terminator = line_terminator

        self.backlog = Queue()
        self._device = None
        self._stop_event = Event()
        self._connected = False
        Thread.__init__(self, name=name)
        self.setDaemon(True)

    def connect(self):
        """
        Connects device on serial port

        Using the pyserial library this function opens up a connection to a serial port using the vid and pid to
        identify the desired device.

        Returns:
            bool: The return value. True for success, False otherwise.
        """
        port = ''

        # list all comports that are connected and iterate them
        for comport in list_ports.comports():
            # if pid and vid is matching port is found
            if comport.pid == self.pid and comport.vid == self.vid:
                port = comport.device

        # try to connect port
        try:
            self._device = Serial(port)
        except SerialException as e:
            logger.exception('Could not connect serial device!')
            return False
        else:
            logger.info('Connected to: {}'.format(self._device.name))
            return True

    def disconnect(self):
        """Disconnects serial port

        Disconnects the serial port _device and sets the _connected flag to Flase
        """
        self._device.close()
        self._connected = False

    def is_connected(self):
        """Basically a getter for _connected flag

        Returns:
            bool: True if the class is connected. False otherwise.
        """
        return self._connected

    def run(self):
        """Override of Thread.run

        This is the mainloop for this thread. Once that is done the mainloop begins and
        reads byte wise the buffer of the device until the line terminator is red.
        If the red input is int cast able the number is stored to the backlog.
        If the device is plugged out during mainloop, the SerialException is caught and a
        reconnect will be tried until success.
        """
        while not self.is_connected() and not self._stop_event.is_set():
            self._connected = self.connect()
            sleep(3)

        ean = ''
        # mainloop
        while not self._stop_event.is_set():
            input_byte = None
            try:
                if self._device.in_waiting < 1:
                    sleep(0.05)
                    continue
                input_byte = self._device.read().decode('ascii')
            except SerialException:
                logger.exception('Lost connection to serail device!')
                self._connected = self.connect()
                sleep(3)
            except AttributeError:
                logger.exception('Scanner is not connected!')
                self._connected = self.connect()
                sleep(3)

            if input_byte == self.line_terminator and is_int(ean):
                self.backlog.put(int(ean))
                ean = ''
            elif input_byte:
                ean += input_byte

    def join(self, timeout=None):
        """Override of the Thread.join

        In order to terminate the Thread the mainloop must be stopped. To do that this
        method triggers the _stop_event in order to break the loop and joins the Thread
        after that.

        Args:
            timeout (float, optional): timeout in secs for the Thread.join call.
        """
        self._stop_event.set()
        if self.is_alive():
            Thread.join(self, timeout)

        try:
            self.disconnect()
        except AttributeError:
            pass

    def __del__(self):
        self.join()


def is_int(v):
    """ Helper function

    Checks if a variable is cast able to int.

    Args:
        v: variable to be checked.

    Returns:
        bool: True if cast able. Else False.
    """
    try:
        int(v)
        return True
    except ValueError:
        return False

the errors I logged look like that

2020-01-30 20:32:53,777: INFO: __main__.<module>: Broker was started.
2020-01-30 20:32:53,781: ERROR: Helpers.EANScanner.connect: Could not connect serial device!
Traceback (most recent call last):
  File "...\Helpers\EANScanner.py", line 90, in connect
    self._device = Serial(port, baudrate=9200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=0, rtscts=0)
  File "...\AppData\Local\Programs\Python\Python38-32\lib\site-packages\serial\serialwin32.py", line 31, in __init__
    super(Serial, self).__init__(*args, **kwargs)
  File "...\AppData\Local\Programs\Python\Python38-32\lib\site-packages\serial\serialutil.py", line 240, in __init__
    self.open()
  File "...\AppData\Local\Programs\Python\Python38-32\lib\site-packages\serial\serialwin32.py", line 62, in open
    raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
serial.serialutil.SerialException: could not open port 'COM6': PermissionError(13, 'Access denied', None, 5)

I got Win10 64bit on both devices (the notebook where everything is fine and the desktop where it messes up) using python 3.8.1 and the latest version of pySerial

I would guess that there is some kind of driver issue or something like that but maybe I just got a stupid mistake



Solution 1:[1]

Thats error means your COM port is already in use and getting data, try to use ser.close() to close the connection

Solution 2:[2]

I had this same issue - I know this was asked over a year ago, but I was searching for answers today and couldn't find anything.

Here is what I discovered - I had a system monitoring software running (NZXT Cam) - it apparently intercepts the COM port connection before I could open it elsewhere. That blocked it and caused this error.

Disable any monitoring software you've got in the background, then try again!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Reem Alon
Solution 2 dStucky