I am working on a small proof of concept and using python to illustrate the idea. The idea is the program will run in a loop and will check for input. Now if the input falls under a threshold then it sends a notification. But I am trying to restrict the notification at an interval of 4 sec. And thats where I am loosing either with the logic or with some syntax. Either way It is doing some unexpected things
1: keep on entering 0 and it will display the below threshold message until it reaches a 4 sec mark and then it just prints out the message 4 times in a single line. I want them to show after every 4 seconds. The idea is (A)the input might change in that 4 sec and the notification switches. (B)I want the notification to play out as a reminder with a recurrence of 4 sec every time the script hits the condition if weightIn < 0.5..if it is true then the notification goes out after 4 sec from the first time it was sent
Sorry if I tried over explaining it. I am pretty new to python
import threading
def main():
while True:
weightIn = float(input("Get value: "))
threshold = .5
def operation():
if weightIn < 0.5:
#send notification at an interval of 4 sec
threading.Timer(4.0, operation).start()
print("Below weight threshhold...send notification")
else:
print("You are good")
if threshold is not None:
operation()
main()
First avoid declaring functions in a loop. Then ask yourself, if an object would not be appropriate, because it properly encloses state attributes.
But for the algorithmic part, it is simple (if I have correctly understood the problem ...). Store the timestamp of last notification and send a new one if more the 4 seconds have elapsed. In pseudo-code :
last_notification_time = 0
threshold = 0.5
loop:
weighIn = get_new_value()
if weightIn < threshold:
time = get_time_in_seconds()
if (time > last_notification_time + 4):
last_notification_time = time
send_notification()
# actual processing
In Python, it could look like :
#import time
def main():
last_notification_time = 0
threshold = 0.5
while True:
weighIn = float(input("Get value: "))
if weightIn < threshold:
cur_time = time.time()
if (cur_time > last_notification_time + 4):
last_notification_time = time
print("Below weight threshhold...send notification")
# actual processing
main()
Related
This question already has answers here:
How to create a python loop that allows other code to run as well
(3 answers)
How do I get input at the same time while constantly increasing a value in python?
(1 answer)
Closed 1 year ago.
I'm trying to make a program that makes you lose "energy" for a game.
I made it so when you press enter you gain "energy":
if question == '':
print("press enter to gain energy")
while True:
energyup = input()
if energyup == "":
energy += energygain
print(energy)
I also want to make it so you lose energy every 0.5 seconds. I don't know how to do this.
I tried adding:
while True:
energy -= energyloss
print(energy)
time.sleep(1)
to the bottom of the program, but that makes you lose energy WAY too fast and I don't know if there is a way to make 1 line of code sleep while everything else continues (I'm using time.sleep which affects the whole program) and on top of that it makes the energy gaining system just not work.
Sorry if this is a dumb question I just started learning programing and this is my first question on this site.
Instead of time.sleep, just check if it has been 0.5 seconds past the last time energy was lost:
prev_time = time.time()
while True:
# rest of the game loop
curr_time = time.time()
if curr_time - prev_time > 0.5:
energy -= energyloss
prev_time = curr_time
This lets the rest of the game loop code to run concurrently.
You need to use threads. Thread A is responsible for consumption, and thread B listens for input
energy = 0
energyloss = 1
energygain = 1
lock = threading.Lock()
def consumption():
global energy
while 1:
with lock:
energy -= energyloss
time.sleep(0.5)
print(energy)
threading.Thread(target=consumption).start()
Use threading.Lock to ensure thread safety
You also need to call with lock when increasing energy
I see solution with threading which might be helpful but from your problem statement, I believe you only need to have a function that will provide the diff between the total energy accumulated and the one lost with time.
To do so, you may start a timer at the beginning and create a function that will use the current time minus the execution time to calculate the energy lost each time.
The below might be enough for you case:
import time
energy_gain_constant = 5
energy_loss_constant = -2
total_energy_gain = 0
start_time = time.time()
def print_total_energy():
print(total_energy_gain + int((time.time() - start_time) / 0.5) * energy_loss_constant)
print("press enter to gain energy")
while True:
energyup = input()
if energyup == "":
total_energy_gain += energy_gain_constant
print_total_energy()
Adding debug logs into the method that prints how it will behave:
def print_total_energy():
total_energy_lost = int((time.time() - start_time) / 0.5) * energy_loss_constant
print(f'Total execution time: {time.time() - start_time}')
print(f'Total energy lost: {total_energy_lost}')
print(f'Total energy gained: {total_energy_gain}')
print(f'Total Energy: {total_energy_gain + total_energy_lost}')
Output:
Total execution time: 12.982820272445679
Total energy lost: -50
Total energy gained: 65
Total Energy: 15
I'm making a program that runs something for the amount of minutes the user alots (it's an idle game in beta). I put on a timer for one minute and noticed that the program ran over the minute by a couple of seconds-- Not very noticable, but I was wondering if this is because of how long a loop takes to execute? This is my code:
import time
foreverloop = True
automodeOn = False
idleSec = 0
idleMin = 0
pages = 0
pps = 0
while foreverloop:
if automodeOn == False:
msg = input("BTCG Command >> ")
if msg == 'auto':
autotime = input("How long would you like to go idle for? Answer in minutes.")
automodeOn = True
elif msg == 'autoMORE':
pps += .5
else:
pages += pps
print("You have auto-read",pps,"pages.")
idleSec += 1
if idleSec == 60:
idleSec = 0
idleMin += 1
if idleMin == int(autotime):
print("Idle mode turning off.")
automodeOn = False
time.sleep(1)
You could measure the time it takes for a number of lines of code to execute by measuring the start time:
start = time.time()
before any number of lines you'd like to measure the time, then at the end adding:
end = time.time()
the time elapse is then calculated as their subtraction:
elapsed_time = end-start
I suggest that you read about code complexity, the most popular of which is the Big O notation.
edit: as denoted in a comment, timeit is the better option if you're looking to precisely measure the time it takes for a certain line or function to execute, the main difference between the 2 approaches is that timeit is made specifically for this purpose and as part of this takes as a parameter a variable number indicating the number of times the specified code is run before determining how long it takes on average to run.
Instead of making the program wait in adittion to the time it takes to execute, I would use time.time() to get the system's current UNIX time in seconds as a float and only continue if a certain time has passed:
import time
time_begin = time.time()
wait_time = 60 # seconds to wait
while time.time() < time_begin + wait_time:
# do logic
print("Time passed:", time.time() - time_begin)
time.sleep(1) # can be whatever
print(wait_time, "seconds has passed!")
I have a workflow in which I need to call a python method when either of:
1. specified timeout occurs, or
2. size of input data (list) reaches a threshold, like 10 data points
What is the best way to support the workflow?
[Edit] - The methods would be called in a serverless API so it needs to be stateless. Does it make sense to use some sort of queues to store and retrieve the data and how?
You could do it like this:
while True: #Keep checking condition
if timeoutCondition or len([list]) > 10: #check conditions
class.method() #execute method
You can pull the status at a certain interval, if timeout or data reaches threshold, do the thing you want.
import time
max_count = 10
timeout = 60 #1min
count_increase = 0
next_timeout = time.time() + timeout
while True:
current_time = time.time
count_increase = get_count() - count
if count >= max_count or current_time >= next_timeout:
do_what_you_want()
count_increase = 0
next_timeout = time.time() + timeout
time.sleep(1)
I'm creating a test for Google Assistant based on while loop. The code will play a long mp3 file and I'm try to identify if the assistant will do a false trigger and count how many times.
I'm running on pycharm/pytest and getting the trigger status by UIAutomator provided by Google.
import android
import time
play_music(music.mp3)
start_time = time.time()
trigger = 0
hours = 1
command_timeout = hours * 60 * 60
while trigger < 3 or time.time() - start_time < command_timeout:
if trigger_screen.is_in_screen():
trigger += 1
time.sleep(10)
stop_music()
The conditions to stop the loop is 3 false triggers or one hour of test, but the loop isn't stop after one hour of test, could someone help me?
You're using an or statement when you should be using an and statement:
while trigger < 3 and time.time() - start_time < command_timeout:
With your current code, the while loop only terminates when BOTH conditions are
False, when you really want it to terminate when either one or the other is False.
You need to swap the or in your code with and like shown below:
import android
import time
play_music(music.mp3)
start_time = time.time()
trigger = 0
hours = 1
command_timeout = hours * 60 * 60
while trigger < 3 and time.time() - start_time < command_timeout:
if trigger_screen.is_in_screen():
trigger += 1
time.sleep(10)
stop_music()
Bassically the code you wrote continues the loop as long as one of the conditions is met, which explains why your music continued to play (less than 3 triggers so the loop still runs)
I am writing a program for real time pitch detection. Here's the outline of the code :-
def pitch_detection :
result = []
while True :
// apply pitch detection algorithm
if pitch_energy > threshold :
result.append(pitch)
return result
I want to brrak from the loop if pitch_energy > threshold is False for sometime
What I am doing right now is timeout the loop after sometime.
Like this :-
How would I stop a while loop after n amount of time?
Save the time whenever you make an append to the list. Then compare it to the current time when you don't make a correction. If the time since you last made an append is greater than some threshold, you break:
def pitch_detection :
result = []
start = time.time()
MAX_TIME_ALLOWED = 5 # seconds
while True :
// apply pitch detection algorithm
if pitch_energy > threshold :
result.append(pitch)
start = time.time() # reset the time when we append.
else:
if (time.time() - start) > MAX_TIME_ALLOWED:
break
return result
This assumes you actually want to use elapsed time to decide when to break. If you want to use number of iterations of the loop, just use a counter that starts at 0, and increment it in the else block, rather than time.time().
def pitch_detection :
result = []
no_append = 0
MAX_TIME_ALLOWED = 5 # seconds
while True :
// apply pitch detection algorithm
if pitch_energy > threshold :
result.append(pitch)
no_append = 0
else:
no_append += 1
if no_append > MAX_TIMES_ALLOWED:
break
return result
You can use an alarm to time yourself out after four seconds. It'll require some setup to get going, since you need a function and an exception class to use.
import signal
# Define a couple things.
class TimeoutException(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutException()
# Set the alarm handler.
signal.signal(signal.SIGALRM,timeout_handler)
alarmOn = False
try:
while True:
# Pitch detection algorithm
if pitch_energy <= threshold:
# False condition - start your alarm.
if not alarmOn:
signal.alarm(4)
alarmOn = True
else:
# True condition - turn off the alarm.
alarmOn = False
signal.alarm(0)
result.append(pitch)
except TimeoutException: # This happens if four seconds pass without signal.alarm(0) being called.
print "We're done."
signal.alarm(0) # Turn the alarm off
The signal.alarm() function starts a timer with whatever value you give it, in seconds. If that many seconds pass without the alarm being reset, then a SIGALRM signal is sent. The way the code above works, it will catch that SIGALRM signal and throw our custom TimeoutException. This allows us to break out of the while loop, since we catch that exception.
EDIT: looking at dano's answer, it's entirely possible that this one is overly complicated. The main difference between ours is that this solution will immediately interrupt what you're doing if four seconds pass - that could stop your pitch detection algorithm right in the middle. dano's solution will always wait until that certain point in the code to check the time.