diff --git a/CLAUDE.md b/CLAUDE.md index d1dac06..621f972 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,7 +7,16 @@ Reproduzierbares Arch-Linux-Setup basierend auf archinstall + Post-Install-Autom - `config/` — archinstall-Konfiguration (inkl. custom-commands die das Repo nach /opt/moonarch klonen, root-owned) - `scripts/` — Post-Install- und Helper-Scripts - `packages/` — Paketlisten (offiziell + AUR), getrennt gepflegt -- `defaults/` — XDG-Configs, Shell-Config, Helper-Binaries, systemd User-Services, greetd/moongreet-Config, Wallpaper +- `defaults/` — XDG-Configs, Shell-Config, Helper-Binaries, systemd Services, udev-Regeln, greetd/moongreet-Config, Wallpaper + +## Battery Conservation Mode + +Laptops mit `charge_control_end_threshold`-Support (ThinkPad, Framework, etc.) erhalten einen Waybar-Toggle: +- Klick auf das Battery-Modul schaltet zwischen 80% und 100% Ladegrenze um +- Bei aktiver Conservation erscheint ein ♥-Icon neben der Battery-Anzeige +- Zustand wird in `/var/lib/moonarch/batsaver-threshold` persistiert und beim Boot via systemd-Service wiederhergestellt +- udev-Regel gibt Gruppe `wheel` Schreibzugriff auf den Threshold (kein sudo nötig) +- Auf Desktops ohne Battery-Support versteckt sich das Feature komplett ## Konventionen diff --git a/DECISIONS.md b/DECISIONS.md index 79f1602..386b456 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1,5 +1,11 @@ # Decisions +## 2026-04-08 – Battery conservation mode: udev + sysfs + Waybar toggle +- **Who**: Dominik, ClaudeCode +- **Why**: Laptops with `charge_control_end_threshold` support benefit from limiting charge to 80% to extend battery lifespan. Needed a user-friendly toggle without requiring sudo. +- **Tradeoffs**: udev RUN approach for permissions (group wheel gets write access) vs polkit/pkexec (password prompt on every toggle). Chose udev for seamless UX. State persisted in `/var/lib/moonarch/` (system-wide, not per-user) — acceptable since charge threshold is a hardware setting, not a user preference. Fixed 80% threshold instead of configurable — KISS, matches industry standard. +- **How**: udev rule grants wheel group write on `charge_control_end_threshold`. Toggle script writes sysfs + state file. systemd oneshot service restores on boot. Waybar shows ♥ icon when active, hidden when inactive. Click on battery module toggles. + ## 2026-04-07 – Walker theme: gtk-inherit → moonarch with fixed colors - **Who**: Dominik, ClaudeCode - **Why**: gtk-inherit theme relied on GTK4 color inheritance which works but doesn't update live when switching GTK themes (Walker service needs restart). Explicit color definitions make the theme self-contained and predictable. diff --git a/README.md b/README.md index 54cf740..f1c7460 100644 --- a/README.md +++ b/README.md @@ -131,11 +131,15 @@ defaults/ moonarch-waybar-cpugov Waybar module: CPU governor status moonarch-waybar-gpustat Waybar module: GPU utilization moonarch-waybar-hidpp Waybar module: Logitech HID++ device battery + moonarch-waybar-batsaver Waybar module: battery conservation mode indicator + moonarch-batsaver-toggle Toggle battery charge limit (80% ↔ 100%) shell/zshrc Zsh config: prompt, aliases, FZF, completion etc/greetd/ greetd daemon + greeter Niri config etc/moongreet/ moongreet configuration etc/systemd/user/ Systemd user services (cliphist, kanshi, walker, nautilus) + etc/systemd/system/ System service (battery conservation restore on boot) + etc/udev/rules.d/ udev rules (battery threshold permissions) backgrounds/wallpaper.jpg Default wallpaper (shared by desktop, greeter, lock screen) ``` diff --git a/defaults/bin/moonarch-batsaver-toggle b/defaults/bin/moonarch-batsaver-toggle new file mode 100755 index 0000000..beb483d --- /dev/null +++ b/defaults/bin/moonarch-batsaver-toggle @@ -0,0 +1,28 @@ +#!/usr/bin/bash +# ABOUTME: Toggles battery conservation mode between 80% and 100% charge limit. +# ABOUTME: Writes to sysfs (immediate) and state file (persistence across reboots). + +THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold" +STATE_DIR="/var/lib/moonarch" +STATE_FILE="${STATE_DIR}/batsaver-threshold" +CONSERVATION_LIMIT=80 + +[[ -f "$THRESHOLD_FILE" ]] || exit 1 + +CURRENT=$(cat "$THRESHOLD_FILE") + +if [[ "$CURRENT" -le "$CONSERVATION_LIMIT" ]]; then + NEW=100 +else + NEW="$CONSERVATION_LIMIT" +fi + +# Apply immediately +echo "$NEW" > "$THRESHOLD_FILE" || exit 1 + +# Persist for next boot +mkdir -p "$STATE_DIR" +echo "$NEW" > "$STATE_FILE" + +# Signal Waybar to refresh the batsaver module (SIGRTMIN+9) +pkill -RTMIN+9 waybar diff --git a/defaults/bin/moonarch-waybar-batsaver b/defaults/bin/moonarch-waybar-batsaver new file mode 100755 index 0000000..6d50a26 --- /dev/null +++ b/defaults/bin/moonarch-waybar-batsaver @@ -0,0 +1,19 @@ +#!/usr/bin/bash +# ABOUTME: Waybar module showing battery conservation mode status. +# ABOUTME: Outputs heart icon when active (threshold ≤80), empty when inactive. + +THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold" + +# No battery threshold support → no output → Waybar hides module +[[ -f "$THRESHOLD_FILE" ]] || exit 0 + +THRESHOLD=$(cat "$THRESHOLD_FILE") + +if [[ "$THRESHOLD" -le 80 ]]; then + jq --compact-output -n \ + --arg text "♥" \ + --arg tooltip "Battery Conservation: ON (limit ${THRESHOLD}%)" \ + --arg class "on" \ + '{text: $text, tooltip: $tooltip, class: $class}' +fi +# Threshold > 80 → no output → Waybar hides module diff --git a/defaults/etc/systemd/system/moonarch-batsaver.service b/defaults/etc/systemd/system/moonarch-batsaver.service new file mode 100644 index 0000000..8f1a2b7 --- /dev/null +++ b/defaults/etc/systemd/system/moonarch-batsaver.service @@ -0,0 +1,15 @@ +# ABOUTME: Restores battery charge threshold from saved state on boot. +# ABOUTME: Only runs on laptops with threshold support and a saved state file. + +[Unit] +Description=Restore battery conservation mode threshold +After=sysinit.target +ConditionPathExists=/sys/class/power_supply/BAT0/charge_control_end_threshold +ConditionPathExists=/var/lib/moonarch/batsaver-threshold + +[Service] +Type=oneshot +ExecStart=/bin/sh -c 'cat /var/lib/moonarch/batsaver-threshold > /sys/class/power_supply/BAT0/charge_control_end_threshold' + +[Install] +WantedBy=multi-user.target diff --git a/defaults/etc/udev/rules.d/90-moonarch-battery.rules b/defaults/etc/udev/rules.d/90-moonarch-battery.rules new file mode 100644 index 0000000..1baa703 --- /dev/null +++ b/defaults/etc/udev/rules.d/90-moonarch-battery.rules @@ -0,0 +1,4 @@ +# ABOUTME: udev rule granting wheel group write access to battery charge threshold. +# ABOUTME: Enables unprivileged toggling of conservation mode via moonarch-batsaver-toggle. + +SUBSYSTEM=="power_supply", ATTR{type}=="Battery", RUN+="/bin/sh -c 'chgrp wheel /sys%p/charge_control_end_threshold 2>/dev/null; chmod g+w /sys%p/charge_control_end_threshold 2>/dev/null'" diff --git a/defaults/xdg/waybar/config b/defaults/xdg/waybar/config index e07475f..952ad75 100644 --- a/defaults/xdg/waybar/config +++ b/defaults/xdg/waybar/config @@ -21,7 +21,7 @@ "bluetooth", "group/sound", "backlight", - "battery", + "group/battery", "group/indicators" ], "group/indicators": { @@ -58,6 +58,13 @@ "transition-left-to-right": true } }, + "group/battery": { + "orientation": "inherit", + "modules": [ + "battery", + "custom/batsaver" + ] + }, "group/sys": { "orientation": "inherit", "modules": [ @@ -306,13 +313,26 @@ }, "format": "{capacity}% {icon}", "format-icons": [ - "", - "", - "", - "", - "" + "󰂎", + "󰁺", + "󰁻", + "󰁼", + "󰁽", + "󰁾", + "󰁿", + "󰂀", + "󰂁", + "󰂂", + "󰁹" ], - "max-length": 25 + "max-length": 25, + "on-click": "moonarch-batsaver-toggle" + }, + "custom/batsaver": { + "exec": "moonarch-waybar-batsaver", + "return-type": "json", + "interval": 30, + "signal": 9 }, "bluetooth": { // "controller": "controller1", // specify the alias of the controller if there are more than 1 on the system