DEV Community

Cover image for Magic Mouse Low Battery Alert
samselfridge
samselfridge

Posted on

Magic Mouse Low Battery Alert

One of the worst things about the Apple Magic mouse is the fact that the OS doesn't give you any kind of low battery alert until it hits 2% battery. Maybe mine is defective, but that's not enough to get through a full work day. This wouldn't be so bad if not for the worst thing about the magic mouse:

You can't charge it and use it at the same time....thanks Apple.

This details a very basic work around. We're going to add a cron job that runs every 15min that will check the battery level and show a notification if its below a certain threshold.

Setup your script

  • Open a new terminal window
  • enter the following commands, I'll explain what they all are later down
    • mkdir bin
    • cd bin
    • touch mouseCheck.sh
    • chmod a+x mouseCheck.sh

Copy all of this black text

#!/bin/bash 

# Edit cron tab
# env EDITOR=nano crontab -e
# */15 * * * *  ~/bin/mouseCheck.sh
#
#

BATT=`ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i mouse -A 20 | grep BatteryPercent | cut -d= -f2 | cut -d' ' -f2`
KEY_BATT=`ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i "Magic Keyboard" -A 20 | grep BatteryPercent | cut -d= -f2 | cut -d' ' -f2`

# defaults to warn at 12%; accepts other number as 1st argument (useful for testing)
COMPARE=${1:-12}
#COMPARE=101

if [ -z "$BATT" ]; then
  echo 'No mouse found.'
  exit 0 
fi

if (( BATT < COMPARE )); then
  osascript -e "display notification \"Mouse battery is at ${BATT}%.\" with title \"Mouse Battery Low\""
fi

if [ -z "$KEY_BATT" ]; then
  echo 'No Keyboard found.'
  exit 0
fi

if (( KEY_BATT < COMPARE )); then
  osascript -e "display notification \"Keyboard battery is at ${KEY_BATT}%.\" with title \"Keyboard Battery Low\""
fi
Enter fullscreen mode Exit fullscreen mode
  • Go back to your terminal and type the following:
    • cat > mouseCheck.sh
  • Paste the above CMD + V
  • Hit CMD + D to return to terminal prompt.

Set up the cronjob

  • Type the following into the same terminal(capitals are important):
    • env EDITOR=nano crontab -e

You should something that looks like this:
Nano Window

paste the following into it:
*/15 * * * * ~/bin/mouseCheck.sh

  • Hit Ctrl + x
  • Hit y
  • Hit Enter

Alt Text

You might get a warning saying 'Terminal wants to administer' your computer, Click Ok.

Alt Text

Thats it! If you battery or keyboard get below 12% you should get an alert like this in the top right. I've found 12% is more than enough to get me through 2 days in case I forget after the first one.

Mine are higher because when writing this article I changed the alert level to get a screen shot.

Stick around and I'll explain what everything does if you're curious and what you can change on your own.

Commands explained:

  • mkdir bin - create a folder called bin. This is typically where executables go.
  • cd bin - change current directory to be bin
  • touch mouseCheck.sh - create an empty file called mouseCheck.sh The .sh means this is a shell script, or will be at least.
  • cat > mouseCheck.sh write something to mouseCheck.sh - in this case we don't tell it what to write, so it will prompt us for input afterwards, until it sees the End of File character (EoF)
  • ctrl + D send the EoF character to close input.

At this point you can see whats in the file with the command: cat mouseCheck.sh cat is the basic command to read text files.

  • env EDITOR=nano crontab -e - Open the cron tab for editing. we need to add the env EDITOR=nano before hand because it lets us make a temporary change to the ENVIRONMENT VARIABLES just for this command. It's a good idea to not change things unless we specifically mean to.

    • If you used lower case editor, or left it out you'll end up in the default text editor VIM, which is a very powerful editor but has a very steep learning curve and is famous for not being able to be easily quit. Alt Text
    • If you end up here by accident you can either:
      • Close your terminal and start over (remember to cd bin)
      • Attempt to exit vim by:
      • Hitting esc then type :q and hit enter
  • Crontab syntax isn't very complicated but its unique and weird the first time you see it, if you're interested I found this was a good read on it: https://www.geeksforgeeks.org/crontab-in-linux-with-examples/

    • */15 * * * * ~/bin/mouseCheck.sh translates to run the script mouseCheck.sh located in the bin directory/folder in my home directory (~) every 15 minutes.

Script Explained

#!/bin/bash 
Enter fullscreen mode Exit fullscreen mode

This tells the program where to find the program to run this script. In our case we're using the shell bash thats in the /bin directory. This is different from the bin we put our script in.

# Edit cron tab
# env EDITOR=nano crontab -e
# */15 * * * *  ~/bin/mouseCheck.sh
Enter fullscreen mode Exit fullscreen mode

Honestly this isn't needed...the # at the beginning tell bash to ignore these lines, but I leave this here because I can never remember how to get to the cron editor.

BATT=`ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i mouse -A 20 | grep BatteryPercent | cut -d= -f2 | cut -d' ' -f2`
KEY_BATT=`ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i "Magic Keyboard" -A 20 | grep BatteryPercent | cut -d= -f2 | cut -d' ' -f2`
Enter fullscreen mode Exit fullscreen mode

This sets up 2 variables, one for mouse battery and one for keyboard battery by running several commands each. Each time you see a | its taking the output from one command and using it as the input for the next one.

# defaults to warn at 12%; accepts other number as 1st argument (useful for testing)
COMPARE=${1:-12}
#COMPARE=101

if [ -z "$BATT" ]; then
  echo 'No mouse found.'
  exit 0 
fi

if (( BATT < COMPARE )); then
  osascript -e "display notification \"Mouse battery is at ${BATT}%.\" with title \"Mouse Battery Low\""
fi

if [ -z "$KEY_BATT" ]; then
  echo 'No Keyboard found.'
  exit 0
fi

if (( KEY_BATT < COMPARE )); then
  osascript -e "display notification \"Keyboard battery is at ${KEY_BATT}%.\" with title \"Keyboard Battery Low\""
fi
Enter fullscreen mode Exit fullscreen mode

I've run out of time, but if you're very interested in the rest of these commands drop a comment and I can fill the rest in.

Cheers.

Top comments (8)

Collapse
 
sjimmie profile image
Simon

I too was getting quite annoyed only getting a battery-low warning at 2%. This script is a great workaround.
The only thing I had to add was the path to ioreg as the cron job could not find it

PATH=/usr/sbin:$PATH

Collapse
 
djtnut profile image
David Tepper

Where does this code go?

Collapse
 
sjimmie profile image
Simon

In the mouseCheck.sh, just before the 'BATT=..' command

Collapse
 
sanderadio profile image
Sander

Thank you for posting this! So annoying Apple hasn't built in their own warning. One typo though: Hit CMD + D to return to terminal prompt should be CTR + D (control).

Collapse
 
richard_weinstock_9468fad profile image
Richard Weinstock • Edited

This script is absolutely beautiful, thank-you so much!

Here are some recommendations:

If you have multiple mice or keyboards, consider only the one having the lowest battery level:

BATT=ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i mouse -A 20 | grep BatteryPercent | cut -d= -f2 | cut -d' ' -f2 | sort -n | head -1

KEY_BATT=ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i "Magic Keyboard" -A 20 | grep BatteryPercent | cut -d= -f2 | cut -d' ' -f2 | sort -n | head -1

If you would like to play a sound (From /System/Library/Sounds) along with the notification:

osascript -e "display notification \"Mouse battery is at ${BATT}%.\" with title \"Mouse Battery Low\" sound name \"Bottle\""

osascript -e "display notification \"Keyboard battery is at ${KEY_BATT}%.\" with title \"Keyboard Battery Low\" sound name \"Bottle\""

Collapse
 
matt_c96831fa85 profile image
Matt

You can also check if the mouse is charging with the following:

CHARGING=`ioreg -c AppleDeviceManagementHIDEventService -r -l | grep -i mouse -A 20 | grep Transport | cut -d= -f2 | cut -d' ' -f2 | cut -d'"' -f2`

if [ "$CHARGING" = "USB" ]; then
  exit 0
fi
Enter fullscreen mode Exit fullscreen mode
Collapse
 
djtnut profile image
David Tepper

When I save the crontab file, it's tacking on this weird extension at the end of the file. See screenshot attached.

Image description

Collapse
 
sjimmie profile image
Simon

That's normal. You are not editing the crontab file directly. Once you save this tmp file and it contains no errors, it will overwrite the actual cron file (in /var/at/tabs/)