Stefan Koelle 87353aa362 Merge pull request #5 from skoelle/renovate/mysql-connector-python-9.x
chore(deps): update dependency mysql-connector-python to v9.7.0
2026-08-10 19:25:00 +02:00
2026-08-10 17:01:27 +02:00
2026-08-10 17:01:27 +02:00
2026-08-10 17:10:05 +02:00
2026-08-01 15:06:34 +02:00
2026-08-04 19:28:44 +02:00
2026-08-10 16:47:13 +02:00
2026-08-10 17:01:27 +02:00
2026-08-10 16:47:13 +02:00
2026-08-04 19:28:44 +02:00
2026-08-04 19:28:48 +02:00
2026-08-04 19:28:48 +02:00
2026-08-01 15:06:34 +02:00
2026-08-10 17:10:05 +02:00
2026-08-04 19:28:48 +02:00

calender_sync

Google Calendar (ICS-Feed) → MariaDB Sync fürs Homelab.

Läuft als Docker Container, pollt periodisch einen privaten Google Calendar ICS-Feed, expandiert RRULE/EXDATE/RECURRENCE-ID und schreibt einzelne Instanzen in eine MariaDB-Datenbank.

Features

  • Automatische Synchronisation alle 15 Minuten (konfigurierbar)
  • Expandiert wiederkehrende Events (RRULE) und Serien-Exceptions (EXDATE, RECURRENCE-ID)
  • Soft-Delete: Entfernte Events werden als deleted=1 markiert, nicht gelöscht
  • Optionales Database-Bootstrap: Erstellt DB und User automatisch bei DB_BOOTSTRAP=true
  • Zeitfenster-konfiguration für Vergangenheit/Future (standardmäßig -90 Tage / +365 Tage)
  • Web-UI zur Anzeige anstehender Termine mit Suchfunktion
  • REST API für programmsprachigen Zugriff auf Kalenderdaten
  • Optionale tägliche E-Mail-Benachrichtigung um konfigurierte Uhrzeit

UI

Voraussetzungen

  • Docker & Docker Compose
  • MariaDB Instanz (z.B. als Proxmox LXC)
  • Google Calendar mit privatem ICS-Feed

Quick Start

  1. MariaDB Setup

    Entweder manuell ausführen:

    mysql -u root -p < mariadb-setup.sql
    

    Oder automatisch beim Start (in .env setzen):

    DB_BOOTSTRAP=true
    DB_ROOT_USER=root
    DB_ROOT_PASSWORD=dein_root_passwort
    
  2. .env anlegen

    cp .env.example .env
    

    Variablen anpassen, insbesondere:

    • ICS_URL: Privater ICS-Link aus den Google Calendar Einstellungen
    • DB_PASSWORD: Sicheres Passwort für den calendar_sync User
  3. Starten

    docker compose up -d
    

Demo / Lokaler Test (ohne Docker)

Schneller Weg um Web-UI und API lokal zu testen, ohne MariaDB oder Docker:

./demo.sh

Das Script erstellt eine virtuelle Python-Umgebung, installiert Dependencies, legt eine SQLite Demo-Datenbank mit 4 Beispiel-Terminen an und startet die API auf Port 8000.

Endpoints:

Demo-Events (4 Stück):

Termin Zeit Status
Team Daily heute 14:0015:00 CONFIRMED
Yoga Kurs heute 18:3020:00 CONFIRMED
Projekt-Deadline morgen Ganztag TENTATIVE
Arzttermin übermorgen 10:0011:30 CONFIRMED

Die Demo verwendet SQLite (DB_BACKEND=sqlite) statt MariaDB. Die Events werden relativ zum heutigen Datum erstellt.

Konfiguration

Variable Default Beschreibung
ICS_URL required Privater ICS-Feed aus Google Calendar
CALENDAR_LABEL default Label für den Kalender (für Multi-Kalender)
DB_HOST mariadb.fritz.box MariaDB Host
DB_PORT 3306 MariaDB Port
DB_NAME calendar_sync Datenbank-Name
DB_USER required Datenbank-User
DB_PASSWORD required Datenbank-Passwort
SYNC_INTERVAL_MINUTES 15 Sync-Intervall in Minuten
WINDOW_PAST_DAYS 90 Wie viele Tage in die Vergangenheit synchronisieren
WINDOW_FUTURE_DAYS 365 Wie viele Tage in die Zukunft synchronisieren
LOG_LEVEL INFO Python Logging Level
DB_BOOTSTRAP false DB + User beim Start erstellen
DB_ROOT_USER - Root-User fürs Bootstrap
DB_ROOT_PASSWORD - Root-Passwort fürs Bootstrap
API_PORT 8000 Port für den API/Web-UI Container
TIMEZONE UTC Zeitzone für API/Web-UI Anzeige (z.B. Europe/Berlin)

Optionale E-Mail-Benachrichtigung

Sendet täglich eine HTML-Email mit den anstehenden Terminen. Wird aktiviert wenn SMTP_HOST und NOTIFY_EMAIL gesetzt sind.

Variable Default Beschreibung
SMTP_HOST - SMTP Server Hostname
SMTP_PORT 587 SMTP Server Port
SMTP_USER - SMTP Login Username
SMTP_PASSWORD - SMTP Login Passwort
SMTP_FROM - Absender E-Mail Adresse
SMTP_USE_TLS true TLS verschlüsselung nutzen
NOTIFY_EMAIL - Empfänger E-Mail Adresse
NOTIFY_TIME 6 Uhrzeit für Benachrichtigung (Stunde, 0-23)
NOTIFY_TIMEZONE Europe/Berlin Zeitzone für die Benachrichtigung

Subject-Logik:

  • 1 Termin: Kalender heute: 09:00 - Meeting mit Team
  • 2+ Termine: Kalender heute: 3 Termine

Hinweis: Ganztagstermine werden nicht in der Benachrichtigung berücksichtigt.

Datenbank-Schema

Tabelle calendar_events:

Spalte Typ Beschreibung
id BIGINT PK Auto-Increment
calendar_label VARCHAR(64) Kalender-Label
instance_key VARCHAR(255) SHA1-basierte eindeutige Instanz-ID
uid VARCHAR(255) ICS UID
recurrence_id VARCHAR(64) RECURRENCE-ID bei Serien-Exceptions
summary VARCHAR(512) Titel
description TEXT Beschreibung
location VARCHAR(512) Ort
start_at DATETIME Startzeit (UTC)
end_at DATETIME Endzeit (UTC)
all_day TINYINT(1) Ganz-tagig Flag
status VARCHAR(32) Event-Status
deleted TINYINT(1) Soft-Delete Flag
last_seen_at DATETIME Letzte Synchronisation
created_at DATETIME Erstellungszeitpunkt
updated_at DATETIME Letzte Änderung

Tabelle daily_notification_log (optional, für E-Mail-Benachrichtigung):

Spalte Typ Beschreibung
id INT PK Auto-Increment
notify_date DATE Datum der Benachrichtigung
sent_at DATETIME Zeitpunkt des Versands
event_count INT Anzahl Termine in der Email

Web-UI & API

Das Projekt enthält eine FastAPI-basierte Webanwendung die als separater Container (calendar-api) läuft und auf Port 8000 erreichbar ist.

Endpoints

Endpoint Beschreibung
GET / HTML-Seite mit anstehenden Terminen und Suchfunktion
GET /api/health Health Check (gibt {"status": "ok"} zurück)
GET /api/events?limit=10&search=... JSON-Liste zukünftiger Events (nicht gelöscht)
GET /api/events/{event_id} Einzelnes Event als JSON

API Beispiel

# Alle anstehenden Events (max. 10)
curl http://localhost:8000/api/events

# Suche nach Titel
curl "http://localhost:8000/api/events?search=Meeting&limit=5"

# Einzelnes Event
curl http://localhost:8000/api/events/42

JSON Response Format

{
  "events": [
    {
      "id": 1,
      "summary": "Teammeeting",
      "description": "Wöchentliches Teammeeting",
      "location": "Konferenzraum 1",
      "start_at": "2025-01-15T10:00:00",
      "end_at": "2025-01-15T11:00:00",
       "all_day": false,
       "status": "CONFIRMED",
       "timezone": "Europe/Berlin"
     }
  ],
  "count": 1,
  "query_time": "2025-01-15T09:30:00Z",
  "timezone": "Europe/Berlin"
}

CI/CD

GitHub Actions Workflow (docker-publish.yml) baut und published das Docker Image automatisch nach GitHub Container Registry:

ghcr.io/skoelle/calender_sync:latest

Lizenz

Lizenziert unter der MIT License - Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de)

S
Description
No description provided
Readme MIT
253 KiB
Languages
Python 80.8%
HTML 16%
Shell 2.7%
Dockerfile 0.5%