python - pySerial PermissionError(13,'访问被拒绝',无,5)
问题描述
我想为冰箱创建一个经理,因此我想使用 EAN 扫描仪来扫描物品。到目前为止,我为自己编写了一个 EANScanner 类,以便从串行端口读取 EAN,一切都很好。但是现在我想继续在我的桌面上运行并遇到奇怪的问题(至少对我来说很奇怪),当我尝试连接到扫描仪的端口时,我总是收到 PermissionError(13, 'Access denied', None, 5) 。一旦我在设备管理器中卸载设备并重新启动,只要我不拔下它并重新插入,我就可以连接到扫描仪的端口,然后我需要再次执行该过程......这很烦人,因为我也如果扫描仪被拔下并重新插入,希望能够为我的班级重新连接。
这是 EANScanner 类的 python 文件(希望这对你来说不是那么乱,我愿意接受任何建议)
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)
我使用 python 3.8.1 和最新版本的 pySerial 在两个设备(一切都很好的笔记本和搞砸的桌面)上都获得了 Win10 64bit
我猜有某种驱动程序问题或类似的问题,但也许我只是犯了一个愚蠢的错误
解决方案
那是错误意味着您的 COM 端口已在使用中并正在获取数据,请尝试使用 ser.close() 关闭连接
推荐阅读
- c++ - 虚函数、覆盖它们的类模板和不完整的类型
- oracle - 使用 Kafka Connect API JDBC Sink 连接器示例到 Oracle 数据库的 Kafka 主题
- android - 如何将 Android 日志条目存储为字符串
- javascript - 通过 jQuery 检索并显示特定值
- c++ - 在 bazel 中创建仅系统标头库的正确方法是什么?
- python - 如何让用户通过 Python 中的命令行指定枚举
- r - 从不规则间距 x 和 y 的 ncdf 创建光栅砖
- xcode - 如何在 Xcode 10 中设置观察点?
- python - 尝试在 Windows 10 上安装库“pycld2”时收到错误
- python - 设置类变量