#!/usr/bin/env python3 import sys import re from sys import stdout from os import path, environ from os.path import join, isdir from collections import namedtuple, OrderedDict POWER_CLASS = '/sys/class/power_supply' BATTERIES = ( environ.get('BATTERY', 'BAT0'), 'cw2015-battery' ) DISCHARNGING = 'Discharging' RESET = '0' RED = '0;31' GREEN = '0;32' YELLOW = '0;33' BLUE = '0;34' MAGENTA = '0;35' CYAN = '0;36' BatteryInfo = namedtuple( 'BatteryInfo', [ 'name', 'model', 'manufacturer', 'technology', 'capacity', 'status', 'currrent_percent', 'time_to_empty', 'charging_current' ] ) def print_help(): text = """ battery [-h] [-d] [-i] -h ... help -d ... dump all values -i ... short info """.strip() pattern = re.compile(r'^\s+', re.MULTILINE) text = pattern.sub('', text) print(text) def find_battery_uevent(batteries): for battery in batteries: path = join(POWER_CLASS, battery) if isdir(path): return join(path, 'uevent') return None def start_color(color): return '\033[' + color + 'm' def colored(text, color): return start_color(color) + text + start_color(RESET) def read_battery(filename): with open(filename) as file: lines = file.readlines() items = map(lambda line: line.strip().split('=', 2), lines) return OrderedDict(items) def load_battery_info(info): return BatteryInfo( name = info['POWER_SUPPLY_NAME'], model = info.get('POWER_SUPPLY_MODEL_NAME', ''), manufacturer = info.get('POWER_SUPPLY_MANUFACTURER', ''), technology = info['POWER_SUPPLY_TECHNOLOGY'], capacity = float(info['POWER_SUPPLY_CHARGE_FULL']) / 1e6, status = info['POWER_SUPPLY_STATUS'], currrent_percent = int(info['POWER_SUPPLY_CAPACITY']), time_to_empty = int(info.get('POWER_SUPPLY_TIME_TO_EMPTY_NOW', 0)), charging_current = int(float(info['POWER_SUPPLY_CURRENT_NOW']) / 1e3) ) def terminal_colored(text, color): if sys.stdout.isatty(): return colored(text, color) else: return text def format_status(info): color = RED if info.status == DISCHARNGING else GREEN return terminal_colored(info.status, color) def format_percent(info): color = GREEN if info.currrent_percent > 30 else RED return terminal_colored(f'{info.currrent_percent}%', color) def format_time_to_empty(info): if info.time_to_empty == 0: return '??:??' else: hours = info.time_to_empty // 60 minutes = info.time_to_empty % 60 return terminal_colored(f"{hours}:{minutes:02d}", CYAN) def battery_model(info): model = '' if info.model: model += info.model if info.manufacturer: if model: model += ' - ' model += info.manufacturer if model: model += ': ' return model def print_battery_detail(info): model = battery_model(info) capacity = terminal_colored(str(info.capacity), YELLOW) print(f"Battery: {model}{info.technology} {capacity} Ah") print("Battery level: " + format_percent(info)) print("Battery status: " + format_status(info)) if info.status == DISCHARNGING: time_to_empty = format_time_to_empty(info) print(f"Time to empty: {time_to_empty} [hour:minutes]") print(f"{info.status} current: {info.charging_current} mA") def print_battery_info(info): percent = format_percent(info) status = format_status(info) state = f"level={percent} status={status}" if info.status == DISCHARNGING: time_to_empty = format_time_to_empty(info) state += f" duration={time_to_empty}" print(state) def dump_battery_info(uevent, battery): print(f"# {uevent}") for key, value in battery.items(): print(f"{key} = {value}") def main(args): uevent = find_battery_uevent(BATTERIES) if not uevent: print("No battery found") return battery = read_battery(uevent) info = load_battery_info(battery) if '-h' in args: print_help() elif '-d' in args: dump_battery_info(uevent, battery) elif '-i' in args: print_battery_info(info) else: print_battery_detail(info) if __name__ == '__main__': main(sys.argv) """ cat /sys/class/power_supply/cw2015-battery/uevent POWER_SUPPLY_NAME=cw2015-battery POWER_SUPPLY_TYPE=Battery POWER_SUPPLY_CAPACITY=100 POWER_SUPPLY_STATUS=Full POWER_SUPPLY_PRESENT=1 POWER_SUPPLY_VOLTAGE_NOW=4314000 POWER_SUPPLY_TIME_TO_EMPTY_NOW=0 POWER_SUPPLY_TECHNOLOGY=Li-ion POWER_SUPPLY_CHARGE_FULL=9800000 POWER_SUPPLY_CHARGE_FULL_DESIGN=9800000 POWER_SUPPLY_CURRENT_NOW=0 """