Pull low battery warning into shell

This commit is contained in:
David Heinemeier Hansson
2026-05-19 21:28:32 +02:00
parent 15f461c1df
commit 1a630b1239
12 changed files with 119 additions and 69 deletions
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# omarchy:summary=Send the low battery warning notification and run battery-low hooks.
# omarchy:args=<percentage>
# omarchy:hidden=true
set -euo pipefail
if (($# != 1)); then
echo "Usage: omarchy-battery-low <percentage>" >&2
exit 1
fi
level=$1
if [[ ! $level =~ ^[0-9]+$ ]]; then
echo "Battery percentage must be a number" >&2
exit 1
fi
omarchy-notification-send -g "󱐋" -u critical "Time to recharge!" "Battery is down to ${level}%" -i battery-caution -t 30000
omarchy-hook battery-low "$level"
-25
View File
@@ -1,25 +0,0 @@
#!/bin/bash
# omarchy:summary=Designed to be run by systemd timer every 30 seconds and alerts if battery is low
# omarchy:hidden=true
BATTERY_THRESHOLD=10
NOTIFICATION_FLAG="/run/user/$UID/omarchy_battery_notified"
BATTERY_LEVEL=$(omarchy-battery-remaining)
BATTERY_STATE=$(upower -i $(upower -e | grep 'BAT') | grep -E "state" | awk '{print $2}')
send_notification() {
notify-send -u critical "󱐋 Time to recharge!" "Battery is down to ${1}%" -i battery-caution -t 30000
omarchy-hook battery-low "$1"
}
if [[ -n $BATTERY_LEVEL && $BATTERY_LEVEL =~ ^[0-9]+$ ]]; then
if [[ $BATTERY_STATE == "discharging" ]] && (( BATTERY_LEVEL <= BATTERY_THRESHOLD )); then
if [[ ! -f $NOTIFICATION_FLAG ]]; then
send_notification $BATTERY_LEVEL
touch $NOTIFICATION_FLAG
fi
else
rm -f $NOTIFICATION_FLAG
fi
fi
-1
View File
@@ -10,7 +10,6 @@ FIRST_RUN_MODE=~/.local/state/omarchy/first-run.mode
if [[ -f $FIRST_RUN_MODE ]]; then
rm -f "$FIRST_RUN_MODE"
bash "$OMARCHY_PATH/install/first-run/battery-monitor.sh"
bash "$OMARCHY_PATH/install/first-run/recover-internal-monitor.sh"
bash "$OMARCHY_PATH/install/first-run/cleanup-reboot-sudoers.sh"
bash "$OMARCHY_PATH/install/first-run/firewall.sh"
@@ -1,9 +0,0 @@
[Unit]
Description=Omarchy Battery Monitor Check
After=graphical-session.target
[Service]
Type=oneshot
ExecStart=%h/.local/share/omarchy/bin/omarchy-battery-monitor
Environment=DISPLAY=:0
LogLevelMax=warning
@@ -1,11 +0,0 @@
[Unit]
Description=Omarchy Battery Monitor Timer
Requires=omarchy-battery-monitor.service
[Timer]
OnBootSec=1min
OnUnitActiveSec=30sec
AccuracySec=10sec
[Install]
WantedBy=timers.target
-8
View File
@@ -1,8 +0,0 @@
if omarchy-battery-present; then
powerprofilesctl set balanced || true
# Enable battery monitoring timer for low battery notifications
systemctl --user enable --now omarchy-battery-monitor.timer
else
powerprofilesctl set performance || true
fi
-10
View File
@@ -1,10 +0,0 @@
echo "Enable battery low notifications for laptops"
if ls /sys/class/power_supply/BAT* &>/dev/null && [[ ! -f ~/.local/share/omarchy/config/systemd/user/omarchy-battery-monitor.service ]]; then
mkdir -p ~/.config/systemd/user
cp ~/.local/share/omarchy/config/systemd/user/omarchy-battery-monitor.* ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now omarchy-battery-monitor.timer || true
fi
+5
View File
@@ -0,0 +1,5 @@
echo "Move low battery notifications into omarchy-shell"
systemctl --user disable --now omarchy-battery-monitor.timer 2>/dev/null || true
rm -f "$HOME/.config/systemd/user/omarchy-battery-monitor.service" "$HOME/.config/systemd/user/omarchy-battery-monitor.timer"
systemctl --user daemon-reload 2>/dev/null || true
+1
View File
@@ -19,6 +19,7 @@ User-installed plugins live alongside these conceptually but on disk under
| Clipboard mgr | `omarchy.clipboard-picker`| `overlay` | `clipboard-picker/ClipboardPicker.qml`|
| Omarchy menu | `omarchy.menu` | `menu` | `menu/Menu.qml` |
| Notifications | `omarchy.notifications` | `service` | `notifications/Service.qml` |
| Battery mon. | `omarchy.battery-monitor` | `service` | `battery-monitor/Service.qml` |
| Idle monitor | `omarchy.idle` | `service` | `idle/Service.qml` |
| Lock screen | `omarchy.lock` | `service` | `lock/Service.qml` |
| OSD | `omarchy.osd` | `panel` | `osd/Osd.qml` |
+73
View File
@@ -0,0 +1,73 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.UPower
Item {
id: root
property var shell: null
property string omarchyPath: Quickshell.env("OMARCHY_PATH")
readonly property int batteryThreshold: 10
PersistentProperties {
id: persisted
reloadableId: "omarchy-battery-monitor"
property bool notifiedLowBattery: false
}
function batteryPercentage() {
var device = UPower.displayDevice
if (!device || !device.isPresent) return -1
return Math.round(Number(device.percentage || 0) * 100)
}
function isDischarging() {
var device = UPower.displayDevice
return !!(device && device.isPresent
&& UPower.onBattery
&& device.state === UPowerDeviceState.Discharging)
}
function checkBattery() {
var level = batteryPercentage()
if (level < 0) {
persisted.notifiedLowBattery = false
return
}
if (isDischarging() && level <= batteryThreshold) {
if (!persisted.notifiedLowBattery) {
persisted.notifiedLowBattery = true
sendLowBatteryWarning(level)
}
} else {
persisted.notifiedLowBattery = false
}
}
function sendLowBatteryWarning(level) {
if (warningProcess.running) return
warningProcess.command = [
"omarchy-battery-low",
String(level)
]
warningProcess.running = true
}
Process { id: warningProcess }
Timer {
interval: 30000
running: true
repeat: true
triggeredOnStart: true
onTriggered: root.checkBattery()
}
Connections {
target: UPower
function onOnBatteryChanged() { root.checkBattery() }
}
}
@@ -0,0 +1,14 @@
{
"schemaVersion": 1,
"id": "omarchy.battery-monitor",
"name": "Battery Monitor",
"version": "1.0.0",
"author": "Omarchy",
"description": "Low battery warning service",
"kinds": [
"service"
],
"entryPoints": {
"service": "Service.qml"
}
}
+4 -5
View File
@@ -108,11 +108,10 @@ Item {
// - omarchy-action: a user-action confirmation toast ("Theme changed",
// "Screenshot saved"). The user JUST did something — their feedback
// should show.
// - urgency=critical AND app_name=notify-send: bare-CLI emergency alerts
// (omarchy-battery-monitor uses this for low-battery; a few scripts
// use it for emergency failures). Trusted because it's almost always
// omarchy or system shell scripts — chat apps set app_name to
// their brand (Discord/Slack/Vesktop) which falls outside this rule.
// - urgency=critical AND app_name=notify-send: bare-CLI emergency alerts.
// Trusted because it's almost always omarchy or system shell scripts
// chat apps set app_name to their brand (Discord/Slack/Vesktop), which
// falls outside this rule.
function shouldBypassDnd(notification) {
var appName = String(notification.appName || "")
if (appName === "omarchy-action") return true