使用pyserial列出com端口,而无需重新连接蓝牙设备

时间:2020-10-24 19:16:24

标签: bluetooth pyserial

我正在构建一个GUI,该GUI通过COM端口连接到Windows上的蓝牙设备,这很容易。在启动过程中,工具栏类列出了可用的COM端口。

class ToolBar(QtGui.QMainWindow):
def __init__(self, parent=None):
    QtGui.QMainWindow.__init__(self)

    self.menu = self.menuBar()
    #self.menu.installEventFilter(self)
    self.coms = QMenu('COM Selection', self)
    self.group = QActionGroup(self.coms)
    self.checkSerial = serial.tools.list_ports.comports()

    self.populate()

    for text in self.texts:
        action = QAction(text, self.coms, checkable=True, checked=text==self.texts[0])
        self.coms.addAction(action)
        self.group.addAction(action)
    self.group.setExclusive(True)
    self.group.triggered.connect(self.onTriggered)
    self.menu.addMenu(self.coms)

def populate(self):
    self.texts = [p.device for p in self.checkSerial]
    self.checkSerial.clear()
    
    return False
    
def onTriggered(self, action):
    print(action.text())
    Constants.comPort = action.text()

当按下开始/停止按钮时,MainWindow类中的closeCom函数将读取用户选择以连接到COM。但是,其中一个COM已被serial.tools.list_ports列出,当我尝试连接以读取数据时,它似乎已连接并升高。如果我在不调用工具栏的情况下启动GUI,因此未列出COMS,则在脚本中以文本形式输入COM端口是没有问题的。

    def closeCom(self):
    if self.log==False:
        self.serialPort.close()
        print('stopped logging')  
        self.timer.stop()
        self.saver.stop()
        self.file.close()
    if self.log==True:

        self.portName = 'COM4'
        self.portName = Constants.comPort
        baudRate = 9600
        self.serialPort = serialPlot(self.portName, baudRate)   # initializes all required variables
        self.serialPort.readSerialStart()   #data starting to save

我尝试使用蓝牙,因为虽然找不到如何使用pyserial中的设备地址连接到设备的示例,但该模块在查找设备时似乎无法连接。

import bluetooth   

devices = bluetooth.discover_devices(lookup_names=True) 
print(type(devices))   
print("Devices found: %s" % len(devices))   
for item in devices:     
    print(item)

因此,总而言之,我的问题是,我可以在将它们以pyserial列出后清除COM,以便我可以连接吗;如果没有,我可以使用蓝牙库找到的地址进行连接。我愿意接受建议,因为这整个星期我都坚持不懈!

这是完整的代码,以防万一。

非常感谢!

import serial
import serial.tools.list_ports
import time
import threading
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QHBoxLayout, QLabel, QSizePolicy, QSlider, QSpacerItem, \
    QVBoxLayout, QWidget
from PyQt5.QtWidgets import QAction, QActionGroup, QMenu, QApplication    
import pyqtgraph as pg

import sys
import queue

import bluetooth   

devices = bluetooth.discover_devices(lookup_names=True) 
print(type(devices))   
print("Devices found: %s" % len(devices))   
for item in devices:     
    print(item)

#import win32com.client
#wmi = win32com.client.GetObject("winmgmts:")
#for serial in wmi.InstancesOf("Win32_SerialPort"):
      # print (serial.Name, serial.Description)
       
       
app = QtGui.QApplication(sys.argv)
    

class Constants(object):
    #class for storing Gui constants & user input
    #all static rather than object elements
    
    #Varible to store com port that is being logged
    comPort="select com port"

class ToolBar(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self)

        self.menu = self.menuBar()
        #self.menu.installEventFilter(self)
        self.coms = QMenu('COM Selection', self)
        self.group = QActionGroup(self.coms)
        self.checkSerial = serial.tools.list_ports.comports()

        self.populate()

        for text in self.texts:
            action = QAction(text, self.coms, checkable=True, checked=text==self.texts[0])
            self.coms.addAction(action)
            self.group.addAction(action)
        self.group.setExclusive(True)
        self.group.triggered.connect(self.onTriggered)
        self.menu.addMenu(self.coms)
    
    def populate(self):
        self.texts = [p.device for p in self.checkSerial]
        self.checkSerial.clear()
        
        return False
        
    def onTriggered(self, action):
        print(action.text())
        Constants.comPort = action.text()

class serialPlot:

    def __init__(self, serialPort = 'COM', serialBaud = 9600):
        self.port = serialPort
        self.baud = serialBaud

        self.isRun = True
        self.isReceiving = False
        self.thread = None

        #creating text file for data save
        self.file = open("data.txt","w+")
        header = "elapsed time milliseconds, rpm, L power watts, R power watts, \n"
        self.file.write(str(header))
        self.file.close()

        print('Trying to connect to: ' + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.')
        try:
            self.serialConnection = serial.Serial(serialPort, serialBaud, timeout=4)
            print('Connected to ' + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.')
        except:
            print("Failed to connect with " + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.')
            
        #timer for logging
        self.elaspedTime = QtCore.QTime()
        self.elaspedTime.start()
        TimeAxisItem.startTime = self.elaspedTime

    def readSerialStart(self):
        if self.thread == None:
            self.thread = threading.Thread(target=self.backgroundThread)
            self.thread.start()
            # Block till we start receiving values
            while self.isReceiving != True:
                time.sleep(0.1)

    def dataSave(self):

        self.file = open("data.txt", "a+")
        self.file.write(self.valueRead.replace("\r\n","\n"))
        self.file.close()


    def backgroundThread(self):    # retrieve data
        time.sleep(1.0)  # give some buffer time for retrieving data
        self.serialConnection.reset_input_buffer()
        while (self.isRun):
            #self.serialConnection.readinto(self.rawData)
            self.rawData = self.serialConnection.readline()
            self.isReceiving = True
            #print(self.rawData)
            self.valueRead  = self.rawData.decode(encoding='UTF-8',errors='ignore')
            self.dataArray = self.valueRead.split('\r\n')
            self.data = self.dataArray[0].split(',')

            try:
                
                dataCollect.time.append(self.elaspedTime.elapsed())
                dataCollect.rpm.append(float(self.data[1]))
                dataCollect.L_power.append(float(self.data[2]))
                dataCollect.R_power.append(float(self.data[3]))

            except ValueError and IndexError:
                dataCollect.time.append(0)
                dataCollect.rpm.append(0)
                dataCollect.L_power.append(0)
                dataCollect.R_power.append(0)
                
            self.dataSave()#save the data

    def close(self):
        self.isRun = False
        self.thread.join()
        self.serialConnection.close()
        print('Disconnected...')
        

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self, parent=None)
        
        self.Tool_Bar = ToolBar(self)
        self.setMenuWidget(self.Tool_Bar)
        
        self.central_widget = QtGui.QStackedWidget()
        self.setCentralWidget(self.central_widget)
        
        self.login_widget = LoginWidget(self)

        self.login_widget.startStop.clicked.connect(self.changeState)
        self.login_widget.startStop.clicked.connect(self.plotter)
        
        self.login_widget.Close.clicked.connect(self.closeGui)
        
        self.login_widget.saveData.clicked.connect(self.saveData)
        
        self.central_widget.addWidget(self.login_widget)
        
        self.log=False


        
        #creating text file for data save
        self.file = open("data.txt","w+")
        header = "elapsed time milliseconds, rpm, L power watts, R power watts, \n"
        self.file.write(str(header))
        self.file.close()
        
        #data
        for i in range(1000):
            dataCollect.time.append(0)
            dataCollect.rpm.append(0)
            dataCollect.L_power.append(0)
            dataCollect.R_power.append(0)
        
        
        self.login_widget.w1.slider.valueChanged.connect(self.update_plot)


    def update_plot(self):
        
        value = dataCollect.value
        dataCollect.time = queue.deque(maxlen = value)
        dataCollect.rpm = queue.deque(maxlen = value)
        dataCollect.L_power = queue.deque(maxlen = value)
        dataCollect.R_power = queue.deque(maxlen = value)
        
    def closeGui(self):
        QtGui.QApplication(sys.argv).exit()
                
                
    def closeCom(self):
        if self.log==False:
            self.serialPort.close()
            print('stopped logging')  
            self.timer.stop()
            self.saver.stop()
            self.file.close()
        if self.log==True:

            self.portName = 'COM4'
            self.portName = Constants.comPort
            baudRate = 9600
            self.serialPort = serialPlot(self.portName, baudRate)   # initializes all required variables
            self.serialPort.readSerialStart()   #data starting to save


    def changeState(self):
        self.log = not self.log
        self.closeCom()
        
        
            
    def Display(self):

        #update labels
        rpm = str(sum([dataCollect.rpm[i] for i in range(80)])/80)
        self.login_widget.LiveValueRPM.setText(rpm)
        L = str(sum([dataCollect.L_power[i] for i in range(80)])/80)
        self.login_widget.LiveValueLeft.setText(L)
        R = str(sum([dataCollect.R_power[i] for i in range(80)])/80)
        self.login_widget.LiveValueRight.setText(R)
        
        QtGui.QApplication.processEvents()

        
    def updater(self):
        

        self.curve0.setData(dataCollect.time, dataCollect.L_power, clear=True)
        self.curve1.setData(dataCollect.time, dataCollect.R_power, clear=True)
        self.curve2.setData(dataCollect.time, dataCollect.rpm, clear=True)            

        QtGui.QApplication.processEvents()
            
    def plotter(self):
        
        #self.login_widget.plot.getPlotItem().addLegend()
        
        self.curve0 = self.login_widget.plot.getPlotItem().plot(clear=True,pen='b', name='rpm')
        self.curve1 = self.login_widget.plot.getPlotItem().plot(pen='g', name='Left Power')
        self.curve2 = self.login_widget.plot.getPlotItem().plot(pen='r', name='Right Power')
        
        self.login_widget.plot.getPlotItem().setLabel('bottom', 'Time [hrs,mins,secs]')
        self.login_widget.plot.getPlotItem().setLabel('left', "Power [W] or [rpm]")
        
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updater)
        self.timer.start(10)

        self.saver = QtCore.QTimer()
        self.saver.timeout.connect(self.Display)
        self.saver.start(1000)


    def saveData(self):
        

        file_name = QtGui.QFileDialog.getSaveFileName(self,"Save file", "default name here", ".txt;;.csv" )
        saveLocation = file_name[0]
        fileExtension = file_name[1]

        #The data saved during logging as txt file
        data=[]
        with open("data.txt", "r") as f:
            for line in f:
                print(len(line))
                if len(line)  < 64:
                    data.append(line.rstrip())
            
        #saving the data in the preferred form and file location for user
        with open(''.join([saveLocation,fileExtension]), "w", encoding='utf-8') as f:
            for s in data:
                f.write(s)
                f.write("\n")


        
class TimeAxisItem(pg.AxisItem):
    """Internal timestamp for x-axis"""
    startTime = QtCore.QTime().currentTime()
    
    def __init__(self, *args, **kwargs):
        super(TimeAxisItem, self).__init__(*args, **kwargs)

    def tickStrings(self, values, scale, spacing):
        """Function overloading the weak default version to provide timestamp"""
        
        return [TimeAxisItem.startTime.addMSecs(value).toString('hh:mm:ss') for value in values]         
        #return [QtCore.QTime().currentTime().toString('hh:mm:ss') for value in values]  

class dataCollect(object):
    
    time = queue.deque(maxlen = 1000)
    rpm = queue.deque(maxlen = 1000)
    L_power = queue.deque(maxlen = 1000)
    R_power = queue.deque(maxlen = 1000)
    
    
class Slider(QWidget):
    def __init__(self, parent=None):
        super().__init__()
        hbox = QHBoxLayout()
        self.slider = QSlider()
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.setTickPosition(QSlider.TicksBelow)
        self.slider.setTickInterval(100)
        self.slider.setMinimum(0)
        self.slider.setMaximum(1000)
        self.slider.setValue(500)
        self.slider.valueChanged.connect(self.changedValue)
        #self.label = QLabel("50")
        #self.label.setFont(QtGui.QFont("Sanserif", 15))
        hbox.addWidget(self.slider)
        #hbox.addWidget(self.label)
        self.setLayout(hbox)
        #self.show()


    def changedValue(self):
        size = self.slider.value()
        #self.label.setText(str(size)) 
        dataCollect.value = size#number of data points to set graph
        #print(size)
               

class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self)
        
        hbox = QtGui.QGridLayout(self)
        
        L0_layout = QtGui.QGridLayout()

        L1_layout = QtGui.QGridLayout()
        R_layout = QtGui.QGridLayout()

        L0_widgets = QtGui.QFrame()
        L0_widgets.setFrameShape(QtGui.QFrame.StyledPanel)
        L0_widgets.setLayout(L0_layout)

        L1_widgets = QtGui.QFrame()
        L1_widgets.setFrameShape(QtGui.QFrame.StyledPanel)
        L1_widgets.setLayout(L1_layout)
        
        self.startStop = QtGui.QPushButton('Start / Stop Plotting')
        L0_layout.addWidget(self.startStop, 1, 0)
        
        self.Close = QtGui.QPushButton('Close')
        L0_layout.addWidget(self.Close, 2, 0)
        
        self.saveData = QtGui.QPushButton('Save Data')
        L0_layout.addWidget(self.saveData, 3, 0)
        
        #create space
        self.Blank = QtGui.QLabel()
        L0_layout.addWidget(self.Blank, 4, 0)
        
        #set bold text for vaule display
        myFont=QtGui.QFont()
        myFont.setBold(True)
        
        #live readout left power
        self.LeftPower = QtGui.QLabel('Average Left Power (W)')
        self.LeftPower.setFont(myFont)
        self.LeftPower.setStyleSheet("font: 15pt")
        self.LeftPower.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.LeftPower, 5, 0)
        
        self.LiveValueLeft = QtGui.QLabel("0")
        self.LiveValueLeft.setFont(myFont)
        #self.LiveValueLeft.setStyleSheet("font: 15pt")
        self.LiveValueLeft.setStyleSheet("QLabel{color: green; font: 15pt}")
        self.LiveValueLeft.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.LiveValueLeft, 6, 0)
        
        #live readout right power
        self.RightPower = QtGui.QLabel('Average Right Power (W)')
        self.RightPower.setFont(myFont)
        self.RightPower.setStyleSheet("font: 15pt")
        self.RightPower.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.RightPower, 7, 0)
        
        self.LiveValueRight = QtGui.QLabel("0")
        self.LiveValueRight.setFont(myFont)
        #self.LiveValueRight.setStyleSheet("font: 15pt")
        self.LiveValueRight.setStyleSheet("QLabel{color: red; font: 15pt}")
        self.LiveValueRight.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.LiveValueRight, 8, 0)
        
        
        #live readout rpm
        self.RPM = QtGui.QLabel('Average rpm')
        self.RPM.setFont(myFont)
        self.RPM.setStyleSheet("font: 15pt")
        self.RPM.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.RPM, 9, 0)
        
        self.LiveValueRPM = QtGui.QLabel("0")
        self.LiveValueRPM.setFont(myFont)
        #self.LiveValueRPM.setStyleSheet("font: 15pt")
        self.LiveValueRPM.setStyleSheet("QLabel{color: blue; font: 15pt}")
        self.LiveValueRPM.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.LiveValueRPM, 10, 0)
        
        self.AxisAdjust = QtGui.QLabel('Move Silder to Adjust X Axis')
        self.AxisAdjust.setFont(myFont)
        self.AxisAdjust.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        L0_layout.addWidget(self.AxisAdjust, 11, 0)
        
        #self.w1 = CustomWidget()
        self.w1 = Slider()
        L0_layout.addWidget(self.w1, 12, 0)
        
        self.plot = pg.PlotWidget()
        self.plot = pg.PlotWidget(axisItems={'bottom': TimeAxisItem(orientation='bottom')})
        self.plot.plotItem.setMouseEnabled(x=False, y=False)
        self.plot.showGrid(x=True,y=True,alpha=1)
        self.plot.addLegend()
        
        splitter1 = QtGui.QSplitter(QtCore.Qt.Horizontal)
        splitter1.addWidget(L0_widgets)

        splitter3 = QtGui.QSplitter(QtCore.Qt.Horizontal)
        splitter3.addWidget(splitter1)
        splitter3.addWidget(self.plot)
        hbox.addWidget(splitter3)
        
        self.setGeometry(300, 300, 300, 200)
        self.setLayout(hbox)

        
if __name__ == '__main__':
    window = MainWindow()
    window.show()
    app.exec_()

0 个答案:

没有答案