Battery Monitor (Using Shell Scripts)

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"

That was ignorant of me, actually I was thinking that someone may have round figures. (envy). :wink:

So your solution is perfect. I was also thinking of that, but not implementing it

@ DJ Bazzie Wazzie: open -f seem to activate TextEdit, not just bring the first window to foreground, but it is a sweet onle liner, pity it can’t be combined with the -b switch. :slight_smile:

Also mentioned in post #7 :smiley:

Yeah. But that one’s a list-to-text coercion without regard for delimiters. :stuck_out_tongue:

And this is a nice way to get output from a do shell script into a new TextEdit document. Size the window at your own discretion.

do shell script "system_profiler SPPowerDataType | open -fg ; open -b \"com.apple.textedit\""

But it can be combined with -a

do shell script "system_profiler SPPowerDataType | open -f -a textedit"

edit : Just for fun an one liner to get only the battery percentage

do shell script "x=($(ioreg -l | egrep -i '(max|current)capacity' | sed s/[^0-9]//g)); echo ${x[1]} / ${x[0]} '* 100' | bc -l | xargs printf %.2f%%"

or to get is an number


run script (do shell script "x=($(ioreg -l | egrep -i '(max|current)capacity' | sed s/[^0-9]//g)); echo ${x[1]} / ${x[0]} '* 100' | bc -l | xargs printf %.2f")

I use run script so the given number can be coerced into an number no matter which locale settings. English notations shouldn’t have to use run script.

:smiley:

I like ioreg! Thanks!

Here is one that are a little bit more than a line, but shows you your cycles left before the capacity of the battery is down to 80 percent!


set cycles to (do shell script "system_profiler SPPowerDataType | sed -n '/[Cc]ycle count/ s/\\([ \\t]\\{1,\\}[^0-9]\\{1,\\}\\)\\([0-9]*\\).*$/\\2/p'") as number

display dialog "You have : " & (1000 - cycles) & " cycles left!"

# Number of initial cycles will vary! Check with Apple!

Edit

It is also nice to know about a way to coerce a float correctly.

If somebody asks me why i just didn’t do that like this:

set cycles to (do shell script "system_profiler SPPowerDataType | sed -n '/[Cc]ycle count/ s/[^0-9]*\\([0-9]*\\)/\\1/p'") as number

Then I’d say I wanted to show off the modifiers, where {0,} means nought or more (*), {1,} means one or more (+) and {0,1} means zero or 1, which is the way to specify the modifiers with basic regular expressions. :wink:

A nice little script deserves a nice little icon. :wink:

property PowerIcon : a reference to file ((path to library folder from system domain as text) & "PreferencePanes:EnergySaver.prefPane:Contents:Resources:EnergySaver.icns")

Nice. :slight_smile: Rather disturbingly, it works as a property, without recompiling, when the script’s transferred my other computer, whose startup disk has a different name. However, it only works in Script Editor. It errors reassuringly in Script Menu unless recompiled on that machine.

:slight_smile: Sorry about that. Implicit globals doesn’t help either.

So I guess a note about having to recompile when transefering is the way to handle that for the future.

Hi everyone! Sorry that this is a bump, but I stopped working on Battery Monitor in 2011 and I was delighted to see some community members still working to try and find ways to improve it. Today, I came across the old script files, and sure enough, Battery Monitor wasn’t working on 10.8 (I wrote it back in 10.6, so I’m not surprised). As some of you noticed, the string names were capitalized, so I had to do some minor tweaking to get this to work. After a few hours of work, I’m pretty pleased with the changes. Let me know what y’all think. In a way, I’m kind of proud that we got this to work just in AppleScript. I’m also including a link to download the binary file, which is actually needed to run this (due to referencing self-contained images to be shown in dialog boxes). I did the art a long time ago, and I’m planning on making it look sexier. Anyways, enough talk. Here’s version 3.0.0. I just realized I only credited StefanK. Sorry guys, I’ll add you to the creds in next version.

--Battery Monitor 3.0.0
--Written by Panah Neshati, with help from StefanK
--Terms and Conditions: http://www.gnu.org/licenses/gpl.html

--Changes:
----Simplified the interface, removed lots of unneeded icons.
----Now writes data to an actual log file.
----Icons will soon get a makeover.

on roundThis(n, numDecimals)
	set x to 10 ^ numDecimals
	(((n * x) + 0.5) div 1) / x
end roundThis

try
	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 current_charge to item 1 of battery_data
	set max_charge to item 2 of battery_data
	set charge_cycles to item 3 of battery_data
	set amps to item 4 of battery_data
	set volts to item 5 of battery_data
on error
	display dialog "Unable to retrieve battery information." with title "Battery Monitor" with icon 1
	quit
end try
set amps to roundThis(((amps ^ 2) ^ 0.5 / 1000), 2)
set volts to roundThis(volts / 1000, 2)
set pct to (roundThis((current_charge / max_charge) * 100, 1))
--& "%") as string
set icon_disp to (((path to me) & "Contents:Resources:Icons:" & (round roundThis((pct) as number, -1)) & ".icns" as string))
display dialog "Charge: " & pct & "%
Cycles: " & charge_cycles & "
Amperage: " & amps & " amps
Voltage: " & volts & " V" with title "Battery Monitor" buttons {"Log", "OK"} default button 2 with icon alias icon_disp
if button returned of the result is "Log" then
	set m to month of (current date)
	set d to day of (current date)
	set y to year of (current date)
	set temp to (m & " " & d & ", " & y) as string
	set battery_log to open for access POSIX file "/var/tmp/Battery.log" with write permission
	write (((current date) & "
-------------------------
Current Charge: " & current_charge & " mAh
Maximum Charge: " & max_charge & " mAh
Charge Cycles: " & charge_cycles & "
Amperage: " & amps & " amps
Voltage: " & volts & " V
-------------------------
") as string) to battery_log starting at eof
	close access battery_log
	tell application "Finder" to reveal POSIX file "/var/tmp/Battery.log"
end if

Any ideas for other features to add/tidbits of info the user might find interesting/helpful?
Thanks in advance. You guys gave me the courage to work on this much longer than I otherwise would have. Also, sorry about taking forever to do this. Mostly I forgot about it, but I also had trouble finding my MacScripter login (and my email changed).

Let me know what you think of the logs. Should they provide more info than the dialog box, or the same info?

:smiley:
Panah

Model: MacBook Pro
AppleScript: 2.2.4
Browser: Firefox 23.0
Operating System: Mac OS X (10.8)