SerialPort Thread on Windows - python

I need the give SerialConnection object to ThreadClass how can I do that?
I faced an error on Windows OS. But same code have not any error in Linux (Ubuntu).
I create the SerialConnection() object in MainWindow also self.angleThread created same init function.
class MainWindow(QMainWindow):
def __init__(self,parent = None):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# self = QMainWindow class
# self.ui = Ui_MainWindow / user interface class
loadJsonStyle(self, self.ui)
QSizeGrip(self.ui.size_grip)
self.connection = SerialConnection()
self.Rs232 = RS232_Data()
self.angleThread = ThreadClass("filename", index)
I need the serial connection in ThreadClass so both function calling in ThreadClass init.
def __init__(self, filename = "", index = 0):
super(ThreadClass, self).__init__()
self.filename = filename
self.is_running = True
self.index = index
# self.connection.close
self.Rs232 = RS232_Data()
self.connection = SerialConnection()
...
SerialConnection class:
class SerialConnection():
def __init__(self):
portList = serial.tools.list_ports.comports()
self.serialPort = 0
for p in portList:
# print(p.pid)
if p.pid == 24577:
print("Confirmed")
self.getPortName = p.device
self.serialPort = serial.Serial(port=self.getPortName, baudrate=230400, bytesize=8, timeout=10, stopbits=serial.STOPBITS_ONE)
break
else:
## Show dialog
print("There is no device on the line")
def connection_start(self):
try:
# self.serialPort.open()
1 == 1
except Exception:
print("Port is already open")
def connection_close(self):
if self.serialPort.is_open:
self.serialPort.close()
else:
print("Port didnt open")
def serial_write(self, data):
self.data = data
self.serialPort.write(self.data)
def serial_read_string(self):
readData = self.serialPort.readline()
return readData
def serial_read_byte(self,size):
readData = self.serialPort.read(size)
# print(len(readData))
if len(readData) == 0:
print("unconnceted")
return readData
But In the windows I get below error:
raise SerialException("could not open port {!r}: {!r}".format(self.portstr, ctypes.WinError()))
serial.serialutil.SerialException: could not open port 'COM12': PermissionError(13, 'Erişim engellendi.', None, 5)
How can I solve this problem or how can I move the alive connection to ThreadClass ?

Aren't you opening the same port twice?
Once in MainWindow constructor and later second time in ThreadClass constructor.
As far as I know this is forbidden in Windows.
You can just pass SerialConnection instance as a ThreadClass constructor parameter instead of creating it there.

Related

PyQt Signal positional argument disappearing

I'm writing a small application in Python 3.6 and PyQt 5.13.1 to compare file checksums for directories across multiple remote servers. I'm trying to split out the main logic of my application into its own thread, and from that thread use a threadpool to create several more threads to SSH into the remote servers and get information back.
Everything is mostly working, except when the signal I have made for the SSH threads is called, one of the positional arguments ends up missing and I get the following error:
TypeError: ssh_result() missing 1 required positional argument: 'message'
Here is a stripped down version of what I currently have, but is exhibiting the same issue:
import paramiko
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QThread, QThreadPool, QRunnable, pyqtSignal, pyqtSlot, QObject
class SSHWorkerSignals(QObject):
result = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject')
class SSHWorker(QRunnable):
def __init__(self):
super(SSHWorker, self).__init__()
self.ssh_signals = SSHWorkerSignals()
self.ssh_server = 'test.server.corp'
#pyqtSlot()
def run(self):
try:
ssh_client = paramiko.SSHClient()
ssh_client.load_system_host_keys()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
ssh_client.connect(self.ssh_server, port=22, username='test', password='test')
stdin, stdout, stderr = ssh_client.exec_command('uname -a')
std_out = str(stdout.read())
self.ssh_signals.result.emit(self.ssh_server, std_out)
except Exception as e:
self.ssh_signals.result.emit(self.ssh_server, str(e))
finally:
ssh_client.close()
class CompareWorker(QObject):
done = pyqtSignal()
def __init__(self):
super(CompareWorker, self).__init__()
self.ssh_threadpool = QThreadPool()
self.ssh_threadpool.setMaxThreadCount(10)
#pyqtSlot()
def execute(self):
ssh_worker = SSHWorker()
ssh_worker.ssh_signals.result.connect(MainWindow.ssh_result)
self.ssh_threadpool.start(ssh_worker)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.button_compare = QPushButton('Compare')
self.button_compare.clicked.connect(self.compare)
self.setCentralWidget(self.button_compare)
def compare(self):
compare_thread = QThread(self)
self.compare_worker = CompareWorker()
compare_thread.started.connect(self.compare_worker.execute)
self.compare_worker.done.connect(compare_thread.quit)
self.compare_worker.done.connect(self.compare_worker.deleteLater)
self.compare_worker.moveToThread(compare_thread)
compare_thread.start()
def ssh_result(self, server, message):
print('server: ', server, ', result: ', message)
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
window.show()
app.exec_()
If I change the ssh_result() function so that message is an optional argument (def ssh_result(self, server, message=''):), I can see that the first positional argument is disappearing, leaving what should be the second argument to be the first instead, like so:
server: [Errno 11001] getaddrinfo failed , result:
Can anyone help me figure out why this is happening?
The main problem is that MainWindow.ssh_result is not a method that belongs to some instance, so the first "self" parameter does not exist. I also don't see the need for the creation of CompareWorker.
Considering the above, the solution is:
# ...
class SSHWorkerSignals(QObject):
result = pyqtSignal(
"PyQt_PyObject", "PyQt_PyObject"
) # or pyqtSignal(object, object)
class SSHWorker(QRunnable):
# ...
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.button_compare = QPushButton("Compare")
self.button_compare.clicked.connect(self.compare)
self.setCentralWidget(self.button_compare)
self.ssh_threadpool = QThreadPool()
self.ssh_threadpool.setMaxThreadCount(10)
def compare(self):
ssh_worker = SSHWorker()
ssh_worker.ssh_signals.result.connect(self.ssh_result)
self.ssh_threadpool.start(ssh_worker)
def ssh_result(self, server, message):
print("server: ", server, ", result: ", message)
# ...

updating the list store of gtk periodically in python

I'm new at phyton programming and developing gui interface has gtk framework and serial port. It has a treeview whose liststore model. I could the insert new rows easily.
I'm using the serialport recive callback in different thread from main gui thread avoid to not miss any data. After the received a new data, it should update the treeview. However, since the serialport is in different thread, I don't know how to update the list. Please help me to do this.
the gui class:
class MainGUI():
def __init__(self):
self.builder = Gtk.Builder()
self.builder.add_from_file("main.glade")
self.builder.connect_signals(MainGUI)
self.window = self.builder.get_object("window1")
self.mycombobox = self.builder.get_object('comboboxtext1')
self.toggle = self.builder.get_object('togglebutton1')
self.table = self.builder.get_object('treeview2')
self.list = self.builder.get_object('liststore1')
self.scroll_window = self.builder.get_object('scrolledwindow1')
def show(self):
print("App main thread number", format(threading.get_ident()))
self.window.show()
Gtk.main()
#staticmethod
def connect_toggled(_self):
if main.toggle.get_active():
main.toggle.set_label("Disconnect")
serial_port.connect(main.mycombobox.get_active_text())
t3 = threading.Thread(target=serial_port.read_from_port)
t3.start()
serial_port.disconnect()
def row_inserted_event(self, path, iter):
"""The actual scrolling method"""
adj = main.scroll_window.get_vadjustment()
adj.set_value(adj.get_upper() - adj.get_page_size())
def update_table(self):
# for i in range(256):
# main.list.append(['aaa', 'ddds', i])
# if len(main.list) > 50:
# main.list.remove(main.list.get_iter(0))
main.list.append(['aaa', 'ddds', 0])
if len(main.list) > 50:
main.list.remove(main.list.get_iter(0))
print(len(main.list))
if __name__ == "__main__":
serial_port = SerialPort()
ports = SerialPort().list_ports()
main = MainGUI()
for port in ports:
main.mycombobox.append_text(port)
main.mycombobox.set_active(0)
main.toggle.set_label("Connect")
main.update_table()
main.show()
the serial port class:
class SerialPort:
def __init__(self):
self.ser = serial.Serial()
self.baud_rate = 115200
def write(self, data):
self.ser.write(bytes(data))
print(data)
def connect(self, port):
print("serial port thread number = %d" % (threading.get_ident()))
print("connected the port = %s" % (port))
self.ser.port = port
self.ser.baudrate = self.baud_rate
self.ser.timeout = 0
if self.ser.isOpen():
print("already connected this port = %s" % (port))
else:
self.ser.open()
def disconnect(self):
if self.ser.isOpen():
self.ser.close()
print("disconnected port")
def read_from_port(self):
while True:
if self.ser.isOpen():
reading = self.ser.readline()
if len(reading) > 0:
self.received_callback(reading)
time.sleep(0.1)
def received_callback(self, data):
print(data)
def list_ports(self):
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
# ports = glob.glob('/dev/tty[A-Za-z]*')
ports = ['/dev/pts/%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
pass
return result
I believe that your problem is more related to threading + GUI, than GTK.
As far as I know, when you modify the liststore that is the model for the treeview, the latter should be updated instantly. So, there should be no problem there.
A fundamental principle when working with threads and a GUI, is that you should only update the GUI from within its own thread (main loop). So what you need to do, is have your worker thread (serial port connection thread) send the update to the main GUI thread and let it update the treeview. The update can be scheduled with the GLib.idle_add function to let GTK do it when most convenient.
Now, to communicate between threads, you could use the queue module.
I don't quite understand your code. So I'll write a simple example (using gtk3 PyGObject, since you didn't specify).
import threading
import queue
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GLib', '2.0')
from gi.repository import Gtk, GLib
def do_work(com_queue):
# do some work
com_queue.put("update for your treeview")
# continue
class MainGUI(object):
def __init__(self):
self.com_queue = queue.Queue()
self.worker_thread = None
self.liststore = None
# more gui initialization...
def launch_worker_thread(self):
self.worker_thread = threading.Thread(target=do_work, args=(self.com_queue,))
self.worker_thread.start()
Glib.timeout_add(1000, self.check_queue) # run check_queue every 1 second
def check_queue(self):
if self.worker_thread.is_alive():
try:
update = self.com_queue.get()
GLib.idle_add(self.update_treeview, (update,)) # send tuple
except queue.Empty:
pass
return True # to keep timeout running
else:
return False # to end timeout
def update_treeview(self, update):
self.liststore.append(update) # here update the treeview model with tuple
if __name__ == "__main__":
gui = MainGUI()
Gtk.main()
I hope this helps.

PyGTK: Userlogin Dialog

currently I'm working on a Server-Client Application with python.
The Server-Client is working. My problem is the GUI.
I'm trying to do this with GTK.
Since 2 weeks I'm testing around but the login-screen wont work.
So here are my questions:
How can I create and connect multiple windows in GTK? e.g first login-screen then main_window
How can a Text_Entry-Dialog be created (all in PyGTK)?
[Edit-03.01.2016] Code:
#!/usr/bin/python3
# coding=utf8
import socket
from gi.repository import GObject, Gio, Gtk
class MyApplication(Gtk.Application):
# Main initialization routine
def __init__(self, application_id, flags):
Gtk.Application.__init__(self, application_id=application_id, flags=flags)
self.connect("activate", self.new_window)
#main_Window(self)
def new_window(self, *args):
self. snc =start_Connection_Window(self)
print("going on")
def main_Window(self):
print "Here I'm "
self.connect("activate", self.new_MainWindow)
self.snc.close()
def new_MainWindow(self):
main_Window(self)
print "main_Window started"
class start_Connection_Window(Gtk.Window):
def __init__(self, application):
self.Application = application
# Read GUI from file and retrieve objects from Gtk.Builder
try:
GtkBuilder = Gtk.Builder.new_from_file()#Some Glade file with two windows
GtkBuilder.connect_signals(self)
except GObject.GError:
print("Error reading GUI file")
raise
# Fire up the main window
self.start_Connection_Window = GtkBuilder.get_object("start_Connection")
self.start_Connection_Window.set_application(application)
self.ServerIP_Input = GtkBuilder.get_object("ServerIP-Input")
self.Username_Input = GtkBuilder.get_object("Username_Input")
self.Password_Input = GtkBuilder.get_object("Password_Input")
self.start_Connection_Window.show()
def on_btn_Connect_clicked(self, button):
button.set_sensitive(False)
try:
self.host = str(self.ServerIP_Input.get_text())
self.username = str(self.Username_Input)
self.password = str(self.Password_Input)
self.port=1317
self.clientsocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clientsocket.connect((self.host, self.port))
self.LENGTH_SIZE = 4
data='ping'
lenght = str(len(data))
self.clientsocket.send(lenght.zfill(4))
print data
self.clientsocket.send(data)
except:
print "Error!"
button.set_sensitive(True)
self.Application.main_Window()
try:
lenght = self.clientsocket.recv(self.LENGTH_SIZE)
data = self.clientsocket.recv(int(lenght))
print data
if(data == str("ok")):
try:
self.Application.main_Window( )
self.close()
except :
print "Here is the mistake"
else:
print "Failed!"
button.set_sensitive(True)
except:
print "Fail!"
#print "Would Start Conn"
def close(self, *args):
self.start_Connection_Window.destroy()
def on_MainWindow_destroy(self, window):
#self.Application.main_Window()
print "Bye"
def on_Window_destroy(self):
print("Bye aus dem destroyten!")
class main_Window(Gtk.Window):
def __init__(self, application):
self.Application = application
# Read GUI from file and retrieve objects from Gtk.Builder
try:
GtkBuilder = Gtk.Builder.new_from_file()#someGladeFile with two Windows
GtkBuilder.connect_signals(self)
except GObject.GError:
print("Error reading GUI file")
raise
# Fire up the main window
self.MainWindow = GtkBuilder.get_object("main_Window")
self.MainWindow.set_application(application)
self.MainWindow.show()
def on_btn_Connect_clicked(self, button):
print "Would Start Conn"
def close(self, *args):
self.MainWindow.destroy()
def on_MainWindow_destroy(self, window):
#self.Application.new_window()
print "Bye"
def on_Window_destroy(self, window):
#self.Application.new_window()
print "Bye"
def start(self, socket, host, username, password):
self.SClient = SC(host, username, password, self)
self.MainWindow.show()
# Starter
def main():
# Initialize GTK Application
Application = MyApplication("App", Gio.ApplicationFlags.FLAGS_NONE)
print "starting"
# Start GUI
Application.run()
if __name__ == "__main__": main()

Queue communication from serial thread to Tkinter GUI

I am doing simple gui for continuous reading data stream from serial COM port and display the results. I could not get up and running queue to push the data from reading thread to main (GUI) part. I think I am missing some part but cannot figure out what.
I can easily start thread and read data(printing them after) from COM port but it seems nothing is going to queue becase when I am printing output in GUI part is empty. Beside that reading and main thread is running ok.
Do you have an idea how to check if is something in the queue?
Here is part of the code if you could check it.
And also sorry for messed up indention :-P
Thank you
class MyGUI(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
self.queueData = Queue.Queue() # create queue
self.initialize()
def initialize(self):
"""Create the GUI"""
self.grid()
...gui code here...
def processQueueData(self):
try:
rawData = self.queueData.get()
except Queue.Empty:
pass
else:
print 'GUI:'+ rawData
#show result of the task
finally:
self.queueDataID = self.after(50, self.processQueueData)
And reading thread is here:
class MyProcess(threading.Thread):
def __init__(self, parent, queueData): #def __init__(self, startValue)
threading.Thread.__init__(self)
self._stop = False
self.parent = parent
self.queueData = queueData
try:
port = app.boxPort.get()
self.ser = serial.Serial(port, baudrate=19200, timeout=0, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE)
except serial.SerialException:
print ('Cannot open port')
self.stop()
else:
app.labelConStatus.set(u'Connected to ' + port)
def stop(self):
self._stop = True
try:
self.ser.close()
except serial.SerialException:
print ('Cannot close port')
else:
app.labelConStatus.set(u'Disconnected')
def run (self):
while self._stop == False:
data = self.ser.read(1)
n = self.ser.inWaiting()
if n:
data = data + self.ser.read(n)
self.queueData.put(data)
# print 'PORT:'+data

Confirmation box on file transfer over sockets using PyQT

I have a confirmation box which gets called when sending a file over the network. However, the function for the Signal is in the MainWindow class and uses variables from the Worker thread. But it doesn't work because the variables in the worker thread are not in the right scope.
Any idea how I can pass the msg variable to the saveFile function in the MainWindow class from the signal?
Edit: What I needed to do was pass an argument to my signal but I figured it out. Sorry for the confusion. I was unsure what needed to be done.
Here's a working example:
import socket
import select
import sys, os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
CMD_FILE = 1
CLIENT_PORT = 9001
CLIENT_HOST = '127.0.0.1'
class MainWindow(QWidget):
def __init__(self, parent=None):
#super(QWidget, self).__init__(parent)
super(MainWindow, self).__init__(parent)
self.resize(100, 50)
self.thread = Worker()
self.thread.start()
self.file_button = QPushButton('Send a File')
self.connect(self.file_button, SIGNAL("released()"), self.sendFile)
self.connect_button = QPushButton('Connect To Server')
self.connect(self.connect_button, SIGNAL("released()"), self.connectToServer)
self.connect(self.thread, SIGNAL('triggered(PyQt_PyObject)'), self.saveFile)
self.layout = QFormLayout()
self.layout.addRow(self.file_button, self.connect_button)
self.setLayout(self.layout)
def connectToServer(self):
global s
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((str(CLIENT_HOST).strip(), CLIENT_PORT))
print "Connected to ", str(CLIENT_HOST)
except:
print "unable to connect"
def clientAll(self, cmd, msg):
#check if connnected send a message
s.sendall(cmd + msg)
def sendFile(self):
filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
f = open(filename, 'rb')
myFile = f.read()
self.clientAll(chr(CMD_FILE), myFile)
f.close()
print filename, "Sent\n"
def saveFile(self, msg):
reply = QMessageBox.question(self, 'Message',
"Are you sure you wish to download this file?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
filename = QFileDialog.getSaveFileName(self, 'Save File', '.')
f = open(filename, 'wb')
f.write(msg)
f.close()
print filename, "Recieved"
else:
pass
class Worker(QThread):
def __init__(self):
QThread.__init__(self)
self.exiting = False
def __del__(self):
self.exiting = True
self.wait()
def run(self):
source_ip = ''
#socket.gethostbyname(socket.gethostname())
PORT = 9001
### Initialize socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((source_ip, PORT))
#
server_socket.listen(5)
read_list = [server_socket]
### Start receive loop
while True:
readable, writable, errored = select.select(read_list, [], [])
for s in readable:
if s is server_socket:
conn, addr = s.accept()
read_list.append(conn)
else:
msg = conn.recv(12024)
if msg:
cmd, msg = ord(msg[0]),msg[1:]
if cmd == CMD_FILE:
if not msg: break
self.emit(SIGNAL('triggered(PyQt_PyObject)'), msg)
else:
s.close()
read_list.remove(s)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.setWindowTitle('CATS!!! <3')
win.show()
sys.exit(app.exec_())
I think I don't understand exactly your situation.
However, did you try to define a new (custom) signal?
If you define a new signal with pyqtSignal,
you can emit the signal with parameters.
Documentation on signal and slots (new style).

Categories