There are several utilities out there to check the current health of your Macbook and Macbook Pro batteries. However none of them seem to automatically store historical data. The script below can be used to create a historical log of your battery’s health.
- #!/usr/bin/perl
- #################################################
- # bat-stat.pl #
- # #
- # Simple script to log battery statistics on #
- # MacBook/Pro laptops from Apple Computers #
- # #
- # V0.2 #
- # #
- # Feedback: bat-stat@digger.cc #
- # #
- #################################################
- # Load some needed modules.
- #use strict;
- use File::Find ();
- use Socket;
- use Sys::Hostname;
- # Get the hostname of the local machine
- $hostname = hostname();
- ($host,$d1) = split /\./, $hostname;
- # Set some date variables
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time-0);
- $year += 1900;
- $mon += 1;
- if ($mon < 10){
- $mon = "0"."$mon";
- }
- if ($mday < 10){
- $mday = "0"."$mday";
- }
- if ($hour < 10){
- $hour = "0"."$hour";
- }
- if ($min < 10){
- $min = "0"."$min";
- }
- # Collected system profile data
- $profile_hw = `/usr/sbin/system_profiler SPHardwareDataType`;
- @hw = split /\n/, $profile_hw;
- foreach $line (@hw) {
- chomp; # chomp, bachewie chomp
- if ($line =~ m/Boot ROM/) {
- ($d1,$d2,$d3,$bootrom) = split(' ',$line);
- }
- if ($line =~ m/SMC Version/) {
- ($d1,$d2,$smc) = split(' ',$line);
- }
- if ($line =~ m/Serial Number/) {
- ($d1,$d2,$serial) = split(' ',$line);
- }
- }
- $profile_sw = `/usr/sbin/system_profiler SPSoftwareDataType`;
- @sw = split /\n/, $profile_sw;
- foreach $line (@sw) {
- chomp; # chomp, bachewie chomp
- if ($line =~ m/System Version/) {
- ($d1,$d2,$d3,$d4,$d5,$sysver) = split(' ',$line);
- }
- if ($line =~ m/Kernel Version/) {
- ($d1,$d2,$d3,$kernver) = split(' ',$line);
- }
- }
- $profile_power = `/usr/sbin/system_profiler SPPowerDataType`;
- $profile_power = `/usr/sbin/system_profiler SPPowerDataType`;
- @power = split /\n/, $profile_power;
- foreach $line (@power) {
- if ($line =~ m/Connected/) {
- ($d1,$acpower) = split(' ',$line);
- }
- if ($line =~ m/Charging/) {
- ($d1,$charging) = split(' ',$line);
- }
- if ($line =~ m/Manufacturer/) {
- ($d1,$make) = split(' ',$line);
- }
- if ($line =~ m/Device name/) {
- ($d1,$d2,$device) = split(' ',$line);
- }
- if ($line =~ m/Pack Lot/) {
- ($d1,$d2,$d3,$packlot) = split(' ',$line);
- }
- if ($line =~ m/PCB Lot/) {
- ($d1,$d2,$d3,$pcblot) = split(' ',$line);
- }
- if ($line =~ m/Firmware Version/) {
- ($d1,$d2,$firmware) = split(' ',$line);
- }
- if ($line =~ m/Cell Revision/) {
- ($d1,$d2,$cellrev) = split(' ',$line);
- }
- if ($line =~ m/Charge remaining/) {
- ($d1,$d2,$d3,$charge) = split(' ',$line);
- }
- if ($line =~ m/Full charge capacity/) {
- ($d1,$d2,$d3,$d4,$capacity) = split(' ',$line);
- }
- if ($line =~ m/Cycle count/) {
- ($d1,$d2,$cycount) = split(' ',$line);
- }
- if ($line =~ m/Amperage/) {
- ($d1,$d2,$amperage) = split(' ',$line);
- }
- if ($line =~ m/Voltage/) {
- ($d1,$d2,$voltage) = split(' ',$line);
- }
- }
- # Log the data
- if (-s (glob("~/$host.bat-stat.log"))) {
- open LOGFILE, ">>", (glob("~/$host.bat-stat.log"));
- print LOGFILE "$year,$mon,$mday,$hour,$min,$host,$serial,$charge,$capacity,$cycount,$amperage,$voltage, $acpower,$charging,$make,$device,$packlot,$pcblot,$firmware,$cellrev,$bootrom,$smc,$sysver, $kernver\n";
- close(LOGFILE);
- } else {
- open LOGFILE, ">", (glob("~/$host.bat-stat.log"));
- print LOGFILE "Year,Month,Day,Hour,Minute,Hostname,Serial Number,Charge Remaining,Charge Capacity,Cycle Count,Amperage,Voltage,AC Power,Battery Charging,Battery Manufacteur,Battery Device,Battery Pack Lot,Battery PCB Lot,Battery Firmware,Cell Revision,Bootrom Version,SMC Version,System Version,Kernel Version\n";
- print LOGFILE "$year,$mon,$mday,$hour,$min,$host,$serial,$charge,$capacity,$cycount,$amperage,$voltage,$acpower,$charging,$make,$device,$packlot,$pcblot,$firmware,$cellrev,$bootrom,$smc,$sysver,$kernver\n";
- close(LOGFILE);
- }
As always ensure that your path to your perl executable matches the first line of the script. I store the script in my home directory and schedule it in cron. Edit your crontab to have something like this:
- 57 * * * * /Users/USERNAME/bat-stat.pl > /dev/null 2>&amp;amp;amp;amp;amp;amp;amp;1
Adjust USERNAME to your user. The output file will be stored in your home directory as $hostname.bat-stat.log. A sample output is below:
- Year,Month,Day,Hour,Minute,Hostname,Serial Number,Charge Remaining,Charge Capacity,Cycle Count,Amperage,Voltage,AC Power,Battery Charging,Battery Manufacteur,Battery Device,Battery Pack Lot,Battery PCB Lot,Battery Firmware,Cell Revision,Bootrom Version,SMC Version,System Version,Kernel Version
- 2009,02,11,11,57,Ares,W870233ZW0H,3293,5562,0,1814,12096,Yes,Yes,Sony,ASMB012, 0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,12,57,Ares,W870233ZW0H,4528,5562,0,830,12277,Yes,Yes,Sony,ASMB012, 0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,13,57,Ares,W870233ZW0H,5354,5562,0,814,12536,Yes,Yes,Sony,ASMB012, 0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,14,57,Ares,W870233ZW0H,5562,5562,0,129,12622,Yes,No,Sony,ASMB012, 0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,15,57,Ares,W870233ZW0H,5562,5562,0,129,12622,Yes,No,Sony,ASMB012, 0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,16,57,Ares,W870233ZW0H,4738,5587,0,-1505,11977,No,No,Sony,ASMB012,0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,17,57,Ares,W870233ZW0H,2962,5582,0,-1836,11457,No,No,Sony,ASMB012,0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,18,57,Ares,W870233ZW0H,1027,5601,0,-1756,10994,No,No,Sony,ASMB012,0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,20,57,Ares,W870233ZW0H,2597,5611,1,1827,11911,Yes,Yes,Sony,ASMB012, 0001,0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,21,57,Ares,W870233ZW0H,4203,5611,1,833,12234,Yes,Yes,Sony,ASMB012,0001, 0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,22,57,Ares,W870233ZW0H,5035,5611,1,826,12403,Yes,Yes,Sony,ASMB012,0001, 0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
- 2009,02,11,23,57,Ares,W870233ZW0H,5611,5611,1,133,12626,Yes,No,Sony,ASMB012,0001, 0000,0110,0303,MBP22.00A5.B07,1.12f5,10.5.6,9.6.0
And of course, “Why would you want to collect this information?” All batteries have a finite useful life. Most commercial batteries are designed to provide X% of their original capacity for Y number of charging cycles. In the case of Macbook and Macbook Pro’s that number has been reported to be 80% capacity for 300 cycles. (citation needed) Using this tool you can monitor your battery’s health over time to help identifiy usage trends and the affects on the battery’s charge capacity. You can also determine if a change to firmware and/or software has altered the overall trend of your battery capacity.
* Tested against Intel Macbook and Macbook Pros on both 10.4 and 10.5
Macbook / Pro Battery Monitoring | Question Defense great article thank you.
Thanks for the script. A few things to make it work on a new (2010) MacbookPro with Snow Leopard 10.6.2
1. The code above does not contain the quoted newline characters and the quoted ‘.’ (all backslashes are stripped); not sure if the comment allows me to do this (test: bare n or single-backslashed \n or double-backslashed \\n) but you need
split /./ –> split /\./
split /n/ –> split /\n/
and all ‘n’ at the end of the print statements should be newlines (\n) as well
2. Small changes in the output format of /usr/sbin/system_profiler SPHardwareDataType require new code for
if ($line =~ m/SMC Version/) {
($d1,$d2,$d3,$smc) = split(‘ ‘,$line);
if ($line =~ m/Serial Number/) {
($d1,$d2,$d3,$serial) = split(‘ ‘,$line);
(note the added $d3 to catch and additional field in the output).
Süper makale olmuş saolasın!