bind takes a long time - python

I am using over 20 raspberry pis to control heating and other functions in my house. For instance each room has a pi (client) with a temperature sensor, which sends a message to another pi (server) at one of three manifolds to open or close a valve on the heating system.
My problem is the amount of time the server takes to execute the bind instruction. A newly set up pi will typically take a few millisecond to execute the line, but soon the time becomes variable, sometimes milliseconds, usually seconds, but frequently tens of seconds or even hundreds of seconds.
typical code,
elapselp = default_timer() # timing start
port = 12571 # port number, many different ones used
while bound == 0:
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('', port))
bound = 1
elapselp1 = default_timer() - elapselp
print ('bind time = ', elapselp1)
As stated above elapselp1 can be at the low millisecond level, or 200 seconds which causes significant problems.
I usually find I can get back to short times by changing the port number used, which means changing on all the clients, but after some time running happily the times will increase again. Rebooting or powering down does not help. I am using Raspberry 4s and Zero Ws, no difference.
I suspect that some register is not clearing, but outside that am clueless. Can somebody advise please.
I am running Rasparian 3.6 and Python3
Thank you for all your replies, here is the remainder of this section of the code.
As I’m not sure how to input his I’m breaking it down over a number of comments.
elapselp = default_timer()
port =12571
while bound == 0:
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('', port))
bound = 1
elapselp1 = default_timer()- elapselp
print (‘bind time = ‘, elapselp2)
except:
dummy = 1
s1.listen(5)
print ('waiting for input ', end='')
while True:
conn, addr = s1.accept()
print ('connected by ', addr)
conn.send('thank you'.encode())
data = conn.recv(1024).decode()
print ('data = ', data)
time.sleep(5)
conn.close()
s1.close()
if data == '10':
startdaw = default_timer()
GPIO.output(22, GPIO.LOW)
print ('switch dining area heating off')
h1 = 0
dawl = edaw
startdawr = default_timer()
elif data == '11':
GPIO.output(22, GPIO.HIGH)
## A lot of other actions depending on data received here
else:
print ('another code ', data)
if not data:
break
print ('yet another')
I have a number of Raspberry pi Zeros running the code for test along with 7 doing so as part of my control system. The performance is very erratic.
One unit running through the code every 30 seconds in response to a client has been running over 5 days, majority of the bind times have been under 1 millsec, I see some between 1 and 10, but it has recorded one time of 130 seconds.
Another unit which failed to bind for over two hours has now completed over 33,000 binds (this one just closes after the bind, no if statements), and the longest time for a bind is 710 msec.
If I take out the try/except I get no error message, it just drops through and loops back.
I hope there is some useful information in there.

Related

Python Serial communition with device

enter image description here
I am making serial port communication device from a genious guy's work instructables.com.
It will measure the distance of the hamster's running in a day or month.
Using 4, 6 pin of the serial port cable, if the hamster runs, the device can count the numbers how many time did she run.
When I run the py file with Python27 like below, some errors occure.
"python hamster-serial.py progress.txt"
I cannot understand what's going on.
I am using windows8 and Python2.7 version.
Could you check my source, please?
import datetime
import serial
import sys
# Check for commandline argument. The first argument is the the name of the program.
if len(sys.argv) < 2:
print "Usage: python %s [Out File]" % sys.argv[0]
exit()
# Open the serial port we'll use the pins on and the file we'll write to.
ser = serial.Serial("/dev/ttyS1")
# Open the file we're going to write the results to.
f = open(sys.argv[1], 'a')
# Bring DTR to 1. This will be shorted to DSR when the switch is activated as the wheel turns.
ser.setDTR(1)
# The circumferance of the wheel.
circ = 0.000396 # miles
# Total distance traveled in this run of the program.
distance = 0.0
print "%s] Starting logging." % datetime.datetime.now()
start = datetime.datetime.now()
# This function a period of the wheel to a speed of the hamster.
def toSpeed(period):
global circ
seconds = period.days * 24 * 60 * 60 + period.seconds + period.microseconds / 1000000.
return circ / (seconds / 60. / 60.)
# Waits for the DSR pin on the serial port to turn off. This indicates that the
# switch has turned off and the magnet is no longer over the switch.
def waitForPinOff():
while ser.getDSR() == 1:
1 # Don't do anything while we wait.
# Waits for the DSR pin on the serial port to turn on. This indicates that the
# switch has turned on and the magnet is current over the switch.
def waitForPinOn():
while ser.getDSR() == 0:
1 # Don't do anything while we wait.
# The main loop of the program.
while 1:
waitForPinOn()
# Calculate the speed.
end = datetime.datetime.now()
period = end - start
start = end
speed = toSpeed(period)
# Increment the distance.
distance = distance + circ
waitForPinOff()
# We'll calculate the time the switch was held on too so but this isn't too useful.
hold = datetime.datetime.now() - start
# If the switch bounces or the hamster doesn't make a full revolution then
# it might seem like the hamster is running really fast. If the speed is
# more than 4 mph then ignore it, because the hamster can't run that fast.
if speed < 4.0:
# Print out our speed and distance for this session.
print "%s] Distance: %.4f miles Speed: %.2f mph" % (datetime.datetime.now(), distance, speed)
# Log it to and flush the file so it actually gets written.
f.write("%s\t%.2f\n" % (datetime.datetime.now().strftime("%D %T"), speed))
f.flush()
Well, ser = serial.Serial("/dev/ttyS1") is for a linux machine, on windows you'll need something like ser = serial.Serial("COM1") (you can check what COM do you need in the device manager).
As a side note,
def waitForPinOff():
while ser.getDSR() == 1:
1 # Don't do anything while we wait.
Will eat you CPU. You are better of with:
def waitForPinOff():
while ser.getDSR() == 1:
time.sleep(1) # Don't do anything while we wait.

Data saved to text file is inconsistent

My controller is receiving data from a radio module through a serial port, it's recording temperature and humidity to two decimal places every 1 second, using 'a' as a signal to time stamp it. For example:
a21.12 65.43
a21.13 65.40
Here is the code I'm using:
import serial
import datetime
connected = False
locations=['/dev/ttyUSB0','/dev/ttyUSB1','/dev/ttyUSB2','/dev/ttyUSB3']
for device in locations:
try:
print "Trying...",device
ser = serial.Serial(device, 9600)
break
except:
print "Failed to connect on",device
while not connected:
serin = ser.read()
connected = True
with open('tempdata.txt', 'w') as text_file:
while 1:
if ser.read() is 'a':
text_file.write(datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'))
text_file.write(" ")
x = ser.read()
text_file.write(x)
text_file.flush()
ser.close()
When I check my text file afterwards the result seems to be different every time. If I let it run for just 2 or 3 seconds I sometimes get a correct result, sometimes I only get the humidity, sometimes I get the time stamp with a number that is half temperature, half humidity (like 2.16.3). If I let it run for more than a few seconds the file is just completely blank.
The basis for my code is from a question previously asked on here and it worked fine until I added the time stamp part. I tried changing the radio transfer rate from 9600 to 4800 but that just turned the numbers into garbage characters.
I'm running this on a Raspberry Pi 2 model B so I could be demanding too much from it in a short time.
You are calling read() twice and writing only the output of the second call. I don't imagine that is your intent.
You can change this section:
with open('tempdata.txt', 'a') as text_file:
while 1:
content = ser.read()
if content is 'a':
text_file.write(datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'))
text_file.write(" ")
text_file.write(content)
text_file.flush()

Serial data transmission input-output delay with Raspberry Pi

The Goal:
Drive several servo/RC motors wireless from one pi to another pi.
In essence, I want to build a RC remote control using a pi, with a second pion the receiver end.
Now I have a serial transmission over a RF link module that is stable and has very few corrupt entries. The serial transmission has a max baud rate of 4800 due to the RF link module.
Problem:
It seems there is a 2-4 seconds difference between the transmitter pi printing values and the receiver pi printing values. I cannot figure out where and why this delay comes from and why is it so large. Please note that the signal on the receiving pi is exactly the same data that is sent by the transmitter pi, but 2-4 seconds later. EVEN when I bypassed the the transmitter/receiver module and connected the Tx and Rx pins with a jumper wire the same delay was seen.
What is causing the data on the receiving Pi to be decoded so much later? I have pasted in the code below.
---------- Tx Pi -----------------
import serial
import struct
ser = serial.Serial("/dev/ttyAMA0")
ser.baudrate = 4800
iCount = 0
bProgramLoop = True
while (bProgramLoop == True):
iOne = iCount
if (iOne == 100):
iOne = 0
iTwo += 1
iCount = 0
if (iTwo == 100):
iTwo = 0
iThree += 1
if (iThree == 100):
iThree = 0
iFour += 1
if (iFour == 100):
iFour = 0
iFive += 1
if (iFive == 100):
iFive = 0
lData = [iOne,iTwo,iThree,iFour,iFive] # i have done it like this so that I can track in real time where the transmitter is and receiver is with respect to real time changes on the transmitter side
sData = struct.pack('5B',*lData)
ser.write(sData)
print sData
iCount += 1
-------------- Rx Pi -----------------
import serial
import struct
ser = serial.Serial("/dev/ttyAMA0")
ser.baudrate = 4800
bProgramLoop = True
while (bProgramLoop == True):
sSerialRead = ser.read(5)
tData = struct.unpack('5B',sSerialRead)
print tData
The time difference between when the Tx Pi prints the string sData and the Rx Pi prints the touple tData is somewhere between 2-4 seconds. Is the struct.unpack function slow?
I need this time difference to be absolutely minimal. Any ideas?
First, I'm not sure the ser.write() is an async call. If this is using the pySerial library, the docs say that it is a blocking call.
Perhaps try:
...
ser.write(sData)
ser.flush() # Force the 'send'
print sData
...
Also, your ldata might be easier to populate like so:
lData = [iCount % 100, iCount % 10000, ...etc]
Also, setting a write timeout might help (but I don't think so).
(Posted on behalf of the OP).
As suggested by Doddie use the ser.flush command just after ser.write. This results in a near instant response on the Rx side. The overall mainloop sample rate has dropped a bit, but for me at least that is not a deal breaker.

Python 2.7 simple packet sniffer

I wrote simple packet sniffer in Python. I need to receive packets non-stop and send one packet every 10 seconds. I tried this:
current = time.time()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("xx.xx.xx.xx",xxxx))
time.sleep(0.5)
while True:
msg = str(s.recv(4096))
time.sleep(0.010)
print msg
if current==current+10:
s.send("<myPacket/>")
current = time.time()
but it doesn't work good. Anyone have better idea?
Your time handling is bad, use this instead:
While True:
...
time.sleep(10)
Your code doesn't work because:
'current' can never be equal to itself+10.
Also note that time.time() returns a float value e.g: 1440185304.78
which is very accurate to that exact moment, you should never assume you can find that exact float +10 back.
Using a larger/smaller statement is better in this case since the exact value might have passed while your loop is running whatever is in it, e.g:
t = time.time()
while True:
while time.time() < t + 10:
time.sleep(0.1)
t = time.time()
print ("hi")

How to quickly read single byte serial data using Python

I am reading serial data in Python using the following code:
port = "COM11"
baud = 460800
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
while 1:
# Read from serial port, blocking
data =ser.read(1)
print data
# some further processing of data
I am sending data at very fast rate but when I use this code I am getting data at a very slow rate, maybe around 2 - 3 data per second. This is too slow because I want to do real time plotting.
So, instead of above code I tried:
while 1:
# Read from serial port, blocking
data =ser.read(1)
data1=(data)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data1 = (data1 + ser.read(n))
print data1
Now the speed at which data is updated is the same but instead of a single byte I am checking a number of bytes in input queue and reading them. I am receiving around 3850 bytes per loop so this one appears much faster to me but in fact it is almost the same, the only change is that I am not reading a greater number of bytes.
I want to read a single byte and check for the real time it was received. To do so I cannot use second method where I use ser.inWaiting(). How can I read single byte data faster than using the approaches above?
Here's some test code I wrote for a project that you can try different baud settings with. Basically it sends out some data on Tx (which could be connected directly to Rx) and expects the data to be echoed back. It then compares the returned data with the sent data and lets you know if/when errors occur. Note that if there are no errors then the output will remain blank and at the end of test it will print "0 Comm Errors".
import serial, time
test_data = "hello this is so freakin cool!!!" + '\r' #Must always be terminated with '\r'
echo_timeout = 1 #the time allotted to read back the test_data string in seconds
cycleNum = 0
errors = 0
try:
ser = serial.Serial(port="COM1", baudrate=115200, timeout=1)
ser.flush()
print "starting test"
for x in xrange(100):
cycleNum += 1
d = ser.write(test_data)
ret_char = returned = ''
start_time = time.time()
while (ret_char <> '\r') and (time.time() - start_time < echo_timeout):
ret_char = ser.read(1)
returned += ret_char
if not returned == test_data:
errors += 1
print "Cycle: %d Sent: %s Received: %s" % (cycleNum, repr(test_data), repr(returned) )
except Exception as e:
print 'Python Error:', e
finally:
if 'ser' in locals():
print "%d Comm Errors" % errors
if ser.isOpen():
ser.close()
print "Port Was Successfully Closed"
else:
print "Port Already Closed"
else:
print "Serial Variable Was Never Initialized"

Categories