From 3b57ff62b1b1a36156ba1d7b476b227ec574e098 Mon Sep 17 00:00:00 2001 From: Death916 Date: Wed, 5 Feb 2025 05:49:17 -0800 Subject: [PATCH] added alarm framework --- deathclock/__pycache__/news.cpython-311.pyc | Bin 2685 -> 2823 bytes deathclock/alarm.py | 2 +- deathclock/app.py | 108 ++++++++++---------- deathclock/news.py | 2 +- 4 files changed, 54 insertions(+), 58 deletions(-) diff --git a/deathclock/__pycache__/news.cpython-311.pyc b/deathclock/__pycache__/news.cpython-311.pyc index db2237fad1afc7505a2bd9876de342cf80209719..38dcdd0f83307a679aefcf719df0c50760addad7 100644 GIT binary patch delta 864 zcmew>(k{lgoR^o2fq{V`C3SInDBDCn2}ZYx>T>D~DU3NRQ7kFUEeuhtObqS}DJ(4v zDXhzw7#LPFfz*R=6x+rWK1N2C$;FKS8962wGg&d7n!Jw5ST2RJh9MrVtb`q;7=lxn zQkW-yWD;g%nas-UAu@q6mc5p_gcBkOBC}X0$1_VwmGFW%5S#_qU&E5cG4Za10f>gk zF)*Ysq_DO!Ny4}cE)229Ygua;vf%couufjdtXL1XBn#|ekcJx8EN&1D!ZoZY;yfTR z5Kdv6!&1YL#Ry`9FtR!u1_p*2h6+X`yV$FE85ok8Fn!Mf(wxGP!Z|sRMOacA#DidD z!x!*PE@Ty+Jb^`yk!$jL7I8*?5TBi)hHW-O3isrPEN)U07<)L8wFEP0^7s{jJUiKn zbu**zHgXIc`+*4k`$=2+ZhT@!t9~s0s4Le-!3P@cM zP*@;xQ9$jAfLe#+Qy!rnzZr&eEHCn?Ug1%_z@z$sgF#Yi^F?+&M)Qxd0=$MF)EERr zdg?E5$Q7$FFfgp=b>v_^$id>s!+wyT(UFJ!u%#oHs{s2^0Tx#g?xW(2t|F7oIQ8TV zL9PeIeGw?^ia_yK1acynV4vK?scfafD*u52lYnRdsnujJQet3WxW!VEnVVX~3^I`g zM5s)@#i`C^#=yV;irC`f$=qBz{x=wS8^G`b6CP G4gdfdf}i>T delta 801 zcmZn{`zyk?oR^o2fq{YHsl%l764r@)5{z~e)#c=wTNt8Pm>Ap{Qdn9TQdpNUF)*xV z0;vPxDAtWRe2k3DldBp3GqO*vX0qaFV`5;K&QQWQ`67$NjM}kjxYhw;dJ$GGN2lQ#dd~phSG~dKPg;p2-JUl_tMr z;g{r0VLCQjl0woLY2?6-?h^Pt7YS%1kXT;%8uBnEZ>)iBWa3ExR>4 zHv!a#uj=ih#lbk&6OqR|M2L9B)WS zZuaHSV>JIDE5K{`L5)E`q^JG@hg`7=0|UbfUPngegN!VWtn3Fl7#&&J4@)?5x#+VW z(Pwcn=00M^=wdv16Q>@d{^W<8GK_4K|8Xjt%CpLUV8A4bKoL~L!@$6x$yTHU_F741 zZfX%T0|P@5%j9S-buJSI1_n@66=zNE;nH#Yz{JRC@__+Pu&FT0e_+5QK7z!)fCw~M Gu$2HrBA2uP diff --git a/deathclock/alarm.py b/deathclock/alarm.py index f80b346..e3b36a0 100644 --- a/deathclock/alarm.py +++ b/deathclock/alarm.py @@ -14,7 +14,7 @@ class Alarm: def add_alarm(self, alarm_time,current_time): self.alarms.append(alarm_time) - self.alarm_times.append(alarm_time.time()) + self.current_time = current_time print(f"Alarm set for {alarm_time}") diff --git a/deathclock/app.py b/deathclock/app.py index b29b7fe..f106822 100644 --- a/deathclock/app.py +++ b/deathclock/app.py @@ -1,24 +1,34 @@ -from dash import Dash, html, dcc -from dash.dependencies import Input, Output +from dash import Dash, html, dcc, Input, Output, State import datetime from time import strftime, localtime from weather import Weather from news import News from scores import NBAScores import alarm + app = Dash(__name__) # Initialize classes weather_obj = Weather() news_obj = News() scores_obj = NBAScores() -#uses arbitrary date in the past as initial value +alarm_obj = alarm.Alarm() + +# Uses arbitrary date in the past as initial value _last_news_update = datetime.datetime(2000, 1, 1) _cached_news = [] _initial_run = True _timer_elapsed = False + +# Layout includes: +# - The clock display (clickable) as an H1 element +# - A hidden time input that will appear on clicking the clock +# - An output div for the selected time app.layout = html.Div([ - html.H1(id='clock-display', style={'textAlign': 'center'}), + html.H1(id='clock-display', style={'textAlign': 'center', 'cursor': 'pointer'}), + dcc.Input(id='time-input', type='time', style={'display': 'none', 'margin': '0 auto'}), + html.Div(id='output-selected-time', style={'textAlign': 'center', 'marginBottom': '20px'}), + html.Div([ # Container for scores and weather html.Div([ @@ -38,9 +48,6 @@ app.layout = html.Div([ ]) - - - @app.callback( Output('clock-display', 'children'), Input('clock-interval', 'n_intervals') @@ -48,6 +55,33 @@ app.layout = html.Div([ def update_time(n): return strftime("%B %d, %I:%M %p", localtime()) + +# When the clock display is clicked, show the time input. +@app.callback( + Output('time-input', 'style'), + Input('clock-display', 'n_clicks'), + State('time-input', 'style') +) +def toggle_time_input(n_clicks, current_style): + if n_clicks and n_clicks % 2 == 1: + # On odd clicks, display the time input. + return {'display': 'block', 'margin': '0 auto'} + return {'display': 'none', 'margin': '0 auto'} + + +# Callback to process the selected time from the time input. +@app.callback( + Output('output-selected-time', 'children'), + Input('time-input', 'value') +) +def process_selected_time(time_value): + if time_value: + # Here you can pass time_value to another function if desired. + alarm_obj.add_alarm(time_value, datetime.datetime.now()) + return f'Alarm time: {time_value}' + return 'No time selected yet.' + + @app.callback( Output('weather-display', 'children'), Input('weather-interval', 'n_intervals') @@ -55,48 +89,34 @@ def update_time(n): def update_weather(n): try: print("UPDATING WEATHER...") - print_time() weather_obj.get_weather_screenshot() return html.Div([ html.H2("Sacramento Weather"), - html.Img(src=app.get_asset_url('sacramento_weather_map.png'+ f"?v={datetime.datetime.now().timestamp()}"), - style={'maxWidth': '500px'}) + html.Img(src=app.get_asset_url('sacramento_weather_map.png' + + f"?v={datetime.datetime.now().timestamp()}"), + style={'maxWidth': '500px'}) ]) except Exception as e: return html.Div(f"Weather update error: {str(e)}") - - + + @app.callback( Output('news-ticker', 'children'), Input('news-interval', 'n_intervals') ) def update_news(n): - global _last_news_update, _cached_news, _initial_run current_time = datetime.datetime.now() - try: - - print("Fetching fresh news due to timer...") headlines_dict = news_obj.get_news() - if not isinstance(headlines_dict, dict): - raise ValueError("News update error: Invalid data format") - if not headlines_dict: - raise ValueError("No news fetched") - combined_text = " | ".join(headlines_dict.keys()) - text_px = len(combined_text) * 8 # Approx 8px per character - scroll_speed = 75 # px per second - duration = text_px / scroll_speed # seconds to scroll across - - # Enforce a floor duration so it's not too quick for short text + text_px = len(combined_text) * 8 # Approximate 8px per character + scroll_speed = 75 # pixels per second + duration = text_px / scroll_speed # seconds required to scroll across if duration < 20: duration = 20 - ticker_style = {"animationDuration": f"{duration}s"} - combined_items = " | ".join([f"{headline}" for headline in headlines_dict.keys()]) - _cached_news = html.Div( html.Span(combined_items, className="news-item", style=ticker_style), className='ticker' @@ -104,31 +124,12 @@ def update_news(n): _last_news_update = current_time _initial_run = False return _cached_news - except Exception as e: - print(f"News update error: {str(e)}") - # Fallback to cached news or load from local file if _cached_news: - print("Using cached news...") - else: - print("Loading news from news.txt...") - try: - with open("news.txt", "r") as file: - local_news = file.read().strip() - if local_news: - _cached_news = html.Div( - html.Span(local_news, className="news-item", style={"animationDuration": "20"}), - className='ticker' - ) - except FileNotFoundError: - print("news.txt not found.") - _cached_news = html.Div("No news available.") - - return _cached_news + return _cached_news + return html.Div("No news available.") - - #get the scores from the scores API @app.callback( Output('nba-scores-display', 'children'), Input('nba-interval', 'n_intervals') @@ -138,7 +139,6 @@ def update_scores(n): games = scores_obj.get_scores() if not games: return html.Div("No games available", className='text-center') - return html.Div([ html.Div([ html.Div([ @@ -150,13 +150,9 @@ def update_scores(n): ], className='score-box') for game in games ], className='score-container') - except Exception as e: return html.Div("Scores unavailable") -#print time and date -def print_time(): - print(strftime("%B %d, %I:%M %p", localtime())) + if __name__ == '__main__': app.run_server(debug=False, host='0.0.0.0', port=8050) - diff --git a/deathclock/news.py b/deathclock/news.py index 3bc7e66..4290a55 100644 --- a/deathclock/news.py +++ b/deathclock/news.py @@ -29,7 +29,7 @@ class News: for post in d.entries[:20]: # Limit to 20 entries per feed if self._news_dict_length >= 20: # Max 20 total entries return self._news_dict - + self._news_dict[post.title] = { 'source': d.feed.title, 'publish_date': post.published,