Read and write to UART pyserial using timeout functionality - python-3.x

I have written a UART py-serial script, which looks like.
import serial
import time
try:
ser = serial.Serial(
#port='/dev/ttyAMA0',
port='/dev/ttyUSB1',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=2
)
print ('Connection is open : ',str(ser.isOpen()))
except Exception as e:
print ("Something got wrong: ", e)
ser.write(b'hello..')
and have a similar script as receiver.
what I want is:
suppose timeout = 5
ser.write(b'Helloo...')
ser.flush()
ser.readline()
the other script is reading it and sending a response via serial only.
this readline should wait maximum for this timeout, if it received response in 2 seconds then it should not wait for 5seconds.
But using this timeout it waits for 2 seconds, even if the data is received in a second.
so my concern is to wait maximum for timeout, but if data received earlier it should end and proceed.
Not able to find this functionality, please help.

found a way for this to work:
pyserial have this inbuit functionality, for eg:
ser.read_until(b'#') #just specify EOL here
It will break if this (#) is found. if not, will wait for timeout and return at end.
You can also use seperate timeouts for read and write:
timeout=5 #read timeout
write_timeout=5 # write timeout

Related

Program gets stuck on reading serial communication of arduino via Pyserial

m trying to create a tool that help to simulate key press
but at part of this code mentioned below, the program gets stuck and its not proceeding
ser = serial.Serial(ACM)
ser.baudrate = 115200
ser.timeout = None
ser.flushInput()
ser.flushOutput()
ser.write(cmd)
p = ser.readline()
pr = p.decode("utf-8")
print(cmd)
print(pr)
ser.close()
print("Closed")
" ser.readline() is not reading the output of serial com /dev/ttyACM*
Thanks
The PySerial documentation is unmistakable:
Be careful when using readline(). Do specify a timeout when opening
the serial port otherwise it could block forever if no newline
character is received.
You define: ser.timeout = None so what exactly do you expect your program to do, but block forever if you don't receive a newline?
Either make sure the sent lines are terminated or use a reasonable timeout.

My if & elif not working on sockets (python 3)

I tried to create a server that receives commands from the client
And to identify which command the client wrote I used if & elif
But when I run the program and write a command from the client, only the first command works (the command on the if) and if I try another command (from elif & else)
The system just doesn't respond (like she's waiting for something)
The Server Code:
import socket
import time
import random as rd
soc = socket.socket()
soc.bind(("127.0.0.1", 7777))
soc.listen(5)
(client_socket, address) = soc.accept()
if(client_socket.recv(4) == b"TIME"):
client_socket.send(time.ctime().encode())
elif(client_socket.recv(4) == b"NAME"):
client_socket.send(b"My name is Test Server!")
elif(client_socket.recv(4) == b"RAND"):
client_socket.send(str(rd.randint(1,10)).encode())
elif(client_socket.recv(4) == b"EXIT"):
client_socket.close()
else:
client_socket.send(b"I don't know what your command means")
soc.close()
The Client Code:
import socket
soc = socket.socket()
soc.connect(("127.0.0.1", 7777))
client_command_to_the_server = input("""
These are the options you can request from the server:
TIME --> Get the current time
NAME --> Get the sevrer name
RAND --> Get a Random int
EXIT --> Stop the connect with the server
""").encode()
soc.send(client_command_to_the_server)
print(soc.recv(1024))
soc.close()
if(client_socket.recv(4) == b"TIME"):
client_socket.send(time.ctime().encode())
This will check the first 4 byte received from the server
elif(client_socket.recv(4) == b"NAME"):
client_socket.send(b"My name is Test Server!")
This will check the next 4 bytes received from the server. Contrary to what you assume it will not check the first bytes again since you called recv to read more bytes. If there are no more bytes (likely, since the first 4 bytes are already read) it will simply wait. Instead of calling recv for each comparison you should call recv once and then compare the result against the various strings.
Apart from that: recv will only return up to the given number of bytes. It might also return less.

How to send message sequences over a socket?

I'm experimenting with communication via sockets in Python. I have a server.py-file and a client.py. The latter is asking for a user input and send this to the server. Depending on the user input, the server is playing 2 different sound. This works a single time but not for a second attempt.
I've put in some print(XYZ) lines to see where the programm is stopping. After sending the first message the "print("...")"-line of my server.py is no longer executed. So it looks like server_socket.accept() is no longer successful. Why is that?
This is server.py:
import socket
import winsound
fnameBeep = "beep.wav"
fnameBop = "bop.wav"
server_socket = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
server_socket.bind(server_addr)
server_socket.listen(1000)
while True:
print("waiting...")
(client_socket, addr) = server_socket.accept()
print("...")
msg = client_socket.recv(1024)
print(msg)
print("Received: " + str(msg, "utf8"))
if str(msg, "utf8") == '1':
winsound.PlaySound(fnameBeep, winsound.SND_FILENAME)
else:
winsound.PlaySound(fnameBop, winsound.SND_FILENAME)
This is client.py:
import socket
client_socket = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
print("Beep = 1; Bop = 2")
client_socket.connect(server_addr)
while True:
print('waiting ...')
UserInput = input('Your choice: ')
print('Sending: ' + UserInput)
client_socket.send(bytes(UserInput, "utf8"))
print('Sent!')
What is going wrong? the general communicaiton is working but I'd like to send a sequence of messages to the server.
The first thing you'll want to do is move your accept() call up to above the top of your while loop -- as it is, your code is trying to accept a new TCP connection after each command, which I think it not what you wanted to do -- presumably you want to keep a single TCP connection open and receive multiple commands over that TCP connection instead.
The second issue is framing: the thing to remember about TCP is that it implements a raw stream of bytes, and doesn't do any fixed framing of messages on its own -- e.g. if you execute the following calls on the sending side:
client_socket.send("123")
client_socket.send("456")
client_socket.send("789")
... the on the receiving side, the server might see the following data-chunks returned from its subsequent recv() calls:
recv() call #1: 12345
recv() call #2: 67
recv() call #3: 89
... or, it might instead (depending on how the network is working, phase of the moon, etc) get the following:
recv() call #1: 1
recv() call #2: 2345678
recv() call #3: 9
or it might get all the sent data in a single call:
recv() call #1: 123456789
or it might even receive each byte via a separate call:
recv() call #1: 1
recv() call #2: 2
recv() call #3: 3
recv() call #4: 4
recv() call #5: 5
recv() call #6: 6
recv() call #7: 7
recv() call #8: 8
recv() call #9: 9
... or any other combination you can imagine.
So the question is, given the uncertainty of the data-chunking, how can your receiver know that your client intended to send ("file_name1.wav" and then "file_name2.wav") rather than just ("file_name1.wavfile_name.wav"), or ("file", "name1.wavfile", "name.wav"), or etc?
In order to parse the incoming TCP bytes unambiguously, the receiver has to know how they are framed. For a simple program like yours, the framing logic could be straightforward -- e.g. just declare a rule that each string will have a newline character at the end. Then your server can simply keep receiving bytes (and adding them to the end of a string) until it sees a newline byte, at which point it knows it has received a full user-command, so it can at that point handle that command, then remove all of the string (up to and including the newline character) before continuing its parsing for the next string.
Another way to do it is to have the sender include a short (fixed-length) header before each command indicating the number of bytes that the receiver should expect to see in the next command. Then the server can read the header (because the header is fixed-length, the server will know how many bytes it needs to read before it has the full header to look at), and then read that-many bytes, then handle the command, then repeat.

How to detect poll timeout in pyzmq

poller = zmq.Poller()
poller.register(socket, zmq.POLLIN)
while(1)
try:
sockets = dict(poller.poll(timeout)) #How to detect timeout
# do job
except SomeTimeoutException:
break
As shown, is there a way to detect when timeout occurs while polling? Couldn't find a way on searching
poll returns tuples with the sockets registered as the first item and a flag denoting whether a frame was received or send. Thus you can just check for the flag, as shown in many pyzmq examples:
socket_dict = dict(poller.poll(timeout))
for polled_socket, flag in socket_dict.items():
if not (flag & zmq.POLLIN):
print("timeout")
If you just need to test one socket, this will work too:
if socket.poll(timeout) & zmq.POLLIN:
print("processing data...")
else:
print("timeout")

Python 3.4 - How to 'run' another script python script continuously, How to pass http get / post to socket

This question is two-fold.
1. So I need to run code for a socket server that's all defined and created in another.py, Clicking run on PyCharm works just fine, but if you exec() the file it just runs the bottom part of the code.
There are a few answers here but they are conflicting and for Python 2.
From what I can gather there are three ways:
- Execfile(), Which I think is Python 2 code.
- os.system() (But I've seen it be said that it's not correct to pass to the OS for this)
- And subprocess.Popen (unsure how to use this either)
I need this to run in the background, it is used to create threads for sockets for the recv portion of the overall program and listen on those ports so I can input commands to a router.
This is the complete code in question:
import sys
import socket
import threading
import time
QUIT = False
class ClientThread(threading.Thread): # Class that implements the client threads in this server
def __init__(self, client_sock): # Initialize the object, save the socket that this thread will use.
threading.Thread.__init__(self)
self.client = client_sock
def run(self): # Thread's main loop. Once this function returns, the thread is finished and dies.
global QUIT # Need to declare QUIT as global, since the method can change it
done = False
cmd = self.readline() # Read data from the socket and process it
while not done:
if 'quit' == cmd:
self.writeline('Ok, bye. Server shut down')
QUIT = True
done = True
elif 'bye' == cmd:
self.writeline('Ok, bye. Thread closed')
done = True
else:
self.writeline(self.name)
cmd = self.readline()
self.client.close() # Make sure socket is closed when we're done with it
return
def readline(self): # Helper function, read up to 1024 chars from the socket, and returns them as a string
result = self.client.recv(1024)
if result is not None: # All letters in lower case and without and end of line markers
result = result.strip().lower().decode('ascii')
return result
def writeline(self, text): # Helper func, writes the given string to the socket with and end of line marker at end
self.client.send(text.strip().encode("ascii") + b'\n')
class Server: # Server class. Opens up a socket and listens for incoming connections.
def __init__(self): # Every time a new connection arrives, new thread object is created and
self.sock = None # defers the processing of the connection to it
self.thread_list = []
def run(self): # Server main loop: Creates the server (incoming) socket, listens > creates thread to handle it
all_good = False
try_count = 0 # Attempt to open the socket
while not all_good:
if 3 < try_count: # Tried more than 3 times without success, maybe post is in use by another program
sys.exit(1)
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create the socket
port = 80
self.sock.bind(('127.0.0.1', port)) # Bind to the interface and port we want to listen on
self.sock.listen(5)
all_good = True
break
except socket.error:
print('Socket connection error... Waiting 10 seconds to retry.')
del self.sock
time.sleep(10)
try_count += 1
print('Server is listening for incoming connections.')
print('Try to connect through the command line with:')
print('telnet localhost 80')
print('and then type whatever you want.')
print()
print("typing 'bye' finishes the thread. but not the server",)
print("eg. you can quit telnet, run it again and get a different ",)
print("thread name")
print("typing 'quit' finishes the server")
try:
while not QUIT:
try:
self.sock.settimeout(0.500)
client = self.sock.accept()[0]
except socket.timeout:
time.sleep(1)
if QUIT:
print('Received quit command. Shutting down...')
break
continue
new_thread = ClientThread(client)
print('Incoming Connection. Started thread ',)
print(new_thread.getName())
self.thread_list.append(new_thread)
new_thread.start()
for thread in self.thread_list:
if not thread.isAlive():
self.thread_list.remove(thread)
thread.join()
except KeyboardInterrupt:
print('Ctrl+C pressed... Shutting Down')
except Exception as err:
print('Exception caught: %s\nClosing...' % err)
for thread in self.thread_list:
thread.join(1.0)
self.sock.close()
if "__main__" == __name__:
server = Server()
server.run()
print('Terminated')
Notes:
This is created in Python 3.4
I use Pycharm as my IDE.
One part of a whole.
2. So I'm creating a lightning detection system and this is how I expect it to be done:
- Listen to the port on the router forever
The above is done, but the issue with this is described in question 1.
- Pull numbers from a text file for sending text message
Completed this also.
- Send http get / post to port on the router
The issue with this is that i'm unsure how the router will act if I send this in binary form, I suspect it wont matter, the input commands for sending over GSM are specific. Some clarification may be needed at some point.
- Recieve reply from router and exception manage
- Listen for relay trip for alarm on severe or close strike warning.
- If tripped, send messages to phones in storage from text file
This would be the http get / post that's sent.
- Wait for reply from router to indicate messages have been sent, exception handle if it's not the case
- Go back to start
There are a few issues I'd like some background knowledge on that is proving hard to find via the old Google and here on the answers in stack.
How do I grab the receive data from the router from another process running in another file? I guess I can write into a text file and call that data but i'd rather not.
How to multi-process and which method to use.
How to send http get / post to socket on router, post needed occording to the router manual is as follows: e.g. "http://192.168.1.1/cgi-bin/sms_send?number=0037061212345&text=test"
Notes: Using Sockets, threading, sys and time on Python 3.4/Pycharm IDE.
Lightning detector used is LD-250 with RLO Relay attached.
RUT500 Teltonica router used.
Any direction/comments, errors spotted, anything i'm drastically missing would be greatly appreciated! Thank you very much in advance :D constructive criticism is greatly encouraged!
Okay so for the first part none of those suggested in the OP were my answer. Running the script as is from os.system(), exec() without declaring a new socket object just ran from __name__, this essentially just printed out "terminated", to get around this was simple. As everything was put into a classes already, all I had to do is create a new thread. This is how it was done:
import Socketthread2
new_thread = Socketthread2.Server() # Effectively declaring a new server class object.
new_thread.run()
This allowed the script to run from the beginning by initialising the code from the start in Socket, which is also a class of Clientthread, so that was also run too. Running this at the start of the parent program allowed this to run in the background, then continue with the new code in parent while the rest of the script was continuously active.

Resources