mirror of
https://github.com/Death916/deathclock.git
synced 2026-04-10 03:04:40 -07:00
modules for classes
This commit is contained in:
parent
88005c1da1
commit
2243c59898
10 changed files with 1070 additions and 1451 deletions
Binary file not shown.
35
deathclock/alarm_module.py
Normal file
35
deathclock/alarm_module.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import datetime
|
||||
from dash import html, dcc, Input, Output, State
|
||||
import alarm # Import Alarm class
|
||||
|
||||
class AlarmModule:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.alarm_obj = self.get_alarm_object()
|
||||
self._alarm_time = None
|
||||
self.setup_callbacks()
|
||||
|
||||
def get_alarm_object(self):
|
||||
return alarm.Alarm()
|
||||
|
||||
def setup_callbacks(self):
|
||||
@self.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:
|
||||
return {'display': 'block', 'margin': '0 auto'}
|
||||
return {'display': 'none', 'margin': '0 auto'}
|
||||
|
||||
@self.app.callback(
|
||||
Output('output-selected-time', 'children'),
|
||||
Input('time-input', 'value')
|
||||
)
|
||||
def process_selected_time(time_value):
|
||||
if time_value:
|
||||
self._alarm_time = time_value
|
||||
self.alarm_obj.add_alarm(time_value, datetime.datetime.now())
|
||||
return f'Alarm time: {time_value}'
|
||||
return 'No time selected yet.'
|
||||
|
|
@ -1,175 +1,49 @@
|
|||
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
|
||||
from dash import Dash, html, dcc
|
||||
from weather_module import WeatherModule
|
||||
from news_module import NewsModule
|
||||
from scores_module import ScoresModule
|
||||
from alarm_module import AlarmModule
|
||||
from clock_module import ClockModule
|
||||
|
||||
app = Dash(__name__)
|
||||
def create_app():
|
||||
app = Dash(__name__)
|
||||
|
||||
# Initialize classes
|
||||
weather_obj = Weather()
|
||||
news_obj = News()
|
||||
scores_obj = NBAScores()
|
||||
alarm_obj = alarm.Alarm()
|
||||
_alarm_time = None
|
||||
app.layout = html.Div([
|
||||
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'}),
|
||||
|
||||
# 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', '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([
|
||||
html.Div([
|
||||
html.H2("NBA Scores"),
|
||||
html.Div(id='nba-scores-display', className='score-container')
|
||||
]),
|
||||
html.Div(id='weather-display')
|
||||
], id='scores-weather-container'),
|
||||
]),
|
||||
#add class back if not working still
|
||||
html.Div(id='news-ticker'),
|
||||
# Intervals
|
||||
dcc.Interval(id='clock-interval', interval=60000, n_intervals=0),
|
||||
dcc.Interval(id='weather-interval', interval=150000, n_intervals=0),
|
||||
dcc.Interval(id='news-interval', interval=300000, n_intervals=0),
|
||||
dcc.Interval(id='nba-interval', interval=300000, n_intervals=0)
|
||||
])
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output('clock-display', 'children'),
|
||||
Input('clock-interval', 'n_intervals')
|
||||
)
|
||||
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.
|
||||
global alarm_time
|
||||
alarm_time = time_value
|
||||
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')
|
||||
)
|
||||
def update_weather(n):
|
||||
try:
|
||||
print("UPDATING WEATHER...")
|
||||
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'})
|
||||
])
|
||||
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("UPDATING NEWS...")
|
||||
headlines_dict = news_obj.get_news()
|
||||
# Combine source and headline for each news item
|
||||
combined_items = " | ".join([f"{data['source']}: {headline}"
|
||||
for headline, data in headlines_dict.items()])
|
||||
|
||||
text_px = len(combined_items) * 8
|
||||
scroll_speed = 75
|
||||
duration = max(text_px / scroll_speed, 20)
|
||||
|
||||
ticker_style = {"animationDuration": f"{duration}s"}
|
||||
|
||||
_cached_news = html.Div(
|
||||
html.Span(combined_items, className="news-item", style=ticker_style),
|
||||
className='ticker'
|
||||
)
|
||||
_last_news_update = current_time
|
||||
_initial_run = False
|
||||
return _cached_news
|
||||
|
||||
except Exception as e:
|
||||
if _cached_news:
|
||||
return _cached_news
|
||||
return html.Div("No news available.")
|
||||
|
||||
|
||||
@app.callback(
|
||||
Output('nba-scores-display', 'children'),
|
||||
Input('nba-interval', 'n_intervals')
|
||||
)
|
||||
def update_scores(n):
|
||||
try:
|
||||
games = scores_obj.get_scores()
|
||||
if not games:
|
||||
return html.Div("No games available", className='text-center')
|
||||
return html.Div([
|
||||
html.Div([
|
||||
html.Div([
|
||||
html.Span(f"{game['away_team']} {game['away_score']}"),
|
||||
html.Span(" @ "),
|
||||
html.Span(f"{game['home_team']} {game['home_score']}")
|
||||
], className='game-score'),
|
||||
html.Div(f"Period: {game['period']}", className='game-period')
|
||||
], className='score-box')
|
||||
for game in games
|
||||
], className='score-container')
|
||||
except Exception as e:
|
||||
return html.Div("Scores unavailable")
|
||||
html.H2("NBA Scores"),
|
||||
html.Div(id='nba-scores-display', className='score-container')
|
||||
]),
|
||||
html.Div(id='weather-display')
|
||||
], id='scores-weather-container'),
|
||||
]),
|
||||
html.Div(id='news-ticker'),
|
||||
dcc.Interval(id='clock-interval', interval=60000, n_intervals=0),
|
||||
dcc.Interval(id='weather-interval', interval=150000, n_intervals=0),
|
||||
dcc.Interval(id='news-interval', interval=300000, n_intervals=0),
|
||||
dcc.Interval(id='nba-interval', interval=300000, n_intervals=0)
|
||||
])
|
||||
|
||||
# Check for alarms and play sound if triggered
|
||||
def check_alarms():
|
||||
trigg = alarm_obj.check_alarm()
|
||||
if trigg:
|
||||
print("ALARM TRIGGERED!")
|
||||
# Play alarm sound here using dash audio component
|
||||
check_alarms()
|
||||
ClockModule(app)
|
||||
WeatherModule(app)
|
||||
NewsModule(app)
|
||||
ScoresModule(app)
|
||||
alarm_module = AlarmModule(app)
|
||||
|
||||
def check_alarms():
|
||||
trigg = alarm_module.alarm_obj.check_alarm()
|
||||
if trigg:
|
||||
print("ALARM TRIGGERED!")
|
||||
|
||||
check_alarms()
|
||||
|
||||
return app
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = create_app()
|
||||
app.run_server(debug=False, host='0.0.0.0', port=8050)
|
||||
|
|
|
|||
15
deathclock/clock_module.py
Normal file
15
deathclock/clock_module.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from time import strftime, localtime
|
||||
from dash import Input, Output
|
||||
|
||||
class ClockModule:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.setup_callbacks()
|
||||
|
||||
def setup_callbacks(self):
|
||||
@self.app.callback(
|
||||
Output('clock-display', 'children'),
|
||||
Input('clock-interval', 'n_intervals')
|
||||
)
|
||||
def update_time(n):
|
||||
return strftime("%B %d, %I:%M %p", localtime())
|
||||
47
deathclock/news_module.py
Normal file
47
deathclock/news_module.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import datetime
|
||||
from dash import html, Input, Output
|
||||
from news import News # Import News class
|
||||
|
||||
class NewsModule:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.news_obj = self.get_news_object()
|
||||
self._last_news_update = datetime.datetime(2000, 1, 1)
|
||||
self._cached_news = []
|
||||
self._initial_run = True
|
||||
self.setup_callbacks()
|
||||
|
||||
def get_news_object(self):
|
||||
return News()
|
||||
|
||||
def setup_callbacks(self):
|
||||
@self.app.callback(
|
||||
Output('news-ticker', 'children'),
|
||||
Input('news-interval', 'n_intervals')
|
||||
)
|
||||
def update_news(n):
|
||||
current_time = datetime.datetime.now()
|
||||
try:
|
||||
print("UPDATING NEWS...")
|
||||
headlines_dict = self.news_obj.get_news()
|
||||
combined_items = " | ".join([f"{data['source']}: {headline}"
|
||||
for headline, data in headlines_dict.items()])
|
||||
|
||||
text_px = len(combined_items) * 8
|
||||
scroll_speed = 75
|
||||
duration = max(text_px / scroll_speed, 20)
|
||||
|
||||
ticker_style = {"animationDuration": f"{duration}s"}
|
||||
|
||||
self._cached_news = html.Div(
|
||||
html.Span(combined_items, className="news-item", style=ticker_style),
|
||||
className='ticker'
|
||||
)
|
||||
self._last_news_update = current_time
|
||||
self._initial_run = False
|
||||
return self._cached_news
|
||||
|
||||
except Exception as e:
|
||||
if self._cached_news:
|
||||
return self._cached_news
|
||||
return html.Div("No news available.")
|
||||
35
deathclock/scores_module.py
Normal file
35
deathclock/scores_module.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
from dash import html, Input, Output
|
||||
from scores import NBAScores # Import NBAScores class
|
||||
|
||||
class ScoresModule:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.scores_obj = self.get_scores_object()
|
||||
self.setup_callbacks()
|
||||
|
||||
def get_scores_object(self):
|
||||
return NBAScores()
|
||||
|
||||
def setup_callbacks(self):
|
||||
@self.app.callback(
|
||||
Output('nba-scores-display', 'children'),
|
||||
Input('nba-interval', 'n_intervals')
|
||||
)
|
||||
def update_scores(n):
|
||||
try:
|
||||
games = self.scores_obj.get_scores()
|
||||
if not games:
|
||||
return html.Div("No games available", className='text-center')
|
||||
return html.Div([
|
||||
html.Div([
|
||||
html.Div([
|
||||
html.Span(f"{game['away_team']} {game['away_score']}"),
|
||||
html.Span(" @ "),
|
||||
html.Span(f"{game['home_team']} {game['home_score']}")
|
||||
], className='game-score'),
|
||||
html.Div(f"Period: {game['period']}", className='game-period')
|
||||
], className='score-box')
|
||||
for game in games
|
||||
], className='score-container')
|
||||
except Exception as e:
|
||||
return html.Div("Scores unavailable")
|
||||
34
deathclock/weather_module.py
Normal file
34
deathclock/weather_module.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import datetime
|
||||
import os
|
||||
from dash import html, Input, Output
|
||||
from weather import Weather # Import Weather class
|
||||
|
||||
class WeatherModule:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.weather_obj = self.get_weather_object()
|
||||
self.setup_callbacks()
|
||||
|
||||
def get_weather_object(self):
|
||||
if not os.path.exists('assets'):
|
||||
os.makedirs('assets')
|
||||
return Weather()
|
||||
|
||||
def setup_callbacks(self):
|
||||
@self.app.callback(
|
||||
Output('weather-display', 'children'),
|
||||
Input('weather-interval', 'n_intervals')
|
||||
)
|
||||
def update_weather(n):
|
||||
try:
|
||||
print("UPDATING WEATHER...")
|
||||
screenshot_path = self.weather_obj.get_weather_screenshot()
|
||||
image_name = os.path.basename(screenshot_path)
|
||||
return html.Div([
|
||||
html.H2("Sacramento Weather"),
|
||||
html.Img(src=self.app.get_asset_url(image_name
|
||||
+ f"?v={datetime.datetime.now().timestamp()}"),
|
||||
style={'maxWidth': '500px'})
|
||||
])
|
||||
except Exception as e:
|
||||
return html.Div(f"Weather update error: {str(e)}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue