Я хотел создать менеджер для холодильника, и поэтому я хотел использовать сканер EAN для сканирования предметов. До сих пор я написал себе класс EANScanner, чтобы читать EAN из последовательного порта, и все было хорошо. Но теперь я хотел продолжить на своем рабочем столе и столкнулся со странными проблемами (по крайней мере, странными для меня). Я всегда получаю PermissionError (13, «Доступ запрещен», None, 5), когда я пытаюсь подключиться к компорту сканера. После того, как я удалю устройство в devicemanager и перезапущу, я могу подключиться к компорту сканера, если я не отсоединяю его и не подключаю снова, затем мне нужно повторить процедуру ... Это довольно раздражает, потому что я тоже хотел иметь возможность восстановить соединение для моего класса, если сканер отключен и снова подключен.
вот файл python класса EANScanner (надеюсь, что это не такой беспорядок для вас, Я открыт для любых советов)
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
зарегистрированные мной ошибки выглядят так:
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)
Я получил Win10 64bit на обоих устройствах (ноутбук, где все хорошо, и рабочий стол, где все портит) используя python 3.8.1 и последнюю версию pySerial
Я бы предположил, что есть какая-то проблема с драйверами или что-то в этом роде, но, возможно, я просто получил глупую ошибку