Reading a serial signal from a USB port with Python - python

I'm new to this, so I apologize if my question is uneducated:
I have a USB device for which I know the ProductID and VendorID. From what I understand, it should be a HID device which sends a serial stream to my computer. I was to write a script in python in order to read that serial stream, but I am getting nowhere. Is there a way for Python's serial library to find a device from a PID and VID?

You can find on OSX:
tty
/dev/ttys000
Or:
$ who
trane console Sep 1 05:18
trane ttys000 Sep 1 05:19
trane ttys001 Sep 1 05:19
$ w
13:04 up 1 day, 7:46, 3 users, load averages: 1.85 2.02 3.87
USER TTY FROM LOGIN# IDLE WHAT
trane console - Sun05 31:45 -
trane s000 - Sun05 - w
trane s001 - Sun05 9 -bash
You can try something like this:
import serial;
import io;
import time;
import os;
if __name__ == '__main__' :
try :
# configure the serial connections (the parameters differs on the device you are connecting to)
with serial.Serial(port='/dev/ttyUSB0', baudrate=9600, timeout=1,
xonxoff=False, rtscts=False, dsrdtr=True) as s:
for line in s:
print(line)
except :
print('Program exit !')
pass
finally :
ser.close()
pass
Or:
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()
According to your device, you can adjust some parameters as:
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS

You can also just do an 'ls /dev/tty*.*' and find the USB device rather than go through to voluminous amount of garbage dumped by 'ioreg'.

Related

Pyserial send and receive multiple commands

I'm working on a script to send a list of commands to a device and return the output.
When the device first boots up, it has a few prompts. I am able to get through the prompts.
However, after completing the prompts, when I try to send a command the command isn't sent.
Commands
The commands.txt is set up like this:
200,
2,no
2,
The first line (200) is to let the device boot up.
The 2nd and 3rd lines answer 2 different prompts.
Issues
The issues come after these 3 inputs. The code runs and completes. Python prints out each of the commands. So the list is processed by Python. However, I don't think the device is receiving the commands.
In the log, the \n and no are written out, but none of the commands after it are. The commands do show when I use ser.inWaiting()
When I access the device through putty and run the commands through the console, everything works as expected.
Why aren't the commands going through?
Small update:
I read somewhere that python may be sending the commands to quickly, so I tried sending the commands 1 char at a time with a .01 delay.
It still didn't work:
for i in lines[1]:
cmd = i
encoded_cmd = cmd.encode("utf-8")
ser.write(encoded_cmd)
sleep(0.1)
print(cmd)
Code
import serial
import time
from time import sleep
from datetime import datetime
# create list of commands
with open('commands.txt') as commands:
list_of_commands = [tuple(map(str, i.split(','))) for i in commands]
# open and name log file
date = datetime.now().strftime("%Y-%m-%d")
log = open(f'{date}.txt', 'w+')
# serial configuration
info = open('info.txt', 'r')
lines = info.readlines()
port = lines[0].strip('\n')
baud = int(lines[1].strip('\n'))
try:
# open port
ser = serial.Serial(port=port, baudrate=baud, timeout=5, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, write_timeout=0)
except ConnectionError:
log.write(''.join('There was a connection error'))
else:
# run commands
x = 0
for lines in list_of_commands:
ser.close()
ser.open()
sleep(2)
cmd = lines[1]
encoded_cmd = cmd.encode("utf-8")
sleep_time = int(lines[0])
ser.write(encoded_cmd)
time.perf_counter()
# log output
while 1:
test = ser.readline()
text = test.decode('utf-8')
print(text)
log.write(''.join(text))
print(time.perf_counter())
print(time.perf_counter() - x)
if time.perf_counter() - x > sleep_time:
x = time.perf_counter()
ser.flushInput()
ser.flushOutput()
break
print(cmd)
# close port
ser.close()
# close files
log.close()
From the question it's obvious that multiple issues are intermingled. The same observation comes when reading the code. So I tried to list some of those I struggled with.
Issues
Try-except-else
What is the intention behind try .. except .. else ?
Not sure, its used correctly on purpose here. See try-except-else explained:
The else clause is executed if and only if no exception is raised. This is different from the finally clause that’s always executed.
The serial connection
Why opening and closing inside the loop:
ser.close()
ser.open()
Why the misleading comment:
# close server
ser.close()
Usage of sleep_time
What is the purpose of using the first column sleep_time of your CSV commands.txt inside a conditional break inside you read-loop?
sleep_time = int(lines[0])
Instead the sleep is fix 2 seconds before sending the command:
sleep(2)
How to debug
I would recommend adding some print (or log) statements to
verify the list_of_commands has been read correctly
verify which commands (cmd or even encoded_cmd) have been sent to the serial output

PySerial - carriage return (\r) not working as expected

I'm trying to communicate with a board via serial (rs232) port using PySerial.
The board is a Renesas rl78 and below is my sample code. (Basically what I'm trying here is to execute some pre-defined commands. So here commands is again a command that returns a list of other commands)
import serial, time, io
ser = serial.Serial()
ser.port = "/dev/cu.usbserial"
ser.baudrate = 19200 # as used for HyperTerminal
ser.timeout = 10 #non-block of 10 seconds
ser.bytesize = serial.EIGHTBITS
ser.parity=serial.PARITY_NONE
ser.stopbits=serial.STOPBITS_ONE
ser.xonoff = False
ser.rtscts = True
ser.dsrdtr = True
ser.dtr = True
ser.rts = True
try:
ser.open()
except Exception, e:
print "error open serial port: " + str(e)
exit()
if ser.is_open:
try:
#ser.reset_input_buffer() #flush input buffer, discarding all its contents
#ser.reset_output_buffer() #flush output buffer, aborting current output
#write data
ser.write(b'commands\r')
ser.reset_input_buffer()
time.sleep(2)
in_wait = ser.in_waiting
while True:
if in_wait != 0:
output = ser.read(in_wait)
print(output)
break
else:
break
ser.close()
except Exception, e1:
print "error communicating...: " + str(e1)
else:
print "cannot open serial port "
And from the device's standpoint, we have to hit return (carriage return \r) in order to execute a command using any terminal application. i.e HyperTerminal or Serial for Mac.
So the above code does not return any output but just an empty string (this is what you get in the terminal when you just hit return (\r)). The device is behaving like it got a return (\r) and the command is completely ignored.
To make sure that it is not an issue with PySerial I tried to use PySerial's miniterm to get this terminal behavior, and I was able to successfully execute the commands
Again the catch here is to set CR as the EOL to get the commands to execute successfully.
python -m serial.tools.miniterm -e --eol=CR
So I'm puzzled here on what is wrong with my code and why it is not executing the commands.

Python(Spyder3, Win10) Write to Serial port more than once

I am trying to communicate with a microcontroller through a serial port.
For example, I write 7 to the microcontroller and I read a series of (47) numbers back, I then send 7 to it again and I read the same numbers back. I can keep going like this.
I have tried using Matlab and I can finish what I want to write and read from serial port very well. However, when I turn to use Spyder 3, under Win10, I can only write and read once. As I mentioned, if I write 7 and I can get 47 numbers back, but after that when I send 7 I can not get anything back and I need to re-plug serial port. My code is shown below. Thank you.
import serial
import time
"""Cmd definition"""
cmd_readreg = [7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
regNo = 47
""" setup serial """
with serial.Serial() as ser:
#ser = serial.Serial()
ser.port = 'COM8'
ser.bandrate = 19200
""" open serial """
ser.open()
if ser.is_open:
print ("Device connected.")
else:
print ("Check device connection.")
""" send read register cmd to serial, cmd = 7 """
ser.write(cmd_readreg)
time.sleep(.1)
#print (ser.BYTESIZES)
""" read from serial"""
if ser.readable():
reg1 = ser.read(size=regNo)
print (reg1)
else:
print ("no readable data")
""" send read register cmd to serial, cmd = 7 """
ser.write(cmd_readreg)
time.sleep(.1)
#print (ser.BYTESIZES)
""" read from serial"""
if ser.readable():
reg2 = ser.read(size=regNo)
print (reg2)
else:
print ("no readable data")

Read Serial Python

I am reading serial data on my Raspberry Pi with the console:
stty -F /dev/ttyUSB0 1:0:9a7:0:3:1c:7f:15:4:5:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
cat < /dev/ttyUSB0 &
echo -n -e '\x2F\x3F\x21\x0D\x0A' > /dev/ttyUSB0
And I am getting data line for line:
/ISk5MT174-0001
0.9.1(210832)
0.9.2(1160808)
0.0.0(00339226)
0.2.0(1.03)
C.1.6(FDF5)
1.8.1(0004250.946*kWh)
1.8.2(0003664.811*kWh)
2.8.1(0004897.813*kWh)
2.8.2(0000397.465*kWh)
F.F.0(0000000)
!
Now I am trying to do this with python:
import serial
SERIALPORT = "/dev/ttyUSB0"
BAUDRATE = 300
ser = serial.Serial(SERIALPORT, BAUDRATE)
print("write data")
ser.write("\x2F\x3F\x21\x0D\x0A")
time.sleep(0.5)
numberOfLine = 0
while True:
response = ser.readline()
print("read data: " + response)
numberOfLine = numberOfLine + 1
if (numberOfLine >= 5):
break
ser.close()
But I only get "write data" and no response from my USB0 device.
Any suggestions?
Kind Regards
I'm guessing your device is the same as discussed here:
https://www.loxforum.com/forum/faqs-tutorials-howto-s/3121-mini-howto-z%C3%A4hlerauslesung-iskra-mt174-mit-ir-schreib-lesekopf-und-raspberry
If so, you need to know that by default, pySerial opens ports with 8 databits and no parity.
(see: https://pythonhosted.org/pyserial/pyserial_api.html -> __init__)
So, at the very least you want to:
ser = serial.Serial(SERIALPORT, BAUDRATE, SEVENBITS, PARITY_EVEN)
Perhaps you also need to set other flags, but I don't read stty :)
To see what that string of numbers means, run the first stty command and then run:
stty -F /dev/ttyUSB0 -a
It'll output the settings in human readable form, that might bring you closer to a solution.
Good luck!

How can I read GPS data under Linux?

I used win7 before to read the GPS data from the com port. From now on I would like to read the data under Ubuntu but the same code is not working. Here is my code:
import serial, sys, time, threading
from datetime import datetime, timedelta
class MeasureModule():
def __init__(self, port, baudrate, sync_time=0, sync_nr=0):
self.port = port;
self.baudrate = baudrate;
def start(self):
try:
self.serial = serial.serial_for_url(self.port, self.baudrate, timeout=1)
except AttributeError:
self.serial = serial.Serial(self.port, self.baudrate, timeout=1)
start = time.clock()
while(time.clock()-start<11):
data = self.readline()
print(data)
self.stop();
def stop(self):
self.serial.close()
def readline(self, timeout=1, endline='\n'):
buff='';
try:
tic = time.clock()
ch = self.character(self.serial.read(1))
# you can use if not ('\n' in buff) too if you don't like re
while ((time.clock() - tic) < timeout) and (not ch in endline):
buff += ch
ch = self.character(self.serial.read(1))
except serial.SerialException, e:
return buff
return buff
def character(self,b):
if sys.version_info >= (3, 0):
return b.decode('latin1')
else:
return b
I called the function in the following way:
for i in range (0,4):
try:
print "Starting measurement /dev/ttyACM%d" % i
gs = GPSModule('/dev/ttyACM%d' % i, 4800, 1, 1)
gs.start()
except:
print "Unable to connect"
run#FXR:/dev$ dmesg | grep tty
[ 0.000000] console [tty0] enabled
[ 4.764464] cdc_acm 2-1.6:1.1: ttyACM0: USB ACM device
[ 4.767620] cdc_acm 2-1.6:1.3: ttyACM1: USB ACM device
[ 4.771525] cdc_acm 2-1.6:1.9: ttyACM2: USB ACM device
[ 4.808622] usb 2-1.4.4: pl2303 converter now attached to ttyUSB0
But I'm not receiving anything.
How can I do the same things under Ubuntu? How can I read the GPS data from com port?
Ok!
This code is VEEERY Ugly and Old I did that in 2006 I was a beginner and naive.
Now baby steps!
Use the command dmesg or check your console messages to know WHICH USB device is attached your GPS. In MY CASE was USB0
After that play with this code
import serial
import socket
ser = serial.Serial('/dev/ttyUSB0', 4800, timeout=1)
latitude = ''
longitude = ''
def readgps(latitude,longitude):
"""Read the GPG LINE using the NMEA standard"""
while True:
line = ser.readline()
if "GPGGA" in line:
latitude = line[18:26] #Yes it is positional info for lattitude
longitude = line[31:39] #do it again
return(latitude,longitude)
print "Finished"
Sure you have to call the function ;) please do not forget.
Remeber the gps is always sending data and communicating.
For educational purposes do a :
print line after ser.readline()
so you can see the whole data not only lat and long coordinates.
Remeber the USB GPS is just a fancy serial device ;)
This code is very simple and I am sure you will understand and make WAY better code/programs.
You don't open /dev/ttyUSB0 with your program. How is your GPS module plugged ?
What happens if you do :
stty -F /dev/ttyACM0 4800
cat /dev/ttyACM0
in a console ?
You probably have to add yourself to the group that the gps is under. This is posted really late, but I recently tried to configure a usb gps puck on linux, and I had to do sudo adduser -aG USERMAME dialout in the terminal. This just adds the user to the group (dialout) which the gps is under. If you don't know the group, cd to /dev (in terminal) and type ll (or ls -Flh if that doesn't work) This will diplay all of the permissions and groups. There is one column that is of particular interest; this is one of the last columns (I think third to last -- sorry, I'm on Windows right now), and you might see about six or seven items in the list called "dialout". If your file -- your usb -- shows up there, then that is the group. Otherwise, just look for the group and sudo adduser... yourself.
Be sure you log out first, and then -- after logging back in -- go to the terminal again and type cat /dev/ttyACM0. If you still see nothing, then you need to configure and tell it the correct rate at which to dump its info (the baud rate); so, type (as someone else mentioned) stty -F /dev/ttyACM0 4800 which configures the baud rate to 4800. You should google the correct baud rate, but the last command essentially says, take this file (-F) and speak to me at this rate (4800).
I hope this helps someone because I certainly had some trouble getting my usb gps puck to work on linux-mint. Good luck to all linux users (I'm a recent convert). :D

Categories