13 Commits

Author SHA1 Message Date
112ca3e276 LiquidGUI [1.3.0.0]
- Linux fixes.
2025-02-11 23:31:37 +00:00
0f45cbf272 LiquidGUI [1.3.0.0]
- Continued refactoring.
2025-02-10 20:15:05 +00:00
89129fc6e5 LiquidGUI [1.3.0.0]
- Continued refactoring.
2025-02-10 20:13:22 +00:00
c05e8da224 LiquidGUI [1.3.0.0]
- Lots of refactoring.
2025-02-08 23:26:03 +00:00
ce4b1ec24c LiquidGUI [1.3.0.0]
- Moved CPU widget to top position.
2025-01-29 21:17:22 +00:00
aedd54b6a9 LiquidGUI [1.3.0.0]
- Unified Labels class to handle Linux and Windows.
2025-01-29 21:13:16 +00:00
3cf0709dd8 LiquidGUI [1.3.0.0]
- Round psutil result by 2 decimal places.
2025-01-27 00:24:57 +00:00
2226ebbe69 LiquidGUI [1.3.0.0]
- Initial psutil support for system vitals.
2025-01-27 00:17:44 +00:00
f9e01cfd8e LiquidGUI [1.2.0.0]
- Linux Support.
2024-12-30 14:38:47 +00:00
4d91e54e65 LiquidGUI [1.2.0.0]
- Linux Support
2024-12-30 14:08:06 +00:00
3cc53d0c81 LiquidGUI [1.2.0.0]
- Linux Support
2024-12-26 12:34:07 +00:00
03fca21675 LiquidGUI [1.2.0.0]
- Linux Support
2024-12-26 12:32:51 +00:00
040fff0677 LiquidGUI [1.2.0.0]
- Linux Support
2024-12-26 00:43:39 +00:00
15 changed files with 2969 additions and 54 deletions
+9 -1
View File
@@ -4,9 +4,17 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"name": "Python: LiquidCTL",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/main.pyw",
"console": "integratedTerminal",
"justMyCode": true
},
{ {
"name": "Python: Current File", "name": "Python: Current File",
"type": "python", "type": "debugpy",
"request": "launch", "request": "launch",
"program": "${file}", "program": "${file}",
"console": "integratedTerminal", "console": "integratedTerminal",
+1 -1
View File
@@ -6,6 +6,6 @@ class MessageHandler():
msg = QMessageBox() msg = QMessageBox()
msg.setWindowTitle("LiquidGUI Error") msg.setWindowTitle("LiquidGUI Error")
msg.setText("No suitable devices could be detected. Please ensure you have a cooler \ msg.setText("No suitable devices could be detected. Please ensure you have a cooler \
both compatible with LiquidCTL, and connected to the system.") compatible with LiquidCTL, and connected to the system.")
msg.setIcon(QMessageBox.Icon.Warning) msg.setIcon(QMessageBox.Icon.Warning)
msg.exec() msg.exec()
Binary file not shown.
Executable
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
pyside6-rcc resources.qrc -o resources.py
pyinstaller main.pyw --onefile --icon resources/LiquidGUI.png --name LiquidGUI
+2 -2
View File
@@ -18,5 +18,5 @@ class MinMaxCurrent:
self.min = _cur self.min = _cur
return (f"🟢 Current: {self.cur}{_unit}\n" return (f"🟢 Current: {self.cur}{_unit}\n"
f"❄️ Min: {self.min}{_unit} / " f"Min: {self.min}{_unit} / "
f"☀️ Max: {self.max}{_unit}") f"Max: {self.max}{_unit}")
+8
View File
@@ -0,0 +1,8 @@
import platform
os = None
_platform = platform.platform()
if _platform.startswith("Linux"):
os = "Linux"
elif _platform.startswith("Windows"):
os = "Windows"
+33
View File
@@ -0,0 +1,33 @@
from interfaces.liquidctl_helper_interface import LiquidCTL_Helper_Interface
import subprocess
import re
class LiquidCTL_Helper(LiquidCTL_Helper_Interface):
device_name = str()
device_temp = 0
device_fanSpeed = 0
device_pumpSpeed = 0
device_fwVers = str()
devices = None
def ForceInit(self):
NotImplemented
def TestConnectionState(self):
output = subprocess.run(["liquidctl", "status"], stdout=subprocess.PIPE, universal_newlines=True)
if len(output.stdout) > 0:
return False
else:
return True
def Update(self):
output = subprocess.run(["liquidctl", "status"], stdout=subprocess.PIPE, universal_newlines=True)
self.device_name = str(re.search(r'^[^\n]*', output.stdout).group(0))
self.device_temp = float(re.search(r'Liquid temperature\s+(\d+\.?\d*)', output.stdout).group(1))
self.device_fanSpeed = int(re.search(r'Fan speed\s+(\d+)', output.stdout).group(1))
self.device_pumpSpeed = int(re.search(r'Pump speed\s+(\d+)', output.stdout).group(1))
def SetFanSpeed(self, speed):
NotImplemented
@@ -1,11 +1,12 @@
from liquidctl import find_liquidctl_devices, cli from interfaces.liquidctl_helper_interface import LiquidCTL_Helper_Interface
from liquidctl import find_liquidctl_devices, cli # type: ignore
class LiquidCTL_Helper(): class LiquidCTL_Helper(LiquidCTL_Helper_Interface):
device_name = None device_name = str()
device_temp = 0 device_temp = 0
device_fanSpeed = 0 device_fanSpeed = 0
device_pumpSpeed = 0 device_pumpSpeed = 0
device_fwVers = None device_fwVers = str()
devices = find_liquidctl_devices() devices = find_liquidctl_devices()
try: try:
+28
View File
@@ -0,0 +1,28 @@
from interfaces.vitals_helper_interface import VitalsHelperInterface
from enum import Enum
import psutil
class VitalsHelperLinux(VitalsHelperInterface):
class HWSensor(Enum):
lin_cpu_amd = ("k10temp", "Tctl")
lin_gpu_amd = ("amdgpu", "edge")
lin_mobo_asus = ("asus_wmi_sensors", "Motherboard Temperature")
def get_temps(self, _hw_sensor: HWSensor):
temps = psutil.sensors_temperatures()
if _hw_sensor.value[0] in temps:
for entry in temps[_hw_sensor.value[0]]:
if entry.label == _hw_sensor.value[1]:
return round(entry.current, 2)
class VitalsHelperWindows(VitalsHelperInterface):
def __init__(self):
print(f"{self.__class__.__name__} is not Implemented")
class HWSensor(Enum):
pass
def get_temps(self, _hw_sensor: HWSensor):
return 0
+48
View File
@@ -0,0 +1,48 @@
from abc import ABC, abstractmethod, abstractproperty
class LiquidCTL_Helper_Interface(ABC):
@property
@abstractmethod
def device_name(self) -> str:
pass
@property
@abstractmethod
def device_temp(self) -> float:
pass
@property
@abstractmethod
def device_fanSpeed(self) -> float:
pass
@property
@abstractmethod
def device_pumpSpeed(self) -> float:
pass
@property
@abstractmethod
def device_fwVers(self) -> str:
pass
@property
@abstractmethod
def devices(self) -> None:
pass
@abstractmethod
def ForceInit(self) -> None:
pass
@abstractmethod
def TestConnectionState(self) -> None:
pass
@abstractmethod
def Update(self) -> None:
pass
@abstractmethod
def SetFanSpeed(self, speed) -> None:
pass
+8
View File
@@ -0,0 +1,8 @@
from abc import ABC, abstractmethod
class VitalsHelperInterface(ABC):
@abstractmethod
def get_temps(self, HWSensor):
""" Return Temperatures """
pass
+94 -36
View File
@@ -1,16 +1,30 @@
# External Dependencies # External Dependencies v####################################
import sys import sys
import win32mica from PySide6.QtWidgets import (QApplication,
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QProgressBar, QPushButton QMainWindow,
from PySide6.QtCore import Qt, QTimer, QThreadPool QWidget,
from PySide6.QtGui import QFont, QIcon QVBoxLayout,
import darkdetect QProgressBar,
# Internal Imports QPushButton)
from LiquidCTL_Helper import LiquidCTL_Helper from PySide6.QtCore import (Qt,
from MessageHandler import MessageHandler QTimer,
from styles import Labels QThreadPool)
from PySide6.QtGui import QIcon
## Internal Imports #########################################
import resources
import common import common
import resources, pkg_resources.extern from MessageHandler import MessageHandler
## Platform Imports #########################################
import globals
from styles import Labels
if globals.os == "Windows":
from helpers.liquidctl_helper_windows import LiquidCTL_Helper
from helpers.vitals_helper import VitalsHelperWindows as VitalsHelper
import win32mica # type: ignore
import darkdetect # type: ignore
elif globals.os == "Linux":
from helpers.liquidctl_helper_linux import LiquidCTL_Helper
from helpers.vitals_helper import VitalsHelperLinux as VitalsHelper
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
@@ -18,14 +32,22 @@ class MainWindow(QMainWindow):
def __init__(self, lctl): def __init__(self, lctl):
super(MainWindow, self).__init__() super(MainWindow, self).__init__()
self.setWindowTitle("LiquidGUI (v.1.1.3.0)") self.setWindowTitle("LiquidGUI (v.1.3.0.0) DEV")
self.setFixedSize(450, 500) self.setFixedSize(450, 700)
self.lctl = lctl self._lctl = lctl
self.__vitals_helper = VitalsHelper()
# Widgets ########################################## # Widgets ##########################################
self.lbl_device_name = Labels.MainLabel() self.lbl_device_name = Labels.MainLabel()
self.lbl_cpu_temp = Labels.SubLabel(value="💻 CPU Temp:")
self.min_max_cur_cpu_temp = common.MinMaxCurrent()
self.prg_cpu_temp = QProgressBar(textVisible=False,
minimum=0,
maximum=105)
self.lbl_value_prg_cpu_temp = Labels.SubLabelValue()
self.lbl_temp = Labels.SubLabel(value="💧 Liquid Temperature:") self.lbl_temp = Labels.SubLabel(value="💧 Liquid Temperature:")
self.min_max_cur_temp = common.MinMaxCurrent() self.min_max_cur_temp = common.MinMaxCurrent()
self.prg_temp = QProgressBar(textVisible=False, self.prg_temp = QProgressBar(textVisible=False,
@@ -46,6 +68,7 @@ class MainWindow(QMainWindow):
minimum=1900, minimum=1900,
maximum=2700) maximum=2700)
self.lbl_value_prg_pumpspeed = Labels.SubLabelValue() self.lbl_value_prg_pumpspeed = Labels.SubLabelValue()
self.btn_reset_min_max = QPushButton("Reset Min/Max") self.btn_reset_min_max = QPushButton("Reset Min/Max")
self.btn_reset_min_max.clicked.connect(self.on_reset_min_max) self.btn_reset_min_max.clicked.connect(self.on_reset_min_max)
@@ -55,6 +78,9 @@ class MainWindow(QMainWindow):
widget = QWidget(self) widget = QWidget(self)
layout = QVBoxLayout(widget) layout = QVBoxLayout(widget)
layout.addWidget(self.lbl_device_name) layout.addWidget(self.lbl_device_name)
layout.addWidget(self.lbl_cpu_temp)
layout.addWidget(self.prg_cpu_temp)
layout.addWidget(self.lbl_value_prg_cpu_temp)
layout.addWidget(self.lbl_temp) layout.addWidget(self.lbl_temp)
layout.addWidget(self.prg_temp) layout.addWidget(self.prg_temp)
layout.addWidget(self.lbl_value_prg_temp) layout.addWidget(self.lbl_value_prg_temp)
@@ -73,12 +99,12 @@ class MainWindow(QMainWindow):
self.setCentralWidget(widget) self.setCentralWidget(widget)
self.setContentsMargins(20, 20, 20, 20) self.setContentsMargins(20, 20, 20, 20)
# Threading ####################################### # Threading #######################################################################
self.thread_manager = QThreadPool() self.thread_manager = QThreadPool()
self.timer = QTimer() self.timer = QTimer()
self.timer.setInterval(1000) self.timer.setInterval(1000)
self.timer.timeout.connect(lambda: self.thread_manager.start(self.lctl.Update)) self.timer.timeout.connect(lambda: self.thread_manager.start(self._lctl.Update))
self.timer.timeout.connect(self.update_widgets) self.timer.timeout.connect(self.update_widgets)
self.timer.start() self.timer.start()
@@ -88,47 +114,79 @@ class MainWindow(QMainWindow):
self.min_max_cur_temp = common.MinMaxCurrent() self.min_max_cur_temp = common.MinMaxCurrent()
self.min_max_cur_fanspeed = common.MinMaxCurrent() self.min_max_cur_fanspeed = common.MinMaxCurrent()
self.min_max_cur_pumpspeed = common.MinMaxCurrent() self.min_max_cur_pumpspeed = common.MinMaxCurrent()
self.min_max_cur_cpu_temp = common.MinMaxCurrent()
self.timer.start() self.timer.start()
def update_widgets(self): def update_widgets(self):
""" Update widgets using LiquidCTL library.""" """ Update widgets using LiquidCTL library."""
self.lbl_device_name.setText(self.lctl.device_name)
self.prg_temp.setValue(self.lctl.device_temp) # Platform Specific Widgets #######################################################
if globals.os == "Windows":
self.__vitals_helper()
elif globals.os == "Linux":
self.lbl_value_prg_cpu_temp.setText(
self.min_max_cur_cpu_temp.builder(
self.__vitals_helper.get_temps(
self.__vitals_helper.HWSensor.lin_cpu_amd), "°C"))
self.prg_cpu_temp.setValue(
self.__vitals_helper.get_temps(
self.__vitals_helper.HWSensor.lin_cpu_amd))
# Cross Platform Widgets ##########################################################
self.lbl_device_name.setText(
self._lctl.device_name)
self.prg_temp.setValue(
self._lctl.device_temp)
self.lbl_value_prg_temp.setText( self.lbl_value_prg_temp.setText(
self.min_max_cur_temp.builder( self.min_max_cur_temp.builder(
self.lctl.device_temp, "°C")) self._lctl.device_temp, "°C"))
self.prg_fanspeed.setValue(self.lctl.device_fanSpeed)
self.prg_fanspeed.setValue(
self._lctl.device_fanSpeed)
self.lbl_value_prg_fanspeed.setText( self.lbl_value_prg_fanspeed.setText(
self.min_max_cur_fanspeed.builder( self.min_max_cur_fanspeed.builder(
self.lctl.device_fanSpeed, " rpm")) self._lctl.device_fanSpeed, " rpm"))
self.prg_pumpspeed.setValue(self.lctl.device_pumpSpeed)
self.prg_pumpspeed.setValue(
self._lctl.device_pumpSpeed)
self.lbl_value_prg_pumpspeed.setText( self.lbl_value_prg_pumpspeed.setText(
self.min_max_cur_pumpspeed.builder( self.min_max_cur_pumpspeed.builder(
self.lctl.device_pumpSpeed, " rpm")) self._lctl.device_pumpSpeed, " rpm"))
if self.lctl.device_fwVers is not None:
self.lbl_fwvers.setText(f"Firmware: v{self.lctl.device_fwVers}") if len(self._lctl.device_fwVers) > 0:
self.lbl_fwvers.setText(f"Firmware: v{self._lctl.device_fwVers}")
def main(): def main():
""" Initialize application and setup window parameters. """ """ Initialize application and setup window parameters. """
app = QApplication(sys.argv) app = QApplication(sys.argv)
icon = QIcon(":/icons/LiquidGUI.ico") window = MainWindow(LiquidCTL_Helper())
if globals.os == "Windows":
window.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
icon = QIcon(":/icons/LiquidGUI.ico")
if darkdetect.isDark():
win32mica.ApplyMica(window.winId(), win32mica.MicaTheme.DARK)
elif darkdetect.isLight():
win32mica.ApplyMica(window.winId(), win32mica.MicaTheme.LIGHT)
elif globals.os == "Linux":
app.setDesktopFileName("LiquidGUI")
icon = QIcon(":/icons/LiquidGUI.png")
app.setWindowIcon(icon) app.setWindowIcon(icon)
window = MainWindow(LiquidCTL_Helper())
window.setWindowIcon(icon)
window.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
# Show error and quit app if no devices are found # Show error and quit app if no devices are found
if window.lctl.TestConnectionState(): if window._lctl.TestConnectionState():
MessageHandler().ShowNoDevicesFoundError() MessageHandler().ShowNoDevicesFoundError()
sys.exit(1) sys.exit(1)
else: else:
if darkdetect.isDark():
win32mica.ApplyMica(window.winId(), win32mica.MICAMODE.DARK)
elif darkdetect.isLight():
win32mica.ApplyMica(window.winId(), win32mica.MICAMODE.LIGHT)
window.show() window.show()
app.exec() app.exec()
+2703 -3
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -2,5 +2,6 @@
<RCC version="1.0"> <RCC version="1.0">
<qresource prefix="icons"> <qresource prefix="icons">
<file alias="LiquidGUI.ico">resources/LiquidGUI.ico</file> <file alias="LiquidGUI.ico">resources/LiquidGUI.ico</file>
<file alias="LiquidGUI.png">resources/LiquidGUI.png</file>
</qresource> </qresource>
</RCC> </RCC>
+26 -7
View File
@@ -1,27 +1,46 @@
from PySide6.QtWidgets import QLabel from PySide6.QtWidgets import QLabel
from PySide6.QtGui import QFont from PySide6.QtGui import QFont
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
import globals
def _set_os_family_font(ClassName: str):
_font = None
if globals.os == "Linux":
if ClassName == MainLabel.__name__ or SubLabel.__name__:
_font = "Noto Sans"
elif ClassName == SubLabelValue.__name__:
_font = "Noto Sans Mono"
elif globals.os == "Windows":
if ClassName == MainLabel.__name__ or SubLabel.__name__:
_font = "Calibri"
elif ClassName == SubLabelValue.__name__:
_font = "Cascadia Code"
return _font
class MainLabel(QLabel): class MainLabel(QLabel):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setAlignment(Qt.AlignmentFlag.AlignCenter) self.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.setFont(QFont("Calibri", self.setFont(QFont(_set_os_family_font(__class__.__name__),
18, 16,
weight=QFont.Weight.ExtraBold)) weight=QFont.Weight.ExtraBold))
class SubLabel(QLabel): class SubLabel(QLabel):
""" Formatting for sub-labels. """ """ Formatting for sub-labels. """
def __init__(self, value): def __init__(self, value):
super().__init__() super().__init__()
self.setFont(QFont("Calibri", 12, weight=QFont.Weight.Thin)) self.setFont(QFont(_set_os_family_font(__class__.__name__),
12,
weight=QFont.Weight.Thin))
self.setText(value) self.setText(value)
class SubLabelValue(QLabel): class SubLabelValue(QLabel):
""" Formatting for values. """ """ Formatting for values. """
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setAlignment(Qt.AlignmentFlag.AlignRight) self.setAlignment(Qt.AlignmentFlag.AlignRight)
self.setFont(QFont("Cascadia Code", 8)) self.setFont(QFont(_set_os_family_font(__class__.__name__), 8))