Ludwig Mey ed3f803464 Redesign layout: 3-per-row 2-row grid, 6 days, bigger fonts
- Show 6 days in a 3x2 grid (3 columns, 2 rows) with info panel
  spanning the full right column
- Day columns explicitly grid-placed to prevent auto-flow into panel column
- Larger fonts throughout: event cards 14px, day number 26px, clock 52px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-28 20:13:50 +12:00

Family Calendar Display

A smart display application for Raspberry Pi that shows a color-coded, week-view family calendar with live weather, styled after wall-mounted family calendar devices (e.g. Skylight).

Project created: February 14, 2026 UI redesigned: June 30, 2026 — switched from a scrolling event list over a photo background to a light-themed week grid with per-person event colors.

Features

  • 📅 Week-View Calendar - SundaySaturday grid with a "Next Week" preview column, Prev/Next navigation
  • 👨‍👩‍👧‍👦 Color-Coded Family Members - Events tagged [Name] are shown in that person's color (see below)
  • 🔎 Filter by Person - Dropdown to show only one family member's events
  • 🌤️ Weather - Current temperature and icon in the header (OpenWeatherMap)
  • 🕐 Real-time Clock - Current time and date display
  • 📌 Read-only by design - The "+" button is a visual affordance only; this app reads a public iCal feed and cannot write events back to Google Calendar. Add/edit events directly in Google Calendar.

The previous rotating-background-photo and dad-joke features were dropped in the redesign to match the cleaner device look. The /api/background and /api/joke endpoints still exist server-side if you want to bring them back.

Family Member Colors

Prefix an event title in Google Calendar with [Name] (case-insensitive) and the app will strip the prefix and color the event card accordingly. Unprefixed events fall back to a neutral gray "Family" color.

Name / alias Color
[Ludwig] or [Dad] Blue
[Michelle] or [Mom] Pink
[Jason] Green
[Daniel] Yellow

Example: an event titled [Daniel] Football Practice displays as Football Practice in Daniel's yellow card. Member names/aliases/colors are configured in config.py (FAMILY_MEMBERS).

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. Set Up Family Member Colors (optional)

Prefix event titles in your calendar with [Name] to color-code them per person — see Family Member Colors above. Edit FAMILY_MEMBERS in config.py to change names, aliases, or colors.

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

The Pi uses labwc (Wayland). Create the autostart entry:

mkdir -p ~/.config/autostart
nano ~/.config/autostart/chromium-kiosk.desktop

Add the following:

[Desktop Entry]
Type=Application
Name=Chromium Kiosk
Exec=chromium-browser --ozone-platform=wayland --kiosk --noerrdialogs --incognito --disable-infobars --simulate-touch-screen --force-show-cursor http://localhost:5002
X-GNOME-Autostart-enabled=true

Reboot

sudo reboot

The display should now start automatically on boot!

Restarting Without Rebooting

A helper script is included to restart both the Flask service and the Chromium kiosk without rebooting:

bash ~/restart-calendar.sh

This will:

  1. Restart the calendar-display systemd service
  2. Kill and relaunch Chromium in the correct Wayland session

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 - Used only by the legacy events fetch; the week view always fetches two weeks at a time

Update Intervals (in seconds):

  • WEATHER_UPDATE_INTERVAL - Weather refresh interval (default: 900)
  • CALENDAR_UPDATE_INTERVAL - Calendar refresh interval (default: 300)

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
};

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?start=YYYY-MM-DD - Sunday-starting week of events plus a "Next Week" preview, color-coded by family member (cached per-week for 5 min). start defaults to the current week if omitted.
  • GET /api/background - Random background image (no longer used by the UI, kept for future use)
  • GET /api/joke - Dad joke (no longer used by the UI, kept for future use)

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 the iCal URL in .env is correct and the calendar is set to Public
  • Check the calendar ID is correct

Events showing the wrong color / "Family" instead of a person

  • The event title must start with [Name] exactly, e.g. [Daniel] Football Practice
  • Check FAMILY_MEMBERS in config.py for the recognized aliases

Display not starting on boot

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

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
Python 43.8%
JavaScript 34.4%
CSS 17.6%
HTML 4.2%