- Replace emoji weather icons with OWM icon images to fix rendering issues on Linux displays (e.g. ⛅ showing as a rectangle) - Fix forecast daily max/min to use true high/low across all 3-hour slots instead of just the first entry of the day - Update README: correct BACKGROUND interval (60 min), update kiosk setup for labwc/Wayland, add restart-calendar.sh instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
315 lines
8.7 KiB
Markdown
315 lines
8.7 KiB
Markdown
# 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
|
|
|
|
```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. Add Background Images
|
|
|
|
Place your images in the `static/backgrounds/` directory:
|
|
|
|
```bash
|
|
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 `static/js/app.js`:
|
|
```javascript
|
|
const INTERVALS = {
|
|
BACKGROUND: 3600000, // Milliseconds (3600000 = 60 minutes)
|
|
...
|
|
};
|
|
```
|
|
|
|
### 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` - Number of days ahead to show events (default: 5)
|
|
|
|
**Update Intervals (in seconds):**
|
|
- `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:
|
|
|
|
```javascript
|
|
const INTERVALS = {
|
|
TIME: 1000, // 1 second
|
|
WEATHER: 900000, // 15 minutes
|
|
CALENDAR: 300000, // 5 minutes
|
|
BACKGROUND: 3600000, // 60 minutes
|
|
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` to your desired value in milliseconds
|
|
- 300000 = 5 minutes
|
|
- 1800000 = 30 minutes
|
|
- 3600000 = 60 minutes (default)
|
|
|
|
## 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/](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:
|
|
- [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
|