Exiting Python While True loop - python-3.x

I am using a temperature sensor (HS18B20) on my raspberry pi. Every second or so, temperature is recorded onto a spreadsheet and sent to dropbox using a while True loop. It will do this forever until ctrl + c is pressed. In order to upload to dropbox, I cannot have the same file name as another file. The program will give an error and stop. Obviously, I could simply create a file with a different name everytime but to combat having hundreds of different files on dropbox, I delete the file on dropbox and immediately upload the new spreadsheet to dropbox. I have no problem with this technique, except for one thing...
If the program is stopped via ctrl + c right after the file is deleted and during the uploading of the file, the new file doesn't get uploaded and only gets deleted on dropbox (the local .xls file is never deleted; just replaced).
toc = time.strftime("%b %-d, %Y. %H:%M:%S")
dbx.files_delete('/Temperature Data ' + toc + '.xls')
with open(time.strftime("%m_%d_%Y") + '.xls', "rb") as f:
dbx.files_upload(f.read(), '/Temperature Data ' + toc + '.xls')
print("Uploaded to Dropbox")
I thought I set up a fail safe, but it still does not work.
Here is a snippet from my code.
def signal_handler(signal, frame):
signal interrupted
interrupted = True
signal.signal(signal.SIGINT, signal_handler)
interrupted = False
...
while True:
print("Temperature Taken")
a += 1
c += 1
if temp_f < input_bad:
ws.write(a,0,temp_f)
ws.write(a,1,time.strftime("%H:%M:%S %p"))
ws.write(a,2,"YES")
while c % 6 == 0:
c += 1
dbx.files_delete('/Temperature Data ' + toc + '.xls')
with open(time.strftime("%m_%d_%Y") + '.xls', "rb") as f:
dbx.files_upload(f.read(), '/Temperature Data ' + toc + '.xls')
print("Uploaded to Dropbox")
if interrupted:
print("Saving...")
dbx.files_delete('/Temperature Data ' + toc + '.xls')
with open(time.strftime("%m_%d_%Y") + '.xls',"rb") as f:
dbx.files_upload(f.read(), '/Temperature Data ' + toc + '.xls')
quit()
If I ctrl + c the program while it's taking a temperature readings, no problem! The program finishes its loop until c % 6 == 0 and then saves and closes.
If I ctrl + c the program while its saving, yes problem...
I could just print("Do not close the program") when its saving, but I would like to make this idiot proof.
Any tips? Thanks!

You can register a signal handler and the quit the loop when at the end of processing.
import signal
import sys
userQuitRequested = False
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
userQuitRequested = True
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C to quit')
You can then check for userQuitRequested in your loop at the appropriate time, and break if True.

Related

Telnet.read_very_eager in FOR loop and the first often returns b' ' while the rest works fine

I'm using Telnetlib to control a VIAVI 5800.Here is my code.
And I log results of telnet.read_very_eager. Sometimes the first read returns b'', maybe say it occurs a lot. I really don't understand why only the first read has this problem while the others just work fine. I also tried adding more time after I finishing changing the time slot, this still happens.
import telnetlib
import time
from robot.libraries.BuiltIn import BuiltIn
for vc4 in range(vc4, vc4_end):
for tug3 in range(stm_start, tug3_end):
for tug2 in range(1, 8):
for tu12 in range(1, 4):
tu12_com = ":SENSE:SDH:DS1:E1:LP:C12:CHANNEL" + " " + str(tu12) + "\n"
tug2_com = ":SENSE:SDH:DS1:E1:LP:C2:CHANNEL" + " " + str(tug2) + "\n"
tug3_com = ":SENSE:SDH:DS1:E1:LP:C3:CHANNEL" + " " + str(tug3) + "\n"
vc4_com = ":SENSE:SDH:CHANNEL:STMN" + " " + str(vc4)
tn.write(tu12_com.encode('ascii')) # change tu12
time.sleep(0.1)
tn.write(tug2_com.encode('ascii')) # change tug2
time.sleep(0.1)
tn.write(tug3_com.encode('ascii')) # change tug3
time.sleep(0.1)
tn.write(vc4_com.encode('ascii')) # change vc4
time.sleep(1.5)
tn.write(b":ABOR\n")
time.sleep(1)
tn.write(b":INIT\n")
time.sleep(5)
tn.write(b":SENSE:DATA? TEST:SUMMARY\n")
time.sleep(2)
result = tn.read_very_eager()
result_num = str(vc4) + "-" + str(tug3) + "-" + str(tug2) + "-" + str(tu12)
BuiltIn().log_to_console(result_num)
BuiltIn().log_to_console(result)
The results are like under:
results saved in excel workbook
results in RF Ride console
I'm so confused and wondering can anyone explain this. Thanks a lot.
BTW, my python version is:
C:\Users\Quinn>python -V
Python 3.7.9

files are saved repeatedly with single name, no looping, no ranging

My codes runs well, but have one flaw. They are not saving accordingly. For example, Let's say I caught 3 jpeg files, when I ran the codes, it saves 3 times on slot 1, 3 times on slot 2, and 3 times on slot 3. So I ended up with 3 same files.
I think there is something wrong with my looping logic?
If I changed for n in range(len(soup_imgs)): to for n in range(len(src)):, the operation saves infinitely of the last jpeg files.
soup_imgs = soup.find(name='div', attrs={'class':'t_msgfont'}).find_all('img', alt="", src=re.compile(".jpg"))
for i in soup_imgs:
src = i['src']
print(src)
dirPath = "C:\\__SPublication__\\"
img_folder = dirPath + '/' + soup_title + '/'
if (os.path.exists(img_folder)):
pass
else:
os.mkdir(img_folder)
for n in range(len(src)):
n += 1
img_name = dirPath + '/' + soup_title + '/' + str({}).format(n) + '.jpg'
img_files = open(img_name, 'wb')
img_files.write(requests.get(src).content)
print("Outputs:" + img_name)
I am amateur in coding, just started not long ago as a hobby of mine. Please give me some guidance, chiefs.
Try this when you are writing your image files:
from os import path
for i, img in enumerate(soup_imgs):
src = img['src']
img_name = path.join(dirPath, soup_title, "{}.jpg".format(i))
with open(img_name, 'wb') as f:
f.write(requests.get(src).content)
print("Outputs:{}".format(img_name))
You need to loop over all image sources, rather than using the last src value from a previous for block.
I've also added a safer method for joining directory and file paths that should be OS independent. Finally, when opening a file, always use the with open() as f: construct - this way Python will automatically close the filehandle for you.

Get a new unix timestamp when writing to a file

First post so apologies for any formatting issues ect.
Context - Using a PIR sensor to log visits to a store using a Pi-3.
My aim here is to write a new unix timestamp to a file every time the sensor detects motion.
Below is what code i have so far, this outputs a text file with a unix timestamp. but the stamp appears to be the same for every detection
GPIO.setmode(GPIO.BOARD)
GPIO_PIR = 11
print "PIR Module Test (CTRL-C to exit)"
GPIO.setup(GPIO_PIR,GPIO.IN)
Current_State = 0
Previous_State = 0
Variable= int(time.time())
try:
print "Waiting for PIR to settle ..."
while GPIO.input(GPIO_PIR)==1:
Current_State = 0
print " Ready"
while True :
Current_State = GPIO.input(GPIO_PIR)
if Current_State==1 and Previous_State==0:
print "Motion detected"
Previous_State=1
file = open("textFile.txt", 'a+')
file.write(Variable + "\n")
file.close()
elif Current_State==0 and Previous_State==1:
print " Ready"
Previous_State=0
time.sleep(0.01)
except KeyboardInterrupt:
print " Quit"

How to Infinitely Update Labels with while loop tkinter

Hi I have some simple code here. https://pastebin.com/97uuqKQD
I would simply like to add something like this, to the button function, so while the root window is open the datetime and exrates are constantly regotten from the xe website and displayed.
amount = '1'
def continuousUpdate():
while amount == '0':
results()
def results():
#Get xe data put to labels etc here
btnConvert = tk.Button(root, text="Get Exchange Rates",command=continuousUpdate).place(x=5,y=102)
Once I input the two exrates and they then display on there respective labels I would like the program to continuously grab the data from xe over and over again.
Like this code here which runs in IPython no problems,
import requests
from bs4 import BeautifulSoup
from datetime import datetime
amount = '1'
while amount != '0':
t = datetime.utcnow()
url1 = "http://www.xe.com/currencyconverter/convert/" + "?Amount=" + amount + "&From=" + cur1 + "&To=" + cur2
url2 = "http://www.xe.com/currencyconverter/convert/" + "?Amount=" + amount + "&From=" + cur2 + "&To=" + cur1
#url = "http://www.xe.com/currencycharts/" + "?from=" + cur1 + "&to=" + cur2
html_code1 = requests.get(url1).text
html_code2 = requests.get(url2).text
soup1 = BeautifulSoup(html_code1, 'html.parser')
soup2 = BeautifulSoup(html_code2, 'html.parser')
i = i + 1
rate1 = soup1.find('span', {'class', 'uccResultAmount'})
rate2 = soup2.find('span', {'class', 'uccResultAmount'})
print ('#',i, t,'\n', cur1,'-',cur2, rate1.contents[0], cur2,'-',cur1, rate2.contents[0], '\n')
I thought I would just be able to throw the entire results function into a while loop function then simply call that function but no luck any help would be appreciated.???
Put this at the end of your results function without the while loop:
after_id = root.after(milliseconds,results)
This way it just keeps running itself after that time you specified. And this code will cancel it.
root.after_cancel(after_id)
Answering your other question in the comments:
To make a cancel button make sure after_id is global. Also if the time you specify is very low (very fast recall) it might restart again before you can cancel it. So to be safe better make a global boolean and put .after in an if boolean==True. And you can set that boolean to False whenever you hit cancel button or to True whenever you hit the start button, here's how you can do it:
# button_call default will be True so if you click on the button
# this will be True (no need to pass var through). You can use this to set
# your restart boolean to True
def func(button_call=True):
global restart
global after_id
if button_call:
restart = True
if restart:
after_id = root.after(ms,lambda: func(button_call=False) )
# This way you know that func was called by after and not the button
Now you can put this in your cancel button function:
def cancel():
global restart
global after_id
root.after_cancel(after_id)
restart = False
Let me know if this works (haven't tested it myself).

Python3 Two-Way Serial Communication: Reading In Data

I am trying to establish a two-way communication via Python3. There is a laser range finder plugged into one of my USB ports and I'd like to send/receive commands to that. I have a sheet of commands which can be sent and what they would return, so this part is already there.
What I need is a convenient way to do it in real-time. So far I have the following code:
import serial, time
SERIALPORT = "/dev/ttyUSB0"
BAUDRATE = 115200
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.bytesize = serial.EIGHTBITS #number of bits per bytes
ser.parity = serial.PARITY_NONE #set parity check: no parity
ser.stopbits = serial.STOPBITS_ONE #number of stop bits
ser.timeout = None #block read
ser.xonxoff = False #disable software flow control
ser.rtscts = False #disable hardware (RTS/CTS) flow control
ser.dsrdtr = False #disable hardware (DSR/DTR) flow control
ser.writeTimeout = 0 #timeout for write
print ("Starting Up Serial Monitor")
try:
ser.open()
except Exception as e:
print ("Exception: Opening serial port: " + str(e))
if ser.isOpen():
try:
ser.flushInput()
ser.flushOutput()
ser.write("1\r\n".encode('ascii'))
print("write data: 1")
time.sleep(0.5)
numberOfLine = 0
while True:
response = ser.readline().decode('ascii')
print("read data: " + response)
numberOfLine = numberOfLine + 1
if (numberOfLine >= 5):
break
ser.close()
except Exception as e:
print ("Error communicating...: " + str(e))
else:
print ("Cannot open serial port.")
So in the above code I am sending "1" which should trigger "getDistance()" function of the laser finder and return the distance in mm. I tried this on Putty and it works, returns distances up to 4 digits. However, when I launch the above Python script, my output is only the following:
Starting Up Serial Monitor
Exception: Opening serial port: Port is already open.
write data: 1
read data:
and it goes forever. There is no read data or whatsoever.
Where am I mistaken?
Apparently much more simpler version of the code solved the issue.
import serial
import time
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout = 1) # ttyACM1 for Arduino board
readOut = 0 #chars waiting from laser range finder
print ("Starting up")
connected = False
commandToSend = 1 # get the distance in mm
while True:
print ("Writing: ", commandToSend)
ser.write(str(commandToSend).encode())
time.sleep(1)
while True:
try:
print ("Attempt to Read")
readOut = ser.readline().decode('ascii')
time.sleep(1)
print ("Reading: ", readOut)
break
except:
pass
print ("Restart")
ser.flush() #flush the buffer
Output, as desired:
Writing: 1
Attempt to Read
Reading: 20
Restart
Writing: 1
Attempt to Read
Reading: 22
Restart
Writing: 1
Attempt to Read
Reading: 24
Restart
Writing: 1
Attempt to Read
Reading: 22
Restart
Writing: 1
Attempt to Read
Reading: 26
Restart
Writing: 1
Attempt to Read
Reading: 35
Restart
Writing: 1
Attempt to Read
Reading: 36
It seems to me that your ser.timeout = None may be causing a problem here. The first cycle of your while loop seems to go through fine, but your program hangs when it tries ser.readline() for the second time.
There are a few ways to solve this. My preferred way would be to specify a non-None timeout, perhaps of one second. This would allow ser.readline() to return a value even when the device does not send an endline character.
Another way would be to change your ser.readline() to be something like ser.read(ser.in_waiting) or ser.read(ser.inWaiting()) in order to return all of the characters available in the buffer.
try this code
try:
ser = serial.Serial("/dev/ttyS0", 9600) #for COM3
ser_bytes = ser.readline()
time.sleep(1)
inp = ser_bytes.decode('utf-8')
print (inp)
except:
pass

Resources