Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Solved]Help with Threading
#1
Hello,

I am trying to get my program to have a reminders function where I can ask it to remind me to do stuff & after a certain amount of time it will remind me about the thing I told it to remind me about.

The only problem I have is that while it's waiting to remind me about the reminder, I would like to still use my program.
Right now, I can set a reminder but it will lock me out of the program until the reminder pops up.

How do I fix it so once the reminder is set I can still use my program & after the specified amount of time, the reminder will just print to the terminal?

Thanks in advance.

Snippet:
    #-------------------------------------------------------------------------------------
    #                               Set Reminders
    #-------------------------------------------------------------------------------------
    if ('remind me' in command):
        command = command.replace("remind me", "")    
        autoTypeAnimation("Ok, I will remind you" + command)
        import threading
        t =  threading.Thread(target=waiting(command))
        t.start()


def waiting(command):
    print("Reminder Set")
    # Wait 5s then bring up reminder
    time.sleep(5)
    autoTypeAnimation("FYI: I was told to remind you" + command)
Full code:
#-------------------------------------------------------------------------------------
#                                  Imports
#-------------------------------------------------------------------------------------
import json
import random
import datetime
import operator
import os
import subprocess
import time
import sys
import webbrowser
import requests
from bs4 import BeautifulSoup
import wikipedia
import wolframalpha
import pywhatkit
 

from BX_Intents import (greetings, farewell, thanks, noAnswer)
from BX_External_Functions import (autoTypeAnimation, StartupText, ShutdownText, 
                                    UserInput, listen, speak)
#-------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------
#                           Commander Name (You) and A.I Name
#-------------------------------------------------------------------------------------
Commander = "Commander"
AI_Name = 'Baxter'
#-------------------------------------------------------------------------------------

#-------------------------------------------------------------------------------------
#                                  WishMe Function
#-------------------------------------------------------------------------------------
def wishMe():
    hour = int(datetime.datetime.now().hour)
    if hour>=0 and hour<12:
        speak("Good Morning" + Commander)
    elif hour>=12 and hour<18:
        speak("Good Afternoon" + Commander)   
    else:
        speak("Good Evening" + Commander) 
#-------------------------------------------------------------------------------------


#-------------------------------------------------------------------------------------
#                                       Main
#-------------------------------------------------------------------------------------
def BAXTER():
    command = UserInput() #Take user input from terminal
    command=str(command).lower()

    #-------------------------------------------------------------------------------------
    #                       General Conversation (From Intents.py) 
    #-------------------------------------------------------------------------------------
    #Greetings
    patterns, responses = greetings()
    if (command in patterns):
        results = (random.choice(responses))
        autoTypeAnimation(results) #Print results to terminal
        speak(results)

    #Farewell
    patterns, responses = farewell()
    if (command in patterns):
        results = (random.choice(responses))
        autoTypeAnimation(results)
        speak(results)
    
    #Thanks
    patterns, responses = thanks()
    if (command in patterns):
        results = (random.choice(responses))
        autoTypeAnimation(results)
        speak(results)
    
    #No Response
    patterns, responses = noAnswer()
    if (command in patterns):
        results = (random.choice(responses))
        autoTypeAnimation(results)
        speak(results)
    
    #-------------------------------------------------------------------------------------
                            #Search Wikipedia (General Info)
    #-------------------------------------------------------------------------------------
    if ('weather' not in command):
        if ('who is' in command) or ('what is the' in command) or ('what is a' in command) or ("what is" in command):
            if ('time' not in command):
                if ('news' not in command):
                    speak('Searching...')
                    command = command.replace("who is","")
                    command = command.replace("what is the","")
                    command = command.replace("what is a","")
                    command = command.replace("what is","")
                    results = wikipedia.summary(command, sentences = 2)
                    autoTypeAnimation(results)
                    speak(results) 
                    
    #-------------------------------------------------------------------------------------
                    #Search Wolfram Alpha (Math/Conversions, Definitions)
    #-------------------------------------------------------------------------------------
    if ('news' not in command):
        if ('weather' in command) or ('calculate' in command) or ("what's" in command) or ('define' in command) or ("what" in command):
                speak('Searching...')
                command = command.replace("calculate","")
                command = command.replace("what's","")
                command = command.replace("define","")
                # Wolframalpha App Id
                appId = 'JH9XHR-W9J76L7H5A'
                # Wolfram Instance
                client = wolframalpha.Client(appId)
                res = client.query(''.join(command))
                results = next(res.results).text
                autoTypeAnimation(results)
                speak(results)

    #-------------------------------------------------------------------------------------
                            #Open Stuff on the Internet
    #-------------------------------------------------------------------------------------
    #Open Youtube Videos (Ex: 'Play __ on youtube')
    if ('youtube' in command):
        autoTypeAnimation("Launching Youtube...")
        speak('Launching Youtube')
        command = command.replace("youtube","")
        pywhatkit.playonyt(command)

    #Open Google Maps and Find The Location of A You Want
    if ('where is' in command):
        command = command.replace("where is","")
        autoTypeAnimation("Locating" + command + "...")
        speak('Locating' + command)
        webbrowser.open_new_tab("https://www.google.com/maps/place/" + command)

    #Search Stuff on Google
    if ('search' in command):
        command = command.replace("search", "")
        autoTypeAnimation("Searching" + command + " on Google")
        speak('Searching' + command)
        pywhatkit.search(command)
    
    #Close Firefox
    if ('close firefox' in command):
        autoTypeAnimation("Terminating Firefox...")
        speak('Closing Firefox')
        command = command.replace("close firefox", "")
        browser = "firefox.exe"
        os.system("taskkill /f /im " + browser)   

    #-------------------------------------------------------------------------------------
                            #Open Stuff on the Computer
    #-------------------------------------------------------------------------------------
    #Open Windows Media Player and Auto Play the Playlist Called Music
    if ('play music' in command) or ('media player' in command) or ('drop the needle' in command):
        autoTypeAnimation("Launching music...")
        speak("Launching Music")
        command = command.replace("play music", "")
        command = command.replace("media player", "")
        command = command.replace("drop the needle", "") 
        subprocess.Popen("C:\Program Files (x86)\Windows Media Player\wmplayer.exe /Playlist Music")

    #Close Windows Media Player
    if ('stop music' in command):
        autoTypeAnimation("Terminating music...")
        speak('Closing Music')
        command = command.replace("stop music", "")
        mediaPlayer = "wmplayer.exe"
        os.system("taskkill /f /im " + mediaPlayer)   

    #-------------------------------------------------------------------------------------
    #                               Set Reminders
    #-------------------------------------------------------------------------------------
    if ('remind me' in command):
        command = command.replace("remind me", "")    
        autoTypeAnimation("Ok, I will remind you" + command)
        import threading
        t =  threading.Thread(target=waiting(command))
        t.start()
        #autoTypeAnimation("FYI: I was told to remind you" + command)


    #-------------------------------------------------------------------------------------
                            #Stop Program/Script Command
    #-------------------------------------------------------------------------------------
    if ('stop' in command) or ('shutdown' in command) or ('quit' in command):
        speak("Shutting Down...")
        results = "Terminating program..."
        autoTypeAnimation(results)
        ShutdownText()
        exit()
    #-------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------

def waiting(command):
    print("Reminder Set")
    # Wait 5s then bring up reminder
    time.sleep(5)
    autoTypeAnimation("FYI: I was told to remind you" + command)

#------------------------------------------------------------------------------------------
#                                   Run The Program
#------------------------------------------------------------------------------------------
StartupText()
wishMe()
speak("How may I be of service?") 

while True:
    BAXTER()
#------------------------------------------------------------------------------------------
Reply
#2
I would use threading.Timer instead of threading.Thread. No need to call time.sleep(). The Timer will run a function after a given time interval.
Reply
#3
If I do this t = threading.Timer(5,waiting(command)) to try and pass the command to my waiting() it ignores the 5sec timer:
    #-------------------------------------------------------------------------------------
    #                               Set Reminders
    #-------------------------------------------------------------------------------------
    if ('remind me' in command):
        command = command.replace("remind me", "")    
        autoTypeAnimation("Ok, I will remind you" + command)
        import threading
        t = threading.Timer(5,waiting(command))
        t.start()

def waiting(command):
    print("Reminder Set")
    # Wait 5s then bring up reminder
    # time.sleep(5)
    autoTypeAnimation("FYI: I was told to remind you" + command)
& it will throw this error:
Error:
Commander: Exception in thread Thread-1: Traceback (most recent call last): File "C:\Users\BX-PC\AppData\Local\Programs\Python\Python39\lib\threading.py", line 973, in _bootstrap_inner self.run() File "C:\Users\BX-PC\AppData\Local\Programs\Python\Python39\lib\threading.py", line 1286, in run self.function(*self.args, **self.kwargs) TypeError: 'NoneType' object is not callable
But if I do (don't pass the command to the waiting()):
    #-------------------------------------------------------------------------------------
    #                               Set Reminders
    #-------------------------------------------------------------------------------------
    if ('remind me' in command):
        command = command.replace("remind me", "")    
        autoTypeAnimation("Ok, I will remind you" + command)
        import threading
        t = threading.Timer(5,waiting)
        t.start()

def waiting():
    print("Reminder Set")
    # Wait 5s then bring up reminder
    # time.sleep(5)
    autoTypeAnimation("FYI: I was told to remind you")
It works as intended.

Is there any way to have it so I can pass the command value to the waiting function & have it work properly?
Reply
#4
(Sep-04-2022, 08:12 PM)Extra Wrote: t = threading.Timer(5,waiting(command))
Use
t = threading.Timer(5, waiting, args=(command,))
Reply
#5
Thanks, that worked!
Reply
#6
One more quick question:

How do I stop the threading.timer once the program exits?

I tried usingt.cancel()
    #-------------------------------------------------------------------------------------
    #                               Set Reminders
    #-------------------------------------------------------------------------------------
    if ('remind me' in command):
        command = command.replace("remind me", "")
        autoTypeAnimation("In how many hours should I remind you" + command +"?")
        remindTime = UserInput()   
        remindTimerMinutes = float(remindTime)*60 #Sec->Min
        remindTimerHours = remindTimerMinutes*60 #Min->Hrs
        autoTypeAnimation("Ok, I will remind you" + command + " in " + str(remindTime) + " hours")
        t = threading.Timer(remindTimerHours, reminderWait, args=(command,))
        t.start()
    
    #-------------------------------------------------------------------------------------
    #                       Stop Program/Script Command
    #-------------------------------------------------------------------------------------
    if ('stop' in command) or ('shutdown' in command) or ('quit' in command):
        speak("Shutting Down...")
        results = "Terminating program..."
        autoTypeAnimation(results)
        ShutdownText()
        t.cancel()
        exit()
    #-------------------------------------------------------------------------------------
But get this error and the reminder still waits & pops up even when I stop the code :
Error:
line 256, in BAXTER t.cancel() UnboundLocalError: local variable 't' referenced before assignment Baxter: Reminder Alert! I was told to remind you to do stuff
Is there any way to cancel the threading.timer when the program exits?
Reply
#7
Your create timer code is inside a function. The "t" variable is local to the function and is not visible to the code that cancels the timer. This doesn't matter because you don't need to keep track of active timers. Threading keeps track of timers for you.
import threading
from time import sleep

def printit(msg):
  print(msg)

# Make a bunch of timers
for i in range(10):
  threading.Timer(i, printit, args=(str(i),)).start()

# Let a few expire
sleep(3)

# Cancel all the rest
for timer in threading.enumerate():
  if isinstance(timer, threading.Timer):
    print(timer)
    timer.cancel()
Output:
0 1 2 3 <Timer(Thread-5, started 2628)> <Timer(Thread-6, started 14644)> <Timer(Thread-7, started 4544)> <Timer(Thread-8, started 3752)> <Timer(Thread-9, started 14668)> <Timer(Thread-10, started 13564)>
Your time seems backwards to me. The user enters a time in hours, which you convert to seconds. But "remindTimerHours" is a time in seconds, not a time in hours. The time in hours is in remindTime. remindTimerMinutes is correctly named. Totally unnecessary, but correctly named. I know this is nitpicking but using good variable and function names goes a long way in making code easier to understand. Your project is likely to be several files and hundreds of lines of code when done. It will be a lot easier to maintain and modify if you take time to write good code from the start.
    remindTime = UserInput()   
    remindTimerMinutes = float(remindTime)*60 #This is hours to minutes
    remindTimerHours = remindTimerMinutes*60 #This is minutes to seconds
I would do it this way:
    remindTimerHours = UserInput() 
    remindTime = float(remindTimerHours) * 3600
Or maybe opt for a more natural way of entering a time. How many hours is 10 minutes? 0.16?
def hms2seconds(timestr):
    """Convert timestr string to seconds.
    valid timestr formats are Hours:Minutes:Seconds, Minutes:Seconds, Seconds
    """
    t = 0
    for value in map(float, timestr.split(":")):
        t = t * 60 + value
    return t
    

while True:
    timestr = input("Enter wait time (H:M:S) ")
    if not timestr:
        break
    try:
        print(hms2seconds(timestr))
    except ValueError:
      print("Not a valid time string")
Gribouillis and Extra like this post
Reply
#8
Thanks! This helped out a lot! It now works properly.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Concurrent futures threading running at same speed as non-threading billykid999 13 1,989 May-03-2023, 08:22 AM
Last Post: billykid999
  Tutorials on sockets, threading and multi-threading? muzikman 2 2,161 Oct-01-2021, 08:32 PM
Last Post: muzikman

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020