I am trying to do simple serial link program for school project and I have small problem. I created class to maintain serial communication, but when I unplug and plug back serial port, it doesnt change state of serial connection (self.ser have still same object like when it was initalized). I want it to recconnect and continue to work. Can you please help me and tell mi what I am doing wrong? I am new to python. Thank you very much!
import serial
import uuid
class SerialWrapper:
def __init__(self):
self.ser = serial.Serial("COM3", 9600)
def handleconnect(self):
try:
if self.ser is None:
self.ser = serial.Serial("COM3", 9600)
self.ser.close()
self.ser.open()
print("Reconnecting...")
except:
if not (self.ser is None):
self.ser.close()
self.ser = None
print("Disconnecting")
else:
print("No Connection")
def serialwrite(self, data):
self.handleconnect()
try:
datalength = self.ser.write(data.encode())
print("Writing data...")
return datalength
except:
print("Error in writing data")
def serialread(self, datalength):
self.handleconnect()
try:
data = self.ser.read(datalength).decode()
print("Reading data...")
return data
except:
print("Error in reading data")
def main():
ser = SerialWrapper()
while 1:
value = uuid.uuid4().hex
length = ser.serialwrite(value)
print(ser.serialread(length))
main()
So I found that on every end of cycle must be port closed with self.ser.close() and then at the start of new cycle openened again with self.ser.open()
Related
I've got a gui that I'm playing with that uses pyserial. In it I'm using pyserial's ReaderThread to monitor the serial output of my serial device and print it out on a console window.
I also am using pyserial's Serial() implementation for sending commands to the serial device.
Usually I don't need to grab the response to a ser.write() and just let the ReaderThread handle it.
However there are now occasions where I'd like in pause the ReaderThread do a ser.read() to a variable, act on the variable, and unpause the ReaderThread to let it continue it's thing.
Tried ReaderThread.stop(), but it seems to be dropping the connection.
Also tried creating my own readerThread.run() function that has mutex locking and replacing the run method with it, but that's turning out to be a bit squirrelly.
Am I missing an easy way to do this?
Figured a way by monkey patching the ReaderThread Class:
def localinit(self, serial_instance, protocol_factory):
"""\
Initialize thread.
Note that the serial_instance' timeout is set to one second!
Other settings are not changed.
"""
super(ReaderThread, self).__init__()
self.daemon = True
self.serial = serial_instance
self.protocol_factory = protocol_factory
self.alive = True
self._lock = threading.Lock()
self._connection_made = threading.Event()
self.protocol = None
self._stop_event = threading.Event()
print("****************************************************")
print(" localinit ")
print("****************************************************")
def localrun(self):
"""Reader loop"""
print("****************************************************")
print(" localrun ")
print("****************************************************")
if not hasattr(self.serial, 'cancel_read'):
self.serial.timeout = 1
self.protocol = self.protocol_factory()
try:
self.protocol.connection_made(self)
except Exception as e:
self.alive = False
self.protocol.connection_lost(e)
self._connection_made.set()
return
error = None
self._connection_made.set()
while self.alive and self.serial.is_open:
while self._stop_event.is_set():
#print("local run while")
time.sleep(1)
try:
data = self.serial.read(self.serial.in_waiting or 1)
except serial.SerialException as e:
# probably some I/O problem such as disconnected USB serial
# adapters -> exit
error = e
break
else:
if data:
# make a separated try-except for called user code
try:
self.protocol.data_received(data)
except Exception as e:
error = e
break
self.alive = False
self.protocol.connection_lost(error)
self.protocol = None
def localpause(self):
self._stop_event.set()
def localresume(self):
self._stop_event.clear()
Then in my main code:
ReaderThread.run = localrun
ReaderThread.__init__ = localinit
ReaderThread.pause = localpause
ReaderThread.resume = localresume
self.reader = ReaderThread(serialPort, SerialReaderProtocolLine)
self.reader.start()
def write_read_cmd(self, cmd_str):
if(serialPort.isOpen() == False):
print("Serial port not yet open")
return
app.serialcom.reader.pause()
serialPort.reset_input_buffer() # flush the buffer
serialPort.reset_input_buffer() # flush the buffer
serialPort.reset_input_buffer() # flush the buffer
serialPort.write(bytes(cmd_str, encoding='utf-8'))
line = serialPort.readline()
app.serialcom.reader.resume()
line = line.decode("utf-8")
return line
I am trying to make an Uart Class in python which can receive data and send it. The meaning for my program is so that I can just use it as a driver and put it in the constructor and get the data I want, for example: Uart = uart(arg1, arg2) where arg1 sends a number or a string for what kind of data I need, FX. Temperature or water level, and arg2 is the data I receive.
import serial
import time
class uart():
uart = serial.Serial('/dev/serial0', baudrate=9600)
def __init__(self, write, read):
self.read = read
self.write = write
def read(self, read):
if uart.isopen():
try:
while True:
self.value = uart.readline()
return self.value
except:
print("failed to recive data")
def write(self, write):
if uart.isopen():
try:
self.uart.write()
finally:
print("sent")
time.sleep(1)
if __name__ == '__main__':
myPh = uart("22",'')
Okay, i tried something more easy and i got the read def running, but the write wont work like i want i too..
import serial
import time
class uart(object):
uart = serial.Serial('/dev/serial0', baudrate=9600)
# def __init__(self, write, read):
# self.read = read()
# self.write = write()
def write(self):
self.uart.write()
print("sent")
time.sleep(3)
def read(self):
while True:
self.value = uart.readline()
time.sleep(2)
print(self.value)
return self.value
if __name__ == '__main__':
while True:
myTemp = uart()
myTemp.write('hello')
myTemp.read()
For a few weeks I'm stuck with, how to open a serial COM port from a thread,
to be able to write/read it from another thread. In my example, when I write to the port from another thread, there is access denied.
When I open the port from Main GUI, it works fine, I can write it from the thread, but I need to give a user possibility to choose the COM number.
This is my code, if anybody could take a look and help, it would be great...
class Connect(QThread):
connectResult = QtCore.pyqtSignal(str)
position1 = QtCore.pyqtSignal(str)
actuPosResult = QtCore.pyqtSignal(str)
def __init__(self, myvar, parent=None):
QThread.__init__(self, parent)
self.myvar = str(myvar) # value from spinbox
def run(self):
self.pserial = serial.Serial()
try:
COMnumber= self.myvar
self.pserial = serial.Serial('COM'+COMnumber, 115200,timeout=None)
r='COM '+COMnumber+' connected.'
self.pserial.write("c".encode('ascii')+"\n".encode('ascii'))
incomingByte = self.pserial.read()
decodedByte = incomingByte.decode("utf-8")
if decodedByte == ('c'):
r='Atmega On-Line'
self.connectResult.emit(r)
pos1='---'
self.position1.emit(pos1)
else :
r=' No answer from Atmega.'
self.connectResult.emit(r)
def stop(self):
self.terminate()
class ReadingEncoder(QThread):
actuPosResult = QtCore.pyqtSignal(str)
def __init__(self, mojazmienna, parent=None):
QThread.__init__(self, parent)
self.mojazmienna = str(mojazmienna)
def run(self):
Try:
self.pserial = serial.Serial()
self.pserial = serial.Serial('COM3', 115200,timeout=1)
self.pserial.write("p".encode('ascii')+"\n".encode('ascii'))
incomingByte = self.pserial.read()
decodedByte = incomingByte.decode("utf-8")
actualPos = ''
if decodedByte == ('a'):
while decodedByte != ('\n'):
incomingByte = self.pserial.read()
decodedByte = incomingByte.decode("utf-8")
actualPos = actualPos + decodedByte
pos= actualPos.rstrip('\n')# pozycja w formacie string
print(pos)
self.actuPosResult.emit(pos)
except (EOFError, OSError, IOError, ValueError, RuntimeError, BrokenPipeError, InterruptedError, TimeoutError):
print('Thread readingEncoder error')
self.pserial.close()
You just open the serial port and start the thread.
import atexit
class SerialPort(QThread):
connectResult = QtCore.pyqtSignal(str)
position1 = QtCore.pyqtSignal(str)
actuPosResult = QtCore.pyqtSignal(str)
def __init__(self, port=None, baud=115200, timeout=1):
super().__init__()
self.ser = serial.Serial()
self.ser.port = port
self.ser.baudrate = baud
self.ser.timeout = timeout
self.running = False
atexit.register(self.ser.close) # Make sure the serial port closes when you quit the program.
def set_port(port_num):
self.ser.port = "COM"+str(port_num)
def start(self, *args, **kwargs):
self.running = True
self.ser.open()
super().start()
self.ser.write("c\n".encode("ascii"))
def run(self):
while self.running:
try:
incomingByte = self.ser.read()
decodedByte = incomingByte.decode("utf-8")
if decodedByte == ('c'):
r='Atmega On-Line'
self.connectResult.emit(r)
pos1='---'
self.position1.emit(pos1)
else:
r=' No answer from Atmega.'
self.connectResult.emit(r)
except:
pass
# time.sleep(0.01) # You may want to sleep or use readline
You use this class by having a button call the start method.
serial = SerialPort("COM3")
btn = QtGui.QPushButton("Connect")
btn.clicked.connect(serial.start)
You can typically only open a serial port once unless you know that you have both ends available to you.
The serial port exists on the main thread and exists the entire time. You don't need to continuously open and close the serial port. All of the reading happens in the thread. To write just call serial.write(b"c\n"). You shouldn't need the writing to happen in the thread.
To have the user select the com port just use a QLineEdit.
myserial = QtGui.QLineEdit("3")
myserial.textChanged.connect(serial.set_port)
You're trying to open the port multiple times.
Instead of doing that, you have a couple of alternatives;
Create a Serial object once, and pass it to the thread that has to work with it.
Provide the name of the serial port to use to the the thread that has to work with it, and let it open the port.
In both cases make sure that your thread closes the port properly when it exits!
I hope the title is appropriate. If not please suggest an alternative. I am working with the following Python Client Class.
import Queue
import socket
import struct
import threading
import time
class ClientCommand(object):
CONNECT, SEND, RECEIVE, CLOSE = range(4)
def __init__(self, type, data=None):
self.type = type
self.data = data
class ClientReply(object):
ERROR, SUCCESS = range(2)
def __init__(self, type, data = None):
self.type = type
self.data = data
class SocketClientThread(threading.Thread):
def __init__(self, cmd_q = Queue.Queue(), reply_q = Queue.Queue()):
super(SocketClientThread, self).__init__()
self.cmd_q = cmd_q
self.reply_q = reply_q
self.alive = threading.Event()
self.alive.set()
self.socket = None
#self.stopped = False
self.handlers = {
ClientCommand.CONNECT: self._handle_CONNECT,
ClientCommand.CLOSE: self._handle_CLOSE,
ClientCommand.SEND: self._handle_SEND,
ClientCommand.RECEIVE: self._handle_RECEIVE
}
def run(self):
while self.alive.isSet():
#while not self.stopped:
try:
cmd = self.cmd_q.get(True, 0.1)
self.handlers[cmd.type](cmd)
except Queue.Empty as e:
continue
def stop(self):
self.alive.clear()
def join(self, timeout=None):
self.alive.clear()
threading.Thread.join(self, timeout)
def _handle_CONNECT(self, cmd):
try:
self.socket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((cmd.data[0], cmd.data[1]))
self.reply_q.put(self._success_reply())
except IOError as e:
self.reply_q.put(self._error_reply(str(e)))
def _handle_CLOSE(self, cmd):
self.socket.close()
reply = ClientReply(ClientReply.SUCCESS)
self.reply_q.put(reply)
def _handle_SEND(self, cmd):
try:
print "about to send: ", cmd.data
self.socket.sendall(cmd.data)
print "sending data"
self.reply_q.put(self._success_reply())
except IOError as e:
print "Error in sending"
self.reply_q.put(self._error_reply(str(e)))
def _handle_RECEIVE(self, cmd):
try:
#TODO Add check for len(data)
flag = True
while flag:
print "Receiving Data"
data = self._recv_n_bytes()
if len(data) != '':
self.reply_q.put(self._success_reply(data))
if data == "Stop":
print "Stop command"
flag = False
except IOError as e:
self.reply_q.put(self._error_reply(str(e)))
def _recv_n_bytes(self):
data = self.socket.recv(1024)
return data
def _error_reply(Self, errstr):
return ClientReply(ClientReply.ERROR, errstr)
def _success_reply(self, data = None):
return ClientReply(ClientReply.SUCCESS, data)
My main script code -
import socket
import time
import Queue
import sys
import os
from client import *
sct = SocketClientThread()
sct.start()
host = '127.0.0.1'
port = 1234
sct.cmd_q.put(ClientCommand(ClientCommand.CONNECT, (host, port)))
try:
while True:
sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE))
reply = sct.reply_q
tmp = reply.get(True)
data = tmp.data
if data != None:
if data != "step1":
//call function to print something
else:
// call_function that prints incoming data till server stops sending data
print "Sending OK msg"
sct.cmd_q.put(ClientCommand(ClientCommand.SEND, "Hello\n"))
print "Done"
else:
print "No Data"
except:
#TODO Add better error handling than a print
print "Server down"
So here is the issue. Once the thread starts, and the Receive handler is called, I get some data, if that data is not "Step1", I just call a function (another script) to print it.
However, if the data is "step1", I call a function which will then continue printing whatever data the server sends next, till the server sends a "Stop" message. At this point, I break out of the "Receive Handler", and try to send an "Ok" message to the Server.
However, as soon as I break out of the "Receive Handler", it automatically calls upon that function again. So while I am trying to send back a message, the client is again waiting for data from the server. So due to the "Receiver function" being called again, the "Send function" blocks.
I can't seem to understand how to switch between receiving and sending. What is wrong with my approach here and how should I fix this? Do I need to re-write the code to have two separate threads for sending and receiving?
If you require any more details please let me know before you decide to flag my question for no reason.
However, as soon as I break out of the "Receive Handler", it
automatically calls upon that function again.
This is because you call sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE)) within the while True loop that's run through for each single chunk of data received, i. e. for each data before "step1" one more command to call the "Receive Handler" (which itself loops until "Stop") is put into the ClientCommand queue, and those commands are of course then executed before the SEND command. If you place the RECEIVE call before this while True loop, your approach can work.
The error is
if msgid != "step1":
NameError: name 'msgid' is not defined
Instead of
#TODO Add better error handling than a print
print "Server down"
you had better written
raise
and spotted it immediately.
From my understanding python can only run 1 thread at a time so if I were to do something like this
import socket, select
from threading import Thread
import config
class Source(Thread):
def __init__(self):
self._wait = False
self._host = (config.HOST, config.PORT + 1)
self._socket = socket.socket()
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._sock = None
self._connections = []
self._mount = "None"
self._writers = []
self._createServer()
Thread.__init__(self)
def _createServer(self):
self._socket.bind(self._host)
self._socket.listen(2)
self._connections.append(self._socket)
self._audioPackets=[]
def _addPacket(self, packet):
self._audioPackets.append(packet)
def _removePacket(self, packet):
self._audioPackets.remove(packet)
def _getPacket(self):
if len(self._audioPackets) > 0:
return self._audioPackets[0]
else:
return None
def _sendOK(self, sock):
sock.send("OK")
def _sendDenied(self, sock):
sock.send("DENIED")
def _sendMount(self, sock):
sock.send("mount:{0}".format(self._mount))
def _sendBufPacket(self, sock, packet):
packet = "buffer:%s" % packet
sock.send(packet)
def recv(self, sock, data):
data = data.split(":", 1)
if data[0] == "WAIT": self._wait = True
elif data[0] == "STOP_WAITING": self._wait = False
elif data[0] == "LOGIN":
if data[1] == config.SOURCE_AUTH:
self._source = sock
self._sendOK(sock)
else:
self._sendClose(sock)
elif data[0] == "MOUNT":
if self._source == sock:
self._mount = data[1]
else:
self._sendClose(sock)
elif data[0] == "CLIENT":
self._sendMount(sock)
self._writers.append(sock)
def _sendCloseAll(self):
for sock in self._connections:
sock.send("CLOSE")
sock.close()
def _sendClose(self, sock):
sock.send("CLOSE")
sock.close()
def main(self):
while True:
rl, wl, xl = select.select(self._connections, self._writers, [], 0.2)
for sock in rl:
if sock == self._socket:
con, ip = sock.accept()
self._connections.append(con)
else:
data = sock.recv(config.BUFFER)
if data:
self.recv(sock, data)
else:
if sock in self._writers:
self._writers.remove(sock)
if sock in self._connections:
self._connections.remove(sock)
for sock in wl:
packet = self._getPacket()
if packet != None:
self._sendBufPacket(sock, packet)
def run(self):
self.main()
class writeThread(Thread):
def __init__(self):
self.running = False
def make(self, client):
self.client = client
self.running = True
def run(self):
host = (config.HOST, config.PORT+1)
sock = socket.socket()
sock.connect(host)
sock.send("CLIENT")
sock.send("MOUNT:mountpoint")
while self.running:
data = sock.recv(config.BUFFER)
if data:
data = data.split(":", 1)
if data[0] == "buffer":
self.client.send(data[1])
elif data[0] == "CLOSE":
self.client.close()
break
if __name__=="__main__":
source = Source()
source.start()
webserver = WebServer()
webserver.runloop()
if I need to build the webserver part I will. But, I'll explain it.
Okay, so basically when someone connects to the websever under the mountpoint that was set, They will get there own personal thread that then grabs the data from Source() and sends it to them. Now say another person connects to the mount point and the last client as well as the source is still going. Wouldn't the new client be blocked from getting the Source data considering there are two active threads?
Your understanding of how Threads work in Python seems to be incorrect, based on the question you are asking. If used correctly, threads will not be blocking: you can instantiate multiple thread with Python. The limitation is that, due to the Global Interpreter Lock (GIL), you cannot get the full parallelism expected in thread programming (e.g. simultaneous execution and thus, reduced runtime).
What is going to happen in your case is that the two threads will take, together, the same amount of time that they would take if they were executed sequentially (although that is not necessarily what happens in practice).
Okay, I have copy and pasted some Python3 code that I have already written for a project that I am currently working on. With modification, you can make this code serve your purposes.
The code uses multiprocessing and multithreading. For my purposes, I am using multiprocessing so that sockets will run on one processor, and I can run a GUI program on another processor. You can remove the multiprocessor part if you prefer. The code below runs a socket message server. The server will listen for clients one at a time. Once a client has connected, a new thread will be initiated to handle all the communications between the server and each client. The server will then continue to search for for clients. At the moment however, the server only listens to data being sent from each client, and then it prints it to the terminal. With a small amount of effort, you can modify my code to send information from the server to each client individually.
import multiprocessing
import threading
from threading import Thread
class ThreadedServer(object):
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket(AF_INET, SOCK_STREAM)
self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(3) #Allow 3 Clients to connect to this server
while True:
#The program will search for one client at a time
print("Searching for Client")
client, address = self.sock.accept()
print(address, " is connected")
#client.settimeout(60)
#Once a client has been found, start a individual client thread
d = threading.Thread(target = self.listenToClient, args=(client, address))
d.daemon = True
d.start()
def listenToClient(self, client, address):
size = 1024
while True:
try:
data = client.recv(size)
if not data:
break
if data:
print(data)
#client.send(response)
else:
raise error('Client disconnected')
except:
client.close()
return False
def dataSharingHost():
#Using Sockets to send information between Processes
#This is the server Function
#ThreadServer(Host_IP, Port_Number), for LocalHost use ''
ThreadedServer('', 8000).listen()
def Main():
commServer = multiprocessing.Process(target=dataSharingHost, args=())
commServer.daemon = True
commServer.start()
if __name__== '__main__':
Main()
And to be fair, my code is modified from https://www.youtube.com/watch?v=qELZAi4yra8 . The client code is covered in those videos. I think the 3rd video covers the multiple client connects.