Dominic Böttger

← Zurück zum Blog

Veröffentlicht am 14. Januar 2026 von Dominic Böttger (vor 2 Monaten) · 8 Min. Lesezeit

Ich wollte schon immer, dass mein Computer automatisch zwischen hellem und dunklem Theme wechselt – basierend auf dem tatsächlichen Tageslicht, nicht auf willkürlichen festen Zeiten wie „8 bis 18 Uhr”. In Heidelberg geht die Sonne im Winter um 16:30 Uhr unter, bleibt aber im Sommer bis 21 Uhr oben. Ein fester Zeitplan funktioniert da einfach nicht.

In dieser Anleitung zeige ich dir, wie du einen wirklich intelligenten Auto-Dark-Mode unter Linux einrichtest, der:

  • Echte Sonnenauf- und Sonnenuntergangszeiten für deine GPS-Koordinaten berechnet
  • Deinen Standort automatisch per IP-Geolokalisierung erkennt
  • Sowohl dein Desktop-Theme ALS AUCH die Bildschirm-Farbtemperatur umschaltet
  • Die bürgerliche Dämmerung für sanfte Übergänge vor dem eigentlichen Sonnenauf-/untergang nutzt

Das Endergebnis

Einmal konfiguriert, wechselt dein System automatisch:

TageszeitThemeBildschirmtemperatur
Nach SonnenaufgangHelles Theme (Catppuccin Latte)6000K (neutrales Tageslicht)
Nach SonnenuntergangDunkles Theme (Tokyo Night)4000K (warm, augenschonend)

Der Wechsel erfolgt zur bürgerlichen Dämmerung – etwa 30 Minuten vor Sonnenaufgang und nach Sonnenuntergang – und bietet dir so einen sanften, natürlichen Übergang, der zur Wahrnehmung des sich ändernden Lichts passt.

Voraussetzungen

Diese Anleitung ist für Omarchy geschrieben, eine opinionierte Arch-Linux-Distribution mit Hyprland. Du brauchst:

  • Omarchy installiert
  • sunwait für Sonnenauf-/untergangsberechnungen
  • hyprsunset für die Bildschirmtemperatursteuerung (in Omarchy enthalten)

Schritt 1: sunwait installieren

sunwait ist ein kleines Hilfsprogramm, das Sonnenauf- und Sonnenuntergangszeiten anhand von GPS-Koordinaten berechnet. Es unterstützt verschiedene Dämmerungstypen (bürgerlich, nautisch, astronomisch) und kann entweder Zeiten ausgeben oder auf ein Ereignis warten.

yay -S sunwait

Funktionstest

# Prüfen, ob es gerade Tag oder Nacht ist (bürgerliche Dämmerung)
sunwait poll civil 48.14N 11.58E
# Gibt zurück: DAY oder NIGHT

# Heutige Sonnenauf- und Sonnenuntergangszeiten abrufen
sunwait list civil 48.14N 11.58E
# Gibt z.B. zurück: 07:25, 17:19

Schritt 2: Das Auto-Theme-Skript erstellen

Erstelle ein Skript unter ~/.local/bin/omarchy-auto-theme (oder an einem anderen Ort in deinem PATH):

#!/bin/bash
#
# Auto-switches theme and screen temperature based on real sunrise/sunset
# Uses IP geolocation and sunwait for accurate sun position calculation
#

CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/omarchy"
LOCATION_CACHE="$CACHE_DIR/location"
STATE_FILE="$CACHE_DIR/auto-theme-state"

# Theme configuration - customize these!
LIGHT_THEME="Catppuccin Latte"
DARK_THEME="Tokyo Night"

# Screen temperature (night light)
DAY_TEMP=6000
NIGHT_TEMP=4000

mkdir -p "$CACHE_DIR"

# Get location (cached for 24 hours)
get_location() {
    local cache_age=86400  # 24 hours

    if [[ -f "$LOCATION_CACHE" ]]; then
        local file_age=$(($(date +%s) - $(stat -c %Y "$LOCATION_CACHE")))
        if [[ $file_age -lt $cache_age ]]; then
            cat "$LOCATION_CACHE"
            return 0
        fi
    fi

    # Fetch from ipinfo.io
    local loc
    loc=$(curl -s --connect-timeout 5 ipinfo.io/loc 2>/dev/null)

    if [[ -n "$loc" && "$loc" =~ ^-?[0-9]+\.[0-9]+,-?[0-9]+\.[0-9]+$ ]]; then
        echo "$loc" > "$LOCATION_CACHE"
        echo "$loc"
        return 0
    fi

    # Fallback: use cached even if old
    if [[ -f "$LOCATION_CACHE" ]]; then
        cat "$LOCATION_CACHE"
        return 0
    fi

    return 1
}

# Convert location to sunwait format
format_location() {
    local loc="$1"
    local lat lon lat_dir lon_dir

    lat=$(echo "$loc" | cut -d',' -f1)
    lon=$(echo "$loc" | cut -d',' -f2)

    # Determine direction
    if (( $(echo "$lat < 0" | bc -l) )); then
        lat_dir="S"
        lat=$(echo "$lat" | tr -d '-')
    else
        lat_dir="N"
    fi

    if (( $(echo "$lon < 0" | bc -l) )); then
        lon_dir="W"
        lon=$(echo "$lon" | tr -d '-')
    else
        lon_dir="E"
    fi

    echo "${lat}${lat_dir} ${lon}${lon_dir}"
}

# Check if it's day or night using sunwait
is_daytime() {
    local location="$1"
    local result

    # sunwait poll returns: DAY (exit 1) or NIGHT (exit 3)
    # Using civil twilight (default) for smooth transitions
    result=$(sunwait poll civil $location 2>/dev/null)

    [[ "$result" == "DAY" ]]
}

# Set screen temperature via hyprsunset
set_temperature() {
    local temp="$1"

    # Ensure hyprsunset is running
    if ! pgrep -x hyprsunset > /dev/null; then
        setsid uwsm-app -- hyprsunset &
        sleep 1
    fi

    hyprctl hyprsunset temperature "$temp" 2>/dev/null
}

# Main logic
main() {
    local location loc_formatted current_state new_state

    location=$(get_location)
    if [[ -z "$location" ]]; then
        echo "Failed to get location" >&2
        exit 1
    fi

    loc_formatted=$(format_location "$location")

    # Determine day/night state
    if is_daytime "$loc_formatted"; then
        new_state="day"
    else
        new_state="night"
    fi

    # Read previous state
    current_state=""
    [[ -f "$STATE_FILE" ]] && current_state=$(cat "$STATE_FILE")

    # Only switch if state changed (or forced)
    if [[ "$1" == "--force" ]] || [[ "$current_state" != "$new_state" ]]; then
        if [[ "$new_state" == "day" ]]; then
            echo "Switching to day mode (light theme)"
            # Replace with your theme switching command
            omarchy-theme-set "$LIGHT_THEME"
            set_temperature "$DAY_TEMP"
        else
            echo "Switching to night mode (dark theme)"
            omarchy-theme-set "$DARK_THEME"
            set_temperature "$NIGHT_TEMP"
        fi

        echo "$new_state" > "$STATE_FILE"
    else
        echo "Already in $new_state mode, no change needed"
    fi
}

# Handle arguments
case "$1" in
    --status)
        location=$(get_location)
        loc_formatted=$(format_location "$location")
        echo "Location: $location"
        echo "Formatted: $loc_formatted"
        echo "Sun state: $(sunwait poll civil $loc_formatted 2>/dev/null)"
        echo "Current theme state: $(cat "$STATE_FILE" 2>/dev/null || echo 'unknown')"
        ;;
    --force|"")
        main "$1"
        ;;
    --help)
        echo "Usage: $(basename $0) [--status|--force|--help]"
        echo "  --status  Show current state and location info"
        echo "  --force   Force theme switch even if state unchanged"
        echo "  --help    Show this help"
        ;;
    *)
        echo "Unknown option: $1"
        exit 1
        ;;
esac

Mach es ausführbar:

chmod +x ~/.local/bin/omarchy-auto-theme

Schritt 3: Den systemd Timer einrichten

Wir verwenden einen systemd User-Timer, um das Skript alle 5 Minuten auszuführen. Dieser Ansatz ist ressourcenschonend – das Skript beendet sich sofort, wenn keine Änderung nötig ist.

Erstelle die Service-Datei unter ~/.config/systemd/user/omarchy-auto-theme.service:

[Unit]
Description=Auto switch theme based on sunrise/sunset
After=graphical-session.target

[Service]
Type=oneshot
ExecStart=%h/.local/bin/omarchy-auto-theme
Environment=DISPLAY=:0
Environment=WAYLAND_DISPLAY=wayland-1

[Install]
WantedBy=default.target

Erstelle die Timer-Datei unter ~/.config/systemd/user/omarchy-auto-theme.timer:

[Unit]
Description=Check and switch theme every 5 minutes based on sunrise/sunset

[Timer]
OnStartupSec=10sec
OnUnitActiveSec=5min
Persistent=true

[Install]
WantedBy=timers.target

Hinweis: Wir verwenden OnStartupSec statt OnBootSec, weil dies ein User-Timer ist – er löst relativ zum Start deiner Benutzersitzung aus, nicht zum Systemstart.

Aktiviere und starte den Timer:

systemctl --user daemon-reload
systemctl --user enable --now omarchy-auto-theme.timer

Überprüfe, ob er läuft:

systemctl --user status omarchy-auto-theme.timer

Aufwachen aus dem Suspend behandeln

Der systemd Timer funktioniert hervorragend, aber es gibt einen Haken: Wenn dein Laptop über Nacht schläft und erst nach Sonnenaufgang aufwacht, löst der Timer nicht sofort aus. User-Level-Timer feuern nach dem Aufwachen nicht zuverlässig.

Die Lösung ist, sich in after_sleep_cmd von hypridle einzuklinken. Bearbeite ~/.config/hypr/hypridle.conf und aktualisiere die after_sleep_cmd-Zeile:

general {
    # ... andere Einstellungen ...
    after_sleep_cmd = hyprctl dispatch dpms on && omarchy-auto-theme
}

Jetzt wird die Theme-Prüfung sofort ausgeführt, wenn dein System aus dem Suspend aufwacht.

Schritt 4: Alles testen

Aktuellen Status prüfen:

omarchy-auto-theme --status

Du solltest eine Ausgabe wie diese sehen:

Location: 48.1374,11.5755
Formatted: 48.1374N 11.5755E
Sun state: NIGHT
Current theme state: night

Theme-Wechsel erzwingen, um die Funktion zu prüfen:

omarchy-auto-theme --force

Dämmerungstypen verstehen

Das Skript verwendet standardmäßig die „bürgerliche Dämmerung”, aber du kannst dies für unterschiedliches Verhalten anpassen:

DämmerungstypSonnenpositionWirkung
daylightAm HorizontExakter Moment des Sonnenauf-/untergangs
civil6° unter dem HorizontGenug Licht zum Arbeiten im Freien ohne künstliches Licht
nautical12° unter dem HorizontHorizont auf See noch sichtbar
astronomical18° unter dem HorizontHimmel vollständig dunkel

Die bürgerliche Dämmerung wird empfohlen, weil sie dem Zeitpunkt entspricht, an dem Menschen den Übergang zwischen Tag und Nacht natürlich wahrnehmen. Der Wechsel erfolgt etwa 30 Minuten vor dem tatsächlichen Sonnenaufgang und nach dem tatsächlichen Sonnenuntergang.

Um sie zu ändern, passe die Funktion is_daytime() an:

result=$(sunwait poll nautical $location 2>/dev/null)

Anpassungsmöglichkeiten

Fester Standort (ohne IP-Geolokalisierung)

Wenn du keine IP-Geolokalisierung verwenden möchtest, erstelle einen permanenten Standort-Cache:

echo "48.1374,11.5755" > ~/.cache/omarchy/location
chmod 444 ~/.cache/omarchy/location  # Schreibgeschützt machen

Anderes Prüfintervall

Bearbeite die Timer-Datei und ändere OnUnitActiveSec:

OnUnitActiveSec=10min  # Alle 10 Minuten prüfen statt 5

Dann neu laden: systemctl --user daemon-reload

Nur Bildschirmtemperatur (ohne Theme-Wechsel)

Wenn du nur den Nachtlicht-Effekt ohne Theme-Wechsel möchtest, kommentiere die Theme-Set-Zeilen im Skript aus und behalte nur die set_temperature-Aufrufe.

Fehlerbehebung

Timer läuft nicht:

systemctl --user status omarchy-auto-theme.timer
journalctl --user -u omarchy-auto-theme.service -n 20

Falscher Standort:

curl -s ipinfo.io/loc  # Erkannten Standort prüfen
# Bei Fehler überschreiben:
echo "DEIN_LAT,DEIN_LON" > ~/.cache/omarchy/location

Bildschirmtemperatur ändert sich nicht:

pgrep hyprsunset  # Prüfen, ob es läuft
hyprctl hyprsunset temperature 4000  # Manueller Test

Warum dieser Ansatz?

  1. Echte Standorterkennung: Das Setup erkennt deinen Standort automatisch per IP und funktioniert auch auf Reisen – keine manuellen Koordinaten-Updates nötig.

  2. Bürgerliche Dämmerung: Der Übergang erfolgt, wenn es sich anfühlt, als würde sich Tag/Nacht ändern, nicht im exakten astronomischen Moment.

  3. Einheitliche Steuerung: Sowohl das Omarchy-Theme ALS AUCH die Bildschirmtemperatur wechseln gemeinsam für ein stimmiges Erlebnis.

  4. Ressourcenschonend: Der 5-Minuten-Polling-Ansatz verbraucht vernachlässigbare Ressourcen – das Skript beendet sich in Millisekunden, wenn keine Änderung nötig ist.

Fazit

Mit diesem Setup passt sich dein Linux-Desktop intelligent an den natürlichen Lichtzyklus an. Kein manuelles Theme-Wechseln mehr und keine Probleme mit Dark Mode um 16 Uhr im Winter, während alles noch auf den Sommerfahrplan eingestellt ist.

Das System ist vollständig automatisch – es erkennt deinen Standort, berechnet die echten Sonnenauf- und Sonnenuntergangszeiten und wechselt nahtlos dein gesamtes Desktop-Erlebnis. Deine Augen werden es dir danken.

Geschrieben von Dominic Böttger

← Zurück zum Blog

Aktuelle Blogbeiträge