Python CGI - Sending long strings to serial port - python

I have a Python CGI script on Raspberry Pi which converts the contents of a text box to 1's and 0's. I'm looking to have a string of 1000 ish max.
The binary string is formatted slightly and sent to an arduino via the serial port... the arduino uses the data in the string to do stuff with LED's. If I cut and paste the binary string into the arduino serial monitor, all works fine, when I try to automote this via the following python code, everything starts to work but stops soon into the cycle.
I can control how long this takes to work by altering the time.sleep(3) after the ser.write command..... but I don't want to set an unecessary long delay I would like to ensure the code waits for the string to send before moving on to printing the HTML stuff back, (and stopping the light display on the arduino).
Having said this, the entire string MUST be getting through to the arduino as the arduino waits for '\n' at the end of the string to process it.
Guess this must be a school boy error.... tips and pointers much appreciated. Here is the CGI code I'm using.
#!/usr/bin/python
# Import modules for CGI handling and serial
import cgi, cgitb, serial, time, binascii
# Create instance of FieldStorage
form = cgi.FieldStorage()
#define serial port
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
#Wait while serial connects
time.sleep(3)
# Get data from fields
prayer = form.getvalue('prayer')
# Convert to binary
binprayer = bin(int(binascii.hexlify(prayer), 16))
# remove the '0b' from the front end of the string
bintrimint = binprayer[2:]
# add a \n to the end
bintrim = bintrimint + '\n'
ser.write(bintrim)
time.sleep(3)
print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Binary Prayer - a test script</title>"
print "</head>"
print "<body>"
print "<h2>You entered the following text: %s</h2>" % prayer
print "<h2>%s</h2>" % binprayer
print "<h2>%s</h2>" % bintrim
print "</body>"
print "</html>"

I had a look at http://pyserial.sourceforge.net/pyserial_api.html
write(data)
Parameters: data – Data to send.
Returns: Number of bytes written.
I think you should make sure you write everything.

Related

How would i write a program in python that connects to a DGT chess board and prints the moves being made in real time?

I am trying to write a program in python that connects to a DGT chess board and recieves the data and prints the moves in real time as they are being made (example: ng1f3). Ive tried asking chat gpt but as usual it has been no help. Ive also looked online for similar projects but found nothing like what i am trying to do.
ive tried getting the data using the serial library. the port and the baudrate are both correct. the board sends 8 bytes of data for each move. this code runs but does not print anything when i move the pieces on the board. ive even tried contacting the manufacturer to see if the boards have any sort of protection against this but they said they couldnt help me with this and instead just sent me the document with the description of the comunication protocol (one drive link to file: https://1drv.ms/b/s!AqF5qQ2nPQ81nkBZqQAMfY93mfdJ?e=eia1mO). i am also fairly new to python and this website.
import serial
ser = serial.Serial("COM7", 9600)
while True:
data = ser.read(8)
print(data)
edit: I have since tried:
import serial
ser = serial.Serial("COM7", 9600, timeout=2)
ser.write(bytes([0x45])) # message to request serial number
test = ser.read(20)
output = test.decode('ascii', errors='replace') # convert bytes to string print(output)
A response was received, but it wasn't quite as expected.
If you feel confident that everything is connected properly, try doing this:
import serial
ser = serial.Serial("COM7", 9600, timeout=2)
ser.write(bytes([0x45])) # I think this is the message to request serial number.
test = ser.read(20) # Not sure how many bytes are returned
print(test) # this prints a byte string
print(test.hex()) # this prints the byte string as a string of hex w/out the "0x/" characters
print("The Message ID is " + str(test[0:1])) # You sent a'0x45' command you get back a'0x91' reply
print("The length of the message is " + str(test[1:3]))
print("The Serial number is " + str(test[3:8]))
Does that print anything at all?
edit: Changed the serial write to a byte type.
edit 2: It looks like the board might write something upon start up. Another thing to try is:
import serial
ser = serial.Serial("COM7", 9600, timeout=5) # timeout long enough to turn on board
test = ser.read(1000) # excess amount to read, but we don't want to miss anything
print(test)
edit 3: Now that we have verified communications with the board, we can start experimenting with trying to write a script that will read the movement of the chess pieces. Let's try this:
import serial
ser = serial.Serial("COM7", 9600, timeout=2)
DTG_REQ_UPDATE_BOARD = bytes([0x44])
while 1:
timeout = 0
ser.write(DTG_REQ_UPDATE_BOARD)
while timeout < 10:
movement = ser.read(20)
if movement != 0:
print(movement)
timeout = 10
else:
timeout += 1
continue
Turn on your board.
Start the above script.
Start moving pieces like you would if you were playing a game.
Look for things to start printing out in your console/terminal.
It's a quick and dirty way of looping (it's an infinite loop and you will have to force stop the process when you are done running your script), but it should do the job for testing purposes.

readline() in pySerial sometimes captures incomplete values being streamed from Arduino serial port

Every one second, Arduino prints (in serial) 'current time in milliseconds and Hello world'. On serial monitor, the output looks fine.
But in pySerial, sometimes there is line break at the middle of string.
313113 Hel
lo world
314114 Hello world
315114 Hello world
My python code is as:
import serial
import time
ser = serial.Serial(port='COM4',
baudrate=115200,
timeout=0)
while True:
str = ser.readline() # read complete line
str = str.decode() # decode byte str into Unicode
str = str.rstrip()
if str != "":
print(str)
time.sleep(0.01)
What am I doing wrong?
My configuration:
Python 3.7
pySerial 3.4
Board Arduino Mega
The problem definitely seems to be caused by very fast reads where the data is read when the serial output from the Arduino hasn't finished sending full data.
Now with this fix, the pySerial will be able to receive the complete data and no data is missed. The main benefit is that it can be used for any type of data length and the sleep time is quite low.
I have fixed this issue with code below.
# This code receives data from serial device and makes sure
# that full data is received.
# In this case, the serial data always terminates with \n.
# If data received during a single read is incomplete, it re-reads
# and appends the data till the complete data is achieved.
import serial
import time
ser = serial.Serial(port='COM4',
baudrate=115200,
timeout=0)
print("connected to: " + ser.portstr)
while True: # runs this loop forever
time.sleep(.001) # delay of 1ms
val = ser.readline() # read complete line from serial output
while not '\\n'in str(val): # check if full data is received.
# This loop is entered only if serial read value doesn't contain \n
# which indicates end of a sentence.
# str(val) - val is byte where string operation to check `\\n`
# can't be performed
time.sleep(.001) # delay of 1ms
temp = ser.readline() # check for serial output.
if not not temp.decode(): # if temp is not empty.
val = (val.decode()+temp.decode()).encode()
# requrired to decode, sum, then encode because
# long values might require multiple passes
val = val.decode() # decoding from bytes
val = val.strip() # stripping leading and trailing spaces.
print(val)

Pyserial writes data but does not read

I'm relatively new to programming, so bear with me. I'm trying to communicate with the measurement device METEX M-4650CR https://sigrok.org/wiki/Voltcraft_M-4650CR and I'm using a windows 7 64bit OS. I simply want to read out the data the device measures to my python procedure and display it and calculate with it.
I found in the manual http://elektron.pol.lublin.pl/elekp/labor_instr/METEX_M-4650CR_Manual.pdf (page 25ff), that it works with a baudrate of 1200, a bytesize of 7 (with ASCII coding) and 2 stopbits.
Furthermore, it can be requested to send data to the computer by simply giving it the command "M". It then returns 14 bytes to the computer. Without anything to measured connected to it, it should return something like 'DC 00.0000V CR'. CR is the terminator here (I hope that is the right name).
Here is my code:
import pyserial
import time
ser = serial.Serial(port='COM5', baudrate=1200,
bytesize=7, stopbits=2, timeout=1,
rtscts=False, dsrdtr=True)
time.sleep(1)
ser.write("M")
time.sleep(1)
bytestoread = ser.inWaiting()
print bytestoread
output = ''
output += ser.read(1000)
print 'output:' + str(output)
time.sleep(1)
ser.close()
My problem is, that I cannot read out the data properly with pyserial. I send the command "M" to the METEX and in the display it says 'send' for a short moment, so I guess my write command works fine. But after that (it should have send the data), all I get when from ser.inWaitung is '0L' or '1L' and the ser.read command gives nothing at all.
I don't think it is a problem of the hardware, because with another programme, called 'serialwatcher', I'm able read out the data correctly. It gives exactly the characters described in the manual.
I also tried the following while loop, having the problem, that most of the time inWaiting == 0, such that it never initialises the loop.
while ser.inWaiting() > 0:
output += ser.read(1)
if output != '':
output = outpus.rstrip()
print output
So, how can I read out the data correctly, that were send to the serial port? Thanks in advance.
Unfortunately I cannot test your code because I have no serial device with me, but you could try the following:
You could set a flag, e.g. alive when you are expecting data and simply try to read something. This worked for me when I was trying to receive data from a really old spectrometer.
while alive: #loop
text = ser.read(1) #try to read one line
if text: #if there is data
n = ser.inWaiting() #look if there is more to read
if n: #if so
text = text + ser.read(n) #get all of it
A more sophisticated example can be found here wxTerminal - Pyserial example You could also simply try to modify this brilliant code for your purpose and see if you are more successful.

How can I read my data correctly?

I have my Arduino connected to an OLIMEX-SHIELD-EKG-EMG, and there is this Arduino example for EKG capture and interface to Electric Guru for OLIMEXINO-328/Arduino boards.
I ran the Arduino software and then I made sure it's working using the Guru and it's all fine.
I tried to read the data from the serial port using Python and saving it to a text file, so I can use it for other stuff (Windows commands in my case). When I open the file the data is all garbage.
So what did I do wrong and how can I fix it?
Thank you all in advance.
This is my code:
import serial
from time import sleep
f = open("data2.txt", "w")
port = "\\.\COM4"
ser = serial.Serial(port, 38400, timeout=0)
while True:
data = ser.read(9999)
if len(data) > 0:
print ('Got:',data)
sleep(0.5)
print ('not blocked')
f.write( str(data) + "\n\n" )
f.close()
ser.close()
And this the data I get:
b'\x05\r\x1c\x1e\x10K\x12\x8a\x01\x0e\x14&\x1b\x1bW\x12\x80\x00\x7f\x11 \rZC:\x82\x12_.\x1a?\x10^\x12\x8a\x1a__\\x01:Q\x12\x8a\x15\x01\x1a\x1f\x1c6L\x1a\x82\x00t\x1e\x0c\x18\x19s:\x8a\x05]-\x01\x0e[G\x12\x8a\x15_\x0b9\x17>R\x12\x8a\x08__\x7f\x08:S\x1a\x82\x01\r\x18\x1d4\x10j:\x8a\n_0\x06\x10\x12Y\x10\x8a\nRH\x1c\x0bw#\x12\x80\x08\x7f\x0f7\x1f\x1bT:\x8a+\x7fU%\x18P:\x8a\x00\x0b}\x006\x11K\x12\x8a\x00Z\x19&\x16>\x1a\x82\x01\x02D\x1d\nYb:\x8a*$\x15\x12\x1cX:\x8a\x1b\x7f[\x06\x1bP\x12\x8a+\x0c\x1f?\x1b-F\x1a\x82\x05Z\x13\x0f7\x14}:\x8a\nUb\x19\n7^\x10\x8a\x15_\n\x14\x132_\x12\x80\x1d\x7f_x\x05\x15N:\x8a\x05<`\x025\x11I:\x8a\x0bZ1\x0f4\x18S\x12\x8a\x0bQK8\x0bvB\x1a\x82\x11\x7f\x0e\x1a\x18\x14q\x1a\x82\x07\xc1\xe1\x05\x14\x13q:\x8a+Sb\x02\x1b\x0cM\x12\x8a\x01\x1f\x1b%\x15\x15]\x1a\x82\x01B\x01.(\x1d\x7f\x1a\x82\xc2\xc1\x05,9\x1at\x10\x8a,__X\x024N\x1a\x80(xD!\x15\x10I\x1a\x82\x08|.
That looks to me like binary data. So i guess either each 16 or each 32 bit are a single numeric. You would have to cast the data you have and then format it into a text file.
It looks like ser.read() returns bytes not string. You need to decode that to if you want string. Use data.decode(your_encoding). You need to know the encoding.
For more see docs.
Decoding in UTF-16 could be promising...
data=b'\x05\r\x1c\x1e\x10K\x12\x8a\x01\x0e\x14&\x1b\x1bW\x12\x80\x00\x7f\x11 \rZC:\x82\x12_.\x1a?\x10^\x12\x8a\x1a__\\x01:Q\x12\x8a\x15\x01\x1a\x1f\x1c6L\x1a\x82\x00t\x1e\x0c\x18\x19s:\x8a\x05]-\x01\x0e[G\x12\x8a\x15_\x0b9\x17>R\x12\x8a\x08__\x7f\x08:S\x1a\x82\x01\r\x18\x1d4\x10j:\x8a\n_0\x06\x10\x12Y\x10\x8a\nRH\x1c\x0bw#\x12\x80\x08\x7f\x0f7\x1f\x1bT:\x8a+\x7fU%\x18P:\x8a\x00\x0b}\x006\x11K\x12\x8a\x00Z\x19&\x16>\x1a\x82\x01\x02D\x1d\nYb:\x8a*$\x15\x12\x1cX:\x8a\x1b\x7f[\x06\x1bP\x12\x8a+\x0c\x1f?\x1b-F\x1a\x82\x05Z\x13\x0f7\x14}:\x8a\nUb\x19\n7^\x10\x8a\x15_\n\x14\x132_\x12\x80\x1d\x7f_x\x05\x15N:\x8a\x05<`\x025\x11I:\x8a\x0bZ1\x0f4\x18S\x12\x8a\x0bQK8\x0bvB\x1a\x82\x11\x7f\x0e\x1a\x18\x14q\x1a\x82\x07\xc1\xe1\x05\x14\x13q:\x8a+Sb\x02\x1b\x0cM\x12\x8a\x01\x1f\x1b%\x15\x15]\x1a\x82\x01B\x01.(\x1d\x7f\x1a\x82\xc2\xc1\x05,9\x1at\x10\x8a,__X\x024N\x1a\x80(xD!\x15\x10I\x1a\x82\x08|.'
data.decode('UTF-16')
u'\u0d05\u1e1c\u4b10\u8a12\u0e01\u2614\u1b1b\u1257\x80\u117f\u0d20\u435a\u823a\u5f12\u1a2e\u103f\u125e\u1a8a\u5f5f\u785c\u3130\u513a\u8a12\u0115\u1f1a\u361c\u1a4c\x82\u1e74\u180c\u7319\u8a3a\u5d05\u012d\u5b0e\u1247\u158a\u0b5f\u1739\u523e\u8a12\u5f08\u7f5f\u3a08\u1a53\u0182\u180d\u341d\u6a10\u8a3a\u5f0a\u0630\u1210\u1059\u0a8a\u4852\u0b1c\u4077\u8012\u7f08\u370f\u1b1f\u3a54\u2b8a\u557f\u1825\u3a50\x8a\u7d0b\u3600\u4b11\u8a12\u5a00\u2619\u3e16\u821a\u0201\u1d44\u590a\u3a62\u2a8a\u1524\u1c12\u3a58\u1b8a\u5b7f\u1b06\u1250\u2b8a\u1f0c\u1b3f\u462d\u821a\u5a05\u0f13\u1437\u3a7d\u0a8a\u6255\u0a19\u5e37\u8a10\u5f15\u140a\u3213\u125f\u1d80\u5f7f\u0578\u4e15\u8a3a\u3c05\u0260\u1135\u3a49\u0b8a\u315a\u340f\u5318\u8a12\u510b\u384b\u760b\u1a42\u1182\u0e7f\u181a\u7114\u821a\uc107\u05e1\u1314\u3a71\u2b8a\u6253\u1b02\u4d0c\u8a12\u1f01\u251b\u1515\u1a5d\u0182\u0142\u282e\u7f1d\u821a\uc1c2\u2c05\u1a39\u1074\u2c8a\u5f5f\u0258\u4e34\u801a\u7828\u2144\u1015\u1a49\u0882\u2e7c'

Pyserial testing

I am new to Pyserial and Hardware area. I am trying to run the sample applications given in http://pyserial.sourceforge.net/shortintro.html#opening-serial-ports
import serial
ser = serial.Serial(0) # open first serial port
print ser.portstr # check which port was really used
ser.write("hello") # write a string
ser.close()
I have written this program in a python file and running it. Now if I want to test this application to check if I am sending correct string (eg: Hyperterminal or something) how can I do this. Can anyone guide me?
Use virtual serial port for your test.
For Windows I use com0com and socat for Linux.
Then, use Putty for visualization of your send.
Another quick way to test a physical serial port is to take a wire/screwdriver, crocodile clamp or anything that you have in hand and bridge the RX and TX (receive and transmit) together. At that point, everything that you send out will be looped back at you. YOu can receive it afterward by using this code snippet here:
import serial
ser = serial.Serial(0, timeout = 1) # open first serial port
print ser.portstr # check which port was really used
ser.write("hello") # write a string
msg = ser.read("100") #read the content of the input buffer until you get 100 byte or a timeout event
print(msg) #print the content you might need to decode it print(decode(msg))
ser.close()
The key aspect again for this code to work properly is to bridge RX and TX together. A lot of tutorial will show you how to do this.

Categories

Resources