A real-time calendar monitoring application built with Rust that displays your current and upcoming events with live countdowns. Perfect for keeping track of your schedule on a separate monitor or display.
- Real-time Updates: Live countdown timers with WebSocket connections
- Current Event: Shows active meeting/event with time remaining
- Next Event: Displays upcoming event with start countdown
- Time Blocks: Special support for time blocks (events with
[brackets]) - Multi-Calendar Support: Read from multiple ICS files simultaneously
- Smart Caching: Efficient 5-minute caching to reduce load times
- Google Calendar OAuth: Easy "Login with Google" integration - no complex setup needed
- ICS File Support: Read from local
.icsfiles or live URLs - Multi-Source Support: Combine Google Calendar with ICS feeds seamlessly
- Recurring Events: Full support for weekly recurring events with
RRULEandUNTILclauses - Timezone Handling: Proper timezone conversion (supports Europe/Istanbul)
- Cross-midnight Events: Handles events that span midnight correctly
- Event Filtering: Separate handling of regular events vs time blocks
- Responsive Design: Mobile and desktop friendly
- Grid Layout: Clean CSS Grid-based layout
- Live Animations: Heartbeat effect for active current events
- Date Display: Smart date formatting (Tomorrow, weekday names, etc.)
- Status Indicators: Visual connection status and event states
- Async Architecture: Non-blocking I/O operations
- Efficient Parsing: Fast ICS file processing with deduplication
- Memory Safe: Built with Rust's memory safety guarantees
- Low Resource Usage: Minimal CPU and memory footprint
The application displays three main sections:
βββββββββββββββββββββββββββββββββββββββββββ
β π
Calendar Monitor π Connect β
β π Time Block: Draft.dev β
β 22:00-01:00 β’ 45:23 remaining β
βββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββ¬βββββββββββββββββββ
β π― Current Event β βοΈ Next Event β
β β β
β Team Standup β Project Review β
β 10:00-10:30 β Tomorrow β
β β° 05:23 remaining β 14:00-15:00 β
β β Starts in 3h β
ββββββββββββββββββββββββ΄βββββββββββββββββββ
curl -sSL https://raw.githubusercontent.com/systemcraftsman/calendar-monitor/main/install.sh | sudo bashThis automatically:
- β Detects your architecture (x86_64, ARM64, ARMv7)
- β Downloads the correct binary for your system
- β Sets up systemd service for auto-start
- β
Creates configuration at
/etc/calendar-monitor/config.toml - β Works on Raspberry Pi (ARM64/ARMv7)
| Platform | Architecture | Status |
|---|---|---|
| π§ Linux x86_64 | Intel/AMD 64-bit | β Fully Supported |
| π Raspberry Pi 4 | ARM64 (aarch64) | β Fully Supported |
| π Raspberry Pi 3 | ARMv7 | β Fully Supported |
| π macOS Intel | x86_64 | β Fully Supported |
| π macOS Apple Silicon | ARM64 | β Fully Supported |
| πͺ Windows 10/11 | x86_64 | β Fully Supported |
-
Configure your calendars:
sudo vim /etc/calendar-monitor/config.toml
-
Start the service:
sudo systemctl start calendar-monitor sudo systemctl enable calendar-monitor # Auto-start on boot
-
Access the interface: http://localhost:3000
-
Connect Google Calendar (optional): Click "Connect Google Calendar"
- π¦ Manual Installation - Download pre-built binaries
- π¨ Build from Source - For developers
- π³ Docker - Coming soon
Calendar Monitor uses a flexible configuration system with TOML files:
Configuration locations (in order of priority):
./calendar-monitor.toml(current directory)~/.config/calendar-monitor/config.toml(user config)/etc/calendar-monitor/config.toml(system config)
Sample configuration:
[server]
host = "0.0.0.0" # Bind to all interfaces ("127.0.0.1" for localhost only)
port = 3000 # Web server port
cache_ttl_seconds = 300 # Cache duration
[ics]
file_paths = [
"https://calendar.google.com/calendar/ical/your-id/public/basic.ics",
"https://outlook.live.com/owa/calendar/your-id/calendar.ics",
"/path/to/local/calendar.ics",
]
[google]
# Optional: Google Calendar OAuth integration
client_id = "your-google-client-id"
client_secret = "your-google-client-secret"
redirect_uri = "http://localhost:3000/auth/google/callback"For dynamic configuration or deployment:
# Server configuration
export CALENDAR_MONITOR_HOST="127.0.0.1"
export CALENDAR_MONITOR_PORT="8080"
export CALENDAR_MONITOR_CACHE_TTL="600"
# Calendar sources (comma-separated)
export ICS_FILE_PATHS="https://cal1.ics,https://cal2.ics,/local/cal.ics"
# Google OAuth (optional)
export GOOGLE_CLIENT_ID="your-client-id"
export GOOGLE_CLIENT_SECRET="your-client-secret"
export GOOGLE_REDIRECT_URI="http://localhost:3000/auth/google/callback"Easiest setup - just click "Connect Google Calendar" button:
- No complex configuration needed
- Works around company restrictions
- Automatic authentication flow
- Direct API access
See Google OAuth Setup Guide for details.
ICS_FILE_PATHS=./calendars/work.ics,./calendars/personal.icsICS_FILE_PATHS=https://calendar.google.com/calendar/ical/your-calendar-id/basic.icsCombine Google Calendar OAuth with ICS feeds:
ICS_FILE_PATHS=./local-calendar.ics,https://remote-calendar.com/feed.ics
# Plus Google OAuth for additional eventsπ Google Calendar
- Open Google Calendar
- Go to Settings β Your calendar β Integrate calendar
- Copy the "Secret address in iCal format"
- Configure your calendar source in
calendar-monitor.tomlor set environment variable:export ICS_FILE_PATHS=https://calendar.google.com/calendar/ical/your-id/private-key/basic.ics
π Outlook Calendar
- Open Outlook.com
- Go to Settings β View all Outlook settings β Calendar β Shared calendars
- Publish your calendar and copy the ICS link
- Configure your calendar source in
calendar-monitor.tomlor set environment variable:export ICS_FILE_PATHS=https://outlook.live.com/owa/calendar/your-calendar-id/calendar.ics
π Apple iCloud Calendar
- Open iCloud Calendar
- Click the share icon next to your calendar
- Enable "Public Calendar" and copy the link
- Change
webcal://tohttps://in the URL - Configure your calendar source in
calendar-monitor.tomlor set environment variable:ICS_FILE_PATHS=https://p01-calendarws.icloud.com/published/2/your-calendar-id
Time blocks are special events with titles enclosed in brackets:
[Draft.dev] β Detected as time block
[Red Hat Work] β Detected as time block
Regular Meeting β Regular event
Time blocks appear in the top section and don't interfere with regular meeting scheduling.
calendar-monitor/
βββ src/
β βββ main.rs # Web server, routes, WebSocket handling
β βββ calendar.rs # ICS parsing, calendar service, caching
β βββ meeting.rs # Meeting data structure and methods
βββ static/
β βββ app.js # Frontend JavaScript, WebSocket client
β βββ style.css # CSS styling and responsive design
βββ templates/
β βββ index.html # HTML template
βββ Cargo.toml # Dependencies and project metadata
βββ calendar-monitor.toml # Configuration file (optional)
βββ README.md
- Axum - Modern web framework
- Tokio - Async runtime
- Serde - JSON serialization
- Chrono - Date/time handling
- iCal - ICS file parsing
- reqwest - HTTP client
- anyhow - Error handling
- tracing - Structured logging
- HTML5 - Semantic markup
- CSS3 - Grid layout, animations, responsive design
- JavaScript (ES6+) - WebSocket client, DOM manipulation
- WebSocket - Real-time communication
# Enable debug logging
RUST_LOG=debug cargo run
# Run with auto-reload (requires cargo-watch)
cargo install cargo-watch
cargo watch -x run# Optimized release build
cargo build --release
# Run production binary
./target/release/calendar-monitor# Run unit tests
cargo test
# Run with coverage (requires cargo-tarpaulin)
cargo tarpaulin --out html| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Serve main HTML page |
/ws |
GET | WebSocket upgrade for real-time updates |
/api/meetings |
GET | JSON API for current meeting data |
/auth/google/login |
GET | Google OAuth login redirect |
/auth/google/callback |
GET | Google OAuth callback handler |
/static/* |
GET | Static assets (CSS, JS) |
{
"current_meeting": {
"title": "Team Standup",
"start_time": "2024-01-15T10:00:00Z",
"end_time": "2024-01-15T10:30:00Z",
"description": null,
"location": "Conference Room A"
},
"next_meeting": {
"title": "Project Review",
"start_time": "2024-01-15T14:00:00Z",
"end_time": "2024-01-15T15:00:00Z"
},
"countdown_seconds": 1823,
"active_time_blocks": [
{
"title": "[Draft.dev]",
"start_time": "2024-01-15T19:00:00Z",
"end_time": "2024-01-15T22:00:00Z"
}
]
}No events showing
- Check your configuration file or environment variables
- Verify ICS file/URL accessibility
- Check logs:
RUST_LOG=debug cargo run - Ensure events are for today/tomorrow
WebSocket connection failed
- Check if port 3000 is available
- Verify firewall settings
- Try a different browser or incognito mode
- Check browser console for errors
Recurring events not working
- Verify RRULE format in ICS file
- Check timezone settings
- Currently only supports
FREQ=WEEKLYrules - Enable debug logging to see parsing details
Time zones incorrect
- Check ICS file timezone specification
- Currently hardcoded for Europe/Istanbul
- Modify
parse_ical_datetimefor your timezone - See technical documentation for details
The application is optimized for production with clean logging:
# Production mode (default)
cargo run
# Development with debug logging
RUST_LOG=debug cargo run
# Run comprehensive test suite
cargo testProduction Benefits:
- Clean, minimal logging output
- Optimized performance without debug overhead
- 15 comprehensive unit tests ensure reliability
- All debugging functionality covered by tests
- Installation Guide - Complete installation instructions for all platforms
- Google OAuth Setup - Easy Google Calendar integration (recommended)
- Testing Guide - Comprehensive test documentation and coverage
- Technical Documentation - Detailed code explanation and Rust concepts
- ICS Setup Guide - Manual calendar file setup
We welcome contributions! Here's how to get started:
- Fork the repository
- Create a feature branch
git checkout -b feature/amazing-feature
- Make your changes
- Add tests if applicable
- Run the test suite
cargo test cargo clippy cargo fmt - Commit your changes
git commit -m 'Add amazing feature' - Push to the branch
git push origin feature/amazing-feature
- Open a Pull Request
- Follow Rust naming conventions
- Add documentation for public functions
- Include tests for new functionality
- Use
cargo fmtfor consistent formatting - Run
cargo clippyto catch common issues
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
- Rust Community - Amazing language and ecosystem
- Axum Framework - Excellent web framework
- iCal-rs - ICS parsing library
- Tokio - Async runtime
Built with β€οΈ and π¦ Rust
Report Bug β’ Request Feature β’ Documentation