- 29. Mai
- 11:53
- 2010
Updated- 29. Mai
- 11:59
- 2010
Calculating Battery Health
Recently a twitter-collegue noticed that in iStat Nano his battery-health heavily fluctuates between 90% and 96%. He asked if that would occur to other MacBook users. I quickly took a look at the Battery section and after letting my battery drain, I couldn't see any fluctuation (constantly 96%). However yesterday, my health was up to 97%.
Consequence: Let's tear iStat nano apart!
So, tearing OSX apps open is as easy as it can get. You simply go to the app you like, do a right click and select "Show Package Contents" (or something similar, I'm not using an english osx). There you go, the application lies open in front of you. Resources, language files, etc.
In our case, as it is with most dashboard widgets, we see a lot of javascripts, stylesheets, htmls, images and, not to my surprise, a file called iStatNano.bundle. This tells us that the dashboard widgets gets it's data through an interface, which is an app. Repeat the steps from above on the iStatNano.bundle and you will see a Contents folder with the following content:
- Info.plist
- MacOs (containing a compiled program)
- Resources (with language files)
- s
Wait,.. What?! s? That's definitely not a standard folder. Open that one quickly before it disappears!
Congratulations, you just opened up the interface's source.
The developer ships the whole source with it, including a nice xcodeproj file. That makes our formula-finding a lot easier. Open that one, note that you need Xcode installed.
There it lies, the holy grail: ISNDataMinerBattery.m. On line 163:
latestData = [[NSArray arrayWithObjects:time,percentage,source,status,cycles,[NSString stringWithFormat:@"%@%% (%imAh)",capacity_percentage, [current_capacity intValue]],nil] retain];
I guess it's pretty obvious that this line tells us where the health is calculated, namely capacity_percentage
[NSString stringWithFormat:@"%@%% (%imAh)",capacity_percentage, [current_capacity intValue]],nil]
Lets move up to line 109 to 114
max_capacity = [NSNumber numberWithInt:[[sensorData objectForKey:@"DesignCapacity"] intValue]]; current_capacity = [NSNumber numberWithInt:[[sensorData objectForKey:@"MaxCapacity"] intValue]]; capacity_percentage = [NSNumber numberWithFloat:((float)[current_capacity floatValue] / (float)[max_capacity floatValue])*100]; capacity_percentage = [NSNumber numberWithInt:[capacity_percentage intValue]]; if([capacity_percentage intValue] > 100) capacity_percentage = [NSNumber numberWithInt:100];
There you go. The battery health is calculated by a simple and straight forward percentage calculation. current_capacity/max_capacity * 100.
So it doesn't seem that a fluctuating battery health is iStat Nano's fault.
ioStatus = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceNameMatching("AppleSmartBattery"), &sensorsIterator);
Note that I don't know a lot of ObjC. I've only once came close to it by getting emesene 1.x sound working on OSX via PyObjC. However, my guess is that the program gets it's battery data through the daemon "AppleSmartBattery". Considering I'm guessing right, which might not be the case,..
Why does the value fluctuate then?
Because of a flaky battery? Or is capacity not accurately measurable?
I'm open for discussion/suggestion/correction.
Thanks for reading