Automated schedule synchronization that actually works
Extracts your schedule from WebUntis and syncs it to Google Calendar every 30 minutes.
Features β’ Installation β’ Usage β’ Showcase β’ Setup Guide
Note from the Developer
POV: Me at 2 AM building this instead of studying...
Also me at 6 AM writing a Chemistry exam... YES, I did this. Worth it? Absolutely.
- Automated Sync: Updates every 30 minutes via cron
- Duplicate Prevention: UID-based tracking prevents duplicate entries
- Room Change Detection: Handles room changes and updates
- Note Extraction: Separates exam notes from regular room information
- Live Dashboard: Web interface showing sync status and history
- Headless Operation: Runs on servers without GUI using Selenium
- Python 3.8+
- Google Calendar API credentials
- WebUntis account
- Chrome/Chromium browser (for Selenium)
git clone https://github.com/YOUR_USERNAME/untis-calendar-sync.git
cd untis-calendar-syncpython3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtCreate .env file:
UNTIS_SCHOOL='YourSchoolName'
UNTIS_USERNAME='your.username'
UNTIS_PASSWORD='your_password'
UNTIS_WEEKS=4
UNTIS_HEADLESS=true- Go to Google Cloud Console
- Create a new project
- Enable Google Calendar API
- Create OAuth 2.0 credentials (Desktop app)
- Download credentials and save as
credentials.json
./run_full_sync.shThis will:
- Authenticate with Google (opens browser)
- Extract 4 weeks of schedule data
- Create calendar events
# Full sync (extract from WebUntis + sync to Calendar)
./run_full_sync.sh
# Status check
./check_status.shAdd to crontab:
*/30 * * * * /path/to/untis-calendar-sync/auto_sync.sh >> /path/to/logs/cron.log 2>&1This runs a full sync every 30 minutes, detecting changes, cancellations, and room updates.
Start the web server:
python3 status_server.pyAccess dashboard at http://localhost:8080/dashboard
Features:
- Last sync time
- Next sync countdown
- Changes today/this week
- Event statistics
Automatic Holiday Detection:
- Gesetzliche Feiertage werden automatisch fΓΌr dein Bundesland erkannt
- Standard: Bayern (
BY). Γndere inuntis_sync_improved.py:
parser = ImprovedUntisParser('weekly_data/week_1.json', bundesland='BY')
# BY=Bayern, NW=NRW, BW=Baden-WΓΌrttemberg, HE=Hessen, SN=Sachsen, etc.Manual School Holidays:
Schulfreie Tage die keine gesetzlichen Feiertage sind (z.B. BuΓ- und Bettag auΓerhalb Sachsen, BrΓΌckentage, pΓ€dagogische Tage) in school_holidays.json eintragen:
{
"custom_holidays": [
"2025-11-19",
"2025-05-30",
"2025-03-15"
]
}Das System erkennt automatisch:
- β Fehlende Wochentage in WebUntis-Daten
- β Ordnet Lessons korrekt zu (ohne Day-Shift)
- β Funktioniert fΓΌr jeden Wochentag (nicht nur Mittwoch)
Events are color-coded in Google Calendar (default: Orange).
Change in untis_sync_improved.py:
'colorId': '6', # 1=Blue, 3=Purple, 6=Orange, 11=RedAdjust in .env:
UNTIS_WEEKS=4 # Extract 1-8 weeks aheadEdit crontab entry:
*/30 * * * * # Every 30 minutes
*/15 * * * * # Every 15 minutes
0 * * * * # Every houruntis-calendar-sync/
βββ extractor.py # WebUntis scraper (Selenium)
βββ untis_sync_improved.py # Parser & Calendar sync logic
βββ sync_all_weeks.py # Multi-week sync orchestrator
βββ auto_sync.sh # Main cron script
βββ run_full_sync.sh # Manual full sync script
βββ status_server.py # Web dashboard server
βββ status_api.py # CLI status tool
βββ check_status.sh # Quick status script
βββ cleanup_calendar.py # Remove all Untis events
βββ remove_duplicates.py # Find & remove duplicates
βββ quick_sync.py # Sync without extraction
- Uses Selenium WebDriver (headless Chrome)
- Logs into WebUntis
- Navigates through weeks
- Scrapes lesson data (subject, time, room, teacher)
- Saves to JSON files (
weekly_data/week_*.json)
- Reads JSON files
- Detects day boundaries (time resets)
- Extracts room information (handles changes with +)
- Separates notes (exams, special events)
- Generates unique IDs (MD5 hash)
- Loads existing Calendar events
- Compares UIDs to prevent duplicates
- Creates new events
- Skips unchanged events
- Updates
sync_status.json
Check credentials in .env:
source .env
echo $UNTIS_USERNAME
echo $UNTIS_SCHOOLCheck parsed data:
cat parsed_lessons_all_weeks.json | python3 -m json.tool | lessRemove duplicates:
python3 remove_duplicates.pyCheck logs:
tail -f logs/auto_sync_*.log
tail -f logs/cron.logInstall/update Chrome:
apt update
apt install chromium-browserEndpoint: http://localhost:8080/status
Response:
{
"current_time": "2025-10-23T23:00:00",
"last_sync": "2025-10-23T22:30:00",
"next_sync": "2025-10-23T23:00:00",
"weeks_extracted": 4,
"total_lessons": 67,
"changes_today": [...],
"changes_this_week": [...]
}Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
MIT License - See LICENSE file for details
This tool:
- Stores credentials locally in
.env - Uses OAuth2 for Google Calendar (token.pickle)
- Does not send data to third parties
- Runs entirely on your infrastructure
Keep sensitive files secure and never commit them to version control.
- Issues: GitHub Issues
- Documentation: This README
- Status: Check
./check_status.sh
- Initial release
- Automated 30-minute sync
- Duplicate prevention
- Room change detection
- Web dashboard
- Note extraction




