Python serial (pySerial) Reading lines with EOL \r instead of \n
Solution 1
What about use simple loop for reading?
def readData():
buffer = ""
while True:
oneByte = ser.read(1)
if oneByte == b"\r": #method should returns bytes
return buffer
else:
buffer += oneByte.decode("ascii")
You can check the serialutil.py file from Pyserial package, They use the same way to achieve method read_until
.
Solution 2
Use read_until() instead:
ser.read_until(b'\r')
Be careful, don't forget the b. Otherwise even if it reads the '\r' the function won't return until the timeout set on the port is reached.
Solution 3
From the docs for readline()
:
The line terminator is always
b'\n'
for binary files; for text files, thenewline
argument toopen()
can be used to select the line terminator(s) recognized.
Of course, you can't use open
here. But what you can do is use io.TextIOWrapper
to convert the byte stream into a text stream:
ser_text = io.TextIOWrapper(ser, newline='\r')
ser_text.readline()
Calum Beck
I'm probably the laziest person I know, but I can't be arsed to find out.
Updated on July 17, 2022Comments
-
Calum Beck almost 2 years
I am communicating with an SR830 lock-in amplifier via an RS232 cable. When reading the data as in the following code:
import serial def main(): ser = serial.Serial( port='COM6', baudrate=19200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) ser.timeout=1 ser.write("OUTP? 1 \r\n".encode()) #Asks the Lock-in for x-value ser.write("++read\r\n".encode()) x=ser.readline() print (x) if __name__ == '__main__': main()
I get a byte string like
b'-3.7486e-008\r'
. However theser.readline()
function does not recognise the \r as an EOL. So I have to wait for the timeout every time I read data, which will be troublesome as I want to take a lot of points as fast as I can. And the length of the number changes a lot so I cannot just useser.read(12)
for example. I have tried using io.TextIOWrapper but it's not clear to me how to implement it. Here's my attempt:import serial import io def main(): ser = serial.Serial( port='COM6', baudrate=19200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) ser.timeout=1 sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser)) sio.write("OUTP? 1 \r\n") #Asks the Lock-in for x-value sio.write("++read\r\n") x=sio.readline() print (x) if __name__ == '__main__': main()
Which just prints a blank space. Any help will be much appreciated, thanks.
EDIT: Here's my working code after the answers, using the loop:
import serial def main(): ser = serial.Serial( port='COM6', baudrate=19200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) ser.timeout=5 ser.write("OUTP? 1 \r\n".encode()) #Asks the Lock-in for x-value ser.write("++read\r\n".encode()) buffer = "" while True: oneByte = ser.read(1) if oneByte == b"\r": #method should returns bytes print (buffer) break else: buffer += oneByte.decode() if __name__ == '__main__': main()
-
SiHa almost 7 yearsPossible duplicate of pySerial 2.6: specify end-of-line in readline()
-
Eric almost 7 yearsYou need at least
newline='\r'
in thatTextIOWrapper
for it to be of any use, else that will look for\n
too
-
-
juhist almost 7 yearsI wouldn't recommend that as a general solution due to the terrible performance, but now that we're talking about low-speed serial interfaces, it'll probably work.
-
Błotosmętek almost 7 yearsYou mean
\r
, not\n
. -
Erik Šťastný almost 7 years@juhist I use this method for communication with multimeter etc. via RS232 where responses are longer than 100 ms and this has absolutely no impact on performance in this cases.
-
juhist almost 7 yearsAttributeError: 'str' object has no attribute 'append'
-
Erik Šťastný almost 7 years@juhist fixed again.
-
Calum Beck almost 7 yearsYeah, I added += and .decode() and it worked! I'll just check the other answers to see what's the fastest. Thanks a lot Erik.
-
Erik Šťastný almost 7 years@Calum Beck I have updated answer, the pyserial use same aproach for the read_until method.
-
Calum Beck almost 7 yearsI also added a break function
-
Eric almost 7 yearsIs the
BufferedRWPair
needed? -
Calum Beck almost 7 yearsHmm, actually, just realised even with that code it still waits for the timeout. I'll just stick with the loop. I can see what's going on that way.
-
Eric almost 7 yearsWhy not set the timeout to 0 then?
-
spitz about 5 yearsKeep getting a
AttributeError: 'Serial' object has no attribute 'read1'
error... -
Eric about 5 years@spitz: I'd file a bug/feature request against pyserial for that