Battery Monitor (Using Shell Scripts)

Just a little AppleScript I made for personal purposes and felt like sharing. Note that it does take a while to gather the information, but it doesn’t eat up RAM. Please credit me if you do use part/all of my code. A comment line at the top referencing this URL would do just fine.

--Battery Monitor 1.0.1
--Copyright © Panah Neshati, 2011.

on replaceText(find, replace, someText)
	set prevTIDs to text item delimiters of AppleScript
	set text item delimiters of AppleScript to find
	set someText to text items of someText
	set text item delimiters of AppleScript to replace
	set someText to "" & someText
	set text item delimiters of AppleScript to prevTIDs
	return someText
end replaceText

set battery_remaining to do shell script "system_profiler | grep 'Charge remaining (mAh):'"
set battery_remaining to replaceText("          Charge remaining (mAh): ", "", battery_remaining)

set battery_capacity to do shell script "system_profiler | grep 'Full charge capacity (mAh):'"
set battery_capacity to replaceText("          Full charge capacity (mAh): ", "", battery_capacity)

set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %") as string

set cycles to do shell script "system_profiler | grep 'Cycle count:'"
set cycles to replaceText("          Cycle count: ", "", cycles)

set amperage to do shell script "system_profiler | grep 'Amperage (mA):'"
set amperage to replaceText("      Amperage (mA): ", "", amperage)

set voltage to do shell script "system_profiler | grep 'Voltage (mV):'"
set voltage to replaceText("      Voltage (mV): ", "", voltage)

display dialog "				Charge: " & percent_charge & "
				Cycles: " & cycles & "
				Amperage: " & amperage & " mA
				Voltage: " & voltage & " mV" with title "Battery Monitor"

Enjoy! :wink:

I’ll bet a dab hand at bash scripting could make this into one script that would be much faster than six calls to system_profiler and grep, but it works nicely (albeit slowly) on my MBP.

Yeah, is there a way to possibly shorten the time? I’ve searched the internet and found this shell command.

do shell script "ioreg -l | grep Capacity | less"

A bit of parsing it and I can get the info I need. I’m busy at the moment, but will rewrite that in a short bit and update it. Thanks for checking it out, Adam.

Hi Panah,

you can accelerate your script by refining the output of System Profiler.
SPPowerDataType displays only the Power Data lines.


"system_profiler SPPowerDataType | grep .

This is an optimized version which retrieves the data with a single shell call


set battery_data to paragraphs of (do shell script "system_profiler SPPowerDataType | awk '/(Charge remaining)|(Full charge capacity)|(Cycle count)|(Amperage)|(Voltage)/ {print $NF}'")
set {battery_remaining, battery_capacity, cycles, amperage, voltage} to battery_data
set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %")

display dialog "				Charge: " & percent_charge & "
				Cycles: " & cycles & "
				Amperage: " & amperage & " mA
				Voltage: " & voltage & " mV" with title "Battery Monitor"


Thank you so much, Stefan! I knew there was a way to retrieve only certain information, but wasn’t sure what the one for Power was.

--Battery Monitor 1.0.2
--Copyright © Panah Neshati and StefanK, 2011.

on replaceText(find, replace, someText)
	set prevTIDs to text item delimiters of AppleScript
	set text item delimiters of AppleScript to find
	set someText to text items of someText
	set text item delimiters of AppleScript to replace
	set someText to "" & someText
	set text item delimiters of AppleScript to prevTIDs
	return someText
end replaceText

set battery_remaining to do shell script "system_profiler SPPowerDataType | grep 'Charge remaining (mAh):'"
set battery_remaining to replaceText("          Charge remaining (mAh): ", "", battery_remaining)

set battery_capacity to do shell script "system_profiler SPPowerDataType | grep 'Full charge capacity (mAh):'"
set battery_capacity to replaceText("          Full charge capacity (mAh): ", "", battery_capacity)

set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %") as string

set cycles to do shell script "system_profiler SPPowerDataType | grep 'Cycle count:'"
set cycles to replaceText("          Cycle count: ", "", cycles)

set amperage to do shell script "system_profiler SPPowerDataType | grep 'Amperage (mA):'"
set amperage to replaceText("      Amperage (mA): ", "", amperage)

set voltage to do shell script "system_profiler SPPowerDataType | grep 'Voltage (mV):'"
set voltage to replaceText("      Voltage (mV): ", "", voltage)

display dialog "				Charge: " & percent_charge & "
				Cycles: " & cycles & "
				Amperage: " & amperage & " mA
				Voltage: " & voltage & " mV" with title "Battery Monitor"

I appreciate your suggestion with using the small shell you wrote to do it, but I don’t really know how to use the ‘awk’ command.

Thanks, I really appreciate your help! No more waiting time :slight_smile:

I’ve updated this program, adding an ‘Export’ feature. Maybe this will become better than coconutBattery.

--Battery Monitor 1.0.4
--Copyright © Panah Neshati and StefanK, 2011.

on replaceText(find, replace, someText)
	set prevTIDs to text item delimiters of AppleScript
	set text item delimiters of AppleScript to find
	set someText to text items of someText
	set text item delimiters of AppleScript to replace
	set someText to "" & someText
	set text item delimiters of AppleScript to prevTIDs
	return someText
end replaceText

set battery_remaining to do shell script "system_profiler SPPowerDataType | grep 'Charge remaining (mAh):'"
set battery_remaining to replaceText("          Charge remaining (mAh): ", "", battery_remaining)

set battery_capacity to do shell script "system_profiler SPPowerDataType | grep 'Full charge capacity (mAh):'"
set battery_capacity to replaceText("          Full charge capacity (mAh): ", "", battery_capacity)

set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %") as string

set cycles to do shell script "system_profiler SPPowerDataType | grep 'Cycle count:'"
set cycles to replaceText("          Cycle count: ", "", cycles)

set amperage to do shell script "system_profiler SPPowerDataType | grep 'Amperage (mA):'"
set amperage to replaceText("      Amperage (mA): ", "", amperage)

set voltage to do shell script "system_profiler SPPowerDataType | grep 'Voltage (mV):'"
set voltage to replaceText("      Voltage (mV): ", "", voltage)

display dialog "				Charge: " & percent_charge & "
				Cycles: " & cycles & "
				Amperage: " & amperage & " mA
				Voltage: " & voltage & " mV" with title "Battery Monitor" buttons {"Export", "OK"} default button 2
if button returned of the result is "Export" then
	set thefile to (choose file name default name "Battery Status.txt" default location (path to desktop)) as string
	set the_file to (open for access thefile with write permission)
	write ("Charge: " & percent_charge & "
Cycles: " & cycles & "
Amperage: " & amperage & " mA
Voltage: " & voltage & " mV") to the_file starting at 1
	close access the_file
end if

Any other criticism is appreciated. Thanks to Adam and Stefan. :wink:

change

set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %") as string

to

set percent_charge to ((((battery_remaining / battery_capacity) * 10000 as integer) / 100) & " %") as string

All those numbers after the comma isn’t neccessary

(You can remove you copyright now :P)

Stefan, your script does not work, as it returns this error:

Line 2 was selected for this error:

set battery_data to paragraphs of (do shell script "system_profiler SPPowerDataType | awk '/(Charge remaining)|(Full charge capacity)|(Cycle count)|(Amperage)|(Voltage)/ {print $NF}'")
set {battery_remaining, battery_capacity, cycles, amperage, voltage} to battery_data
set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %")

display dialog "				Charge: " & percent_charge & "
				Cycles: " & cycles & "
				Amperage: " & amperage & " mA
				Voltage: " & voltage & " mV" with title "Battery Monitor"

Neither does the other one, but (I don’t know if this changes anything) I have a newer model Mac. I have the higher-end 17" MacBook Pro.

Hi Dylan,

Sorry for the bump. Can you tell me what your cycle count is? You can find it in System Profiler. The only way the script would fail would be if the values weren’t returned or if either “Charge remaining” or “Full charge capacity” weren’t numbers. And judging by the error you got, I’d say your cycle count (3rd item of the list) isn’t being returned.

I know it’s been a while since this was active, but.
I got this script to work by fixing the capitalization in the shell script query. Working for me:

set battery_data to paragraphs of (do shell script "system_profiler SPPowerDataType | awk '/(Charge Remaining)|(Full Charge Capacity)|(Cycle Count)|(Amperage)|(Voltage)/ {print $NF}'")
set {battery_remaining, battery_capacity, cycles, amperage, voltage} to battery_data
set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %")

display dialog "Charge: " & percent_charge & return & "Cycles: " & cycles & return & "Amperage: " & amperage & "mA" & return & "Voltage: " & voltage & " mV" with title "Battery Monitor"

Hi n8henrie. Welcome to MacScripter and thanks for your post. :slight_smile:

Your script doesn’t work on my Snow Leopard system because only the first word in each multi-word label is capitalised, eg. “Charge remaining”, not “Charge Remaining”. It works both ways if the initial letters are replaced with regex classes “[Cc]harge [Rr]emaining”). Or, given the unlikelihood of clashes in these cases, they could be simply be replaced with dots (“.harge .emaining”)!

I’d prefer the shell script results to include the labels, to ensure that the figures are attributed to the correct properties instead of simply assuming they occur in a particular order. Edit: I don’t know how to do this with “awk”, but with “sed” it could be something like this:

set battery_data to paragraphs of (do shell script "system_profiler SPPowerDataType | sed -En '/Charge [Rr]emaining|Full [Cc]harge [Cc]apacity/ p ; s/[^A-Z]*Cycle [Cc]ount/Cycles/p ; s/[^A-Z]*(Amperage|Voltage) \\(([^)]+)\\): ([0-9-]+)/\\1: \\3 \\2/p ;'")

if (battery_data is {}) then
	display dialog "Are you sure this machine's a portable?" buttons "Er." default button 1 with title "Battery Monitor" with icon stop
else
	set output to ""
	repeat with this_detail in battery_data
		if (this_detail contains "Remaining") then
			set charge to word -1 of this_detail
		else if (this_detail contains "Capacity") then
			set capacity to word -1 of this_detail
		else
			set output to output & return & this_detail
		end if
	end repeat
	display dialog ("Charge: " & (charge / capacity * 100) & "%" & output) with title "Battery Monitor"
end if

Thanks for the welcome - I’ve found MacScripter helpful many times in the past, so I’m glad to have finally created an account.

Interesting, on 10.8 I had to capitalize all words of a multi-word phrase (as they appear in System Profiler) to get it to work. Good catch.

Good point about labeling the variables as you go - I just opened System Profiler to ensure that the dialog displayed the correct results, but your solution is much more generalizable. Thanks again!

Model: Macbook Pro
Browser: Safari 536.26.17
Operating System: Mac OS X (10.8)

Weird, I’m on a snow leopard machine and the first letter of every word is capitalized and n8henrie script works as expected. When I go a little back his script seems to work in leopard as well.

You can do the same thing with AWK as Nigel did with sed. Personally I prefer to make everything lowercase first and I like your awk better, only because it’s much better readable. So to make everything lowercase I put tr in between or use the tolower function in AWK.


set battery_data to paragraphs of (do shell script "system_profiler SPPowerDataType | tr [A-Z] [a-z] | awk '/(charge remaining)|(full charge capacity)|(cycle count)|(amperage)|(voltage)/ {print $NF}'")
--or make lowercase with AWK itself
set battery_data to paragraphs of (do shell script "system_profiler SPPowerDataType | awk 'tolower($0) ~ /(charge remaining)|(full charge capacity)|(cycle count)|(amperage)|(voltage)/ {print $NF}'")

set {battery_remaining, battery_capacity, cycles, amperage, voltage} to battery_data
set percent_charge to (((battery_remaining / battery_capacity) * 100) & " %")

display dialog "Charge: " & percent_charge & return & "Cycles: " & cycles & return & "Amperage: " & amperage & "mA" & return & "Voltage: " & voltage & " mV" with title "Battery Monitor"

edit: The reason I choose to make everything lowercase is that standard POSIX awk doesn’t have the case insensitive option while GNU AWK (or just GAWK) have this option. In theory it’s the same, most applications with case insensitive string functions is just making every string lowercase before starting to process.

The system_profile result is a mixture of “title case” and “sentence case” on my Snow Leopard machine (MacBook Pro, 10.6.8), but the labels tested for the current purpose only have the initial characters of their first words capitalised.

I’ve just tried pulling out the power lead to see if, by some very unlikely chance, that makes any difference. It doesn’t. Not to case anyway. It does make the Amperage figure go negative, which causes my sed code not to return it. I’ve now adjusted the code to allow for the possibility of a minus sign. :slight_smile:

All the scripts error on my Leopard machine, which isn’t a portable. (I’ve also edited my script to catch this.) Everything returned there by “system_profiler SPPowerDataType” is in title case and those same labels are also in title case on the Snow Leopard machine.

Hello!

I prefer Nigels approach, as by the way he performs the case transformations, doesn’t make you have to readjust the case when you are printing the report! :slight_smile: It is nitpicking! :smiley: And within the output of his do shell script. ( I like to have this turn up in a log now and then.)

It is a nice script, I changed the last line to make the capacity look better, (with maybe a rounding error of the third decimal ).

display dialog (("Charge: " & text 1 thru 5 of ((charge / capacity * 100) as text)) & " %" & output) with title "Battery Monitor"

I like to see the whole story as well:


set theText to do shell script "system_profiler SPPowerDataType" without altering line endings
tell application "TextEdit"
	make new document
	set text of its document 1 to theText
end tell
do shell script "open -b \"com.apple.textedit\""
tell application "System Events"
	tell application process "TextEdit"
		set position of its window 1 to {100, 22}
		set size of its window 1 to {600, 950}
	end tell
end tell

Well it makes it more odd then… Both my solutions to n8henrie script works for Leopard, Snow Leopard and Mountain Lion (don’t have an Lion Machine here). Every word is capitalized and only the words ‘on’ are lowercase. I have an old(er) MacBookPro8.2 running Snow Leopard (which took a lot of effort to remove Lion and install Snow Leopard), an MacBookPro10.1 Mountain Lion machine (which gives the right Amperage), an MacBookPro7.1 running Snow Leopard and an old MacBookPro4.1 running Leopard.

All of them return in capitalized content so I don’t think that the capitalization-issue is OS depended. Maybe it’s hardware depended (MacBookPro model number) or localization issues. My $LANG settings are null for do shell scripts (default is “C”).

Why GUI scripting ? TextEdit is scriptable


set theText to do shell script "system_profiler SPPowerDataType" without altering line endings
tell application "TextEdit"
	activate
	if (count documents) = 0 or length of (get text of document 1) > 0 then make new document
	set text of document 1 to theText
	set bounds of window 1 to {100, 22, 700, 972}
end tell


I am lazy, and UI scripting the window, is a uniform way to do it for different apps, (provided that UI scripting is enabled of course).

I had used the open -b already, to ascertain that only the front window of TextEdit was to come forward too, so it seemed like a good approach. :slight_smile:

I’ll come back to this later, as I am interested in finding out the degradation of the Battery in terms of cycles.

do shell script "system_profiler SPPowerDataType | open -f"

. and maybe a text error if there are fewer than five characters in the calculation result. This may suit your taste:

display dialog ("Charge: " & ((charge / capacity * 10000 as integer) / 100) & "%" & output) with title "Battery Monitor"