This is my code
It performs keep_click_attendance_link() enter code here function until JustBefore time is reached
and then at EndTime it performs the leave_the_meeting() function
import pyautogui
import time
import pause
import datetime
import schedule
YEAR = 2020
MONTH = 11
DATE = 6
HOUR = 13
MINUTES = 3
SECONDS = 15
now = datetime.datetime.now()
EndTime = now.replace(hour=HOUR, minute=MINUTES, second=SECONDS, microsecond=0)
JustBefore= now.replace(hour=HOUR, minute=MINUTES-1, second=SECONDS, microsecond=0)
def leave_the_meeting():
pyautogui.click(1198, 1072)
time.sleep(3)
pyautogui.click(1443, 998)
time.sleep(1)
pyautogui.click(1398, 933)
def click_attendance_link():
pyautogui.click(1665, 674)
time.sleep(9)
def keep_click_attendance_link():
while datetime.datetime.now() < JustBefore:
click_attendance_link()
# Sleep for 60 secs before trying again
time.sleep(9)
keep_click_attendance_link()
while datetime.datetime.now() < EndTime:
# Sleep for 1 sec intervals:
time.sleep(1)
# eventually Leave the meeting at Endtime
leave_the_meeting()
So what I want is it to stop the function keep_click_attendance_link() when the attendance link is clicked. The teacher sends the link at any random time, so I had to program it to continuously click at that spot until 1 minute before the EndTime which is JustBefore. The meeting is on zoom client not on the web browser.
First of all, don't skip lesson.
Secondly, to do what you intend to do, for educational purpose only, you will need a mechanism to detect whether the button has appeared yet. Since you can't directly communicate with the zoom client, you will need to detect pixel by pixel in the screen and analyze whether the color of that pixel/area is the color for the attendance button.
To do that, you will need to find the color code for your button first. It can be simply done by screen capture and put that in any image processing software, even Paint. After you have your color, you can use Pillow module to analyze that particular spot, more on that here.
After the checking mechanism is done, you can integrate that into your code and stop the function execution once the button has been detected.
def check_attendance_link_presence():
# check it here
pass
def keep_click_attendance_link():
clicked = False
while datetime.datetime.now() < JustBefore and not clicked:
presence = check_attendance_link_presence()
if presence:
click_attendance_link()
clicked = True
# Sleep for 60 secs before trying again
time.sleep(60)
p.s. I intentionally not to include the code for the presence checking here for the sake of encouraging you to spend time learning it while you are "taking a break" from your lessons.
Maybe: Define a variable something like clicked = False, and in the attendance function set it to True. Then modify the While in the other function with an and clicked == False. So your while cycle only loops till the clicked flag is False, but after it clicked the attendance, it'll change to True, and the cycle stops.
I think it would be more elegant with callbacks tough.
Related
What I want to achieve here is that when I press * the program should wait for 17 seconds before doing anything else and if I don't press anything it can continue pressing the ] key every 11 seconds. The problem here is that if I were to press the * while we are in any time.sleep period, the press of the key will not go through.
import pyautogui
import time
import keyboard
while not keyboard.is_pressed('*'):
if keyboard.is_pressed('*'):
time.sleep(17)
else:
time.sleep(11)
pyautogui.press(']')
There are a lot of ways to accomplish this.
One of the simpler (but certainly not best) ways is to sleep in shorter increments (say 0.1 sec) to wake up periodically and poll the keyboard. You would track in a variable the system time at which point you are done "waiting" and break out of your loop at that point.
This works for me
import pyautogui
import time
import keyboard
last_star_press = 0 # initialize variable to keep track of time of last * press
while True:
if keyboard.is_pressed('*'):
last_star_press = time.time() # update time of last * press
time.sleep(17)
else:
if time.time() - last_star_press >= 11:
pyautogui.press(']')
last_star_press = time.time() # update time of last key press
time.sleep(1) # add a small delay to reduce CPU usage
I am at a very beginner level with Python and I have a simple project for myself. My goal is to build a simple timer with only two functions using tkinter and python. The first button starts the countdown timer at 30 seconds. And the second button stops it. However, I would like each additional press of the first button to add an additional 30 seconds to whatever time is currently left on the countdown clock. The first two elements have proven not too difficult using this prior thread, but adding additional time to the active timer is something I cannot reach.
Essentially, the goal is to recreate the functionality of the "+30 seconds" button on a microwave, with an updating display, where the initial press both adds 30 seconds and starts the timer, each subsequent press adds an additional 30 seconds to the countdown timer, and the second button stops the timer.
Here's what I've been using for the basic timer logic.
def countdown(t=30):
while t:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
print(timer, end="\r")
time.sleep(1)
t -= 1
print('Done!')
The problem is a little bit more complex than it appears for the following reasons:
If you are not using any library for parallel events, then, the function countdown() will block the main loop and you will not be able to do anything (including click the button again to add more time) while the countdown is running
If you want to add time with the same button, you have to check if there's already a countdown print on screen, if you don't check it, for each click a new clock will appear.
I suggest to use asyncio lib as follow:
import asyncio
# Create a global variable for the time
secs = 0
#This function adds +30secs
def addTime():
global secs
secs+=30
#This is the func that gather the addTime function and the async clock
async def timerAction():
#This "while" is used to simulate multiple cliks on your button.
# If you implement this as a callback delete the "while"
while True:
j = 0 #Counter if a clock is already running
addTime() #Add time
for task in asyncio.all_tasks(): #This loop checks if there's a countdown already running
if task.get_name()=='countdown':
j+=1
if j == 0: #If no running countdown, j==0, and fires the countdown
taskCountdown = asyncio.create_task(countdown(), name='countdown')
await asyncio.sleep(10) #Wait 10secs between each call to the func (each call simulate a click)
async def countdown():
global secs
while secs>0:
mins, secs = divmod(secs, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
print(timer, end="\r")
await asyncio.sleep(1)
secs -= 1
print('Done!')
asyncio.run(timerAction())
Output:
On the fisrt call:
00:30
after 10secs:
00:50
after 10secs:
01:10
and so on...
My use case is, I'm using pynput/Python to make a reaction time registration application. The essence is that someone will press a control key to mark the first time epoch, and then the reactor hits any other key, and the time difference between the two keystrokes will be computed and displayed.
In order to alert the reactor to press a key, I am playing a tone that is about 1 second long when the initiator releases their key. However, since reaction time is on the order of milliseconds, I don't want them to have to wait for the tone to complete to press the button as they currently must, or even initiate a new set of two keystrokes. As soon as the sound fires, you should be free to press more keys.
In this sense, I can't figure out how to make the events non-blocking. Using the listener.start() paradigm doesn't seem to help me here. Code is below:
from pynput import keyboard
from datetime import datetime
from playsound import playsound
INITIATE = {keyboard.Key.enter}
def on_press(key):
global initiated_time
pressed_time = None
reaction_time = None
if key in INITIATE:
initiated_time = datetime.now()
return initiated_time
else:
pressed_time = datetime.now()
reaction_time = pressed_time - initiated_time
reaction_time_ms = int(reaction_time.seconds) * 1000 + int(reaction_time.microseconds)/1000
print('Reaction time %s ms' % (reaction_time_ms))
def on_release(key):
if key in INITIATE:
playsound('bong.mp3')
print('')
with keyboard.Listener(
on_press=on_press,
on_release=on_release
) as listener:
listener.join()
According to the docs here, playsound has a default argument, block, which will play the sound asynchronously if set to False, meaning it will not prevent your script from continuing to run.
This is a really simple question, and I don't know why I haven't got the answer to it, but does anyone know how to correctly add a timer in pygame for Python 3.4.1?
Here's what I have so far:
texta = font.render("Time:"+str(time), True, black)
screen.blit(texta, [500,100])
I have read solutions using loops and many others, but none have worked so far. I want a timer to be displayed on the screen and count the seconds it takes for the user to perform a certain task.
Here is a timer you can use
import pygame, sys
from pygame.locals import *
clock = pygame.time.Clock()
time = 0 #In Seconds
#GameLoop
while True:
milli = clock.tick() #clock.tick() returns how many milliseconds passed since the last time it was called
#So it tells you how long the while loop took
seconds = milli/1000.
time += seconds
print time #So you can see that this works
You can use jues velarde's code above and just print the time variable onto to your pygame surface using
font = pygame.font.Font(YourFont, YourSizeOfText)
text = font.render(str(time), 1, (YourColour)) # The time variable being in jues's code
DISPLAYSURF.blit(text, (YourXValue, YourYValue)
and you would just call this code in a loop when you want too, in your case, when you want to begin timing the user's task, But remember to run jues's code in your program as well so this will work.
Hope i helped!
I want to have a delay between firing bullets for my character. I used to do this before in Java like:
if (System.currentTimeMillis() - lastFire < 500) {
return;
}
lastFire = System.currentTimeMillis();
bullets.add(...);
However, how can I do this in pygame way, in order to get that sys currentTimeMillis.This is how my run (game loop) method looks like:
time_passed = 0
while not done:
# Process events (keystrokes, mouse clicks, etc)
done = game.process_events()
# Update object positions check for collisions...
game.update()
# Render the current frame
game.render(screen)
# Pause for the next frame
clock.tick(30)
# time passed since game started
time_passed += clock.get_time()
As you can see in the previous code, I have created time passed, but I'm not sure if that is correct way of code order, and what else im missing.
Your code is fine, if game.process_events and game.update works as expected.
Edit:
Use pygame.time.get_ticks instead of the clock I mentioned earlier. It was using python's time module, so that clock and clock in your code meant different clocks. This is much better way.
#this should be done only once in your code *anywhere* before while loop starts
newtime=pygame.time.get_ticks()
# when you fire, inside while loop
# should be ideally inside update method
oldtime=newtime
newtime=pygame.time.get_ticks()
if newtime-oldtime<500: #in milliseconds
fire()
Let me explain you what pygame.time.get_ticks() returns:
On first call, it returns time since pygame.init()
On all later calls, it returns time (in milliseconds) from the first call to get_ticks.
So, we store the oldtime and substract it from newtime to get time diff.
Or, even simpler, you can use pygame.time.set_timer
Before your loop:
firing_event = pygame.USEREVENT + 1
pygame.time.set_timer(firing_event, 500)
Then, an event of type firing_event will be posted onto the queue every 500 milliseconds. You can use this event to signal when to fire.