main dotfiles / dot_config / sway / figbar_status.py
Eric Bower  ·  2026-09-08
  1#!/usr/bin/env python3
  2import json
  3import os
  4import subprocess
  5import sys
  6import time
  7
  8def get_sound():
  9    try:
 10        muted = subprocess.check_output(["pamixer", "--get-mute"], text=True, stderr=subprocess.DEVNULL).strip() == "true"
 11        vol = subprocess.check_output(["pamixer", "--get-volume"], text=True, stderr=subprocess.DEVNULL).strip()
 12        label = "MUTED" if muted else "VOL"
 13        return f"[[vol]]{label} {vol}%"
 14    except Exception:
 15        return "[[vol]]VOL ?"
 16
 17def get_battery():
 18    if not os.path.exists("/sys/class/power_supply"):
 19        return None
 20
 21    try:
 22        for bat in os.listdir("/sys/class/power_supply"):
 23            if not bat.startswith("BAT"):
 24                continue
 25
 26            path = f"/sys/class/power_supply/{bat}"
 27            cap_file = f"{path}/capacity"
 28            if not os.path.exists(cap_file):
 29                continue
 30
 31            with open(cap_file) as f:
 32                cap = f.read().strip()
 33
 34            status = "BAT"
 35            stat_file = f"{path}/status"
 36            if os.path.exists(stat_file):
 37                with open(stat_file) as f:
 38                    if f.read().strip() == "Charging":
 39                        status = "CHR"
 40
 41            return f"[[bat]]{status} {cap}%"
 42    except Exception:
 43        pass
 44
 45    return None
 46
 47def get_brightness():
 48    try:
 49        act = subprocess.check_output(["brightnessctl", "-c", "backlight", "get"], text=True, stderr=subprocess.DEVNULL).strip()
 50        max_b = subprocess.check_output(["brightnessctl", "-c", "backlight", "max"], text=True, stderr=subprocess.DEVNULL).strip()
 51        return f"[[brt]]BRT {int(int(act) * 100 / int(max_b))}%"
 52    except Exception:
 53        return None
 54
 55def get_wifi_ssid(iface):
 56    try:
 57        out = subprocess.check_output(["iw", "dev", iface, "link"], text=True, stderr=subprocess.DEVNULL)
 58        for line in out.splitlines():
 59            if "SSID:" in line:
 60                return line.split("SSID:", 1)[1].strip()
 61    except Exception:
 62        pass
 63    return None
 64
 65def get_net():
 66    try:
 67        route = subprocess.check_output(["ip", "route", "show", "default"], text=True, stderr=subprocess.DEVNULL)
 68    except Exception:
 69        return "[[net]]NET Disconnected"
 70
 71    if "dev" not in route:
 72        return "[[net]]NET Disconnected"
 73
 74    iface = route.split("dev")[1].split()[0]
 75    if not iface.startswith(("wl", "wlan")):
 76        return f"[[net]]ETH {iface}"
 77
 78    ssid = get_wifi_ssid(iface)
 79    return f"[[net]]NET {ssid}" if ssid else f"[[net]]NET {iface}"
 80
 81def get_time():
 82    return f"[[time]]{time.strftime('%I:%M %m/%d').lstrip('0')}"
 83
 84def get_workspaces():
 85    try:
 86        out = subprocess.check_output(["swaymsg", "-t", "get_workspaces"], text=True, stderr=subprocess.DEVNULL)
 87        workspaces = json.loads(out)
 88    except Exception:
 89        return None
 90
 91    if not workspaces:
 92        return None
 93
 94    tags = [
 95        f"^[[ws_{w['name']}]] {w['name']} ^" if w.get("focused") else f"[[ws_{w['name']}]] {w['name']} "
 96        for w in sorted(workspaces, key=lambda x: x.get("num", 0))
 97    ]
 98    return "".join(tags)
 99
100def generate_line():
101    status_parts = [p for p in [get_sound(), get_battery(), get_brightness(), get_net(), get_time()] if p]
102    right_status = "  |  ".join(status_parts) + "  "
103
104    ws = get_workspaces()
105    if not ws:
106        return right_status
107
108    return f"{ws}    {right_status}"
109
110def main():
111    try:
112        while True:
113            print(generate_line(), flush=True)
114            time.sleep(1)
115    except (BrokenPipeError, KeyboardInterrupt):
116        try:
117            sys.stdout.close()
118        except Exception:
119            pass
120        sys.exit(0)
121
122if __name__ == "__main__":
123    main()