I had to fetch live chat on Youtube and chose to use pytchat instead of Youtube API. There's no problem to fetch the chat, but it was a bit slow.
from pytchat import LiveChat
from datetime import datetime
chat = LiveChat(video_id = "36YnV9STBqc")
k=[]
while chat.is_alive():
now2 = datetime.now()
current_time2 = now2.strftime("%H:%M:%S")
print("Current Time =", current_time2,"==========") #A
try:
data = chat.get()
now3 = datetime.now()
current_time3 = now3.strftime("%H:%M:%S")
print("Current Time =", current_time3,"~~~~~~~~~~~~~") #B
for c in data.items:
comment=f"[{c.datetime}-{c.message}]"
k.append(comment) #I need to use k later
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print(comment,"Current Time =", current_time,"++++++++++++++++")
data.tick()
except KeyboardInterrupt:
chat.terminate()
break
Below shows the output of a video with 17,649 watching: (B to A took 5 secs)
Current Time = 18:49:33 ========== #A
Current Time = 18:49:33 ~~~~~~~~~~~~~ #B
[2020-05-30 18:49:29-hi] Current Time = 18:49:33 ++++++++++++++++ #4 seconds late
[2020-05-30 18:49:32-how are you] Current Time = 18:49:36 ++++++++++++++++
Current Time = 18:49:38 ========== #A
Current Time = 18:49:38 ~~~~~~~~~~~~~ #B
[2020-05-30 18:49:32-so good] Current Time = 18:49:38 ++++++++++++++++ #6 seconds late
Below shows the output of a video with 702 watching: (B to A took at least 10 secs)
Current Time = 18:49:09 ========== #A
Current Time = 18:49:10 ~~~~~~~~~~~~~ #B
[2020-05-30 18:49:06-hellp] Current Time = 18:49:10 ++++++++++++++++
[2020-05-30 18:49:07-love the music] Current Time = 18:49:15 ++++++++++++++++
Current Time = 18:49:20 ========== #A
Current Time = 18:49:20 ~~~~~~~~~~~~~ #B
[2020-05-30 18:49:15-???] Current Time = 18:49:20 ++++++++++++++++
I assume that different watching amounts will effect the time? It's also 4 to 6 secs late to fetch every chat, is it possible to solve it? Or it's just how Pytchat works?
This is a specification.
Pytchat gets the chat in exactly the same way as the browser.
If your browser displays the time of the chat and the current time down to the second, you'll get the same results.
The response of the YouTube server is presumably affected by the number of people watching the chat and the number of people posting the chat at any given time.
It needs to be verified, but as you pointed out, I'm guessing that if a lot of chat posts are made, it's taking longer for the YouTube server to process them and return the chats that are retrieved.
(If you comment out the data.tick(), you might get a little better results.)
Use
while chat.is_alive():
data = chat.get()
for c in data.sync_items():
#c can then be formatted for ur stuff
print("Formatting stuff")
sync_items() will give you appropriate realtime chat movement.
Related
I have made a trading expert that goes through candlesticks to check if a signal has been found then execute buy , sell orders
for i in range (len(df['Open'])) :
if some logic :
buy or sell
Now I want this expert to work on real-time data, not a historical one and I struggle with making the logic on how it'd work
what I want to do is:
Looking for the last 30 bars then make some calculations on them, then
go in a loop to check the last 2 candlesticks to see if some signal
has been found
..I want the loop to work every 4 hours since I'm working on 4h
timeframe, so with every new candlestick
I'm trying to use MetaTrader5 library
copy_rates_from_pos(
symbol, // symbol name
timeframe, // timeframe
start_pos, // initial bar index
count // number of bars
)
this code would help me find the last 30 bars but still can't get my head around on how to make the for loop !
you could use something like this
import pytz
import pandas as pd
import MetaTrader5 as mt5
import time
from datetime import datetime
from threading import Timer
server_name = "AMPGlobalUSA-Demo"
server_num = # your server num
password = # password
#------------------------------------------------------------------------------
def actualtime():
# datetime object containing current date and time
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
#print("date and time =", dt_string)
return str(dt_string)
#------------------------------------------------------------------------------
def sync_60sec(op):
info_time_new = datetime.strptime(str(actualtime()), '%d/%m/%Y %H:%M:%S')
waiting_time = 60 - info_time_new.second
t = Timer(waiting_time, op)
t.start()
print(actualtime(), f'waiting till next minute and 00 sec...')
#------------------------------------------------------------------------------
def program(symbol):
if not mt5.initialize(login=server_num, server=server_name, password=password):
print("initialize() failed, error code =",mt5.last_error())
quit()
timezone = pytz.timezone("Etc/UTC")
utc_from = datetime.now()
######### Change here the timeframe
rates = mt5.copy_rates_from(symbol, mt5.TIMEFRAME_M1, utc_from, 70)
mt5.shutdown()
rates_frame = pd.DataFrame(rates)
rates_frame['time']=pd.to_datetime(rates_frame['time'], unit='s')
# If you want to work only with open, high, low, close you could use
#rates_frame = rates_frame.drop(['tick_volume', 'real_volume'], axis=1)
print(f"\n", actualtime(),f"|| waiting for signals {symbol} ||\n")
if not mt5.initialize():
print("initialize() failed, error code =",mt5.last_error())
quit()
point = mt5.symbol_info(symbol).point
price = mt5.symbol_info_tick(symbol).ask
request = {
"action": mt5.TRADE_ACTION_PENDING,
"symbol": symbol,
"volume": 1.0,
"type": mt5.ORDER_TYPE_BUY_LIMIT,
"price": price,
"sl": price + 40 * point,
"tp": price - 80 * point,
"deviation": 20,
"magic": 234000,
"comment": "st_1_min_mod_3",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_RETURN,
}
condition_buy_1 = (
(rates_frame.close.iloc[-2] > rates_frame.open.iloc[-2])&
(rates_frame.close.iloc[-2] > rates_frame.close.iloc[-3])
)
if condition_buy_1:
#result = mt5.order_send(request)
print('Sending Order!')
# Im using AMPGlobalUSA-Demo Server
# starting mt5
if not mt5.initialize(login=server_num, server=server_name, password=password):
print("initialize() failed, error code =",mt5.last_error())
quit()
#------------------------------------------------------------------------------
# S T A R T I N G M T 5
#------------------------------------------------------------------------------
authorized=mt5.login(server_num, password=password)
if authorized:
account_info=mt5.account_info()
if account_info!=None:
account_info_dict = mt5.account_info()._asdict()
df=pd.DataFrame(list(account_info_dict.items()),columns=['property','value'])
print("account_info() as dataframe:")
print(df)
else:
print(f"failed to connect to trade account {server_num} with password={password}, error code =",mt5.last_error())
mt5.shutdown()
#------------------------------------------------------------------------------
def trading_bot():
symbol_1 = 'EURUSD'
symbol_2 = 'EURCAD'
while True:
program(symbol_1)
program(symbol_2)
time.sleep(59.8) # it depends on your computer and ping
sync_60sec(trading_bot)
Here you have the basics how to connect and operate with Python and MT5. You can save it as py file. And you have the first script looking for signals in 1 min chart for your symbol. You could have two different scripts mor looking for signals in 5 and 15 min charts, (program_5min.py and program_15min.py). You should then, add a new sync function. For example, for 5 minutes you have to wait for one hour and 0,5,10,15 minutes and so one.
Hope it works for you, have fun!
Hello i have a Person Detector script i want to send an info if any person detected by mail.In order to prevent mail spamming i need a timer for sendMail function.Function might be triggered anytime but it will only respond if its not on cooldown.
I tried using async task but couldn't implemented because if a person detected it goes to a loop where it sends email every 5 minutes even if there isn’t any person detected after the first sight.
Example:
Person detection script is running.
Person detected on camera -> Send an email(start the 5 minute cooldown)
Person sighted again after 2 minutes(didn't send any email because there is still 3 minutes cooldown).
Person sighted after 6 minutes send another email(because 5 minute cooldown is over).
Summary of my code.(Necessary parts only detection and sending mail works cooldown (timer) doesn't work
async def sendAlert():
server.sendmail(sender_email, receiver_email, message)
print('sent!')
await asyncio.sleep(300)
if __name__ == "__main__":
while True:
for i in range(len(boxes)):
if classes[i] == 1 and scores[i] > threshold:
with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
sendAlert(server)
box = boxes[i]
cv2.rectangle(img,(box[1],box[0]),(box[3],box[2]),(255,0,0),2)
If there is a person detected, script will send an alert by email.Afterwards if a person detected again in 5 minutes sendAlert function shouldn't respond until 5 minutes passed
I agree with #Prune that you need to create a small (minimal) use-case and present your code so that it is not only relevant to you, but also relevant to others. Additionally, your question should have a section with a verifiable example. Without these attributes, your question becomes hard for people to grasp, solve and/or suggest any verifiable solution.
However, as I understand, you have some action (sending email if a person is detected) that you would like to perform after certain cool-off period. So, in other words, you want a mechanism of keeping track of time. Hence, you would need the datetime library.
So, your pseudo code should look something like this:
Pseudo Code
import datetime
start = capture_timestamp()
cutoff = '00:05:00'
dt_cutoff = read_in_cutoff_as_timedelta(cutoff)
if person_detected:
now = capture_timestamp()
dt = now - start
if dt >= dt_cutoff:
# Send notification
send_email_notification()
else:
# Do not Send Notification
print('now: {} | dt: {}'.format(now, dt))
You could use datetime.datetime.utcnow() for timestamp. And datetime.timedelta() for defining dt_cutoff. For reading in a time-string as time you could do this:
tm = datetime.datetime.strptime(cutoff).time()
dt_cutoff = datetime.timedelta(hours = tm.hour, minutes = tm.minute, seconds = tm.second)
I hope this gives you some idea about how to model this.
Additional Resources
https://www.guru99.com/date-time-and-datetime-classes-in-python.html
https://docs.python.org/3/library/datetime.html
https://thispointer.com/python-how-to-convert-a-timestamp-string-to-a-datetime-object-using-datetime-strptime/
Complete Solution
Now, finally if you are in a hurry to use a ready made solution, you may use the following class object as shown. All you would need is to instantiate the class object by specifying your cool-off-period (timer_cutoff) and then call the method is_timeout(). If this returns True, then you send your notification. There is also an obj.istimeout attribute which stores this decision (True/False).
import time
# Set cutoff time to 2 seconds to test the output
# after 5 seconds: expect istimeout = True
# and instantiate the TimeTracker class object.
ttk = TimeTracker(timer_cutoff = '00:00:02') # 'HH:MM:SS'
# Wait for 3 seconds
time.sleep(3)
print('start timestamp: {}'.format(ttk.timestamp_start_str))
print('cutoff timestamp'.format(ttk.timestamp_cutoff_str))
print('timer_cutoff: {}'.format(ttk.timer_cutoff_str))
# Now check if cutoff time reached
ttk.is_timeout()
print('Send Notification: {}'.format(ttk.istimeout))
print('now_timestamp: {}'.format(ttk.timestamp_now_str))
class TimeTracker
Here is the class TimeTracker class:
import datetime
class TimeTracker(object):
def __init__(self,
timer_cutoff = '00:05:00',
cutoff_strformat = '%H:%M:%S'):
self.timer_cutoff_str = timer_cutoff
self.cutoff_strformat = cutoff_strformat
self.timestamp_start, self.timestamp_start_str = self.get_timestamp()
self.dt_cutoff = None # timedelta for cutoff
self.timestamp_cutoff = None
self.timestamp_cutoff_str = None
self.update_timestamp_cutoff()
self.timestamp_now = None
self.timestamp_now_str = None
self.dt_elapsed = None
self.istimeout = False
def get_timestamp(self):
ts = datetime.datetime.utcnow()
tss = str(ts)
return (ts, tss)
def readin_cutoff_as_timedelta(self):
td = datetime.datetime.strptime(self.timer_cutoff_str,
self.cutoff_strformat)
tdm = td.time()
self.dt_cutoff = datetime.timedelta(hours = tdm.hour,
minutes = tdm.minute,
seconds = tdm.second)
def update_timestamp_cutoff(self):
self.readin_cutoff_as_timedelta()
self.timestamp_cutoff = self.timestamp_start + self.dt_cutoff
self.timestamp_cutoff_str = str(self.timestamp_cutoff)
def time_elapsed(self):
self.dt_elapsed = self.timestamp_now - self.timestamp_start
def is_timeout(self):
self.timestamp_now, self.timestamp_now_str = self.get_timestamp()
self.time_elapsed()
if (self.dt_elapsed < self.dt_cutoff):
self.istimeout = False
else:
self.istimeout = True
return self.istimeout
I need to figure out if a service should be stopped or started given a start and stop time
e.g.
start_time = '16:00'
stop_time = '7:50'
if the time now is 16:50 the service should be running, if time now is 14:00, service should be stopped
start_time = '7:00'
stop_time = '20:00'
if the time now is 7:05 the service should be running, if the time is 21:00, the service should be stopped... you get the idea
so far I have this, but can't figure out the logic ;
import datetime
def test_time(start_time, stop_time):
now = datetime.datetime.now()
current_hour = int(now.hour)
current_minute = int(now.minute)
start_hour, start_minute = start_time.split(':')
stop_hour, stop_minute = stop_time.split(':')
print(f"hour: {current_hour}, minute: {current_minute}")
Use datetime to convert your text times to times. This gives you an interval during which the service should be on. If that period wraps around midnight, then split it into two intervals.
Then, simply check to see whether the current time is within the on period or off period; also check the status of the service. If the two don't match, then start/stop the service.
def sync_service(start_time, stop_time):
# start_time and stop_time are "datetime" items.
service_on = # Check status of service; return boolean
now = datetime.datetime.now()
# If interval wraps around midnight, then switch times
# to check when service is *off*
wrap_interval = stop_time < start_time
if wrap_interval:
start_time, stop_time = stop_time, start_time
# Should the service be on now?
# Check whether we're within the daily interval,
# and what type of interval we have (on or off)
want_service_on = wrap_interval != (start_time < now < stop_time)
# Adjust service status, if necessary
if want_service_on and not service_on:
service.start()
if not want_service_on and service_on:
service.stop()
Does that get you going?
I’m trying to make code run a minute before sunrise, but since updating the code (via another question) as I’ve changed time zones from GMT, I’m having trouble getting the syntax right when removing one minute.
sunriselessonemin = (ephem.date(sunrise)) + (1*ephem.minute)
Sunrise is obtained by
sunrise, sunset = ephem.localtime(home.next_rising(sun)),ephem.localtime(home.next_setting(sun))
Can anyone help a noob?
Merci
Edited to be more clearer:-)
Here is my original code. The raspberry pi i use reboots via crontab at 4am, on starting, this script runs. It ran fine in the UK, but now im not in that time zone, i needed to add in some local timezone work as per brandons previous advice.
import sys
import os
import time
import ephem
#find time of sun rise and sunset
sun = ephem.Sun()
home = ephem.Observer()
home.lat, home.lon = '45.226691', '0.013133' #your lat long
sun.compute(home)
sunrise, sunset = ephem.localtime(home.next_rising(sun)),ephem.localtime(home.next_setting(sun))
daylightminutes = (sunset - sunrise) * 1440 # find howmany minutes of daylight there are
sunriselessonemin = ephem.date(sunrise + 1*ephem.minute)
print "prog started at(home.date) = %s" %(home.date)
print "datetime = %s" % time.strftime("%Y/%-m/%-d %H:%M:%S")
print "sunrise = %s" %sunrise
print "sunset = %s" %sunset
print "daylight mins = %s" %(daylightminutes)
testmode = "yes" #yes or no
def dostuff() :
if testmode == "yes" or sunrise <= ephem.now() <= sunriselessonemin: #if time now is within a minute of sunrise, start taking pictures
print "it's sunrise!"
if testmode == "yes" :
print "TESTMODE - Taking 10 images with 10 seconds in between and uploading made mp4 to Dropbox"
FRAMES = daylightminutes # number of images you want in timelapse video
if testmode == "yes" :
FRAMES = 10
FPS_IN = 8 # number of images per second you want in video
FPS_OUT = 8 # number of fps in finished video 24 is a good value
TIMEBETWEEN = 60 # number of seconds between pictures, 60 = 1 minute
#take the pictures needed for the time lapse video
if testmode == "yes" :
TIMEBETWEEN = 10
frameCount = 1
while frameCount < (FRAMES + 1):
print "taking image number ", frameCount, " of ", daylightminutes
datetimenowis = ephem.now()
imageNumber = str(frameCount).zfill(7)
os.system("raspistill -o /home/pi/image%s.jpg"%(imageNumber)) # -rot 270 need for cam on side (put -rot 270 before -o)
os.system("/usr/bin/convert /home/pi/image%s.jpg -pointsize 72 -fill white -annotate +40+1590 'Chicken Cam %s' /home/pi/image%s.jpg"%(imageNumber,datetimenowis,imageNumber))
frameCount += 1
time.sleep(TIMEBETWEEN - 10) #Takes roughly 6 seconds to take a picture & 4 to add text to image
#record current time and date in variable datetime
datetimenowis = time.strftime("%Y%m%d-%H%M")
print "It's sunset, processing images into one mp4 video. Time now is ", datetimenowis
# make the timelapse video out of the images taken
os.system("avconv -r %s -i /home/pi/image%s.jpg -r %s -vcodec libx264 -crf 20 -g 15 -vf crop=2592:1458,scale=1280:720 /home/pi/timelapse%s.mp4" %(FPS_IN,'%7d',FPS_OUT,datetimenowis))
#send the timelapse video to dropbox
print "Sending mp4 video to dropbox."
from subprocess import call
photofile = "/home/pi/Dropbox-Uploader/dropbox_uploader.sh upload /home/pi/timelapse%s.mp4 timelapse%s.mp4" %(datetimenowis,datetimenowis)
call ([photofile], shell=True)
print "mp4 uploaded to dropbox! Cleaning up."
#remove the timelapse video copy and all images it is made up of that are held localy on the Rpi
os.system("rm /home/pi/timelapse%s.mp4"%(datetimenowis))
os.system("rm /home/pi/image*")
print "Finished, exiting program."
sys.exit()
while ephem.now() <= sunrise:
time.sleep(1)
dostuff()
The issue at the momnet, is that if i try to tringer the main code at one minute befoe sunset. the code fails here.
pi#raspberrypi ~ $ sudo python timelapseV3.py
Traceback (most recent call last):
File "timelapseV3.py", line 13, in <module>
sunriselessonemin = ephem.date(sunrise + 1*ephem.minute)
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and
'float'
I cant seem to start the code a minute before sunrise like i could before.
cheers
Once you run localtime() on a PyEphem date, you move it away from being a value that PyEphem can reason about and instead create a value that Python’s native datetime module knows about. To use the value in PyEphem, keep a copy of the raw value returned by PyEphem, and do the math with it instead:
sunrise, sunset = home.next_rising(sun), home.next_setting(sun)
sunrise_localtime, sunset_localtime = ephem.localtime(sunrise), ephem.localtime(sunset)
daylightminutes = (sunset_localtime - sunrise_localtime) * 1440 # find howmany minutes of daylight there are
sunriselessonemin = ephem.date(sunrise + 1*ephem.minute)
You should find that this runs without error. Good luck!
I'm writing a small IRC bot which uses data grabbed from a JSON API. It's a list of events, which contains at the front any running event, followed by any future events.
I'd like to alert the channel twice before each event: an hour prior, and five minutes prior. To do this I'm attempting to create threading.Timer events which trigger at the appropriate time. I chose this method because the IRC bot requires running in an infinite loop, so the alerts need to run in their own thread. I've several times had the first alert work, but only if it triggers within ~5 minutes of the bot starting. If I start it say, 8 hours before the next event, it won't trigger the method at all. Here's the alert code: I've cut out the portions of the code which parse the time from the API, since that is already working and is just clutter for purposes of this question.
USE = pytz.timezone('US/Eastern')
ZULU=pytz.timezone('Zulu')
NET = 0
r = requests.get('http://api.pathofexile.com/leagues?type=event')
events=r.json()
NextEvent=events[0];
now = datetime.datetime.now(USE)
nextEventTime = events[0]['startAt']
/\/\
timeConverted=datetime.datetime(eventTimeY, eventTimeM, eventTimeD, eventTimeH, eventTimeMin, 0, 0).replace(tzinfo=ZULU)
until = timeConverted - now
NET = until.total_seconds()
#Race Alerts
def hourAlert():
r = requests.get('http://api.pathofexile.com/leagues?type=event')
events=r.json()
NextEvent=events[0];
now = datetime.datetime.now(USE)
nextEventTime = events[0]['startAt']
\/\/
timeConverted=datetime.datetime(eventTimeY, eventTimeM, eventTimeD, eventTimeH, eventTimeMin, 0, 0).replace(tzinfo=ZULU)
until = timeConverted - now
NET = until.total_seconds()
print("HOURALERT")
if until.total_seconds() > 0:
irc.send(bytes('PRIVMSG '+channel+' '+"EVENT ALERT - 1 HOUR - "+NextEvent['id'] +' - Occurs at '+NextEvent['startAt']+' - '+NextEvent['url']+'\r\n', 'UTF-8')) #gives event info
print("Starting Timer to event - "+str(NET-300))
sAlert = threading.Timer(NET-300, startAlert)
sAlert.start()
else:
NextEvent=events[1];
now = datetime.datetime.now(USE)
nextEventTime = events[1]['startAt']
\/\/
timeConverted=datetime.datetime(eventTimeY, eventTimeM, eventTimeD, eventTimeH, eventTimeMin, 0, 0).replace(tzinfo=ZULU)
until = timeConverted - now
NET = until.total_seconds()
irc.send(bytes('PRIVMSG '+channel+' '+"EVENT ALERT - 1 HOUR - "+NextEvent['id'] +' - Occurs at '+NextEvent['startAt']+' - '+NextEvent['url']+'\r\n', 'UTF-8')) #gives event info
print("Starting Timer to next event - "+str(NET-300))
sAlert = threading.Timer(NET-300, startAlert)
sAlert.start()
def startAlert():
r = requests.get('http://api.pathofexile.com/leagues?type=event')
events=r.json()
NextEvent=events[0];
now = datetime.datetime.now(USE)
nextEventTime = events[1]['startAt']
\/\/
timeConverted=datetime.datetime(eventTimeY, eventTimeM, eventTimeD, eventTimeH, eventTimeMin, 0, 0).replace(tzinfo=ZULU)
until = timeConverted - now
NET = until.total_seconds()
print("STARTALERT")
irc.send(bytes('PRIVMSG '+channel+' '+"EVENT ALERT - STARTING IN 5 MINUTES - "+NextEvent['id'] +' - '+NextEvent['url']+'\r\n', 'UTF-8')) #gives event info
NextEvent=events[1];
if until.total_seconds() > 3600:
print("Starting Timer to 1hr - " + str(NET-3600))
hAlert = threading.Timer(NET-3600, hourAlert)
hAlert.start()
else:
print("Starting Timer to event - " +str(NET-300))
sAlert = threading.Timer(NET-300, startAlert)
sAlert.start()
if until.total_seconds() > 3600:
print("Starting Timer to 1hr - " + str(NET-3600))
hAlert = threading.Timer(NET-3600, hourAlert)
hAlert.start()
elif until.total_seconds() > 300:
print("Starting Timer to event - " + str(NET-300))
hAlert = threading.Timer(NET-300, startAlert)
hAlert.start()
else:
NextEvent=events[1];
now = datetime.datetime.now(USE)
nextEventTime = events[1]['startAt']
\/\/
timeConverted=datetime.datetime(eventTimeY, eventTimeM, eventTimeD, eventTimeH, eventTimeMin, 0, 0).replace(tzinfo=ZULU)
until = timeConverted - now
NET = until.total_seconds()
print("Starting Timer to next event 1h - "+str(NET-3600))
hAlert = threading.Timer(NET-3600, hourAlert)
hAlert.start()
#End Alerts
I suspected for a time that my issue was using the timedelta.seconds value instead of total_seconds(), but I wont know if that works for a few hours yet. The main reason I'm asking here is because this code works in a testbed: if I tell it that the next event is in 30 seconds, and to trigger 15 and 5 before the event, it works just fine. However, when I bring the code back to multi-hour timespans, the events often won't trigger. They don't error out, they just straight don't work: not even the alert prints happen.
Thanks for any help you guys might be!
edit: I should mention, this is the first python program that I've written, but I'm a fairly experienced coder overall. My problem might be language related in that I'm doing something in a way python doesn't want me to. I'm unsure, for example, if nesting events like this would cause them to never trigger, because each is waiting for the full resolution of the child's function before triggering its own.
edit2: After more work, I can get the first alert to work, but despite creating the next Timer according to print statements, it never triggers. Is something with the nesting of triggers wrong?