Ludwig Mey abf1036864 Fix background photo rotation interval from 1 min to 60 min
BACKGROUND interval was set to 60000ms (1 minute) instead of
3600000ms (60 minutes) as intended.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 21:39:30 +13:00

Family Calendar Display

A smart display application for Raspberry Pi that shows time, weather, calendar events, and rotating background images.

Project created: February 14, 2026

Features

  • 🕐 Real-time Clock - Current time and date display
  • 🌤️ Weather - Current weather and 3-day forecast (OpenWeatherMap)
  • 📅 Google Calendar - Calendar events display (supports public iCal feeds)
  • 🖼️ Rotating Backgrounds - Beautiful images from local directory
  • 🎨 Dynamic Text Color - Automatically adjusts text color based on background brightness
  • 😄 Dad Jokes - Random jokes to brighten your day (optional)

Requirements

  • Python 3.8+
  • Raspberry Pi (tested on Pi 3/4) or any Linux system
  • Google Calendar API credentials
  • OpenWeatherMap API key (free tier)

Quick Start

1. Clone the Repository

git clone ssh://git@gitea.meyfamily.co.nz:2222/luddie/Calender.git
cd Calender

2. Install Dependencies

python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -r requirements.txt

3. Configure Environment Variables

cp .env.example .env

Edit .env and add your API keys:

# Get your OpenWeatherMap API key from: https://openweathermap.org/api
OPENWEATHER_API_KEY=your_api_key_here

# Your Google Calendar ID (found in Google Calendar settings)
GOOGLE_CALENDAR_ID=your_calendar_id@group.calendar.google.com

# Generate a secret key for Flask
FLASK_SECRET_KEY=your_random_secret_key

4. Get OpenWeatherMap API Key

  1. Go to OpenWeatherMap
  2. Sign up for a free account
  3. Navigate to "API keys" section
  4. Copy your API key
  5. Add it to your .env file as OPENWEATHER_API_KEY

Find Your Location Coordinates:

  1. Go to LatLong.net
  2. Search for your city
  3. Copy the latitude and longitude values
  4. Add them to your .env file as WEATHER_LAT and WEATHER_LON

5. Set Up Google Calendar

Option 1: Public iCal Feed (Easiest - No Authentication)

  1. Open Google Calendar
  2. Go to Settings (⚙️ gear icon)
  3. Select the calendar you want to display
  4. Scroll down to "Integrate calendar"
  5. Copy the "Public URL to this calendar" in iCal format
    • The URL looks like: https://calendar.google.com/calendar/ical/...@group.calendar.google.com/public/basic.ics
  6. Add this URL to your .env file as GOOGLE_CALENDAR_ICAL_URL
  7. Also copy the Calendar ID (looks like abc123...@group.calendar.google.com)
  8. Add it to your .env file as GOOGLE_CALENDAR_ID

Note: Your calendar must be set to "Public" for this method to work.

Option 2: Google Calendar API with Credentials (Advanced)

If you prefer to use private calendars with authentication:

  1. Go to Google Cloud Console
  2. Create a new project or select existing one
  3. Enable the Google Calendar API
  4. Create credentials (Service Account)
  5. Download the credentials JSON file
  6. Save it as credentials/google_calendar_credentials.json
  7. Share your calendar with the service account email

6. Add Background Images

Place your images in the static/backgrounds/ directory:

cp /path/to/your/images/*.jpg static/backgrounds/

Supported formats: JPG, JPEG, PNG, GIF, WebP

Recommended specifications:

  • Resolution: 1920x1080 or higher
  • Aspect ratio: 16:9 (for full-screen displays)
  • File size: Keep under 5MB for faster loading

Changing Image Rotation Interval:

Edit your .env file:

# Time in seconds (60 = 1 minute)
IMAGE_ROTATION_INTERVAL=60

Or edit static/js/app.js:

const INTERVALS = {
    BACKGROUND: 60000,  // Milliseconds (60000 = 1 minute)
    ...
};

7. Run the Application

python app.py

Visit http://localhost:5000 in your browser.

Raspberry Pi Deployment

Auto-start Flask Application

Create a systemd service:

sudo nano /etc/systemd/system/calendar-display.service

Add the following content:

[Unit]
Description=Calendar Display Flask App
After=network.target

[Service]
User=pi
WorkingDirectory=/home/pi/Calender
ExecStart=/home/pi/Calender/venv/bin/python app.py
Restart=always
Environment="PATH=/home/pi/Calender/venv/bin"

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable calendar-display.service
sudo systemctl start calendar-display.service

Configure Chromium Kiosk Mode

Edit the autostart file:

mkdir -p ~/.config/lxsession/LXDE-pi
nano ~/.config/lxsession/LXDE-pi/autostart

Add these lines:

@xset s off
@xset -dpms
@xset s noblank
@chromium-browser --kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble http://localhost:5000

Disable screensaver and cursor (optional):

sudo apt-get install unclutter
echo "@unclutter -idle 0" >> ~/.config/lxsession/LXDE-pi/autostart

Reboot

sudo reboot

The display should now start automatically on boot!

Configuration

Environment Variables (.env file)

Weather Settings:

  • OPENWEATHER_API_KEY - Your OpenWeatherMap API key
  • WEATHER_LOCATION - City name and country code (e.g., "London,UK")
  • WEATHER_LAT - Latitude of your location
  • WEATHER_LON - Longitude of your location

Calendar Settings:

  • GOOGLE_CALENDAR_ID - Your calendar ID
  • GOOGLE_CALENDAR_ICAL_URL - Public iCal feed URL (easiest method)
  • CALENDAR_DAYS_AHEAD - Number of days ahead to show events (default: 5)

Update Intervals (in seconds):

  • IMAGE_ROTATION_INTERVAL - Background image rotation (default: 60)
  • WEATHER_UPDATE_INTERVAL - Weather refresh interval (default: 900)
  • CALENDAR_UPDATE_INTERVAL - Calendar refresh interval (default: 300)
  • JOKE_UPDATE_INTERVAL - Dad joke refresh interval (default: 3600)

Other:

  • FLASK_SECRET_KEY - Flask session secret key

JavaScript Configuration (static/js/app.js)

For more precise control over update intervals, edit the INTERVALS object:

const INTERVALS = {
    TIME: 1000,              // 1 second
    WEATHER: 900000,         // 15 minutes
    CALENDAR: 300000,        // 5 minutes
    BACKGROUND: 60000,       // 1 minute (change this for image rotation)
    JOKE: 3600000           // 1 hour
};

To change image rotation time:

  1. Open static/js/app.js
  2. Find the INTERVALS object at the top
  3. Change BACKGROUND: 60000 to your desired value in milliseconds
    • 30000 = 30 seconds
    • 60000 = 1 minute
    • 120000 = 2 minutes
    • 300000 = 5 minutes

Project Structure

Calender/
├── app.py                      # Main Flask application
├── config.py                   # Configuration management
├── requirements.txt            # Python dependencies
├── .env                        # Environment variables (create from .env.example)
├── .env.example               # Environment template
├── static/
│   ├── css/style.css          # Styling
│   ├── js/app.js              # Frontend JavaScript
│   └── backgrounds/           # Background images directory
├── templates/
│   └── index.html             # Main display template
└── credentials/
    └── google_calendar_credentials.json  # Google API credentials

API Endpoints

  • GET / - Main display page
  • GET /api/weather - Weather data (cached for 15 min)
  • GET /api/calendar - Calendar events (cached for 5 min)
  • GET /api/background - Random background image
  • GET /api/joke - Dad joke (cached for 1 hour)

Troubleshooting

Weather not loading

  • Check your OpenWeatherMap API key is valid
  • Ensure you're not exceeding the free tier rate limits (60 calls/min)

Calendar not loading

  • Verify Google Calendar API credentials are set up correctly
  • Check the calendar ID is correct
  • Ensure the service account has access to the calendar

Display not starting on boot

  • Check systemd service status: sudo systemctl status calendar-display.service
  • View logs: sudo journalctl -u calendar-display.service -f

Background images not showing

  • Ensure images are in static/backgrounds/
  • Check file permissions: chmod 644 static/backgrounds/*

Contributing

Feel free to submit issues or pull requests!

License

MIT License - Feel free to use and modify for personal use.

Credits

Built with:

Description
Family calender display
Readme 30 MiB
Languages
JavaScript 36.2%
Python 33.3%
CSS 24.4%
HTML 6.1%