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
This commit is contained in:
151
system-settings-tray.py
Executable file
151
system-settings-tray.py
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user