Files
Calender/README.md
Ludwig Mey fc6abfe745 Redesign UI as light-themed week-grid calendar matching Skylight-style device
- Replace scrolling event list + photo background with a Sun–Sat week grid
  plus a "Next Week" preview column; Prev/Next navigation and per-member filter
- Add [Name] event title prefix convention for color-coded family member cards
  (Ludwig/Dad=blue, Michelle/Mom=pink, Jason=green, Daniel=yellow)
- /api/calendar now accepts ?start=YYYY-MM-DD, returns bucketed week payload
  with member/color metadata; fetches 14 days to populate Next Week column
- Drop rotating background photo and dad joke from the display (endpoints kept)
- Update README with new UI overview, prefix convention, and API docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-27 20:32:15 +12:00

298 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```bash
git clone ssh://git@gitea.meyfamily.co.nz:2222/luddie/Calender.git
cd Calender
```
### 2. Install Dependencies
```bash
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
```
### 3. Configure Environment Variables
```bash
cp .env.example .env
```
Edit [.env](.env) and add your API keys:
```bash
# 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](https://openweathermap.org/api)
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](https://www.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](https://calendar.google.com/)
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](https://console.cloud.google.com/)
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](#family-member-colors) above. Edit `FAMILY_MEMBERS` in `config.py` to change names, aliases, or colors.
### 7. Run the Application
```bash
python app.py
```
Visit `http://localhost:5000` in your browser.
## Raspberry Pi Deployment
### Auto-start Flask Application
Create a systemd service:
```bash
sudo nano /etc/systemd/system/calendar-display.service
```
Add the following content:
```ini
[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:
```bash
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:
```bash
mkdir -p ~/.config/autostart
nano ~/.config/autostart/chromium-kiosk.desktop
```
Add the following:
```ini
[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
```bash
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
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:
```javascript
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:
- [Flask](https://flask.palletsprojects.com/) - Web framework
- [OpenWeatherMap API](https://openweathermap.org/api) - Weather data
- [Google Calendar API](https://developers.google.com/calendar) - Calendar integration
- [icanhazdadjoke](https://icanhazdadjoke.com/) - Dad jokes API