Python serial, can write but can't read - python

I am trying to write a very basic script which will allow me to have full control over a device via serial. I can send data (and I know the device receives it, leaving screen open on the device allows me to see the input appearing).
But I cannot receive data, with screen open, and inputting data via screen I get the error:
Traceback (most recent call last): File "serialRec.py", line 4, in
for line in ser: File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 456, in
read
raise SerialException('device reports readiness to read but returned no data (device disconnected?)')
serial.serialutil.SerialException: device reports readiness to read
but returned no data (device disconnected?)
There is no error if I open the port waiting for a message without screen.
My application as I said sends data no problem... What can I do? How can I get this reading? I am running this script on a Ubuntu 12.04 installation... Screen works fine on the device the Ubuntu laptop is attatched to
The sys arguments are: argv[1] = device (/dev/ttyUSB0) and argv[2] = braud rate (e.g. 9600).
import serial
import sys
import time
def enterdata():
ser = serial.Serial(sys.argv[1], sys.argv[2])
scom = raw_input("type away:" )
incli = str(scom)
time.sleep(.2)
if (incli == "exit the app"):
print ("Exiting the data send, nothing was sent from the exit command")
else:
while True:
print ser.readline()
enterdata()
print ("Welcome to the serial CLI")
enterdata()
UPDATE:
I now have it working, but limited and ugly it prints the return on multiple lines from sending one command. Though for this I am going to try a few things out. I will post and share some nice working code once i get it to a good place.
import serial
import sys
import time
def enterdata():
ser = serial.Serial(sys.argv[1], sys.argv[2])
scom = raw_input()
incli = str(scom)
if (incli == "exit the app"):
print ("Exiting the data send, nothing was sent from the exit command")
else:
ser.write(incli+"\r\n")
time.sleep(0.5)
while True:
data = ser.read(ser.inWaiting())
if (len(data) > 0):
for i in range(len(data)):
sys.stdout.write(data[i])
break
ser.close()
enterdata()
print ("Welcome to the serial CLI, hit enter to activate:")
enterdata()
This is the changes I have made, it works. Though it seems to always print double or maybe send an extra character

You might want to try with a listener first, but you have to make sure that your device is sending data to your serial port at the correct baudrate.
import serial, sys
port = your_port_name
baudrate = 9600
ser = serial.Serial(port,baudrate,timeout=0.001)
while True:
data = ser.read(1)
data+= ser.read(ser.inWaiting())
sys.stdout.write(data)
sys.stdout.flush()

Related

Using Python to Automate SMS reply using Raspberry pi w/ Quectel EC25

I made a 4g hotspot last year with a Quectel ec25 and raspberry pi, it has worked just fine for this purpose. Earlier this year I wanted to expand its capabilities to automatically reply to text messages with status updates for certain systems. I was able to figure out sending and receiving a text message with AT commands just fine but I am having trouble getting python to recognize and respond to a text message with key words. I found this code,
http://www.python-exemplary.com/index_en.php?inhalt_links=navigation_en.inc.php&inhalt_mitte=raspi/en/gsm.inc.php, and have modified it slightly to make the EC25 work with the USB serial.
I have 2 SSH sessions going at once, one with the command line up and the other with a minicom session to monitor serial. the EC25 is sending indications to the Pi that it is receiving a message, its output when a message is received is "+CMTI: "ME",0" but the pi has no response to it. The code seems to be unresponsive on this part. it will print "listening for incoming SMS..." but then it will never go beyond that, even when it receives text messages.
reply = ser.read(ser.inWaiting())# Clean buf
print "Listening for incoming SMS..."
while True:
reply = ser.read(ser.inWaiting())
if reply != "":
I have tried it with just ser.read() and ser.inWaiting() but that sends it into a bad feedback loop.
Here is my code.
# SIMSMS1.py
# pip install pyserial
import RPi.GPIO as GPIO
import serial
import time, sys
import datetime
P_BUTTON = 24 # Button, adapt to your wiring
def setup():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(P_BUTTON, GPIO.IN, GPIO.PUD_UP)
SERIAL_PORT = "/dev/ttyUSB3" # Raspberry Pi 3
ser = serial.Serial(SERIAL_PORT, baudrate = 115200, timeout = 5)
setup()
ser.write("AT+CMGF=1\r") # set to text mode
time.sleep(1)
ser.write('AT+QURCCFG="urcport","usbmodem"\r') #set URC Indication
time.sleep(1)
ser.write('AT+CPMS="ME","ME","ME"\r') #set memory to Mobile equipment message storage
time.sleep(1)
ser.write('AT+CMGD=1,4\r') # delete all SMS
time.sleep(1)
reply = ser.read(ser.inWaiting())# Clean buf
print "Listening for incoming SMS..."
while True:
reply = ser.read(ser.inWaiting())
if reply != "":
ser.write("AT+CMGR=1\r") # read message
time.sleep(3)
reply = [ser.read(ser.inWaiting())]
print "SMS received. Content:"
print reply
if "getStatus" in reply:
t = str(datetime.datetime.now())
if GPIO.input(P_BUTTON) == GPIO.HIGH:
state = "Button released"
else:
state = "Button pressed"
ser.write('AT+CMGS="+1xxxxxxxxxx"\r') #designate phone number
time.sleep(3)
msg = "Sending status at " + t + ":--" + state
print "Sending SMS with status info:" + msg
ser.write(msg + chr(26))
time.sleep(3)
ser.write('AT+CMGD=1,4\r') # delete all messages
time.sleep(3)
ser.read(ser.inWaiting()) # Clear buf
time.sleep(5)
this is the output of on the serial, the last line is a message being received
AT+CMGF=1
OK
AT+QURCCFG="urcport","usbmodem"
OK
AT+CPMS="ME","ME","ME"
+CPMS: 0,255,0,255,0,255
OK
AT+CMGD=1,4
OK
+CMTI: "ME",0
I know it has something to do with the "reply = ser.read(ser.inWaiting())" but i cant figure out what to write to make it work. Thank you in advance
The easiest way might be polling the message received.
Maybe the EC25 has some possible gpio. Once any message comes, the gpio would generate a pulse signal.

pyserial write() writes only the first few bytes

I'm performing reads and writes with pyserial to a serial terminal running on a decawave DWM1001C. The serial connection goes from my Linux laptop to the device over a microUSB cable which also powers the device. The DWM1001C offers the serial connection internally on the chip. The connection is opened at the baudrate of 115200 with 8N1, as specified by the DWN1001C reference manual.
The problem I have is that when I call pyserial's write() on the serial device, I can only write a maximum of 7 characters per write call, sometimes as few as 4. Here's a minimal code to reproduce the issue:
import serial
import sys
import time
dev = "/dev/ttyACM0"
baudrate = 115200
try:
ser = serial.Serial(dev, baudrate, timeout=3)
except Exception as e:
print("Failed opening device: " + dev + ": " + str(e))
sys.exit(1)
try:
# Two CR's are required to open the terminal as the device default to "API" mode
ser.write(b"\r\r")
ser.flush()
time.sleep(2)
# only letters up to f are sent
ser.write(b"abcdefg hijklmn opqrstu vwxyz\n")
ser.flush()
time.sleep(2)
except Exception as e:
print("Failed writing instructions to device: " + str(e))
sys.exit(1)
while True:
try:
line = ser.readline()
if line == None:
continue
except Exception as e:
print("Failed reading from serial: " + str(e))
sys.exit(1)
s = line.decode("utf-8")
print("got data: " + s)
By using the readline() call and by monitoring the serial terminal over minicom, I have verified that only the 4-7 first characters appear in the terminal. Minicom can be used to interact with the serial terminal normally, so I assume minicom does something under the hood that this pyserial code doesn't.
I have a hacky workaround: Every time I perform writes, I split the input data into 4 character chunks and send them one-by-one over write(), then sleep for 0.1 seconds. This seems to work, but is likely about as platform specific as it can be.
The pyserial constructor takes a few different flow control flags and I tried setting each of them on independently. They are:
xonxoff=True
rtscts=True
dsrdtr=True
They didn't seem to do anything. I also tried lowering the baudrate to 57600 to no effect.
What should I read on to understand what's going on?

Serial reading to UTF-8 decoding

I'm trying to create a program in python that reads the serial port, then decode the info received (which in this case is GPS coordinates and an ultrasonic sensor), then I need to create some 'if loops' to save this serial data into variables, but it seems to me that my if statement is not well, below I attach the code:
import serial
Ard = serial.Serial(port='COM5', baudrate=9600,
bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=2)
try:
Ard.isOpen()
print("Conexion con el puerto serial: COM5, establecida satisfactoriamente!\n")
except:
print("Error")
exit()
if (Ard.isOpen()):
try:
while (1):
aux = Ard.readline()
a = aux.decode('utf-8')
print(a)
if a == '1':
print("It works")
lat = float(a)
except Exception:
print("It doesn't work")
else:
print("Port is not opening")
I tried not using UTF-8, but using a = float(Ard.readline()), it was working (at least printing serial variables as float), but now it doesn't and it never enters the if loop, I tried if a != 1, and it works, so the thing is that I don't know the decoding or type of variable a is and I need it to be float. I'm reading from an arduino UNO, and I'm using pycharm as python IDE with pyserial, and 3.7 interpreter, please help me.

How do i debug this USB-Serial connection?

I am trying to talk to a Stanford Research Systems SR760 spectrum analyzer on my mac (10.7.5) via Serial, using a Serial-to-USB adapter to connect to my laptop. I am using the Prolific USB-serial driver. Not sure which but I installed it recently. It probably is the PL2303 one.
Using Python, here's some sample code
import time
import serial
# configure the serial connections (the parameters differs on the device you
# are connecting to)
ser = serial.Serial(
port='/dev/cu.PL2303-0000201A',
baudrate=19200,
parity=serial.PARITY_NONE,
bytesize=serial.EIGHTBITS,
stopbits=serial.STOPBITS_ONE,
rtscts=0,
dsrdtr=0,
timeout=2,
)
if ser.isOpen():
ser.flushInput()
ser.flushOutput()
print """Enter your commands below.\r\nInsert "exit" to leave the
application."""
while 1:
# get keyboard input
input = raw_input(">> ")
if input == 'exit':
ser.close()
exit()
else:
ser.write(input + '\r')
out = ''
# let's wait one second before reading output (let's give device
# time to answer)
lines = 0
while 1:
time.sleep(1)
out = out + ser.readline()
lines = lines + 1
if lines > 5:
break
print "read data: " + out
Using the SR760's manual, I send it: *IDN?, a basic "identify" command. I expect for something to pop up in my terminal, nothing does. It just times out. However, if I look at the send queue on the SR760, it will show the identity string, and in fact responds to a bunch of different commands. I'm just not getting anything on my computer and that is the problem. I know it is supposed to work that way because my colleague wrote code that words on his computer (a windows laptop).
How do I even start debugging this? I've tweaked the timeout, and confirmed the sr760 had the same parameters I was expecting.

PySerial - Full-duplex communication

Is it possible to achieve full-duplex communication using PySerial? Specifically, would it be possible to monitor the port continuously for input and write whenever needed? I imagine it should be possible using threads (and serial interfaces are full duplex no?). If not, what would be the best approach to monitoring a serial port when not transmitting? A timeout?
Edit: Here's my attempt at it. This code is targeting TI's CC2540 Bluetooth LE chip. On sending the GATT init message I expect a reply (detailing the operating parameters of the chip)...I'm getting nothing though
import serial
import threading
from time import sleep
serial_port = serial.Serial()
GAP_DeviceInit = \
"\x01\x00\xfe\x26\x08\x03\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
def read():
while True:
data = serial_port.read(9999);
if len(data) > 0:
print 'Got:', data
sleep(0.5)
print 'not blocked'
def main():
serial_port.baudrate = 57600
serial_port.port = '/dev/ttyACM0'
serial_port.timeout = 0
if serial_port.isOpen(): serial_port.close()
serial_port.open()
t1 = threading.Thread(target=read, args=())
while True:
try:
command = raw_input('Enter a command to send to the Keyfob: \n\t')
if (command == "1"):
serial_port.write(message)
except KeyboardInterrupt:
break
serial_port.close()
Yes serial port hardware is full duplex. Yes, you can use threads to do Rx and Tx at the same time. Alternatively, you can use a single thread loop that does reads with a short timeout and alternates between reading and writing.
You didn't specify a timeout, so the read waits for the full number of bytes to receive and only then displays anything.

Categories