diff --git a/bin/omarchy-battery-status b/bin/omarchy-battery-status index 78d373e8..c2eaf249 100755 --- a/bin/omarchy-battery-status +++ b/bin/omarchy-battery-status @@ -23,6 +23,7 @@ battery=$(upower -e 2>/dev/null | grep BAT | head -n 1) battery_info=$(upower -i "$battery") percentage=$(awk '/percentage/ { print int($2); exit }' <<<"$battery_info") +power_rate_raw=$(awk '/energy-rate/ { print $2; exit }' <<<"$battery_info") power_rate=$(awk '/energy-rate/ { rounded = sprintf("%.1f", $2) sub(/\.0$/, "", rounded) @@ -32,32 +33,75 @@ power_rate=$(awk '/energy-rate/ { state=$(awk '/state/ { print $2; exit }' <<<"$battery_info") time_remaining=$(omarchy-battery-remaining-time 2>/dev/null) capacity=$(omarchy-battery-capacity 2>/dev/null) +threshold_start=$(awk '/charge-start-threshold:/ { gsub(/%/, "", $2); print int($2); exit }' <<<"$battery_info") +threshold_end=$(awk '/charge-end-threshold:/ { gsub(/%/, "", $2); print int($2); exit }' <<<"$battery_info") + +[[ -z $threshold_end ]] && threshold_end=$(cat /sys/class/power_supply/BAT*/charge_control_end_threshold 2>/dev/null | head -1) +[[ -z $threshold_start ]] && threshold_start=$(cat /sys/class/power_supply/BAT*/charge_control_start_threshold 2>/dev/null | head -1) + +ac_online=false +for supply in /sys/class/power_supply/*; do + [[ -r $supply/type ]] || continue + [[ $(<"$supply/type") == "Mains" ]] || continue + [[ -r $supply/online ]] || continue + + if [[ $(<"$supply/online") == "1" ]]; then + ac_online=true + break + fi +done + +charge_idle=false +if awk -v rate="${power_rate_raw:-0}" 'BEGIN { exit !(rate <= 0.2) }'; then + charge_idle=true +fi + +charge_holding=false +if [[ $ac_online == "true" && -n $threshold_end ]]; then + if [[ $state == "discharging" || $state == "pending-charge" ]]; then + charge_holding=true + elif [[ $state == "fully-charged" ]] && (( percentage < 99 )); then + charge_holding=true + elif [[ $state == "charging" && $charge_idle == "true" ]] && (( threshold_end < 99 && percentage >= threshold_end )); then + charge_holding=true + fi +fi if [[ $shell_output == "true" ]]; then printf 'percentage\t%s\n' "${percentage}%" - printf 'state\t%s\n' "$state" + if [[ $charge_holding == "true" ]]; then + printf 'state\tholding\n' + else + printf 'state\t%s\n' "$state" + fi printf 'rate\t%s\n' "${power_rate}W" printf 'size\t%s\n' "${capacity}Wh" printf 'time\t%s\n' "$time_remaining" cycles=$(cat /sys/class/power_supply/BAT*/cycle_count 2>/dev/null | head -1) - end=$(cat /sys/class/power_supply/BAT*/charge_control_end_threshold 2>/dev/null | head -1) - start=$(cat /sys/class/power_supply/BAT*/charge_control_start_threshold 2>/dev/null | head -1) [[ -n $cycles ]] && printf 'cycles\t%s\n' "$cycles" - if [[ -n $end ]]; then - if [[ -n $start && $start != $end ]]; then - printf 'threshold\t%s-%s%%\n' "$start" "$end" + if [[ -n $threshold_end ]]; then + if [[ -n $threshold_start && $threshold_start != $threshold_end ]]; then + printf 'threshold\t%s-%s%%\n' "$threshold_start" "$threshold_end" else - printf 'threshold\t%s%%\n' "$end" + printf 'threshold\t%s%%\n' "$threshold_end" fi fi exit 0 fi -if [[ $state == "charging" ]]; then +if [[ $charge_holding == "true" ]]; then + if [[ -n $threshold_start && $threshold_start != $threshold_end ]]; then + threshold_label="${threshold_start}-${threshold_end}%" + else + threshold_label="${threshold_end}%" + fi + + echo "Battery ${percentage}% · Holding at ${threshold_label} · ${power_rate}W / ${capacity}Wh" +elif [[ $state == "charging" ]]; then echo "Battery ${percentage}% · ${time_remaining} to full ·  ${power_rate}W / ${capacity}Wh" else echo "Battery ${percentage}% · ${time_remaining} left ·  ${power_rate}W / ${capacity}Wh" diff --git a/shell/plugins/power/BarWidget.qml b/shell/plugins/power/BarWidget.qml index d047ce45..2869617f 100644 --- a/shell/plugins/power/BarWidget.qml +++ b/shell/plugins/power/BarWidget.qml @@ -34,8 +34,9 @@ Panel { var defaultIcons = ["󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"] var index = Math.max(0, Math.min(9, Math.floor(device.percentage * 10))) + if (root.chargeThresholdActive) return defaultIcons[index] if (device.state === UPowerDeviceState.FullyCharged) return "󰂅" - if (device.state === UPowerDeviceState.Charging || root.chargeThresholdActive) return chargingIcons[index] + if (device.state === UPowerDeviceState.Charging) return chargingIcons[index] if (!UPower.onBattery) return "" return defaultIcons[index] } @@ -64,11 +65,18 @@ Panel { readonly property bool fullyCharged: { var device = UPower.displayDevice - return device && device.isPresent && device.state === UPowerDeviceState.FullyCharged + return device && device.isPresent && device.state === UPowerDeviceState.FullyCharged && !root.chargeThresholdActive } readonly property bool chargeThresholdActive: { var device = UPower.displayDevice - return !!(device && device.isPresent && !UPower.onBattery && device.state === UPowerDeviceState.Discharging) + if (!(device && device.isPresent && !UPower.onBattery)) return false + + var fraction = Math.max(0, Math.min(1, device.percentage)) + if (device.state === UPowerDeviceState.Discharging || device.state === UPowerDeviceState.PendingCharge) return true + if (device.state === UPowerDeviceState.FullyCharged && fraction < 0.99) return true + if (device.state !== UPowerDeviceState.Charging || fraction >= 0.99) return false + + return Number(device.changeRate || 0) <= 0.2 || Number(device.timeToFull || 0) >= 8 * 60 * 60 } readonly property bool batteryFull: fullyCharged || (!UPower.onBattery && batteryFraction >= 1) readonly property bool batteryFlowIdle: batteryFull || chargeThresholdActive @@ -82,7 +90,7 @@ Panel { readonly property bool batteryLow: UPower.onBattery && batteryFraction > 0 && batteryFraction <= 0.2 readonly property bool charging: { var d = UPower.displayDevice - return d && d.isPresent && d.state === UPowerDeviceState.Charging + return d && d.isPresent && d.state === UPowerDeviceState.Charging && !root.chargeThresholdActive } readonly property color batteryFillColor: { @@ -420,8 +428,14 @@ Panel { Column { width: (parent.width - parent.spacing) / 2 spacing: Style.spacing.labelGap - InfoPair { label: UPower.onBattery ? "Time left" : "Time to full"; value: root.batteryFlowIdle ? "-" : (root.batteryInfo.time || "—") } - InfoPair { label: UPower.onBattery ? "Discharging" : "Charging"; value: root.chargeThresholdActive ? "Holding" : (root.batteryFull ? "-" : (root.batteryInfo.rate || "")) } + InfoPair { + label: root.chargeThresholdActive ? "Charge limit" : (UPower.onBattery ? "Time left" : "Time to full") + value: root.chargeThresholdActive ? (root.batteryInfo.threshold || "-") : (root.batteryFlowIdle ? "-" : (root.batteryInfo.time || "—")) + } + InfoPair { + label: root.chargeThresholdActive ? "Battery state" : (UPower.onBattery ? "Discharging" : "Charging") + value: root.chargeThresholdActive ? "Holding" : (root.batteryFull ? "-" : (root.batteryInfo.rate || "")) + } } }