Problem opening serial port with Pyserial - python

I'm trying to read numerical values sent over a bluetooth modem from a serial port using Pyserial. I'm a beginner at Python, and found a good example that I'm trying to make use of.
from threading import Thread
import time
import serial
last_received = ''
def receiving(ser):
global last_received
buffer = ''
while True:
buffer = buffer + ser.read(ser.inWaiting())
if '\n' in buffer:
lines = buffer.split('\n') # Guaranteed to have at least 2 entries
last_received = lines[-2]
#If the modem sends lots of empty lines, you'll lose the
#last filled line, so you could make the above statement conditional
#like so: if lines[-2]: last_received = lines[-2]
buffer = lines[-1]
class SerialData(object):
def __init__(self, init=50):
try:
self.ser = ser = serial.Serial(
port='/dev/tty.FireFly-16CB-SPP',
baudrate=115200,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
except serial.serialutil.SerialException:
#no serial connection
self.ser = None
else:
Thread(target=receiving, args=(self.ser,)).start()
def next(self):
if not self.ser:
return 140 #return anything so we can test when Arduino isn't connected
#return a float value or try a few times until we get one
for i in range(40):
raw_line = last_received
try:
return float(raw_line.strip())
except ValueError:
print 'bogus data',raw_line
time.sleep(.005)
return 0.
def __del__(self):
if self.ser:
self.ser.close()
if __name__=='__main__':
s = SerialData()
for i in range(500):
time.sleep(.015)
print s.next()
I can open the port in another program, and can send/receive data from it. However, the code above doesn't seem to open the port, and just repeats "100" to the terminal window 500 times, but I don't know where it comes from or why the port doesn't open correctly. There isn't a delay from opening the port as it is on the other program, so I don't even know if it attempts to open.
I don't know what else to try, or where the error is so I'm asking for help. What am I doing wrong?

except serial.serialutil.SerialException:
You're catching and silencing errors in connecting. Comment out this block, and see if it produces an error message.

Related

pySerial: Does write_timeout do anything?

I'm wondering if write_timeout even works or if I have to handle the timeout myself.
I want to send data to my STM32 Nucleo-Board via UART. For that I'm using the library pySerial. But if the write operation fails, because the Nucleo-Board isn't powered, I want to throw an error saying "Nucleo-Board not powered". I assume that when the write operation times out after 1 second, the Nucleo-Board has no power. So, I set the write_timeout of the serial.Serial() object to 1, but it seems that write_timeout doesn't do anything.
I created my own class, to add additional methods.
class Serial:
def __init__(self, baudrate: int, port: str, write_timeout: int = None, read_timeout: int = None):
self.baudrate = baudrate
self.port = port
self.write_timeout = write_timeout
self.read_timeout = read_timeout
self.ser = serial.Serial()
self.ser.baudrate = self.baudrate
self.ser.port = self.port
self.ser.write_timeout = self.write_timeout
self.ser.timeout = self.read_timeout
def _serial_ports():
# ...
def serialWrite(self, string: str, size: int = None):
print(self.write_timeout)
print(self.ser.write_timeout)
# check if COM port exists -> because UART cable is connected, COM6 always exists,
# even when no power is connected.
if self.port not in self._serial_ports():
raise serial.SerialException(f"Make sure this COM Port exists.")
try:
print("opened")
self.ser.open()
except serial.SerialException as e:
print("closed")
self.ser.close()
# error handling ...
else:
encodedString = string.encode()
print("write now")
try:
bytes = self.ser.write(encodedString) # times out here -> program hangs (no exception)
except Exception as e:
print(e)
print("Nucleo-Board not powered")
serialPort = Serial(baudrate=115200, port="COM6", write_timeout=1)
feedback = serialPort.serialWrite(f"ABC", 3)
Output
self.write_timeout=1
self.ser.write_timeout=1
opened
write now
I have to kill the program, because it stops working.
The program works, when I plug in the power of the Nucleo-Board.
Solution
The problem was, that I thought the timeout happens on ser.write(). But a timeout never happens on ser.write(), because (as #jasonharper already commented) the board being unpowered doesn't prevent serial data from being sent - it just means the data isn't going anywhere. So in the end, the timeout was a few lines after the write operation at the read operation ser.read(), to get a feedback to know the Nucleo-Board received something. There it can timeout, because it waits until data are received. But the board isn't powered so data will never received. Because I didn't handled the timeout for read operations, the program started to hang.
Current Code
try:
bytes = self.ser.write(encodedString)
except Exception as e:
# never raise
print(e)
print("Nucleo-Board not powered")
feedback = self.ser.read(size) # here it waits forever, because it doesn't receive something of course, because the Nucleo board isn't powered.
Code Solution
self.ser.timeout = 1 # for self.ser.read()

Reconnecting with pySerial

I'm trying to write a function which continuously reads serial input. The function must be able to handle unexpected disconnections from the serial port and reconnect when possible. Despite reading several question posts on stackOverflow and looking through the pySerial documentation, I have yet to find a solution.
Here's my code:
def serialRead(serialPort, queue):
"""Adds serial port input to a queue."""
ser = serial.Serial(serialPort - 1, timeout = 2)
ser.parity = "O"
ser.bytesize = 7
while(True):
try:
if(ser == None):
ser = serial.Serial(serialPort - 1, timeout = 2)
ser.parity = "O"
ser.bytesize = 7
print("Reconnecting")
queue.put(ser.read(27))
ser.write(chr(6).encode())
print("Writing Data...")
except:
if(not(ser == None)):
ser.close()
ser = None
print("Disconnecting")
print("No Connection")
time.sleep(2)
Here's my output:
Enter a Serial Port: 7
Writing Data...
Writing Data...
Writing Data...
Writing Data...
I start with my device connected. After leaving the program run, neither "Disconnecting" or "No Connection" display and the program stops (it doesn't crash).
This code works. Batman tested the program on an Arduino connection and I found that my program had successfully reconnected with the device after a period of time. I hope this code will be useful for those struggling with something similar.

How to check if device is connected Pyserial

I am connecting with my Arduino through a USB port and sending data to it by using PySerial module. At first I can check if the device is connected by using this code:
try:
ser = serial.Serial("COM3", 9600)
except serial.serialutil.SerialException:
print "Arduino not connected"
Now what I want to do is to check periodically if the Arduino is still connected to the computer. I tried ser.isOpen() but this returns true even if the Arduino is disconnected. I would also like to know how to reconnect the device. I mean once you disconnect the device the program can no longer send any data to Arduino.
Most of the answers propose 2 approaches:
In some point of the code, send some sort of message through serial to check if your device is still alive
Start a separate thread and continuously check if the device is alive by opening a communication
The problem with the first solution is that you are not always checking the connection, but only checking in some specific points: this solution isn't very elegant and if badly written could even be not working.
The second solution solves the problem of the first solution, but introduces a new problem: checking the connection, or worst sending a message, in a threaded loop will cause problem or may even interrupt the connection to the device from other functions.
A solution that allows you to constantly check the connection without monopolizing the communication involves the reading of the existing COM:
import serial.tools.list_ports
myports = [tuple(p) for p in list(serial.tools.list_ports.comports())]
print myports
output:
[(u'COM3', u'Arduino Due Programming Port (COM3)', u'some more data...'),
(u'COM6', u'USB Serial Port (COM6)', u'some more data...'),
(u'COM100', u'com0com - serial port emulator (COM100)', u'some more data...')]
then we save the tuple that contains our port:
arduino_port = [port for port in myports if 'COM3' in port ][0]
then we create a function that checks if this port is still present:
import time
def check_presence(correct_port, interval=0.1):
while True:
myports = [tuple(p) for p in list(serial.tools.list_ports.comports())]
if arduino_port not in myports:
print "Arduino has been disconnected!"
break
time.sleep(interval)
At last, we run this function as a daemon thread:
import threading
port_controller = threading.Thread(target=check_presence, args=(arduino_port, 0.1,))
port_controller.setDaemon(True)
port_controller.start()
in this way, you'll check each 0.1 secs if the arduino is still connected, and the thread will end when arduino is disconnected or all other activities have ended
You can set a timeout.
import serial
ser = serial
try:
ser = serial.Serial("COM3", 9600, timeout=10)
while ser.read():
print 'serial open'
print 'serial closed'
ser.close()
except serial.serialutil.SerialException:
print 'exception'
Unfortunately, the best way I can find to do this is to try some communication and see if it fails. A pretty safe way would be:
try:
ser.inWaiting()
except:
print "Lost connection!"
You'll probably still want to close the connection with a ser.close() after the connection is lost, although you may need to place that in a "try:except" block also.
import serial
import time
ser = serial.Serial()
ser.braudrate = 115200
ser.port = "/dev/ttyUSB0"
ser.open()
print(ser.name)
if ser.isOpen():
print("serial is open!")
ser.close()
For example to detect ttyUSB0:
import os
x=os.system("ls /dev/ttyUSB0")
if x==0:
print "connected"
else:
print "disconnected"
i suggest to use a python thread class to istantiate a serial connection, in the run methos put your while loop , set an var that you use for kill iy at the end, the second public var that you use for store data if have receive and load data in main method.. soon paste an example
class Arduino():
def __init__(self,Port='/dev/ttyUSB0',Boud=9600,connState=0):
self.parent=self
self.port=Port
self.boud=Boud
self.connState=connState
self.timeount=1
self.ser=None
self.connect()
def connect(self):
try:
self.ser=serial.Serial(self.port,self.boud,timeout=0.0001)
self.connState=1
return [1,'connect']
except:
self.connState=0
return [0,'no hardware found']
def loadData(self):
self.buffer=self.ser.read(1)
if (self.buffer!=''):
try:
print self.buffer
except Exception, e:
pass
ard=Arduino()
while True:
if ard.connState:
ard.loadData()
else:
print "Arduino not found"
break
and start with:
import threading
class ThController( threading.Thread ):
# Override Thread's __init__ method to accept the parameters needed:
def __init__( self,parent):
self.parent = parent
threading.Thread.__init__ ( self )
def run ( self ):
while self.parent.ctrlattive:
j=json.loads(data)
self.parent.data=j

Have a function time out if a certain condition is not fulfilled in time

The issue I have is that my chat client is supposed to recieve and print data from server when the server sends it, and then allow the client to reply.
This works fine, except that the entire process stops when the client is prompted to reply. So messages pile up until you type something, and after you do that, then it prints all the recieved messages.
Not sure how to fix this, so I decided why not have the client's time to type a reply timeout after 5 seconds, so that the replies can come through regardless. It's pretty flawed, because the input will reset itself, but it works better anyways.
Here's the function that needs to have a timeout:
# now for outgoing data
def outgoing():
global out_buffer
while 1:
user_input=input("your message: ")+"\n"
if user_input:
out_buffer += [user_input.encode()]
# for i in wlist:
s.send(out_buffer[0])
out_buffer = []
How should I go about using a timeout? I was thinking of using time.sleep, but that just pauses the entire operation.
I tried looking for documentation. But I didn't find anything that would help me make the program count up to a set limit, then continue.
Any idea's about how to solve this? (Doesn't need to use a timeout, just needs to stop the message pileup before the clients reply can be sent) (Thanks to all who helped me get this far)
For Ionut Hulub:
from socket import *
import threading
import json
import select
import signal # for trying to create timeout
print("client")
HOST = input("connect to: ")
PORT = int(input("on port: "))
# create the socket
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
print("connected to:", HOST)
#--------- need 2 threads for handling incoming and outgoing messages--
# 1: create out_buffer:
out_buffer = []
# for incoming data
def incoming():
rlist,wlist,xlist = select.select([s], out_buffer, [])
while 1:
for i in rlist:
data = i.recv(1024)
if data:
print("\nreceived:", data.decode())
# now for outgoing data
def outgoing():
global out_buffer
while 1:
user_input=input("your message: ")+"\n"
if user_input:
out_buffer += [user_input.encode()]
# for i in wlist:
s.send(out_buffer[0])
out_buffer = []
thread_in = threading.Thread(target=incoming, args=())
thread_out = threading.Thread(target=outgoing, args=())
thread_in.start() # this causes the thread to run
thread_out.start()
thread_in.join() # this waits until the thread has completed
thread_out.join()
We can use signals for the same. I think the below example will be useful for you.
import signal
def timeout(signum, frame):
raise Exception
#this is an infinite loop, never ending under normal circumstances
def main():
print 'Starting Main ',
while 1:
print 'in main ',
#SIGALRM is only usable on a unix platform
signal.signal(signal.SIGALRM, timeout)
#change 5 to however many seconds you need
signal.alarm(5)
try:
main()
except:
print "whoops"

communication with modem using pyserial

I did not find a reasonable good example of how to talk to a serial modem using pyserial. I have created a code snippet that should do the following, given an instantiated pyserial object ser:
Send an AT command to the modem
Return the modem answer as quickly as possible
Return e.g. None in the case of a timeout
Handle the communication between the script and the modem most reasonable, robust and easy.
Here is the snippet:
def send(cmd, timeout=2):
# flush all output data
ser.flushOutput()
# initialize the timer for timeout
t0 = time.time()
dt = 0
# send the command to the serial port
ser.write(cmd+'\r')
# wait until answer within the alotted time
while ser.inWaiting()==0 and time.time()-t0<timeout:
pass
n = ser.inWaiting()
if n>0:
return ser.read(n)
else:
return None
My question: Is this good, robust code, or can pieces be changed/simplified? I especially do not like the read(n) method, I would expect pyserial to offer a piece of code that just returns the whole buffer content. Also, do I / should I flush the output at the begin, to avoid having some crap in the output buffer before?
Thanks
Alex
Create the Serial object with the param timeout=2 for read timeout.
Mi recipe is:
def send(data):
try:
ser.write(data)
except Exception as e:
print "Couldn't send data to serial port: %s" % str(e)
else:
try:
data = ser.read(1)
except Exception as e:
print "Couldn't read data from serial port: %s" % str(e)
else:
if data: # If data = None, timeout occurr
n = ser.inWaiting()
if n > 0: data += ser.read(n)
return data
I think that this is a good form of manage the communications with the serial port.

Categories