Skip to content

Instantly share code, notes, and snippets.

@winny-
Last active January 8, 2016 09:19
Show Gist options
  • Save winny-/83a94c921740a70934ed to your computer and use it in GitHub Desktop.
Save winny-/83a94c921740a70934ed to your computer and use it in GitHub Desktop.
A horrid DWM status script in python that does't spin up your disk every iteration
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ex: set tabstop=4 expandtab ai:
from __future__ import print_function
from ctypes import cdll, c_char_p
import time
from datetime import datetime
from os import listdir, path
from collections import namedtuple
import dbus
import sys
import struct
import socket
import subprocess
battery_status = namedtuple('battery_status', ['name', 'status', 'percent', 'time_left'])
network_status = namedtuple('network_status', ['type', 'ipv4', 'ssid', 'strength'])
PROPERTIES_INTERFACE = 'org.freedesktop.DBus.Properties'
UPOWER_BUS = 'org.freedesktop.UPower'
UPOWER_INTERFACE = UPOWER_BUS
UPOWER_DEVICE_INTERFACE = UPOWER_BUS + '.Device'
UPOWER_PATH = '/org/freedesktop/UPower'
UPOWER_DEVICE_STATUS_MAP = {
0: 'Unknown',
1: 'Charging',
2: 'Discharging',
3: 'Empty',
4: 'Full',
5: 'Unknown',
6: 'Unknown',
}
NETWORKMANAGER_BUS = 'org.freedesktop.NetworkManager'
NETWORKMANAGER_PATH = '/org/freedesktop/NetworkManager'
NETWORKMANAGER_INTERFACE = NETWORKMANAGER_BUS
NETWORKMANAGER_CONNECTION_ACTIVE_INTERFACE = NETWORKMANAGER_INTERFACE + '.Connection.Active'
NETWORKMANAGER_DEVICE_INTERFACE = NETWORKMANAGER_INTERFACE + '.Device'
NETWORKMANAGER_IP4CONFIG_INTERFACE = NETWORKMANAGER_INTERFACE + '.IP4Config'
NETWORKMANAGER_DEVICE_WIRELESS_INTERFACE = NETWORKMANAGER_DEVICE_INTERFACE + '.Wireless'
NETWORKMANAGER_ACCESSPOINT_INTERFACE = NETWORKMANAGER_INTERFACE + '.AccessPoint'
PITHOS_BUS = 'net.kevinmehall.Pithos'
PITHOS_INTERFACE = PITHOS_BUS
PITHOS_PATH = '/net/kevinmehall/Pithos'
def truncate(s, length, end='...'):
if len(s) <= length + len(end):
return s
return ''.join([s[:length], end])
def construct_store_name_fn(display_name=None):
if display_name is not None:
display_name = c_char_p(display_name.encode())
Xlib = cdll.LoadLibrary('libX11.so')
display = Xlib.XOpenDisplay(display_name)
if display is None:
raise RuntimeError('Could not open display.')
screen = Xlib.XDefaultScreen(display)
root = Xlib.XRootWindow(display, screen)
def store_name(name):
Xlib.XStoreName(display, root, c_char_p(name.encode('iso-8859-1')))
Xlib.XFlush(display)
return store_name
def xsetroot_store_name(name):
subprocess.call(['xsetroot', '-name', name])
def get_batteries_status_sysfs():
ps = '/sys/class/power_supply'
batteries = []
for f in listdir(ps):
if not f.startswith('BAT'):
continue
with open(path.join(ps, f, 'uevent')) as fu:
uevent = dict(line.strip().replace('POWER_SUPPLY_', '', 1).split('=', 1)
for line in fu.readlines())
if uevent['PRESENT'] != '1':
continue
charge_now = float(uevent['CHARGE_NOW'])
charge_full = float(uevent['CHARGE_FULL'])
current_now = float(uevent['CURRENT_NOW'])
status = uevent['STATUS']
percent = min(charge_now / charge_full, 1.0)
if status == 'Charging':
time_left = (charge_full - charge_now) / current_now * 3600.0
elif status == 'Discharging':
time_left = charge_now / current_now * 3600.0
else:
time_left = 0
batteries.append(battery_status(uevent['NAME'],
status,
percent,
int(time_left)))
return batteries
def get_system_bus():
global system_bus
try:
system_bus
except NameError:
system_bus = dbus.SystemBus()
return system_bus
def get_session_bus():
global session_bus
try:
session_bus
except NameError:
session_bus = dbus.SessionBus()
return session_bus
def get_props(object_, interface):
return object_.GetAll(interface, dbus_interface=PROPERTIES_INTERFACE)
def get_prop(object_, interface, prop):
return object_.Get(interface, prop, dbus_interface=PROPERTIES_INTERFACE)
def get_batteries_status_dbus():
system_bus = get_system_bus()
try:
up = system_bus.get_object(UPOWER_BUS, UPOWER_PATH)
devices = up.EnumerateDevices(dbus_interface=UPOWER_INTERFACE)
except dbus.exceptions.DBusException:
return []
L = []
for dev in devices:
d = system_bus.get_object(UPOWER_BUS, dev)
props = get_props(d, UPOWER_DEVICE_INTERFACE)
if not (props['Type'] == 2 and props['IsPresent']):
continue
t = props['TimeToFull'] if int(props['State']) in [0, 1, 4, 5] else props['TimeToEmpty']
L.append(battery_status(path.basename(dev),
UPOWER_DEVICE_STATUS_MAP[int(props['State'])],
props['Percentage'] / 100.0,
t))
return L
def get_network_status_dbus():
system_bus = get_system_bus()
nm = system_bus.get_object(NETWORKMANAGER_BUS, NETWORKMANAGER_PATH)
props = get_props(nm, NETWORKMANAGER_INTERFACE)
if not props['NetworkingEnabled'] or props['Connectivity'] < 2:
return None
for ac in props['ActiveConnections']:
active = system_bus.get_object(NETWORKMANAGER_BUS, ac)
aprops = get_props(active, NETWORKMANAGER_CONNECTION_ACTIVE_INTERFACE)
if aprops['State'] != 2 or aprops['Vpn'] or not aprops['Default']:
continue
devs = aprops['Devices']
for dev in devs:
try:
d = system_bus.get_object(NETWORKMANAGER_BUS, dev)
dprops = get_props(d, NETWORKMANAGER_DEVICE_INTERFACE)
type_ = dprops['DeviceType']
ipv4_cfg = system_bus.get_object(NETWORKMANAGER_BUS, dprops['Ip4Config'])
except dbus.exceptions.DBusException:
continue
try:
addresses = get_prop(ipv4_cfg, NETWORKMANAGER_IP4CONFIG_INTERFACE, 'AddressData')
address = addresses[0]['address']
except dbus.exceptions.DBusException:
network_order = get_prop(ipv4_cfg, NETWORKMANAGER_IP4CONFIG_INTERFACE, 'Addresses')[0][0]
address = socket.inet_ntoa(struct.pack('@I', network_order))
if type_ == 1:
return network_status('ethernet', address, None, None)
elif type_ == 2:
ap_path = get_prop(d,
NETWORKMANAGER_DEVICE_WIRELESS_INTERFACE,
'ActiveAccessPoint')
ap = system_bus.get_object(NETWORKMANAGER_BUS, ap_path)
ap_props = get_props(ap, NETWORKMANAGER_ACCESSPOINT_INTERFACE)
return network_status(
'wireless',
str(address),
''.join(chr(b) for b in ap_props['Ssid']),
ap_props['Strength'] / 100.0,
)
else:
return None
def get_now_playing():
return get_pithos_now_playing()
def get_pithos_now_playing():
session_bus = get_session_bus()
try:
pithos = session_bus.get_object(PITHOS_BUS, PITHOS_PATH)
current_song = pithos.GetCurrentSong(dbus_interface=PITHOS_INTERFACE)
except dbus.exceptions.DBusException:
return None
return dict(**current_song)
# XXX: Not working. Always returns 20C.
def get_cpu_temperature():
with open('/sys/class/thermal/thermal_zone0/temp') as f:
s = f.read()
thousandths = int(s)
return thousandths / 1000.0
def format_seconds(s):
hours = s // 3600
s -= hours * 3600
minutes = s // 60
seconds = s - (minutes * 60)
return '{}{}m'.format(
'{}h'.format(hours) if hours else '',
minutes,
)
def sleep_until_next_minute():
t = time.time()
then = t + 60
then -= (then % 60)
difference = then - t
if difference <= 0.0:
return
time.sleep(difference)
def format_battery(battery, with_name=False):
L = []
if with_name:
L.append(battery.name)
L.append(battery.status[0])
if not battery.status.lower().startswith('full'):
L.extend([
'{:2.0%}'.format(battery.percent),
format_seconds(battery.time_left),
])
return ' '.join(L)
def format_network(network):
if network is None:
return 'no networking'
if network.type == 'ethernet':
return 'ethernet'
elif network.type == 'wireless':
return 'wifi {} {:2.0%}'.format(truncate(network.ssid, 12), network.strength)
else:
raise RuntimeError('unknown network type')
def status_bar(sep=' | '):
L = []
playing = get_now_playing()
if playing is not None:
L.append('{} by {}'.format(
truncate(playing['title'], 20),
truncate(playing['artist'], 20),
))
#L.append('{:.0f}C'.format(get_cpu_temperature()))
L.append(format_network(get_network_status_dbus()))
batteries = get_batteries_status_dbus()
if batteries:
L.append(sep.join(format_battery(b, with_name=len(batteries) > 1)
for b in batteries))
L.append('{:%a %b %d %H:%M}'.format(datetime.now()))
return sep.join(L)
def show_cli(interval=1):
try:
while True:
sys.stdout.write('\r')
sys.stdout.write(status_bar())
sys.stdout.flush()
time.sleep(interval)
except KeyboardInterrupt as e:
sys.stdout.write('\n')
raise e
def main():
#store_name = construct_store_name_fn()
store_name = xsetroot_store_name
while True:
s = status_bar()
store_name(s)
time.sleep(30)
# sleep_until_next_minute()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment