Skip to content

Instantly share code, notes, and snippets.

@NightMachinery
Last active December 6, 2024 21:21
Show Gist options
  • Save NightMachinery/402863ccf37515a804b2f5fa15672375 to your computer and use it in GitHub Desktop.
Save NightMachinery/402863ccf37515a804b2f5fa15672375 to your computer and use it in GitHub Desktop.
A guide on limiting macOS battery charging to at most 80%.

Why?

See BU-808: How to Prolong Lithium-based Batteries.

Related Tools

Several of the following are also compatible with Intel machines, although their functionality may be limited to when the laptop lid is open. For detailed information, please consult their respective documentation.

Limiting Apple Silicon macOS charging to 80%:

1. Install smc:

To install smc on your macOS, follow these steps:

# Install smcfancontrol using Homebrew
brew install --cask smcfancontrol

# Copy the 'smc' binary to /usr/local/bin/ for global access
sudo cp '/Applications/smcFanControl.app/Contents/Resources/smc' /usr/local/bin/

2. Update sudo permissions:

To avoid entering your password every time you use the smc command with sudo, you can update the sudoers file.

  1. Open the sudoers file using the visudo command:
sudo visudo

Or if you don't know vi/vim:

sudo VISUAL=nano visudo
  1. Scroll to the bottom of the file and add the following line. Replace username with your actual macOS username:
username ALL=(ALL) NOPASSWD: /usr/local/bin/smc
  1. Save and exit the editor.

3. Using the Zsh Functions:

Make sure you have added the provided Zsh functions in battery_limit.zsh to ~/.zshenv or another Zsh configuration file.

  • To enable the battery charge limit:

    battery-charge-limit-enable
  • To disable the battery charge limit:

    battery-charge-limit-disable
  • To check the status of the battery charge limit:

    battery-charge-limit-status

With these functions in place and smc installed, you can easily manage the battery charge limit of your macOS device from the terminal.

Automate Charge Limiting on Startup:

To ensure that the battery charge limit is applied automatically after each system restart, you can use cron, a time-based job scheduler, to execute the necessary command upon startup. Here's how to set it up:

  • Ensure that the Zsh helper functions (battery-charge-limit-enable, battery-charge-limit-disable, and battery-charge-limit-status) are defined in ~/.zshenv since this file is sourced by all instances of Zsh, including non-interactive shells that run during the startup process. If you had previously placed the functions in ~/.zshrc, please move them to ~/.zshenv.

  • Open the terminal and type the following command to find out where zsh is installed:

which zsh

The command will output the path to zsh, which usually is /bin/zsh. Note this path as you will need it for the crontab entry.

  • Open the terminal and access the crontab configuration file by typing the following command:
crontab -e
  • If you're not familiar with vi or vim, the default editors in the terminal, you might want to switch to a more user-friendly editor temporarily. To use nano as the editor for crontab, for instance, use this instead:
VISUAL=nano crontab -e
  • In the crontab editor, set the SHELL variable to ensure that zsh is used. Then, add a new line to specify the job that should run at reboot:
SHELL="/bin/zsh"  # Replace "/bin/zsh" with the actual path if different

@reboot battery-charge-limit-enable
  • Save and exit the editor. If you're using nano, you can do so by pressing CTRL+X, then Y to confirm the changes, and Enter to write to the file.

Compatibility

This needs an updated firmware on an Apple Silicon machine.

# Apple Silicon laptops with firmware > 13.0 have a native charge threshold that does not required any userspace daemon running.
# This native limit works even when the laptop is sleeping or powered off therefore it is preferable to the userspace daemon.
# Nonetheless, it only works with fixed thresholds (80% as upper limit and 70% as lower limit).
# CHWA key is the one used to enable/disable the native limit. 01 = 80% limit, 00 = no limit
##
typeset -g smc_command="/usr/local/bin/smc"
typeset -g smc_charge_limit_key="CHWA"
typeset -g smc_charge_limit_status_on="01"
typeset -g smc_charge_limit_status_off="00"
function battery-charge-limit-enable {
if [[ "$(uname)" == "Darwin" ]]; then
if [[ ! -e "${smc_command}" ]]; then
echo 'SMC command not found!'
return 1
fi
sudo "${smc_command}" -k "${smc_charge_limit_key}" -w "${smc_charge_limit_status_on}"
else
echo "Not a Darwin system."
fi
}
function battery-charge-limit-disable {
if [[ "$(uname)" == "Darwin" ]]; then
if [[ ! -e "${smc_command}" ]]; then
echo 'SMC command not found!'
return 1
fi
sudo "${smc_command}" -k "${smc_charge_limit_key}" -w "${smc_charge_limit_status_off}"
else
echo "Not a Darwin system."
fi
}
function battery-charge-limit-status {
if [[ "$(uname)" == "Darwin" ]]; then
if [[ ! -e "${smc_command}" ]]; then
echo 'SMC command not found!'
return 1
fi
local status_raw="$(sudo "${smc_command}" -k "${smc_charge_limit_key}" -r)"
# Extract the bytes using regex
if [[ "$status_raw" =~ 'bytes ([0-9]+)' ]]; then
status_raw=$match[1]
fi
case "$status_raw" in
"${smc_charge_limit_status_on}")
echo "on"
;;
"${smc_charge_limit_status_off}")
echo "off"
;;
*)
echo "Unknown ${smc_charge_limit_key} status: $status_raw"
;;
esac
else
echo "Not a Darwin system."
fi
}
@kushal10
Copy link

Hey @NightMachinery , I added this battery_limit.zsh to my .zshrc but 'battery-charge-limit-enable' thse commands don't work?

@foldfree
Copy link

foldfree commented Dec 6, 2023

Works for me on Sonoma 14.1
Just paste the content of battery_limit.zsh straight into your .zshrc file, however it needs to be enabled again after a reboot.
Also I don't know how to limit charging to 70% instead of 80?

@johnnyoshika
Copy link

johnnyoshika commented Dec 16, 2023

I'm getting this error on Sonoma 14.2 (MacBook Pro M2, 16"):

image

Also, how can I check my firmware version? When I go to my hardware settings, I see the firmware version in what looks like an incompatible format to what's listed in the script above (firmware > 13.0):

System Firmware Version:	10151.61.4

@NightMachinery
Copy link
Author

NightMachinery commented Dec 18, 2023

Works for me on Sonoma 14.1 Just paste the content of battery_limit.zsh straight into your .zshrc file, however it needs to be enabled again after a reboot. Also I don't know how to limit charging to 70% instead of 80?

For the reboot, you need to use sth that runs the code on the OS startup. One easy way is to modify the crontab:

$ crontab -e
SHELL="/usr/local/bin/zsh"
@reboot battery-charge-limit-enable

I am not sure if this works without any problems, I use sth else myself. But it should work.

You need to place the helper Zsh functions into ~/.zshenv though, as ~/.zshrc is not loaded by non-interactive shells.

AFAIK, there is no way to change the 80 percent limit to something else when using this method on Apple Silicon machines.

@NightMachinery
Copy link
Author

I'm getting this error on Sonoma 14.2 (MacBook Pro M2, 16"):

image Also, how can I check my firmware version? When I go to my hardware settings, I see the firmware version in what looks like an incompatible format to what's listed in the script above (firmware > 13.0):
System Firmware Version:	10151.61.4

I don't know. Running
system_profiler SPHardwareDataType
shows this version for me:
System Firmware Version: 8419.60.44

@kushal10
Copy link

Works for me on Sonoma 14.1 Just paste the content of battery_limit.zsh straight into your .zshrc file, however it needs to be enabled again after a reboot. Also I don't know how to limit charging to 70% instead of 80?

Thank you, that worked!

@foldfree
Copy link

Works for me on Sonoma 14.1 Just paste the content of battery_limit.zsh straight into your .zshrc file, however it needs to be enabled again after a reboot. Also I don't know how to limit charging to 70% instead of 80?

For the reboot, you need to use sth that runs the code on the OS startup. One easy way is to modify the crontab:

$ crontab -e
SHELL="/usr/local/bin/zsh"
@reboot battery-charge-limit-enable

I am not sure if this works without any problems, I use sth else myself. But it should work.

You need to place the helper Zsh functions into ~/.zshenv though, as ~/.zshrc is not loaded by non-interactive shells.

AFAIK, there is no way to change the 80 percent limit to something else when using this method on Apple Silicon machines.

Thank you, that worked well, I pasted the functions into a .zshenv file and edited the crontab.

One thing: on my machine, zsh is located at /bin/zsh, not /usr/local/bin/zsh

@johnnyoshika

  1. Did you install smc?
  2. Did you edit your visudo file?
  3. Are you able to open smcFanControl.app from the finder Applications folder?

From your screenshot, it looks like you may have skipped the first 2 steps of the installation guide.
The zsh functions needs them in order to work.

@johnnyoshika
Copy link

@foldfree I did step 1 but may not have done step 2. The instructions seemed to indicate that it was optional but maybe not?

To avoid entering your password every time you use the smc command with sudo, you can update the sudoers file.

I'll try again after editing the visudo file.

@artemgordinskiy
Copy link

Here's the fish version for those who don't use the z shell:
https://gist.github.com/artemgordinskiy/f4db09d41484387691624ef128fd180b

@NightMachinery
Copy link
Author

@foldfree I did step 1 but may not have done step 2. The instructions seemed to indicate that it was optional but maybe not?

To avoid entering your password every time you use the smc command with sudo, you can update the sudoers file.

I'll try again after editing the visudo file.

The visudo changes are indeed optional. Without them, you'll have to input your password each time you use these functions. I'm not sure what's causing the error you're encountering.

@eproxus
Copy link

eproxus commented Jan 25, 2024

bclm now implement this natively (without the need for smcfancontrol) on Apple Silicon Macs. It is also much easier to install and setup than adding it manually to your shell.

@fangar
Copy link

fangar commented Dec 6, 2024

This has worked fine for me until today after an update to Sonoma 14.7.1.

battery-charge-limit-status gives this response:
Unknown CHWA status: CHWA [ ] no data

battery-charge-limit-enable gives this response:
Error: SMCWriteKey() = e00002bc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment