воскресенье, 18 ноября 2012 г.

Linux, Python и велосипеды: индикатор заряда батареи

Доброго времени суток! На домашнем компьютере я использую xubuntu, на которую поверх поставлен Openbox + LXPanel. К моему сожалению, стандартный индикатор батареи в LXPanel не захотел корректо работать, он лишь отображает — подключено ли питание от сети или нет, а заряд всегда отображается как 100%. Разумеется, я бы без особых проблем нашёл десяток тысячу-другую аналогичных индикаторов заряда батареи, но просто ради развлечения написал свой на Python, маленький скрипт на GTK2. Для запуска нужен, разумеется, — сам интерпретатор Python и PyGTK2. Для Debian и бунточек:
sudo apt-get install python python-gtk2
Скачиваем отсюда архив со Python-скриптом и папкой с иконками батареи, проверим что у скрипта battery_indicator.py есть права на исполнение и запускаем. Всё, индикатор батареи висит в системном трее, далее просто закидываем скрипт в автозапуск.

Индикатор батареи имеет 5 состояний отображения иконки. Первые 3 — это потребление батареи, когда питание от сети отключено:
  • Полный заряд батареи — 90-100%;
  • Средний заряд — 30-90%;
  • Низкий заряд — 30% и менее.
Остальные 2 состояния — это:
  • Зарядка батареи от сети;
  • Питание от сети (когда батарея полностью заряжена).
При наведении курсора мыши на индикатор — появляется одно из сообщений:
  • “Charging” — идёт зарядка;
  • “Charged” — батарея заряжена (питание от сети);
  • “Discharging” — разрядка (питание от батареи).
И следом отображается состояние заряда батареи в процентах.

Код скрипта:
import pygtk
pygtk.require('2.0')
import gtk
from os import path
import re

app_title = 'Battery status indicator'
timer_interval = 1000

icons_dir = path.join(path.dirname(__file__), 'icons')
icon_path = {
    'charge': path.join(icons_dir, 'battery-charge-icon.png'),
    'plug': path.join(icons_dir, 'battery-plug-icon.png'),
    'full': path.join(icons_dir, 'battery-full-icon.png'),
    'half': path.join(icons_dir, 'battery-half-icon.png'),
    'low': path.join(icons_dir, 'battery-low-icon.png')
}

icon = gtk.StatusIcon()
icon.set_title(app_title)
icon.set_tooltip(app_title)

def set_timer():
    gtk.timeout_add(timer_interval, update)

def get_info_and_state():
    return {
        'info': open('/proc/acpi/battery/BAT0/info', 'r').read(),
        'state': open('/proc/acpi/battery/BAT0/state', 'r').read()
    }

def get_charge_percent(data):
    full = int(re.search('last full capacity:\s*(\d+) mAh', data['info']).group(1))
    current = int(re.search('remaining capacity:\s*(\d+) mAh', data['state']).group(1))
    return current * 100 / full

def get_status(data):
    return str(re.search('charging state:\s*(\w+)', data['state']).group(1))

last_status = None
last_icon = None
last_val = None
def update(*args):
    global last_status, last_icon, last_val

    data = get_info_and_state()

    val = get_charge_percent(data)
    status = get_status(data)
    if status == 'charged' and val < 100: val = 100

    if status != last_status or val != last_val:
        if status == 'discharging':
            icon.set_tooltip('Battery is discharging, ' + str(val) + '%')
            if val <= 30: new_icon = icon_path['low']
            elif val <= 90: new_icon = icon_path['half']
            elif val <= 100: new_icon = icon_path['full']
            else: raise Exception('Unknown battery percent value!')
            if new_icon != last_icon:
                icon.set_from_file(new_icon)
                last_icon = new_icon
        elif status == 'charging':
            icon.set_tooltip('Battery is charging, ' + str(val) + '%')
            new_icon = icon_path['charge']
            if new_icon != last_icon:
                icon.set_from_file(new_icon)
                last_icon = new_icon
        elif status == 'charged':
            icon.set_tooltip('Battery is charged, ' + str(val) + '%')
            new_icon = icon_path['plug']
            if new_icon != last_icon:
                icon.set_from_file(new_icon)
                last_icon = new_icon
        else:
            raise Exception('Unknown battery status value!')
        last_status = status
        last_val = val

    set_timer()

update()
gtk.main()
P.S. Вот в этом файле: /proc/acpi/battery/BAT0/info, — вы можете посмотреть заявленную производителем ёмкость батареи (design capacity), — и последний максимальный заряд батареи (last full capacity) и по нехитрой формуле (last-full * 100 / design) вы можете узнать сколько процентов ёмкости батареи осталось от изначального значения.

Комментариев нет:

Отправить комментарий