How do I stop an action in a loop? - python

I'm trying to create a script that opens my online classes automatically. I wrote this code:
import webbrowser
import datetime
import time
now = time.strftime("%D, %H:%M")
lesson1 = "03/09/21, 15:38"
lesson2 = "03/10/21, 15:39"
lesson3 = "03/10/21, 15:40"
while True:
while now != lesson1 and now != lesson2 and now != lesson3:
print ("Waiting, the current time is " + now)
now = time.strftime("%D, %H:%M")
time.sleep(1)
if now == lesson1:
print ("LESSON IS OPENING :D")
webbrowser.open("https://google.com")
if now == lesson2:
print ("LESSON IS OPENING :D")
webbrowser.open("https://google.com")
if now == lesson3:
print ("LESSON IS OPENING :D")
webbrowser.open("https://google.com")
Now, the problem is that the first if-statement is executed endlessly, I want to make it execute only one time, than wait until now == lesson2 and execute the second if etc

The problem is in each iteration you are checking if current time is equal to lesson time which causes program to open browser numerous times. Since you are working with hours/minutes, making program sleep 1 min once your current lesson starts would prevent it.
Sample Input:
import webbrowser
import datetime
import time
now = time.strftime("%D, %H:%M")
print("Current Time -- ", now)
lesson1 = "03/10/21, 11:14"
lesson2 = "03/10/21, 11:15"
lesson3 = "03/10/21, 11:16"
while True:
while now != lesson1 and now != lesson2 and now != lesson3:
print ("Waiting, the current time is " + now)
now = time.strftime("%D, %H:%M")
time.sleep(1)
if now == lesson1:
print("Opening Google")
webbrowser.open("https://google.com")
time.sleep(60)
now = time.strftime("%D, %H:%M")
if now == lesson2:
print("Opening Youtube")
webbrowser.open("https://youtube.com")
time.sleep(60)
now = time.strftime("%D, %H:%M")
if now == lesson3:
print("Opening Facebook")
webbrowser.open("https://facebook.com")
time.sleep(60)
now = time.strftime("%D, %H:%M")
Sample output:
Current Time -- 03/10/21, 11:13
Waiting, the current time is 03/10/21, 11:13
Opening Google
Opening Youtube
Opening Facebook

It seems that you want to schedule your code to run at certain times. I recommend using the APScheduler library. Very easy to use and is efficient.

Related

Python live data recording at a consistent rate

I am trying to write a python code that reads live sensor data from an Arduino Uno board. The code will then take the data it read from the sensor, and graph it, as well as writing it to an excel document. I want the code to read sensor data for set amount of time.
The sensor reads data at a much more consistent rate in the Arduino IDE and when running in python without using the time.sleep() function. However, when I don't use the time.sleep() function, the amount of data points I get from the sensor is different every time I run it (it only ranges by a few data points, but I would like it to be the same every time). When I tried using the time.sleep() function to make it read at a consistent rate, the sensor to be reads very slowly and there is a 3-4 second delay between when the sensor reads something and when it shows up in the console, which does not happen without time.sleep(). Is there a way to have the sensor output at a consistent rate without using the time.sleep() function? My python code is below.
import serial
import time
import matplotlib.pyplot as plt
import pandas as pd
import openpyxl
#wb = openpyxl.Workbook() #Create blank new workbook
df = pd.DataFrame(columns=('Time', 'Data'))
ser = serial.Serial('COM21', 9600)
time.sleep(2)
ser.flushInput()
data = ser.readline()
#Sample = input("Enter Sample Name: ")
#Batch = input("Enter Batch Number: ")
Time = [] #Blank list for timestamps of recordings
Data = [] #Blank list for sensor data
while True:
input("Press Enter to Start")
startTime = time.time()
while True:
currentTime = time.time() #Take current time for countdown
data = ser.readline()
Timer = currentTime - startTime #Timer since enter button was pressed
try:
decoded_bytes = float(data[0:len(data)-2].decode("utf-8")) #Convert output data to clean format
Time.append(round(currentTime - startTime, 3))
Data.append(decoded_bytes)
print(decoded_bytes)
except:
continue
if(Timer > 20):
df['Time'] = pd.concat(Time)
df['Data'] = pd.concat(Data)
break
else:
continue
#input("Press Enter to Stop Timer")
#endTime = time.time()
#TotTime = endTime - startTime
#print(str(round(TotTime, 3)) + " Seconds")
#---------------------------------------------------Restart Program------------------------------------------------#
while True: #User prompt to run program again
answer = str(input('Run again? (y/n): '))
if answer in ('y', 'n'): #Value that is not 'y' or 'n' gives error message
break
print('Invalid Input')
if answer == 'y': #Run program again
continue
else: #Stop and close program
print('Goodbye')
exit()

While loop wont run until tray icon is closed

import pystray
import PIL.Image
from datetime import datetime
from text_to_speech import speak
from time import time, sleep
import os
from gtts import gTTS
import vlc
image = PIL.Image.open('hourglass.jpg')
def on_clicked(icon, item):
icon.stop()
icon = pystray.Icon('Hourglass', image, menu=pystray.Menu(
pystray.MenuItem('Exit', on_clicked)))
icon.run()
stop = False ## To loop forever
while stop == False:
print('test')
now = datetime.now()
second = now.second
minute = now.minute
if second == 0 :
myText = 'It is now ' + (now.strftime("%I %p"))
print(myText)
output = gTTS(text=myText, lang='en', slow=False)
output.save("Time.mp3")
p = vlc.MediaPlayer("Time.mp3")
p.play()
sleep(10)
os.remove("Time.mp3")
this is my code. For some reason which i cant figure out until i press on the icon and exit, the rest of the code wont run. I was trying to make an icon try for when i run this in the background.
The icon.run() internally run a loop. So until this loop breaks (by closing the window) the code below will not be executed. If you want for the icon and the code below to run independently, you can use Threads.
import threading
def run_icon():
icon = pystray.Icon('Hourglass', image, menu=pystray.Menu(
pystray.MenuItem('Exit', on_clicked)))
icon.run()
def run_second():
stop = False ## To loop forever
while stop == False:
print('test')
now = datetime.now()
second = now.second
minute = now.minute
if second == 0 :
myText = 'It is now ' + (now.strftime("%I %p"))
print(myText)
output = gTTS(text=myText, lang='en', slow=False)
output.save("Time.mp3")
p = vlc.MediaPlayer("Time.mp3")
p.play()
sleep(10)
os.remove("Time.mp3")
Thread1 = threading.Thread(target=run_icon)
Thread2 = threading.Thread(target=run_second)
Thread1.join() # wait for thread to stop
Thread2.join() # wait for thread to stop
You can use icon.run_detached(). Then just run your main code underneath.

I have functional problem but I cannot see where

I know this is not good to ask this kind of question but I am honest and this is my problem now. I do not know that to do anymore so I have to ask this (also I do not know where else I can ask this). I cannot debug my code that I can see when day changes so I do not know where the problem is.
My code is taking pictures and sending them to twitter between 24 hours. Code is working fine at the first day but after that it is not sending photos anymore. And I do not see any problems in my code. Please take a look and say if you see problem.
from twython import Twython
from picamera import PiCamera
from time import sleep
import datetime
import os
sleep(500)
camera = PiCamera()
camera.rotation = 180
datetimeNow = datetime.datetime.now()
oldDate = 0
newDate = 0
photoAlreadyTaken = 0
CONSUMER_KEY = 'sad...'
CONSUMER_SECRET = 'asd...'
ACCESS_TOKEN_KEY = 'fdsf...'
ACCESS_TOKEN_SECRET = 'asd..'
twitter = Twython(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN_KEY,
ACCESS_TOKEN_SECRET)
while True:
try:
newDate = datetimeNow.day
except:
print("error")
if newDate != oldDate:
if datetimeNow.hour == 14 and photoAlreadyTaken != 1:
photoAlreadyTaken = 1
try:
camera.start_preview()
sleep(5)
camera.capture('/home/pi/strawberry.jpg')
camera.stop_preview()
except:
photoAlreadyTaken = 0
sleep(5)
try:
with open('/home/pi/strawberry.jpg', 'rb') as photo:
twitter.update_status_with_media(status=str(datetimeNow.day) + "-" + str(datetimeNow.month) + "-" + str(datetimeNow.year), media=photo)
except:
photoAlreadyTaken = 0
oldDate = datetimeNow.day
else: #When the first photo is sent this is executed, but I cannot debug how long
photoAlreadyTaken = 0
sleep(500)
After the first cycle of the loop, both newDate and oldDate equal datetime.datetime.now() at the time of script activation forever.
Your reasoning about the value of datetimeNow is a bit off; it's set at activation and you never update it. Consider replacing datetimeNow (static value) with datetime.datetime.now() (function invocation that gives the current date-time); or at least update datetimeNow somewhere inside the loop.
Good luck!

Do not run a python script again within a specific time (e.g. 1 hour)

I'm using this python script:
LINK
It's working great so far.
But now I would like to optimize it, because sometimes it's happening that the script will be executed 2-3 times within 10-20 minutes, because it will always run if there are 3 streams or more (e.g. a 4. stream will be started --> notification will be send again or also if a user decide to cancel this stream and watch another movie --> The script will run again!)
I have tried to use time.sleep but that is not working. I would like to have it like this:
If the program will be executed,it shouldn't be run again within the next 60 minutes.
What do I need to use / code here?
Thanks for help!
Thank you for the Tip, my code does look like this now (can you maybe check?):
** code section ** = my code which I have merged inside the existing script.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Description: Send a PlexPy notification when the total
# number of streams exceeds a threshold.
# Author: /u/SwiftPanda16
# Requires: requests
# PlexPy script trigger: Playback start
# PlexPy script arguments: {streams}
import requests
import sys
**import os
from datetime import datetime, timedelta**
### EDIT SETTINGS ###
PLEXPY_URL = 'xx.xxx.xx:8181'
PLEXPY_APIKEY = 'xxxxxxxxxxxxxxxxxx'
AGENT_ID = 14 # The PlexPy notifier agent id found here: https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
NOTIFY_SUBJECT = 'test' # The notification subject
NOTIFY_BODY = 'Test'
STREAM_THRESHOLD = 3
**### time management ###
one_hour_ago = datetime.now() - timedelta(minutes=60)
filetime = datetime.fromtimestamp(os.path.getctime("timestamp.txt"))
if filetime < one_hour_ago:**
### CODE BELOW ###
def main():
try:
streams = int(sys.argv[1])
except:
print("Invalid PlexPy script argument passed.")
return
if streams >= STREAM_THRESHOLD:
print("Number of streams exceeds {threshold}.".format(threshold=STREAM_THRESHOLD))
print("Sending PlexPy notification to agent ID: {agent_id}.".format(agent_id=AGENT_ID))
params = {'apikey': PLEXPY_APIKEY,
'cmd': 'notify',
'agent_id': AGENT_ID,
'subject': NOTIFY_SUBJECT,
'body': NOTIFY_BODY}
r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=params)
**os.getcwd()
open ('timestamp.txt', 'w')**
else:
print("Number of streams below {threshold}.".format(threshold=STREAM_THRESHOLD))
print("No notification sent.")
return
if __name__ == "__main__":
main()
**else:
pass**
Have the script write a timestamp to an external file and check that file at startup.
Here is an example:
import time
def script_has_run_recently(seconds):
filename = 'last-run-time.txt'
current_time = int(time.time())
try:
with open(filename, 'rt') as f:
last_run = int(f.read().strip())
except (IOError, ValueError) as e:
last_run = 0
if last_run + seconds > current_time:
return True
else:
with open(filename, 'wt') as f:
f.write(str(current_time))
return False
def main():
print('running the main function.')
if __name__ == "__main__":
seconds = 3600 # one hour in seconds
if script_has_run_recently(seconds):
print('you need to wait before you can run this again')
else:
main()

Python script is causing time drift

I have the following Python script:
#!/usr/bin/env python
# coding: utf-8
import time
import serial
import datetime
from datetime import timedelta
import os.path
PATH = '/home/pi/test/'
Y = datetime.datetime.now().strftime('%Y')[3]
def get_current_time():
return datetime.datetime.now()
def get_current_time_f1():
return datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
def get_current_time_f2():
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def compare_time():
current_time = get_current_time()
if current_time.minute == 59 and current_time.second >= 45:
return "new"
def file_date():
if compare_time() == "new":
plusonehour = datetime.datetime.now() + timedelta(hours=1)
return plusonehour.strftime('Z'+Y+'%m%d%H')
else:
return datetime.datetime.now().strftime('Z'+Y+'%m%d%H')
def createCeilFile():
filename = os.path.join(PATH, file_date()+".dat")
fid = open(filename, "w")
fid.writelines(["-Ceilometer Logfile","\n","-File created: "+get_current_time_f1(),"\n"])
return fid
# open the first file at program start
fid = createCeilFile()
# serial port settings
ser=serial.Serial(
port='/dev/ttyUSB0',
baudrate = 19200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
)
counter=0
# read first byte, grab date string, read rest of string, print both in file
while 1:
tdata = ser.read()
time.sleep(3)
data_left = ser.inWaiting()
tdata += ser.read(data_left)
fid.writelines(["-"+get_current_time_f2(),"\n",tdata,"\n"])
#should have ~10 secs before next message needs to come in
#if next string will go into the next hour
if compare_time() == "new":
# close old file
fid.writelines(["File closed: "+get_current_time_f2(),"\n"])
fid.close()
# open new file
fid = createCeilFile()
# then it goes back to 'tdata = ser.read()' and waits again.
It works fine and stores all the data I need in the correct format and so on.
A data message from the device comes trough every 15 seconds. The python script runs for an infinite time and reads those messages. At the beginning of each message the script adds a time, when the message was written to the file and therefor received. And the time is the problem with this script. I have a time drift of about 3 to 4 seconds in 24 hours. Weird about that is, that the time drifts backwards. So if I start with data messages coming in at 11, 26, 41 and 56 seconds during the minute, after 24 hours the messages seem to come in at 8, 23, 38 and 53 seconds in the minute.
Has anyone an explanation for that or maybe a way to compensate it? I thought about restarting the program every hour, after it saved the hourly file. Maybe that helps resetting the weird time drift?

Categories