Files
battery_management/system-settings-tray.py
root c95362ac35 Initial commit: T14 System Settings GUI and Tray application
Features:
- CPU governor control (performance/powersave)
- Fan level control (L1-L7) with thinkfan integration
- Battery charge threshold management (75-80%, 80-90%, 0-100%)
- Quick charge to 100% option
- Automated battery management (time-based and network-based)
- System tray application with auto-start
- Privilege elevation via pkexec helper script
2025-12-11 12:53:22 +01:00

152 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
import tkinter as tk
from tkinter import Menu
import subprocess
import threading
import sys
# Try to import pystray for system tray
try:
from PIL import Image, ImageDraw
import pystray
HAS_TRAY = True
except ImportError:
print("Installing required packages for system tray...")
subprocess.run([sys.executable, "-m", "pip", "install", "pystray", "pillow"], check=True)
from PIL import Image, ImageDraw
import pystray
HAS_TRAY = True
class SystemTrayApp:
def __init__(self):
self.icon = None
self.current_status = {}
self.update_status()
def run_command(self, cmd):
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5)
return result.stdout.strip()
except Exception as e:
return ""
def update_status(self):
"""Get current system status"""
self.current_status = {
'temp': self.run_command("cat /sys/class/hwmon/hwmon5/temp1_input | awk '{print int($1/1000)}'"),
'governor': self.run_command("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"),
'battery': self.run_command("cat /sys/class/power_supply/BAT0/capacity"),
'charging': self.run_command("cat /sys/class/power_supply/BAT0/status"),
'fan': self.run_command("grep '^level' /proc/acpi/ibm/fan | awk '{print $NF}'")
}
def create_image(self):
"""Create system tray icon"""
# Create a simple icon
image = Image.new('RGB', (64, 64), color='black')
draw = ImageDraw.Draw(image)
draw.ellipse([16, 16, 48, 48], fill='#0066cc', outline='white')
return image
def open_full_gui(self, icon=None, item=None):
"""Open the main GUI"""
subprocess.Popen(['python3', '/home/rwiegand/Nextcloud/entwicklung/Werkzeuge/battery_management/system-settings-gui.py'])
def set_governor(self, gov):
subprocess.run(f"pkexec /usr/local/bin/system-settings-helper.sh cpu-governor {gov}", shell=True)
self.update_status()
if self.icon:
self.icon.title = self.get_tooltip()
def set_battery(self, start, end):
subprocess.run(f"pkexec /usr/local/bin/system-settings-helper.sh battery-start {start}", shell=True)
subprocess.run(f"pkexec /usr/local/bin/system-settings-helper.sh battery-end {end}", shell=True)
self.update_status()
if self.icon:
self.icon.title = self.get_tooltip()
def charge_now(self):
subprocess.run("pkexec /usr/local/bin/system-settings-helper.sh battery-start 0", shell=True)
subprocess.run("pkexec /usr/local/bin/system-settings-helper.sh battery-end 100", shell=True)
self.update_status()
if self.icon:
self.icon.title = self.get_tooltip()
def set_fan(self, level):
if level == 2:
# Level 2 = automatic control
subprocess.run("pkexec /usr/local/bin/system-settings-helper.sh fan-start-thinkfan", shell=True)
else:
# Other levels = manual control
subprocess.run("pkexec /usr/local/bin/system-settings-helper.sh fan-stop-thinkfan", shell=True)
subprocess.run(f"pkexec /usr/local/bin/system-settings-helper.sh fan-level {level}", shell=True)
self.update_status()
if self.icon:
self.icon.title = self.get_tooltip()
def get_tooltip(self):
"""Generate tooltip text"""
return f"T14: {self.current_status['temp']}°C | {self.current_status['governor']} | {self.current_status['battery']}% {self.current_status['charging']}"
def create_menu(self):
"""Create system tray menu"""
return pystray.Menu(
pystray.MenuItem("T14 System Settings", pystray.Menu.SEPARATOR),
pystray.MenuItem("Open Full GUI", self.open_full_gui, default=True),
pystray.MenuItem("CPU Governor", pystray.Menu(
pystray.MenuItem("Performance", lambda: self.set_governor("performance")),
pystray.MenuItem("Powersave", lambda: self.set_governor("powersave"))
)),
pystray.MenuItem("Fan Level", pystray.Menu(
pystray.MenuItem("Level 1", lambda: self.set_fan(1)),
pystray.MenuItem("Level 2", lambda: self.set_fan(2)),
pystray.MenuItem("Level 3", lambda: self.set_fan(3)),
pystray.MenuItem("Level 4", lambda: self.set_fan(4)),
pystray.MenuItem("Level 5", lambda: self.set_fan(5)),
pystray.MenuItem("Level 6", lambda: self.set_fan(6)),
pystray.MenuItem("Level 7", lambda: self.set_fan(7))
)),
pystray.MenuItem("Battery", pystray.Menu(
pystray.MenuItem("⚡ Charge to 100% NOW", self.charge_now),
pystray.MenuItem("Conservative (75-80%)", lambda: self.set_battery(75, 80)),
pystray.MenuItem("Moderate (80-90%)", lambda: self.set_battery(80, 90)),
pystray.MenuItem("Full (0-100%)", lambda: self.set_battery(0, 100))
)),
pystray.MenuItem("Refresh Status", lambda: self.refresh_status()),
pystray.MenuItem("Quit", self.quit_app)
)
def refresh_status(self):
self.update_status()
if self.icon:
self.icon.title = self.get_tooltip()
def quit_app(self, icon=None, item=None):
if self.icon:
self.icon.stop()
def run(self):
"""Run the system tray application"""
self.icon = pystray.Icon(
"t14_settings",
self.create_image(),
self.get_tooltip(),
self.create_menu()
)
# Update status every 30 seconds
def update_loop():
import time
while True:
time.sleep(30)
self.refresh_status()
thread = threading.Thread(target=update_loop, daemon=True)
thread.start()
self.icon.run()
if __name__ == "__main__":
app = SystemTrayApp()
app.run()