Python Serial Read all Output (cant break out of while loop) - python

I have this code which im using to connect to a printer and send it commands. It works perfectly until it gets to the while loop, it just cant get out of it. The output prints the first few lines expected in serial than just waits until while loop goes false. how do i get out of the loop?
import serial
import os
import time
ser = serial.Serial('/dev/ttyUSB0', 115200) # open serial port
print("Device Name: " + ser.name)
while True:
response = ser.readline().decode('utf-8')
print(response)
time.sleep(1)

The whole point of a while True: loop is that there is no stop condition. This means that it will keep going until you manually stop your program.
What you can do is add a break statement when you don't read anything anymore.
And don't forget to use a timeout on your serial so it doesn't hang forever waiting for new data:
import serial
import os
import time
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=10) # open serial port
print("Device Name: " + ser.name)
counter = 0
while counter < 10:
response = ser.readline().decode('utf-8')
print(response)
if response == "":
break
time.sleep(1)
With this, it will read everything available then wait 10 seconds for additional data.
If there is no more data, it will return an empty string (no bytes read) and break from the loop.

Related

Unable to read from serial in c#, but works in python

I am unable to read from serial port in C#, all of the settings are matching (baud, sbit etc...), the code actually sends the SCPI code to my gadget, but it is not responding (the gadget).
I have a very similar code in Python 3.7 and that is working correctly, with the same gadget and with every other.
So this is the C# code:
SerialPort com = new SerialPort("COM22",9600,Parity.Even,7,StopBits.Two);
com.Open();
Thread.Sleep(100);
com.DiscardOutBuffer();
com.DiscardInBuffer();
Console.Write("SCPI: ");
string cmd = Console.ReadLine();
com.Write(cmd + "\n");
Thread.Sleep(2000);
string answ = com.ReadExisting();
Console.WriteLine("The answer "+answ);
com.Close();
Here in C# I have also tried ReadChar(), ReadByte() and ReadLine()...
And also I have tried to change HandShake.
And here goes the Python code:
import time
import serial
while 1:
try:
comPort = input("Insert COM port num to use: ")
ser = serial.Serial(
port='COM' + comPort,
baudrate=9600,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
) # serial port settings
ser.isOpen()
break
except Exception:
print("Bad COM port. Try again.")
print('Enter your commands below.\nInsert "exit" to leave the application.')
while 1:
cmd = input("Insert your command: ") # insert the commands
if cmd == 'exit':
ser.close()
exit()
else:
ser.write(str.encode(cmd + '\n')) # send the character to the device
out = " "
time.sleep(2) # wait one second before reading output (give device time to answer)
while ser.inWaiting() > 0:
out += ser.read(1).decode("ascii")
print(">>" + out) # output the answer
As you can see they are very similar, with the same waiting time...

Unable to send/receive data via HC-12/UART in Python

I've written some code to communicate between two Raspberry Pi's, using identical HC-12 433Mhz transceivers. I was able to successfully echo between the two Pi's using a direct serial connection and echo/cat, however am unable to replicate this using HC-12s, which theoretically work by a similar principal. I'm using the port ttyAMA0 on both for this example, but ttyS0 is also available and have tried every combination of these ports.
The following code is common to both the sending and receiving, just writing once for sake of brevity:
import serial
import time
ser = serial.Serial(
port = "/dev/ttyAMA0",
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS
)
print("Serial status: " + str(ser.isOpen()))
This is the sending program:
while True:
print("Sending...")
ser.write("hello\n".encode())
time.sleep(1)
And the receiving program:
while True:
print("Receiving...")
data = ser.readlines()
print(data.decode())
The sending program simply loops as expected, but the receiver prints "Receiving...", and then nothing.
When I keyboard interrupt the receiving program at that point, it says it is currently up to data = ser.readlines().
Any help would be much appreciated - I've spent the better part of the last week trawling and exhausting forums and READMEs to no avail, and this is literally my last option. Am close to insanity on this one!
The pyserial readlines() function relies on the timeout parameter to know when end-of-file is reached - this is warned about in the doco. So with no timeout, the end never occurs, so it keeps buffering all lines read forever.
So you can just add a timeout to the serial port open, and your existing code will begin to work.
ser = serial.Serial(
port = "/dev/ttyAMA0",
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 2 # seconds # <-- HERE
)
A better approach might be to use readline() (note singular, no 's'), for each line in turn:
print( "Receiving..." )
while True:
try:
data = ser.readline()
print( data.decode() )
# TODO - something with data
except:
print( "Error reading from port" )
break
As that will allow the code to act on the input line-by-line.
Use Serial.read_until method. The default termination character is \n.
For example,
data = ser.read_until()
print(data)

Python Serial on Windows: USB monitor loop while reading serial information does not work

I have a website and an usb rfid reader. The python script monitors the usb connection to the rfid reader. If the reader is not connected at the beginning of the script, the content of the website swipes to the right and shows instructions to connect the usb cable of the rfid reader. If then connected, it swipes back to the left and shows the user to identify himself with a rfid card. The reader shall only begin to read the rfid data when a certain content is in the viewport. But I don't get to this step because the serial communication seems to be blocked.
import serial
import mysql.connector
import time
import datetime
from serial.tools import list_ports
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.common.keys import Keys
capabilities = webdriver.DesiredCapabilities().FIREFOX
capabilities["marionette"] = True
binary = FirefoxBinary('C:/Program Files/Mozilla Firefox/firefox.exe')
driver = webdriver.Firefox(firefox_binary=binary, capabilities=capabilities, executable_path="C:/Python37x64/geckodriver.exe")
# ------------------ USB monitorloop -------------------------------------
stop = 0
swipe = 0
driver.get('https://website.php')
while True:
try:
myports = [tuple(p) for p in list(serial.tools.list_ports.comports())]
arduino_port = [port for port in myports if 'COM3' in port ][0]
def check_presence(correct_port, interval=0.1):
global swipe
global stop
while True:
myports = [tuple(p) for p in list(serial.tools.list_ports.comports())]
if arduino_port not in myports:
stop = 1
swipe = swipe + 1
if swipe == 1:
print ("Arduino has been disconnected!")
driver.execute_script("$('.in_viewport,#usb_connect, #header_usb_connect').animate({ left: '+='+'100vw'});");
time.sleep(1.0)
else:
continue
else:
if swipe >= 1 and stop == 1:
swipe = 0
print ("Arduino connected!")
driver.execute_script("$('.in_viewport,#usb_connect, #header_usb_connect').animate({ left: '-='+'100vw'});");
time.sleep(1.0)
else:
continue
import threading
port_controller = threading.Thread(target=check_presence, args=(arduino_port, 0.5,))
port_controller.setDaemon(True)
port_controller.start()
break
except:
stop = 1
if swipe == 0:
print("Connect USB cable")
driver.execute_script("$('.in_viewport,#usb_connect, #header_usb_connect').animate({ left: '+='+'100vw'});");
time.sleep(1.0)
swipe = 1
continue
else:
time.sleep(1.0)
# --------- connecting to COM 3 and database -----------------------
device_port = 'COM3'
baud = 9600
while True:
try:
print ("Trying...",device_port)
connect_arduino = serial.Serial(device_port, baud)
print ("Successfully connected to",device_port)
print ("Try to connect to database")
db = mysql.connector.connect(host="",port="",user="",passwd="",db="")
print ("Successfully connected to database")
break
except mysql.connector.Error as err:
print("Something went wrong: {}".format(err))
print ("failed to connect to database")
time.sleep(1)
continue
# ------- reading the card identification number and current time -------------
while True:
try:
print ("Reading USB device")
rfid_data = connect_arduino.readline()
now = datetime.datetime.now()
print (rfid_data.decode('utf-8'),"read on", now.strftime("%d-%m-%Y"), "at", now.strftime("%H:%M:%S"))
time.sleep(2)
break
except:
time.sleep(2)
continue
I expected to be able to serial.readline() the rfid_data, but I think that the monitor loop is blocking the serial ports and the communication to the ports.
Sorry to throw in the basics here, but have you checked you can read the serial port with something else, say a terminal emulator?
I have had endless problems with serial ports, especially the USB versions. Either something else grabs the port when I don't want it to or something is misbehaving with mapping USB into a COM number. Sometimes you need something else to double check them.
I think your biggest issue is the break statement in your reading loop. It is working as intended and breaking the normal flow of the loop so you only call the serial port read function once.
One way to improve your loop is checking if the RX buffer is empty:
while True:
if connect_arduino.inWaiting() != 0:
print ("Reading USB device")
rfid_data = connect_arduino.readline()
now = datetime.datetime.now()
print (rfid_data.decode('utf-8'),"read on", now.strftime("%d-%m-%Y"), "at", now.strftime("%H:%M:%S"))
If you call readline() only when you're sure there will be data in the buffer and you know the RFID reader sends \r\n as a terminating character you are sure you will always read the tag.
EDIT: It seems what you want is to sniff on the port. You cannot keep the same port open from two different applications directly. If you are on Windows you can try this solution.

multiprocessing with serial port

I've a target board which sends me CPU load for every 1sec which communicates through serial port. I want to write a python code which reads data from serial port for every 1sec second and writes to a file and also it should check for user input i.e. if user enters command it should pass that command to target board.
You can create two threads, one listening for user input, the other polling the serial port every second. Check out threading for information on multithreading in python and pyserial for information on reading from serial ports. The threading package provides your desired repetition functionality: https://docs.python.org/2/library/threading.html#timer-objects
[EDIT]
Sample code, obviously replace /dev/ttyS1 with the desired port and do something useful with the user input:
import serial
import threading
def read_from_serial():
# port = "/dev/ttyS1"
# ser = serial.Serial(port, 19200, timeout = 1)
# print ser.readline()
# ser.close()
print "read"
threading.Timer(1, read_from_serial).start()
if __name__ == "__main__":
serial_thread = threading.Thread(target = read_from_serial())
serial_thread.start()
while True:
print raw_input("User input: ")

esp8266 and cp2102 don't work with python serial

esp8266 and cp2102 don't work! Why?
import serial
sp="/dev/ttyUSB0"
port = serial.Serial(sp)
while True:
port.write("AT+RST")
rcv = port.read(10)
print rcv
I pressed "AT+RST"[Enter] and don't have "READY" after it.
Make sure you include CRLF (\r\n) characters at the end of your command. I lost a day messing with this before I figured that out. I got the local echo back of the command but since I never sent a \r\n I would not get any more data. Here is what works for me as a basic terminal in Python using pyserial:
import serial
import time
ser = serial.Serial('/dev/tty.usbserial-A8004xaO', 115200, timeout=2.5)
while True:
cmd = raw_input("> ");
ser.write(cmd + "\r\n")
ret = ser.read(len(cmd)) # eat echo
time.sleep( 0.2 )
while ( ser.inWaiting() ):
ret = ser.readline().rstrip()
print ret
You aren't setting a baud rate when opening the serial port. The default is probably not appropriate for the ESP8266.

Categories

Resources