diff --git a/.gitignore b/.gitignore index faf297f..6ce517f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *.app .* +!.github +!.vscode +CLAUDE.md diff --git a/README.md b/README.md index a5b14c2..a414830 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,9 @@ Example usage: ```shell # This will enable charging when your battery dips under 80, and disable it when it exceeds 80 battery maintain 80 + +# This will maintain your battery between 70-80%, letting it rest in that range +battery maintain 70-80 ``` After running a command like `battery charging off` you can verify the change visually by looking at the battery icon: @@ -78,9 +81,10 @@ Usage: battery status output battery SMC status, % and time remaining - battery maintain LEVEL[1-100,stop] + battery maintain LEVEL[1-100,stop] or RANGE[lower-upper] reboot-persistent battery level maintenance: turn off charging above, and on below a certain value - eg: battery maintain 80 + eg: battery maintain 80 # maintain at 80% + eg: battery maintain 70-80 # maintain between 70-80% eg: battery maintain stop battery charging SETTING[on/off] diff --git a/battery.sh b/battery.sh index cef907b..d127cc6 100755 --- a/battery.sh +++ b/battery.sh @@ -59,10 +59,11 @@ Usage: output logs of the battery CLI and GUI eg: battery logs 100 - battery maintain PERCENTAGE[1-100,stop] + battery maintain PERCENTAGE[1-100,stop] or RANGE[lower-upper] reboot-persistent battery level maintenance: turn off charging above, and on below a certain value it has the option of a --force-discharge flag that discharges even when plugged in (this does NOT work well with clamshell mode) - eg: battery maintain 80 + eg: battery maintain 80 # maintain at 80% + eg: battery maintain 70-80 # maintain between 70-80% eg: battery maintain stop battery maintain VOLTAGE[${voltage_min}V-${voltage_max}V,stop] (HYSTERESIS[${voltage_hyst_min}V-${voltage_hyst_max}V]) @@ -149,6 +150,34 @@ function valid_percentage() { fi } +function valid_percentage_range() { + # Check if input matches range format: NUMBER-NUMBER + if ! [[ "$1" =~ ^[0-9]+-[0-9]+$ ]]; then + return 1 + fi + + # Extract lower and upper bounds + local lower="${1%-*}" + local upper="${1#*-}" + + # Validate both numbers are valid percentages + if ! valid_percentage "$lower" || ! valid_percentage "$upper"; then + return 1 + fi + + # Check lower < upper + if [[ "$lower" -ge "$upper" ]]; then + return 1 + fi + + # Check bounds are reasonable (lower >= 10, upper <= 100) + if [[ "$lower" -lt 10 ]] || [[ "$upper" -gt 100 ]]; then + return 1 + fi + + return 0 +} + function valid_voltage() { if [[ "$1" =~ ^[0-9]+(\.[0-9]+)?V$ ]]; then return 0 @@ -637,16 +666,32 @@ if [[ "$action" == "maintain_synchronous" ]]; then fi fi - if ! valid_percentage "$setting"; then - log "Error: $setting is not a valid setting for battery maintain. Please use a number between 0 and 100" + # Parse setting - could be single value or range + local lower_bound="" + local upper_bound="" + local is_range=false + + if valid_percentage_range "$setting"; then + # Range format: lower-upper + is_range=true + lower_bound="${setting%-*}" + upper_bound="${setting#*-}" + elif valid_percentage "$setting"; then + # Single value format (backward compatible) + is_range=false + lower_bound="$setting" + upper_bound="$setting" + else + log "Error: $setting is not a valid setting for battery maintain. Please use a number between 0 and 100, or a range like 70-80" exit 1 fi # Check if the user requested that the battery maintenance first discharge to the desired level if [[ "$subsetting" == "--force-discharge" ]]; then # Before we start maintaining the battery level, first discharge to the target level - log "Triggering discharge to $setting before enabling charging limiter" - $battery_binary discharge "$setting" + local discharge_target="$lower_bound" + log "Triggering discharge to $discharge_target before enabling charging limiter" + $battery_binary discharge "$discharge_target" log "Discharge pre battery-maintenance complete, continuing to battery maintenance loop" else log "Not triggering discharge as it is not requested" @@ -655,7 +700,11 @@ if [[ "$action" == "maintain_synchronous" ]]; then # Start charging battery_percentage=$(get_battery_percentage) - log "Charging to and maintaining at $setting% from $battery_percentage%" + if [[ "$is_range" == true ]]; then + log "Maintaining battery between $lower_bound% and $upper_bound% from $battery_percentage%" + else + log "Charging to and maintaining at $setting% from $battery_percentage%" + fi # Loop until battery percent is exceeded while true; do @@ -664,17 +713,17 @@ if [[ "$action" == "maintain_synchronous" ]]; then is_charging=$(get_smc_charging_status) ac_attached=$(get_charger_state) - if [[ "$battery_percentage" -ge "$setting" && ("$is_charging" == "enabled" || "$ac_attached" == "1") ]]; then + if [[ "$battery_percentage" -ge "$upper_bound" && ("$is_charging" == "enabled" || "$ac_attached" == "1") ]]; then - log "Charge above $setting" + log "Charge at or above $upper_bound%" if [[ "$is_charging" == "enabled" ]]; then disable_charging fi change_magsafe_led_color "green" - elif [[ "$battery_percentage" -lt "$setting" && "$is_charging" == "disabled" ]]; then + elif [[ "$battery_percentage" -lt "$lower_bound" && "$is_charging" == "disabled" ]]; then - log "Charge below $setting" + log "Charge below $lower_bound%" enable_charging change_magsafe_led_color "orange" @@ -787,12 +836,12 @@ if [[ "$action" == "maintain" ]]; then is_voltage=true - # Check if setting is value between 0 and 100 - elif ! valid_percentage "$setting"; then + # Check if setting is a percentage range or single value + elif ! valid_percentage "$setting" && ! valid_percentage_range "$setting"; then log "Called with $setting $action" - # If non 0-100 setting is not a special keyword, exit with an error. + # If setting is not a valid percentage/range and not a special keyword, exit with an error. if ! { [[ "$setting" == "stop" ]] || [[ "$setting" == "recover" ]]; }; then - log "Error: $setting is not a valid setting for battery maintain. Please use a number between 0 and 100, or an action keyword like 'stop' or 'recover'." + log "Error: $setting is not a valid setting for battery maintain. Please use a number between 0 and 100, a range like 70-80, or an action keyword like 'stop' or 'recover'." exit 1 fi @@ -803,7 +852,11 @@ if [[ "$action" == "maintain" ]]; then log "Starting battery maintenance at ${setting}V ±${subsetting}V" nohup $battery_binary maintain_voltage_synchronous $setting $subsetting >>$logfile & else - log "Starting battery maintenance at $setting% $subsetting" + if valid_percentage_range "$setting"; then + log "Starting battery maintenance between ${setting/-/% and }%" + else + log "Starting battery maintenance at $setting% $subsetting" + fi nohup $battery_binary maintain_synchronous $setting $subsetting >>$logfile & fi @@ -823,7 +876,11 @@ if [[ "$action" == "maintain" ]]; then else log "Writing new setting $setting to $maintain_percentage_tracker_file" echo $setting >$maintain_percentage_tracker_file - log "Maintaining battery at $setting%" + if valid_percentage_range "$setting"; then + log "Maintaining battery between ${setting/-/% and }%" + else + log "Maintaining battery at $setting%" + fi fi fi @@ -900,7 +957,11 @@ if [[ "$action" == "status" ]]; then if test -f $pidfile; then maintain_percentage=$(cat $maintain_percentage_tracker_file 2>/dev/null) if [[ $maintain_percentage ]]; then - maintain_level="$maintain_percentage%" + if valid_percentage_range "$maintain_percentage"; then + maintain_level="${maintain_percentage/-/% - }%" + else + maintain_level="$maintain_percentage%" + fi else maintain_level=$(cat $maintain_voltage_tracker_file 2>/dev/null) maintain_level=$(echo "$maintain_level" | awk '{print $1 "V ±" $2 "V"}')