diff --git a/README.md b/README.md index 2277788..6640ea2 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A smart display application for Raspberry Pi that shows time, weather, calendar ## Features - 🕐 **Real-time Clock** - Current time and date display -- 🌤️ **Weather** - Current weather and 5-day forecast for Hamilton, New Zealand (OpenWeatherMap) +- 🌤️ **Weather** - Current weather and 3-day forecast for Hamilton, New Zealand (OpenWeatherMap) - 📅 **Google Calendar** - Family calendar events display - 🖼️ **Rotating Backgrounds** - Beautiful images from local directory - 😄 **Dad Jokes** - Random jokes to brighten your day (optional) diff --git a/app.py b/app.py index e5cc9ac..284c977 100644 --- a/app.py +++ b/app.py @@ -44,7 +44,7 @@ def get_weather(): current_response.raise_for_status() current_data = current_response.json() - # Fetch 5-day forecast + # Fetch 3-day forecast forecast_url = f"https://api.openweathermap.org/data/2.5/forecast" forecast_response = requests.get(forecast_url, params=params, timeout=10) forecast_response.raise_for_status() @@ -54,9 +54,9 @@ def get_weather(): daily_forecast = [] seen_dates = set() - for item in forecast_data['list'][:40]: # Next 5 days (8 forecasts per day) + for item in forecast_data['list'][:40]: # Next 3 days (8 forecasts per day) date = datetime.fromtimestamp(item['dt']).date() - if date not in seen_dates and len(daily_forecast) < 5: + if date not in seen_dates and len(daily_forecast) < 3: seen_dates.add(date) daily_forecast.append({ 'date': date.strftime('%a'), diff --git a/static/backgrounds/78971579229__155B8574-CC08-4203-987E-2E0267E5C0C3.jpeg b/static/backgrounds/78971579229__155B8574-CC08-4203-987E-2E0267E5C0C3.jpeg new file mode 100644 index 0000000..a865826 Binary files /dev/null and b/static/backgrounds/78971579229__155B8574-CC08-4203-987E-2E0267E5C0C3.jpeg differ diff --git a/static/backgrounds/IMG_9554.jpeg b/static/backgrounds/IMG_9554.jpeg new file mode 100644 index 0000000..9506dfe Binary files /dev/null and b/static/backgrounds/IMG_9554.jpeg differ diff --git a/static/css/style.css b/static/css/style.css index 2bc0a7e..37fec31 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -46,7 +46,7 @@ body { height: 100vh; display: flex; flex-direction: column; - padding: 2rem; + padding: 1rem; } /* Header */ @@ -54,11 +54,11 @@ body { display: flex; justify-content: space-between; align-items: flex-start; - margin-bottom: 2rem; + margin-bottom: 1rem; background: rgba(0, 0, 0, 0.3); backdrop-filter: blur(10px); - padding: 1.5rem 2rem; - border-radius: 15px; + padding: 1rem 1.5rem; + border-radius: 10px; } .time-display { @@ -67,16 +67,16 @@ body { } .time { - font-size: 5rem; + font-size: 3rem; font-weight: 300; line-height: 1; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); } .date { - font-size: 1.8rem; + font-size: 1.1rem; font-weight: 300; - margin-top: 0.5rem; + margin-top: 0.3rem; opacity: 0.9; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); } @@ -84,25 +84,67 @@ body { .weather-summary { display: flex; align-items: center; - gap: 1rem; + gap: 1.5rem; +} + +.current-weather-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.2rem; +} + +.weather-label { + font-size: 0.85rem; + opacity: 0.8; + text-transform: uppercase; + letter-spacing: 0.05em; } .current-temp { - font-size: 4rem; + font-size: 2rem; font-weight: 300; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); } .weather-icon { - font-size: 4rem; + font-size: 1.8rem; +} + +.header-forecast { + display: flex; + gap: 1rem; +} + +.forecast-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.2rem; +} + +.forecast-icon { + font-size: 1.5rem; +} + +.forecast-temps { + display: flex; + gap: 0.3rem; + font-size: 0.9rem; +} + +.forecast-temps .high { + font-weight: 500; +} + +.forecast-temps .low { + opacity: 0.6; } /* Main content */ .main-content { flex: 1; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2rem; + display: flex; overflow: hidden; } @@ -110,44 +152,45 @@ body { section { background: rgba(0, 0, 0, 0.3); backdrop-filter: blur(10px); - padding: 2rem; - border-radius: 15px; + padding: 1rem 1.5rem; + border-radius: 10px; overflow-y: auto; + flex: 1; } section h2 { - font-size: 2rem; + font-size: 1.3rem; font-weight: 400; - margin-bottom: 1.5rem; + margin-bottom: 0.8rem; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); } section h3 { - font-size: 1.5rem; + font-size: 1.1rem; font-weight: 400; - margin: 1.5rem 0 1rem; + margin: 1rem 0 0.5rem; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); } /* Weather Section */ .weather-description { - font-size: 1.8rem; - margin-bottom: 1rem; + font-size: 1.1rem; + margin-bottom: 0.6rem; text-transform: capitalize; } .weather-details { display: flex; flex-direction: column; - gap: 0.8rem; - margin: 1.5rem 0; + gap: 0.4rem; + margin: 0.8rem 0; } .weather-detail { display: flex; justify-content: space-between; - font-size: 1.3rem; - padding: 0.5rem 0; + font-size: 0.95rem; + padding: 0.3rem 0; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } @@ -159,32 +202,32 @@ section h3 { .forecast-days { display: flex; flex-direction: column; - gap: 1rem; + gap: 0.5rem; } .forecast-day { display: grid; - grid-template-columns: 80px 1fr 120px; + grid-template-columns: 60px 1fr 100px; align-items: center; - padding: 1rem; + padding: 0.6rem; background: rgba(255, 255, 255, 0.05); - border-radius: 10px; - gap: 1rem; + border-radius: 8px; + gap: 0.8rem; } .forecast-day-name { - font-size: 1.3rem; + font-size: 1rem; font-weight: 500; } .forecast-description { - font-size: 1.1rem; + font-size: 0.9rem; opacity: 0.8; text-transform: capitalize; } .forecast-temp { - font-size: 1.3rem; + font-size: 1rem; text-align: right; } @@ -201,36 +244,36 @@ section h3 { .events-list { display: flex; flex-direction: column; - gap: 1rem; + gap: 0.6rem; } .event { background: rgba(255, 255, 255, 0.05); - padding: 1.2rem; - border-radius: 10px; - border-left: 4px solid #4a9eff; + padding: 0.8rem; + border-radius: 8px; + border-left: 3px solid #4a9eff; } .event-time { - font-size: 1.1rem; + font-size: 0.9rem; font-weight: 500; - margin-bottom: 0.5rem; + margin-bottom: 0.3rem; color: #4a9eff; } .event-title { - font-size: 1.4rem; - margin-bottom: 0.3rem; + font-size: 1.1rem; + margin-bottom: 0.2rem; } .event-location { - font-size: 1rem; + font-size: 0.85rem; opacity: 0.7; font-style: italic; } .event-placeholder { - font-size: 1.2rem; + font-size: 1rem; opacity: 0.6; text-align: center; padding: 2rem; @@ -238,15 +281,15 @@ section h3 { /* Footer */ .footer { - margin-top: 2rem; + margin-top: 1rem; background: rgba(0, 0, 0, 0.3); backdrop-filter: blur(10px); - padding: 1.5rem 2rem; - border-radius: 15px; + padding: 0.8rem 1.5rem; + border-radius: 10px; } .joke { - font-size: 1.2rem; + font-size: 0.9rem; font-style: italic; text-align: center; opacity: 0.9; diff --git a/static/js/app.js b/static/js/app.js index f31736e..202bbe9 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -3,7 +3,7 @@ const INTERVALS = { TIME: 1000, // 1 second WEATHER: 900000, // 15 minutes CALENDAR: 300000, // 5 minutes - BACKGROUND: 300000, // 5 minutes + BACKGROUND: 60000, // 1 minute JOKE: 3600000 // 1 hour }; @@ -65,32 +65,28 @@ async function updateWeather() { return; } - // Update current weather + // Update current weather in header const { current, forecast } = data; document.getElementById('current-temp').textContent = `${current.temp}°`; document.getElementById('weather-icon').textContent = WEATHER_ICONS[current.icon] || '🌤️'; - document.getElementById('weather-description').textContent = current.description; - document.getElementById('feels-like').textContent = `${current.feels_like}°`; - document.getElementById('humidity').textContent = `${current.humidity}%`; - document.getElementById('wind-speed').textContent = `${current.wind_speed} km/h`; - // Update forecast - const forecastContainer = document.getElementById('forecast-container'); - forecastContainer.innerHTML = ''; + // Update 3-day forecast in header + const headerForecast = document.getElementById('header-forecast'); + headerForecast.innerHTML = ''; forecast.forEach(day => { const dayElement = document.createElement('div'); - dayElement.className = 'forecast-day'; + dayElement.className = 'forecast-item'; dayElement.innerHTML = ` -