Skip to content

Instantly share code, notes, and snippets.

@lloeki
Last active January 10, 2023 16:04
Show Gist options
  • Save lloeki/2630561 to your computer and use it in GitHub Desktop.
Save lloeki/2630561 to your computer and use it in GitHub Desktop.
Battery status script for Mac OS X
#!/usr/bin/env python
from __future__ import print_function
from __future__ import division
from subprocess import Popen, PIPE
def ioreg_battery_info():
output = Popen(["ioreg", "-r", "-k", "LegacyBatteryInfo", "-w", "0"], stdout=PIPE).communicate()[0]
try: #python3
return str(output, encoding='utf-8')
except TypeError: #python2
return output
def parse_ioreg_dict(output):
return dict(
[ (kw.strip().strip('"'), vw.strip())
for kw, vw
in [ line.split("=", 1)
for line
in output.split('\n') if line.find('=')>0
]
]
)
def is_two_complement_negative(value):
return value > (2**63-1)
def two_complement(value):
return 2**64 - value
def fix_negative(value):
if is_two_complement_negative(value):
return -two_complement(value)
else:
return value
def ioreg_battery_dict():
output = ioreg_battery_info()
return parse_ioreg_dict(output)
def fix_integer(string):
return fix_negative(int(string))
def format_time(string):
minutes = int(string)
if minutes == 65535:
return None
else:
return "%s:%s" % (minutes//60, minutes%60)
def percentage(ratio):
return "%s%%" % (int(ratio*100))
humanize_index = {
"TimeRemaining": format_time,
"AvgTimeToEmpty": format_time,
"AvgTimeToFull": format_time,
"InstantTimeToEmpty": format_time,
"FullToEmptyTime": format_time,
"WearRatio": percentage,
"ChargeRatio": percentage,
}
def humanize_data(k, v):
if k in humanize_index:
return humanize_index[k](v)
else:
return v
def wear_ratio(info):
return int(info["MaxCapacity"]) / int(info["DesignCapacity"])
def charge_ratio(info):
return int(info["CurrentCapacity"]) / int(info["MaxCapacity"])
def full_to_empty_time(info):
if get_data(info, "Amperage") < 0:
return -int(info["MaxCapacity"])*60 / get_data(info, "Amperage")
else:
return 65535
synthetize_index = {
"Amperage": lambda i: fix_integer(i["Amperage"]),
"InstantAmperage": lambda i: fix_integer(i["InstantAmperage"]),
"WearRatio": wear_ratio,
"ChargeRatio": charge_ratio,
"FullToEmptyTime": full_to_empty_time,
}
def synthetize_data(battery_info, k):
if k in synthetize_index:
return synthetize_index[k](battery_info)
def get_data(battery_info, k):
if k in synthetize_index:
return synthetize_data(battery_info, k)
elif k in battery_info:
return battery_info[k]
else:
raise KeyError("%s" % k)
keys_to_show = [
"Temperature",
"CycleCount",
#"DesignCycleCount9C",
"DesignCapacity",
"MaxCapacity",
"WearRatio",
"CurrentCapacity",
"ChargeRatio",
"Voltage",
"Amperage",
"InstantAmperage",
"InstantTimeToEmpty",
"TimeRemaining",
"AvgTimeToEmpty",
"AvgTimeToFull",
"FullToEmptyTime",
]
def print_key_value(k, v):
if v is not None:
print("%s = %s" % (k, v))
battery_info = ioreg_battery_dict()
for k in keys_to_show:
print_key_value(k, humanize_data(k, get_data(battery_info, k)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment