awkでMacBookの電池情報を表示する

ioregコマンドを使ってMacのシステム情報を取得します。データ処理はawkを使っています。

ioregでシステム情報を見る

我が家のMacBookはProもAirもバッテリーの充電回数は1000回です。充放電を繰り返していると、電池寿命まであとどのくらいだろう?というのが気になります。

もちろんSystem Informationで充電回数を見ることはできるんですが、いちいちウィンドウを開いて確認するのも煩わしい。どうにかならないかな?と調べてみたらioregコマンドでSystem Information情報を取れることがわかりました。

ワンライナーでやろう

試しにパイプでつないでみたら1行でできました。 3つのコマンドを使っています。

ioreg
Macのシステム情報を表示するコマンドです。-lで全ての情報を表示します。
grep
awkが処理するデータ量を減らすために”product-name”、”CycleCount”または”Capacity”を含むデータを抽出します。
awk
処理の肝です。grepで前処理したデータから必要なものだけ切り出して計算結果を表示しています。

実行結果は下記のようになります。残充放電回数とSOHの値が電池寿命の目安です。すでに80%まで落ちててちょっとショック。。。

$ blife
Your MacBook's Battery status is
Charge Remaining        2601(mAh)
State of Charge         46%
Cycle Count             81
Cycle Count Remaining   919
Full Charge Capacity    5549(mAh)
State of Health         80.4%

grepで前処理

ioregを実行してみたらものすごい量のデータが流れて行きました。試しに行数を数えたら8710行。(^_^;

awkは処理が遅いうえioregデータの一部にやたら長い行があってそもそも処理できないのと、両方の理由からgrepで前処理をします。

8710行あったデータが7行に減りました。このうち必要なのは6行です。

$ ioreg -l | wc
    8710   69414 1199662
$ ioreg -l | grep '\(product-name\)\|\(CycleCount\)\|\(Capacity\)'
    |   "product-name" = <"MacBookPro8,2">
    | |           "MaxCapacity" = 5549
    | |           "CurrentCapacity" = 2404
    | |           "LegacyBatteryInfo" = {"Amperage"=18446744073709550622,"Flags"=4,"Capacity"=5549,"Current"=2404,"Voltage"=11180,"Cycle Count"=81}
    | |           "CycleCount" = 81
    | |           "DesignCapacity" = 6900
    | |           "DesignCycleCount9C" = 1000

リチウムイオンバッテリーは充放電回数が寿命の指標になります。劣化の度合いは満充電容量値の低下(SOH:State Of Health)で測ります。従ってシステム情報からは充放電回数と充電容量を取り出せば良いことになります。

  • MaxCapacity:現時点での最大充電容量(mAh)。
  • CurrentCapacity:現在の充電容量(mAh)。
  • CycleCount:現在までの充放電回数。
  • DesignCapacity:初期充電容量(mAh)。新品の時の最大充電可能容量です。
  • DesignCycleCount9C:規定充放電回数。これを超えると電池寿命です。

これらの数値を読み取ることができれば、あとは計算して結果を表示するだけ。ちなみにSOHの計算は(MaxCapacity/DesignCapacity)*100です。

awkで処理する

ioregの出力データを見ると、最後のデータが必要な数値になっています。そしてその2つ前にある””で囲まれたデータ(スペースで区切られたものがデータなので、=も一つのデータです)がデータの種類を表しています。処理としては各行の後ろから3つ目のデータを見て取捨選択をし、必要なものだけ最後のデータを取り込めばよさそうです。

awkの処理部分は以下のようになります。行の途中でも行末に\を置くことでエラーを回避できます。

[awk]
awk ‘{
if($(NF-2)==”\”product-name\””)model=$NF;
else if($(NF-2)==”\”MaxCapacity\””)curCap=$NF;
else if($(NF-2)==”\”CurrentCapacity\””)Cap=$NF;
else if($(NF-2)==”\”CycleCount\””)curCC=$NF;
else if($(NF-2)==”\”DesignCapacity\””)maxCap=$NF;
else if($(NF-2)~”\”DesignCycleCount”)maxCC=$NF}
END{
if(model!~”MacBook”)print “Effective only on the MacBook.\n”;
else{
if(curCap!=0)SOC=100*Cap/curCap; # 除算エラー避け
if(maxCap!=0)SOH=100*curCap/maxCap; # 除算エラー避け
printf(“Your MacBook\047s Battery status is\n” \
“Charge Remaining\t%d\(mAh\)\n” \
“State of Charge\t\t%d%%\n” \
“Cycle Count\t\t%d\n” \
“Cycle Count Remaining\t%d\n” \
“Full Charge Capacity\t%d\(\mAh\)\n” \
“State of Health\t\t%3.1f%%\n\n”,
Cap,SOC,curCC,maxCC-curCC,curCap,SOH)}
}’
[/awk]

awkは{}で囲まれた処理を各行のデータに対して実行します。ただし{}の前にBEGINまたはENDがある処理は、各々データ処理の前か後に一回だけ実行されます。

今回のスクリプトは2行目から7行目で入力されたデータの処理をおこないます。$NFが最後のデータ、$(NF-2)が最後のデータの二つ前を表しており、ifかelse ifかの違いはあるもののいずれの行も$(NF-2)の値をチェックして$NFの値を取り込んでいます。

9行目ではMacBookシリーズであるかどうかをチェックしています。電池を持たないMacの場合、正しいデータが取れないことが予想されるためMacBookシリーズ以外では以降の処理をスキップすることでエラーを回避します。また、万が一割り算の分母が0になるデータが取れてしまった場合にエラーで止まるのを回避するため、11,12行目で除算エラーチェックをしています。

全ての情報を処理して必要なデータを取り込んだら、最後にprintfで結果表示をしています。printfは””で囲まれた文字列を表示しますが、文字列中にある%で始まるフォーマット指定に従い、後に続く変数の内容に置き換えます。

このスクリプトはGitHubのTakeru-chan/blifeにblife.shというファイルで置いてあります。

One more thing…

OSXのAutomatorでこのスクリプトをMacアプリに変換してみました。 シェルスクリプトでは結果を文字で出力していましたが、アプリではMacの合成音声に読み上げさせています。 >> Macアプリ版blife