From 1d45734a04e2f6c303f77a6d4eccce4942676b02 Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 26 May 2026 17:22:05 +0100 Subject: [PATCH] quickshell: add estimated time remaining to battery dropdown Reads energy_now/energy_full to calculate hours remaining. Shows "Xh Ym left" when discharging, "Xh Ym to full" when charging, alongside the wattage draw. Co-Authored-By: Claude Opus 4.6 --- settings/hyprland.nix | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/settings/hyprland.nix b/settings/hyprland.nix index b0cfdd6..589350e 100644 --- a/settings/hyprland.nix +++ b/settings/hyprland.nix @@ -683,6 +683,9 @@ in property bool charging: false property string batteryIcon: "\u{f008e}" property real powerDraw: 0.0 + property real energyNow: 0.0 + property real energyFull: 0.0 + property string timeRemaining: "" property string powerProfile: "balanced" function updateIcon() { @@ -705,21 +708,38 @@ in Process { id: batteryProc - command: ["sh", "-c", "cat /sys/class/power_supply/BAT0/capacity; cat /sys/class/power_supply/BAT0/status; cat /sys/class/power_supply/BAT0/power_now 2>/dev/null || echo 0"] + command: ["sh", "-c", "cat /sys/class/power_supply/BAT0/capacity; cat /sys/class/power_supply/BAT0/status; cat /sys/class/power_supply/BAT0/power_now 2>/dev/null || echo 0; cat /sys/class/power_supply/BAT0/energy_now 2>/dev/null || echo 0; cat /sys/class/power_supply/BAT0/energy_full 2>/dev/null || echo 0"] stdout: SplitParser { property int lineNum: 0 onRead: data => { let trimmed = data.trim(); + let num = parseInt(trimmed); lineNum++; if (lineNum === 1) { - let num = parseInt(trimmed); if (!isNaN(num)) batteryWidget.batteryLevel = num; } else if (lineNum === 2) { batteryWidget.charging = (trimmed === "Charging"); } else if (lineNum === 3) { - let uw = parseInt(trimmed); - if (!isNaN(uw)) batteryWidget.powerDraw = uw / 1000000.0; + if (!isNaN(num)) batteryWidget.powerDraw = num / 1000000.0; + } else if (lineNum === 4) { + if (!isNaN(num)) batteryWidget.energyNow = num / 1000000.0; + } else if (lineNum === 5) { + if (!isNaN(num)) batteryWidget.energyFull = num / 1000000.0; lineNum = 0; + // Calculate time remaining + if (batteryWidget.powerDraw > 0.5) { + let hours; + if (batteryWidget.charging) { + hours = (batteryWidget.energyFull - batteryWidget.energyNow) / batteryWidget.powerDraw; + } else { + hours = batteryWidget.energyNow / batteryWidget.powerDraw; + } + let h = Math.floor(hours); + let m = Math.round((hours - h) * 60); + batteryWidget.timeRemaining = h + "h " + m + "m"; + } else { + batteryWidget.timeRemaining = ""; + } } batteryWidget.updateIcon(); } @@ -1235,6 +1255,7 @@ in } Text { text: batteryWidget.powerDraw.toFixed(1) + " W" + + (batteryWidget.timeRemaining !== "" ? " \u2022 " + batteryWidget.timeRemaining + (batteryWidget.charging ? " to full" : " left") : "") color: "#${c.base04}" font.family: "FiraMono Nerd Font" font.pixelSize: 11