I'm very new to code and want the led.off portion to be extendable. Basically, if I hit the button again before the 10 seconds run out. So if the button is hit before lighting up, there is another 10 second wait, starting at press 2.
from time import time, sleep
from signal import pause
led = LED(18) # or whatever pin you've got it on
button = Button(23) # again, adjust as necessary
def light_off_for_10_sec():
led.off()
sleep(10)
led.on()
button.when_pressed = light_off_for_10_sec
The 10 second pause before lighting up works great, but here is what I have tried to use to stretch the led.off period.
def stretched(values):
when_pressed = 10
for value in values:
if value:
sleep(5)
pressed = time()
yield time() - pressed <= 20
led.source = stretched(button.pressed)
pause()```
Related
I am trying to make an auto clicker but when i try to make my code exit it doesnt
here is my code
import mouse
import keyboard
import time
import os
os.system('cls')
def Config():
print("Click every")
hour = int(input("Hour: "))
minute = int(input("Minute: "))
second = int(input("Second: "))
total_time = hour*3600 + minute*60 + second
print("f6 to start and f10 to stop")
keyboard.wait('f6')
while True:
time.sleep(total_time)
mouse.click()
#def Fastest():
print(" Auto clicker!!!")
print(" By ze")
print("-------------------------")
print("Auto click on desired time or Fastest?")
choose = int(input("""
1. Config (No milliseconds)
2. Fastest
"""))
if choose == 1:
Config()
# elif choose == 2:
# Fastest()
#TODO:
# use mouse.click
# make it click with time
# make function fastest start with f1 and stops with f2
# create back up file
i tried an if statement with keyboard.is_pressed('key') thinking it would work but it doesnt my results are that the code exits (if key is pressed then exit)
You need to check if the key is pressed in your infinite loop. If it is pressed, you need to exit
while True:
time.sleep(total_time)
mouse.click()
if keyboard.is_pressed("f10"):
break
But this waits for the sleep function , so you'll need to hold f10 for total_time seconds.
You should use a loop to check for the key, rather than sleeping
import datetime
...
clicking = True
while clicking:
mouse.click()
s = datetime.datetime.now()
while ((datetime.datetime.now()-s).total_seconds() < total_time):
# This runs while the difference in time since you started the loop is less than the time you want to wait
if keyboard.is_pressed("f10"):
clicking = False
break
Use one thread to handle user input and another thread to do the clicking:
from threading import Thread
from msvcrt import getwch
import mouse
done = False
def auto_click():
print("Press \"q\" to quit")
global done
while True:
if getwch() == "q":
done = True
break
Thread( target = auto_click, daemon = True ).start()
while not done: # you can add whatever logic you want including a time gate here
mouse.click()
import PySimpleGUI as sg
import time
q1 = [
[sg.Text("Question 1!"), sg.Button("x", visible=False), sg.Text("Time:"), sg.Text(" ", size=(10,1), key="t")],
[sg.Text("This is where question 1 will be?")],
[sg.Button("Option 1", key="1",button_color=("#ffffff","#151515")), sg.Button("Option 2", key="2",button_color=("#00ff00", "#151515"))],
[sg.Button("Option 3", key="3",button_color=("#00ffff", "#151515")), sg.Button("Option 4", key="4",button_color=("#ff00ff", "#151515"))],
[sg.Button("Submit"), sg.Button("Next Question"), sg.Button("Skip")]
]
window = sg.Window("Question 1",q1)
while True:
event, values = window.Read()
if event is None:
break
seconds = 20
for i in range(seconds):
seconds = seconds - i
window.FindElement("t").Update(seconds)
time.sleep(1)
I'm not sure if I am approaching this the correct way, but I want to make it so that a 20-second timer appears in the upper right corner. However, with the code above, no timer starts, and when you press a button, it freezes the program for 20 seconds.
Apologies if this is discussed in the many notes in this post. If so, feel free to ignore and sorry for taking up the space.
Never put a "sleep" in an event loop. Use a timeout on your window.read instead
Call window.refresh() to have changes appear in your window:
https://pysimplegui.readthedocs.io/en/latest/call%20reference/#window
It states:
Use this call when you want something to appear in your Window immediately (as soon as this function is called). Without this call your changes to a Window will not be visible to the user until the next Read call
There is a timer demo - this demo and the concept of refreshing a window periodically is referenced throughout the documentation, in a demo program and also on Trinket. The docs speak directly about having windows the appear to freeze if you don't call read or refresh periodically. The timer is discussed here in the main docs:
https://pysimplegui.readthedocs.io/en/latest/#persistent-window-example-running-timer-that-updates
One option you have is to save your starting time and during each iteration of your main loop you calculate the time difference and update the timer.
When the difference reaches 20 seconds you stop and progress to the next question, otherwise you safe the current leftover time or whatever you want to do with it and start new.
Here is a basic example:
from time import time
TIME_PER_QUESTION = 20.0
# Loop questions
for i in range(3):
start = time()
current = time()
time_left = TIME_PER_QUESTION
while time_left > 0:
# Update your interface
# doStuff()... update()...
# Spam a bit for testing
print("Leftover time {:.0f}".format(time_left))
# Update current time and our timer
current = time()
time_left = TIME_PER_QUESTION - (current - start)
Of course you could add more ways to break out of the loop and store the leftover time while you do etc. and progress to the next question.
There are more ways to achieve this but thats one thing you could to. (This technique is mainly used for main loops in games and stuff like that)
As mentioned in the comments you could probably also do it using a threaded timer function if you want to.
EDIT
As for updating the text in the gui, I'm not sure if the way you do it works but if you say it never updated maybe try this instead:
window['t'].update("{:.0f}".format(time_left))
I needed to build something similar and I used #Mike from PSG 's example timer above and cut it way down to basics.
def binary_timed(time_allowed=15,default_value=False,query='no text inputed'):
"""
This is a GUI that will present a user with a 'query' which is a string
it gives them a number of seconds to make a binary choice and returns
a default value when the time runs out
"""
#layout options for the GUI
layout = [
[sg.Text(query)],#
[sg.Text('time remaining: %s'%time_allowed,key='timer')],
[
sg.Button('Yes'),
sg.Button('No'),
]
]
#present the user with the gui
window = sg.Window('binary_timed', layout)
time_passed = 0
while (True):
event, values = window.read(timeout=1000)#1000 ms -> 1s wait between read
time_passed += 1
time_remaining = time_allowed-time_passed
window['timer'].update("time remaining: %s"%time_remaining)
if event != sg.TIMEOUT_KEY: #a button has been pressed
window.close()
break
if time_remaining == 0:
window.close()
break
#evauluate our results
if event == sg.WIN_CLOSED: return default_value #pressed the exit button
if event == sg.TIMEOUT_KEY: return default_value
if event == 'Yes': return True
if event == 'No': return False
Using mine as a basis I applied the timeout concept to yours. Hopefully this helps and makes things understandable.
import PySimpleGUI as sg
q1 = [
[sg.Text("Question 1!"), sg.Button("x", visible=False), sg.Text("Time:"), sg.Text(" ", size=(10,1), key="t")],
[sg.Text("This is where question 1 will be?")],
[sg.Button("Option 1", key="1",button_color=("#ffffff","#151515")), sg.Button("Option 2", key="2",button_color=("#00ff00", "#151515"))],
[sg.Button("Option 3", key="3",button_color=("#00ffff", "#151515")), sg.Button("Option 4", key="4",button_color=("#ff00ff", "#151515"))],
[sg.Button("Submit"), sg.Button("Next Question"), sg.Button("Skip")]
]
window = sg.Window("Question 1",q1)
time_elapsed = 0
time_remaining = 20
while True:
event, values = window.read(1000)
time_remaining -= time_elapsed
window['t'].update(time_remaining)
time_elapsed += 1
if event != sg.TIMEOUT_KEY: #a button has been pressed
window.close()
break
if time_remaining == 0:
window.close()
break
So for my reaction time assignment, I ran to multiple issues such as when the timer ended, the red light won't light up nor print out the message saying the user has failed and when I press enter after the timer goes out, I can still press the button and it would light up the green LED and print out the message. The whole point of the assignment is to set up the random timer from 5-10 seconds to press the yellow led before it runs out and give out the total amount of time that the user had gotten when they pressed the button till it runs out and I wonder how to properly do it.
import physense_emu
import time
import random
sensor = physense_emu.Sensor()
#Greeting user to press "enter" to start the reaction time simulator
strtTime = "Start"
#Setting up simulator to start when pressing "enter"
butbucket = input("Press Enter")
strtTime = time.time()
randVal = random.randint(5, 11)
sensor.output("yled", "on")
time.sleep(5)
sensor.output("yled", "off")
stpTime = time.time()
btnStp = "Button_3"
#Setting up reaction time system to light up "green" if user is fast enough to push a button, but if not, then it'll light up "red"
while True:
if (sensor.input(btnStp) == "pressed"):
totalTime = stpTime - strtTime
if totalTime < 10:
sensor.output("gled", "on")
time.sleep(3)
sensor.output("gled","off")
print("Congrats, you passed!")
else:
sensor.output("rled", "on")
time.sleep(3)
sensor.output("rled", "off")
print("I'm sorry, but you failed to react quick enough!")
break
I have a raspberry PI 2. With a relay board, what i use to for a switch sequence (like a traffic light).
I use a tool, called "webiopi" what create buttons on a website. When the button is clicked the function of the python script below is started.
What i want is to break out of the loop (or pause it) when another button is clicked. However, as long this loop is running, the tool don't look at the webpage
A kind of similar question is asked here Exiting a continuous loop in python via webiopi but this is for a single event and the solution doesn't work in my case.
Question is. How can I make this script look at a button what is clicked (can be a gpio switch as well) while the loop is running
GPIO_nek=11
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
for x in range(0, 20):
GPIO.digitalWrite(GPIO_nek, GPIO.LOW)
time.sleep(interval1)
GPIO.digitalWrite(GPIO_schouder, GPIO.LOW)
time.sleep(interval1)
GPIO.digitalWrite(GPIO_nek, GPIO.HIGH)
time.sleep(interval1)
GPIO.digitalWrite(GPIO_rug1, GPIO.LOW)
time.sleep(interval2)
GPIO.digitalWrite(GPIO_schouder, GPIO.HIGH)
if (GPIO.digitalRead(GPIO_ONOFF) == GPIO.LOW):
GPIO.digitalWrite(GPIO_ONOFF, GPIO.HIGH)
break
When monitoring a real time event such as sensors or your button your best solution will be setting up a separate thread or process that contains nothing but an infinite loop that watches the resource and sets a flag when something interesting happens.
The example below sets up a process that automatically takes a picture on the RPI aprox. every minute.
#!/usr/bin/python
#Threading Prototype - Running a background thread that will take
# pictures at the appropriate time
#------------------------------------------------------------------
from multiprocessing import Queue
from multiprocessing import Process
from time import sleep
from datetime import datetime
from datetime import timedelta
from subprocess import call
#Doing the work ---------------------------------------------------
#Global Variables ---
messages = Queue()
start_time = datetime.now()
#Returns number of Milliseconds since start of program
def milliSinceStart():
global start_time
dt = datetime.now() - start_time
ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
return ms
#Process Methods --------------------------------------------------
def processMessages():
print "Message Processor Launched"
while True:
print messages.get() #should halt until message in queue
sleep(0.1) #sleep for a tick just to avoid a run away process
def processPicutres():
print "Picture Taker Launched"
pictureCycleStart = milliSinceStart()
index = 0
while True:
if milliSinceStart() - pictureCycleStart > 10000: #once a minute
a = "blip" + str(index) + ".jpg"
b = "raspistill -n -t 100 -o " + a
messages.put("Click")
call ([b], shell=True)
messages.put("picture taken - " + b)
index = index + 1
pictureCycleStart = milliSinceStart()
sleep(0.1) #wait a tick -- don't hog processor time
def main():
print "MultiProcessing Prototype"
print "Launching message process"
Process(target=processMessages).start()
print "Back from launch"
print "Launching picture taking process"
Process(target=processPicutres).start()
print "Back from launch"
cycleStart = milliSinceStart()
index = 0
while True:
if milliSinceStart() - cycleStart > 1000:
messages.put("Tick " + str(index))
cycleStart = milliSinceStart()
index = index + 1
if __name__ == "__main__":
main()
The main method launches the Messaging and Picture processes and then sets up its own little infinite loop that does nothing more that display the message "Tick" every second. The picture process sets up a separate infinite loop, watching the clock and taking a picture periodically. The Message process monitors the picture process (again, an infinite loop) and when it detects that a picture has been taken, it outputs the fact to the screen.
The important part of this for your purpose is the message queue. The process queue is what is allowing the Picture and Message processes to communicate.
And because the task take place in different processes, it matters not if one process pauses as the others are always active. If you set up a button monitor process you can be checking message queue for this fact and halting your main program when the button is pressed. This pause in the main program would not effect the button process which could then pick up on the fact that the button is pressed again.
If the button is the GPIO switch as you mentioned at the end of the question, instead of the webpage button, then you can make use of an inbuilt GPIO interrupt function that saves your computer the resouces of constant polling:
import RPi.GPIO as GPIO
from threading import Event # We'll use it like time.sleep, but we can interrupt it.
GPIO_nek=11
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
GPIO.setup(GPIO_ONOFF, GPIO.IN, pull_up_down=GPIO.PUD_UP)
done = False # loop control
timer = Event()
def quit_loop(): # Called by inbuilt threaded interrupt
global done
done = True
timer.set() # Interrupt the waiting
GPIO.add_event_detect(GPIO_ONOFF, GPIO.FALLING, callback=quit_loop, bouncetime=300) # Setup interrupt to call quit_loop
Because you're using this to break out of a loop, you want to shorten that loop to a single process:
tasks = [
(GPIO_nek, GPIO.LOW, interval1),
(GPIO_schouder, GPIO.LOW, interval1),
(GPIO_nek, GPIO.HIGH, interval1),
(GPIO_rug1, GPIO.LOW, interval2),
(GPIO_schouder, GPIO.HIGH, 0) ]
for pin, level, interval in tasks * 20: # Above you ran it 20 times, this notation keeps it in a single loop to break our o
if not done:
GPIO.digitalWrite(pin, level)
timer.wait(interval)
else:
timer.clear()
break
By using the threading Event().wait() and .set() instead of the standard time.sleep() you won't even have to wait for the sleep interval to finish.
This may be simpler than I think but I'd like to create timer that, upon reaching a limit (say 15 mins), some code is executed.
Meanwhile every second, I'd like to test for a condition. If the condition is met, then the timer is reset and the process begins again, otherwise the countdown continues.
If the condition is met after the countdown has reached the end, some code is executed and the timer starts counting down again.
Does this involve threading or can it be achieved with a simple time.sleep() function?
You could probably accomplish it with threading really elegantly but if you need a quick fix you could try
import time
timer = 15 * 60 # 60 seconds times 15 mins
while timer > 0:
time.sleep(0.985) # don't sleep for a full second or else you'll be off
timer -= 1
if someCondition:
timer = 15 * 60
executeCode() # called when time is zero and while loop is exited
If the whole process is as simple as you say, I would go about it like this (semi-psuedo-code):
def run_every_fifteen_minutes():
pass
def should_reset_timer():
pass
def main():
timer = 0
while True:
time.sleep(1)
timer+=1
if should_reset_timer():
timer = 0
if timer == 15*60:
run_every_fifteen_minutes()
timer = 0
Note that this won't be exactly fifteen minutes in. It might be late by a few seconds. The sleep isn't guaranteed to sleep only 1 second and the rest of the loop will take some time, too. You could add a system time compare in there if you need it to be really accurate.
Thanks for the help everyone, your answers pointed me in the right direction. In the end I came up with:
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
import subprocess
GPIO.setmode(GPIO.BCM)
PIR_PIN = 4
GPIO.setup(PIR_PIN, GPIO.IN)
timer = 15 * 60 # 60 seconds times 15 mins
subprocess.call("sudo /opt/vc/bin/tvservice -o", shell=True)
try :
print "Screen Timer (CTRL+C to exit)"
time.sleep(5)
print "Ready..."
while True:
time.sleep(0.985)
# Test PIR_PIN condition
current_state = GPIO.input(PIR_PIN)
if timer > 0:
timer -= 1
if current_state: #is true
# Reset timer
timer = 15 * 60
else:
if current_state: #is true
subprocess.call("sudo /opt/vc/bin/tvservice -p", shell=True)
# Reset timer
timer = 15 * 60
else:
subprocess.call("sudo /opt/vc/bin/tvservice -o", shell=True)
except KeyboardInterrupt:
print "Quit"
GPIO.cleanup()
To put it in context, I'm using a PIR sensor to detect motion and switch on an hdmi connected monitor on a Raspberry Pi. After 15 mins of no movement I want to switch the monitor off and then if (at a later time) movement is detected, switch it back on again and restart the time.
The description sounds similar to a dead main's switch / watchdog timer. How it is implemented depends on your application: whether there is an event loop, are there blocking functions, do you need a separate process for proper isolation, etc. If no function is blocking in your code:
#!/usr/bin/env python3
import time
from time import time as timer
timeout = 900 # 15 minutes in seconds
countdown = timeout # reset the count
while True:
time.sleep(1 - timer() % 1) # lock with the timer, to avoid drift
countdown -= 1
if should_reset_count():
countdown = timeout # reset the count
if countdown <= 0: # timeout happened
countdown = timeout # reset the count
"some code is executed"
The code assumes that the sleep is never interrupted (note: before Python 3.5, the sleep may be interrupted by a signal). The code also assumes no function takes significant (around a second) time. Otherwise, you should use an explicit deadline instead (the same code structure):
deadline = timer() + timeout # reset
while True:
time.sleep(1 - timer() % 1) # lock with the timer, to avoid drift
if should_reset_count():
deadline = timer() + timeout # reset
if deadline < timer(): # timeout
deadline = timer() + timeout # reset
"some code is executed"
What is the best way to repeatedly execute a function every x seconds in Python?
How to run a function periodically in python
Maybe you should look into the Linux tool cron to schedule the execution of your script.