diff --git a/config.yaml b/config.yaml index 23814969..f3537e4b 100644 --- a/config.yaml +++ b/config.yaml @@ -31,9 +31,21 @@ config: # For Linux/MacOS platforms, the CPU fan is amongst all fan sensors gathered from the motherboard chipset # If value is AUTO the system monitor will try to auto-select the CPU fan # If auto-detection fails, it might be necessary to manually indicate which fan is the CPU fan - # Value must be 'controller/fan' e.g. 'nct6798/fan2'. Use configuration wizard for help in selection + # Value must be 'controller/fan' e.g. 'it8628/fan1'. Use configuration wizard for help in selection CPU_FAN: AUTO + # SYSTEM fan + # For Linux/MacOS platforms, the System fan is amongst all fan sensors gathered from the motherboard chipset + # If value is AUTO the system monitor will try to auto-select the System fan + # If auto-detection fails, it might be necessary to manually indicate which fan is the System fan + # Value must be 'controller/fan' e.g. 'nct6798/fan2'. Use configuration wizard for help in selection + SYS_FAN: it8628/fan5 + + # SYSTEM temperature sensor + # For Linux/MacOS platforms, the System temperature is amongst all temperature sensors gathered from the motherboard chipset + # Value must be 'controller/index' e.g. 'nct6798/0'. Use configuration wizard for help in selection + SYS_TEMP: it8628/0 + # Address used for ping sensor. Can be internal/external IP (e.g. 8.8.8.8 or 192.168.0.1) or hostname (google.com) PING: 8.8.8.8 diff --git a/library/scheduler.py b/library/scheduler.py index f64460ef..951763c1 100644 --- a/library/scheduler.py +++ b/library/scheduler.py @@ -118,6 +118,12 @@ def CPUFanSpeed(): # logger.debug("Refresh CPU Fan Speed") stats.CPU.fan_speed() +@async_job("CPU_FanPercent") +@schedule(timedelta(seconds=config.THEME_DATA['STATS']['CPU']['FAN_PERCENT'].get("INTERVAL", 0)).total_seconds()) +def CPUFanPercent(): + """ Refresh the CPU Fan Speed % """ + # logger.debug("Refresh CPU Fan Speed %") + stats.CPU.fan_percent() @async_job("GPU_Stats") @schedule(timedelta(seconds=config.THEME_DATA['STATS'].get('GPU', {}).get("INTERVAL", 0)).total_seconds()) @@ -126,6 +132,12 @@ def GpuStats(): # logger.debug("Refresh GPU Stats") stats.Gpu.stats() +@async_job("System_Stats") +@schedule(timedelta(seconds=config.THEME_DATA['STATS'].get("SYSTEM", {}).get("INTERVAL", 0)).total_seconds()) +def SystemStats(): + """ Refresh the System stats """ + # logger.debug("Refresh System stats") + stats.System.stats() @async_job("Memory_Stats") @schedule(timedelta(seconds=config.THEME_DATA['STATS'].get('MEMORY', {}).get("INTERVAL", 0)).total_seconds()) diff --git a/library/sensors/sensors.py b/library/sensors/sensors.py index 0a9ada94..a1d61ec0 100644 --- a/library/sensors/sensors.py +++ b/library/sensors/sensors.py @@ -49,6 +49,10 @@ def temperature() -> float: def fan_percent(fan_name: str = None) -> float: pass + @staticmethod + @abstractmethod + def fan_speed(fan_name: str = None) -> float: + pass class Gpu(ABC): @staticmethod @@ -77,6 +81,21 @@ def frequency() -> float: def is_available() -> bool: pass +class System(ABC): + @staticmethod + @abstractmethod + def fan_percent(fan_name: str = None) -> float: + pass + + @staticmethod + @abstractmethod + def fan_speed(fan_name: str = None) -> float: + pass + + @staticmethod + @abstractmethod + def temperature(sys_name: str = None) -> float: + pass class Memory(ABC): @staticmethod diff --git a/library/sensors/sensors_librehardwaremonitor.py b/library/sensors/sensors_librehardwaremonitor.py index f619a5b3..c7709b05 100644 --- a/library/sensors/sensors_librehardwaremonitor.py +++ b/library/sensors/sensors_librehardwaremonitor.py @@ -64,6 +64,7 @@ handle = Hardware.Computer() handle.IsCpuEnabled = True handle.IsGpuEnabled = True +handle.IsSystemEnabled = True handle.IsMemoryEnabled = True handle.IsMotherboardEnabled = True # For CPU Fan Speed handle.IsControllerEnabled = True # For CPU Fan Speed @@ -238,6 +239,22 @@ def temperature() -> float: return math.nan + @staticmethod + def fan_speed(fan_name: str = None) -> float: + mb = get_hw_and_update(Hardware.HardwareType.Motherboard) + try: + for sh in mb.SubHardware: + sh.Update() + for sensor in sh.Sensors: + if sensor.SensorType == Hardware.SensorType.Control and "#2" in str( + sensor.Name) and sensor.Value is not None: # Is Motherboard #2 Fan always the CPU Fan ? + return float(sensor.Value) + except: + pass + + # No Fan Speed sensor for this CPU model + return math.nan + @staticmethod def fan_percent(fan_name: str = None) -> float: mb = get_hw_and_update(Hardware.HardwareType.Motherboard) @@ -375,6 +392,38 @@ def is_available(cls) -> bool: cls.gpu_name = get_gpu_name() return bool(cls.gpu_name) +class System(sensors.System): + @staticmethod + def fan_percent(fan_name: str = None) -> float: + mb = get_hw_and_update(Hardware.HardwareType.Motherboard) + try: + for sh in mb.SubHardware: + sh.Update() + for sensor in sh.Sensors: + if sensor.SensorType == Hardware.SensorType.Control and "#1" in str( + sensor.Name) and sensor.Value is not None: # Is Motherboard #1 Fan always the System Fan ? + return float(sensor.Value) + except: + pass + + # No Fan Speed sensor for this CPU model + return math.nan + + @staticmethod + def fan_speed(fan_name: str = None) -> float: + mb = get_hw_and_update(Hardware.HardwareType.Motherboard) + try: + for sh in mb.SubHardware: + sh.Update() + for sensor in sh.Sensors: + if sensor.SensorType == Hardware.SensorType.Control and "#1" in str( + sensor.Name) and sensor.Value is not None: # Is Motherboard #1 Fan always the System Fan ? + return float(sensor.Value) + except: + pass + + # No Fan Speed sensor for this CPU model + return math.nan class Memory(sensors.Memory): @staticmethod diff --git a/library/sensors/sensors_python.py b/library/sensors/sensors_python.py index 6401c811..f9d99d54 100644 --- a/library/sensors/sensors_python.py +++ b/library/sensors/sensors_python.py @@ -152,6 +152,24 @@ def temperature() -> float: pass return cpu_temp + @staticmethod + def fan_speed(fan_name: str = None) -> float: + try: + fans = sensors_fans() + if fans: + for name, entries in fans.items(): + for entry in entries: + if fan_name is not None and fan_name == "%s/%s" % (name, entry.label): + # Manually selected fan + return entry.current + elif is_cpu_fan(entry.label) or is_cpu_fan(name): + # Auto-detected fan + return entry.current + except: + pass + + return math.nan + @staticmethod def fan_percent(fan_name: str = None) -> float: try: @@ -170,7 +188,6 @@ def fan_percent(fan_name: str = None) -> float: return math.nan - class Gpu(sensors.Gpu): @staticmethod def stats() -> Tuple[ @@ -405,6 +422,60 @@ def is_available() -> bool: except: return False +class System(sensors.System): + @staticmethod + def fan_percent(fan_name: str = None) -> float: + try: + fans = sensors_fans() + if fans: + for name, entries in fans.items(): + for entry in entries: + if fan_name is not None and fan_name == "%s/%s" % (name, entry.label): + # Manually selected fan + return entry.percent + + elif is_cpu_fan(entry.label) or is_cpu_fan(name): + # Auto-detected fan + return entry.percent + except: + pass + + return math.nan + + @staticmethod + def fan_speed(fan_name: str = None) -> float: + try: + fans = sensors_fans() + if fans: + for name, entries in fans.items(): + for entry in entries: + if fan_name is not None and fan_name == "%s/%s" % (name, entry.label): + # Manually selected fan + return entry.current + + elif is_cpu_fan(entry.label) or is_cpu_fan(name): + # Auto-detected fan + return entry.current + except: + pass + + return math.nan + + @staticmethod + def temperature(sys_temp: str = None) -> float: + try: + sensors_temps = psutil.sensors_temperatures() + if sensors_temps: + arr_sys_temp = sys_temp.split("/") + if sensors_temps[arr_sys_temp[0]]: + if sensors_temps[arr_sys_temp[0]][int(arr_sys_temp[1])]: + return sensors_temps[arr_sys_temp[0]][int(arr_sys_temp[1])].current + + except: + pass + + return math.nan + class Memory(sensors.Memory): @staticmethod diff --git a/library/sensors/sensors_stub_random.py b/library/sensors/sensors_stub_random.py index 07e37748..7c98efba 100644 --- a/library/sensors/sensors_stub_random.py +++ b/library/sensors/sensors_stub_random.py @@ -42,6 +42,10 @@ def load() -> Tuple[float, float, float]: # 1 / 5 / 15min avg (%): def temperature() -> float: return random.uniform(30, 90) + @staticmethod + def fan_speed(fan_name: str = None) -> float: + return random.uniform(800, 2500) + @staticmethod def fan_percent(fan_name: str = None) -> float: return random.uniform(0, 100) @@ -70,6 +74,23 @@ def frequency() -> float: def is_available() -> bool: return True +class System(sensors.System): + @staticmethod + def stats() -> Tuple[ + float, float, float]: # fan (%) / fan speed / temp (°C) + return random.uniform(0, 100), random.uniform(800, 2500), random.uniform(30, 90) + + @staticmethod + def fan_percent(fan_name: str = None) -> float: + return random.uniform(0, 100) + + @staticmethod + def fan_speed(fan_name: str = None) -> float: + return random.uniform(800, 2500) + + @staticmethod + def temperature(sys_temp: str = None) -> float: + return random.uniform(25, 50) class Memory(sensors.Memory): @staticmethod diff --git a/library/sensors/sensors_stub_static.py b/library/sensors/sensors_stub_static.py index 5aa16168..a9a29a87 100644 --- a/library/sensors/sensors_stub_static.py +++ b/library/sensors/sensors_stub_static.py @@ -30,6 +30,7 @@ # Define other sensors CPU_FREQ_MHZ = 2400.0 +CPU_FAN_SPEED = 63.7 DISK_TOTAL_SIZE_GB = 1000 MEMORY_TOTAL_SIZE_GB = 64 GPU_MEM_TOTAL_SIZE_GB = 32 @@ -55,6 +56,10 @@ def load() -> Tuple[float, float, float]: # 1 / 5 / 15min avg (%): def temperature() -> float: return TEMPERATURE_SENSOR_VALUE + @staticmethod + def fan_speed(fan_name: str = None) -> float: + return CPU_FAN_SPEED + @staticmethod def fan_percent(fan_name: str = None) -> float: return PERCENTAGE_SENSOR_VALUE @@ -86,6 +91,25 @@ def frequency() -> float: def is_available() -> bool: return True +class System(sensors.System): + @staticmethod + def stats() -> Tuple[ + float, float, float]: # fan (%) / fan speed / temp (°C) + return (PERCENTAGE_SENSOR_VALUE, + CPU_FAN_SPEED, + TEMPERATURE_SENSOR_VALUE) + + @staticmethod + def fan_percent(fan_name: str = None) -> float: + return PERCENTAGE_SENSOR_VALUE + + @staticmethod + def fan_speed(fan_name: str = None) -> float: + return CPU_FAN_SPEED + + @staticmethod + def temperature(sys_temp: str = None) -> float: + return TEMPERATURE_SENSOR_VALUE class Memory(sensors.Memory): @staticmethod diff --git a/library/stats.py b/library/stats.py index fa1e20ee..5a36eb5a 100644 --- a/library/stats.py +++ b/library/stats.py @@ -43,7 +43,9 @@ ETH_CARD = config.CONFIG_DATA["config"].get("ETH", "") WLO_CARD = config.CONFIG_DATA["config"].get("WLO", "") HW_SENSORS = config.CONFIG_DATA["config"].get("HW_SENSORS", "AUTO") -CPU_FAN = config.CONFIG_DATA["config"].get("CPU_FAN", "AUTO") +CPU_FAN = config.CONFIG_DATA["config"].get("CPU_FAN", "AUTO") +SYS_FAN = config.CONFIG_DATA["config"].get("SYS_FAN", "AUTO") +SYS_TEMP = config.CONFIG_DATA["config"].get("SYS_TEMP", "") PING_DEST = config.CONFIG_DATA["config"].get("PING", "127.0.0.1") if HW_SENSORS == "PYTHON": @@ -256,10 +258,11 @@ def last_values_list(size: int) -> List[float]: class CPU: - last_values_cpu_percentage = [] + last_values_cpu_percentage = [] last_values_cpu_temperature = [] - last_values_cpu_fan_speed = [] - last_values_cpu_frequency = [] + last_values_cpu_fan_speed = [] + last_values_cpu_fan_percent = [] + last_values_cpu_frequency = [] @classmethod def percentage(cls): @@ -339,11 +342,11 @@ def temperature(cls): @classmethod def fan_speed(cls): if CPU_FAN != "AUTO": - fan_percent = sensors.Cpu.fan_percent(CPU_FAN) + fan_speed = sensors.Cpu.fan_speed(CPU_FAN) else: - fan_percent = sensors.Cpu.fan_percent() + fan_speed = sensors.Cpu.fan_speed() - save_last_value(fan_percent, cls.last_values_cpu_fan_speed, + save_last_value(fan_speed, cls.last_values_cpu_fan_speed, config.THEME_DATA['STATS']['CPU']['FAN_SPEED']['LINE_GRAPH'].get("HISTORY_SIZE", DEFAULT_HISTORY_SIZE)) @@ -352,6 +355,45 @@ def fan_speed(cls): cpu_fan_graph_data = config.THEME_DATA['STATS']['CPU']['FAN_SPEED']['GRAPH'] cpu_fan_line_graph_data = config.THEME_DATA['STATS']['CPU']['FAN_SPEED']['LINE_GRAPH'] + if math.isnan(fan_speed): + fan_speed = 0 + if cpu_fan_text_data['SHOW'] or cpu_fan_radial_data['SHOW'] or cpu_fan_graph_data[ + 'SHOW'] or cpu_fan_line_graph_data['SHOW']: + if sys.platform == "win32": + logger.warning("Your CPU Fan sensor could not be auto-detected") + else: + logger.warning("Your CPU Fan sensor could not be auto-detected. Select it from Configuration UI.") + cpu_fan_text_data['SHOW'] = False + cpu_fan_radial_data['SHOW'] = False + cpu_fan_graph_data['SHOW'] = False + cpu_fan_line_graph_data['SHOW'] = False + + display_themed_value( + theme_data=cpu_fan_text_data, + value=int(fan_speed), + unit="rpm", + min_size=4 + ) + display_themed_progress_bar(cpu_fan_graph_data, fan_speed) + display_themed_percent_radial_bar(cpu_fan_radial_data, fan_speed) + display_themed_line_graph(cpu_fan_line_graph_data, cls.last_values_cpu_fan_speed) + + @classmethod + def fan_percent(cls): + if CPU_FAN != "AUTO": + fan_percent = sensors.Cpu.fan_percent(CPU_FAN) + else: + fan_percent = sensors.Cpu.fan_percent() + + save_last_value(fan_percent, cls.last_values_cpu_fan_percent, + config.THEME_DATA['STATS']['CPU']['FAN_PERCENT']['LINE_GRAPH'].get("HISTORY_SIZE", + DEFAULT_HISTORY_SIZE)) + + cpu_fan_text_data = config.THEME_DATA['STATS']['CPU']['FAN_PERCENT']['TEXT'] + cpu_fan_radial_data = config.THEME_DATA['STATS']['CPU']['FAN_PERCENT']['RADIAL'] + cpu_fan_graph_data = config.THEME_DATA['STATS']['CPU']['FAN_PERCENT']['GRAPH'] + cpu_fan_line_graph_data = config.THEME_DATA['STATS']['CPU']['FAN_PERCENT']['LINE_GRAPH'] + if math.isnan(fan_percent): fan_percent = 0 if cpu_fan_text_data['SHOW'] or cpu_fan_radial_data['SHOW'] or cpu_fan_graph_data[ @@ -370,6 +412,101 @@ def fan_speed(cls): display_themed_percent_radial_bar(cpu_fan_radial_data, fan_percent) display_themed_line_graph(cpu_fan_line_graph_data, cls.last_values_cpu_fan_speed) +class System: + last_values_system_fan_percent = [] + last_values_system_fan_speed = [] + last_values_system_temperature = [] + + @classmethod + def stats(cls): + if SYS_FAN != "AUTO": + fan_percent = sensors.System.fan_percent(SYS_FAN) + fan_speed = sensors.System.fan_speed(SYS_FAN) + else: + fan_percent = sensors.System.fan_percent() + fan_speed = sensors.System.fan_speed() + + if SYS_TEMP != "": + sys_temp = sensors.System.temperature(SYS_TEMP) + else: + sys_temp = 0 + + + theme_system_data = config.THEME_DATA['STATS']['SYSTEM'] + save_last_value(fan_percent, cls.last_values_system_fan_percent, + theme_system_data['FAN_PERCENT']['LINE_GRAPH'].get("HISTORY_SIZE", DEFAULT_HISTORY_SIZE)) + save_last_value(fan_speed, cls.last_values_system_fan_speed, + theme_system_data['FAN_SPEED']['LINE_GRAPH'].get("HISTORY_SIZE", DEFAULT_HISTORY_SIZE)) + save_last_value(sys_temp, cls.last_values_system_temperature, + theme_system_data['TEMPERATURE']['LINE_GRAPH'].get("HISTORY_SIZE", DEFAULT_HISTORY_SIZE)) + + # System Fan Speed (%) + system_fan_per_text_data = theme_system_data['FAN_PERCENT']['TEXT'] + system_fan_per_radial_data = theme_system_data['FAN_PERCENT']['RADIAL'] + system_fan_per_graph_data = theme_system_data['FAN_PERCENT']['GRAPH'] + system_fan_per_line_graph_data = theme_system_data['FAN_PERCENT']['LINE_GRAPH'] + + if math.isnan(fan_percent): + fan_percent = 0 + if system_fan_per_text_data['SHOW'] or system_fan_per_radial_data['SHOW'] or system_fan_per_graph_data[ + 'SHOW'] or system_fan_per_line_graph_data['SHOW']: + logger.warning("Your System Fan Speed percent is not supported yet") + system_fan_per_text_data['SHOW'] = False + system_fan_per_radial_data['SHOW'] = False + system_fan_per_graph_data['SHOW'] = False + system_fan_per_line_graph_data['SHOW'] = False + + display_themed_percent_value(system_fan_per_text_data, fan_percent) + display_themed_progress_bar(system_fan_per_radial_data, fan_percent) + display_themed_percent_radial_bar(system_fan_per_graph_data, fan_percent) + display_themed_line_graph(system_fan_per_line_graph_data, cls.last_values_system_fan_percent) + + # System Fan Speed (RPM) + system_fan_rpm_text_data = theme_system_data['FAN_SPEED']['TEXT'] + system_fan_rpm_radial_data = theme_system_data['FAN_SPEED']['RADIAL'] + system_fan_rpm_graph_data = theme_system_data['FAN_SPEED']['GRAPH'] + system_fan_rpm_line_graph_data = theme_system_data['FAN_SPEED']['LINE_GRAPH'] + + if math.isnan(fan_speed): + fan_speed = 0 + if system_fan_rpm_text_data['SHOW'] or system_fan_rpm_radial_data['SHOW'] or system_fan_rpm_graph_data[ + 'SHOW'] or system_fan_rpm_line_graph_data['SHOW']: + logger.warning("Your System Fan Speed RPM is not supported yet") + system_fan_rpm_text_data['SHOW'] = False + system_fan_rpm_radial_data['SHOW'] = False + system_fan_rpm_graph_data['SHOW'] = False + system_fan_rpm_line_graph_data['SHOW'] = False + + display_themed_value( + theme_data=system_fan_rpm_text_data, + value=int(fan_speed), + unit=" rpm", + min_size=4 + ) + display_themed_progress_bar(system_fan_rpm_radial_data, fan_speed) + display_themed_percent_radial_bar(system_fan_rpm_graph_data, fan_speed) + display_themed_line_graph(system_fan_rpm_line_graph_data, cls.last_values_system_fan_speed) + + # System temperature + system_temp_text_data = theme_system_data['TEMPERATURE']['TEXT'] + system_temp_radial_data = theme_system_data['TEMPERATURE']['RADIAL'] + system_temp_graph_data = theme_system_data['TEMPERATURE']['GRAPH'] + system_temp_line_graph_data = theme_system_data['TEMPERATURE']['LINE_GRAPH'] + + if math.isnan(sys_temp): + sys_temp = 0 + if system_temp_text_data['SHOW'] or system_temp_radial_data['SHOW'] or system_temp_graph_data[ + 'SHOW'] or system_temp_line_graph_data['SHOW']: + logger.warning("Your System temperature is not supported yet") + system_temp_text_data['SHOW'] = False + system_temp_radial_data['SHOW'] = False + system_temp_graph_data['SHOW'] = False + system_temp_line_graph_data['SHOW'] = False + + display_themed_temperature_value(system_temp_text_data, sys_temp) + display_themed_progress_bar(system_temp_radial_data, sys_temp) + display_themed_percent_radial_bar(system_temp_graph_data, sys_temp) + display_themed_line_graph(system_temp_line_graph_data, cls.last_values_system_temperature) class Gpu: last_values_gpu_percentage = [] diff --git a/main.py b/main.py index c161c8d7..36f614dd 100755 --- a/main.py +++ b/main.py @@ -222,8 +222,10 @@ def on_win32_wm_event(hWnd, msg, wParam, lParam): scheduler.CPULoad(); time.sleep(0.25) scheduler.CPUTemperature(); time.sleep(0.25) scheduler.CPUFanSpeed(); time.sleep(0.25) + scheduler.CPUFanPercent(); time.sleep(0.25) if stats.Gpu.is_available(): scheduler.GpuStats(); time.sleep(0.25) + scheduler.SystemStats(); time.sleep(0.25) scheduler.MemoryStats(); time.sleep(0.25) scheduler.DiskStats(); time.sleep(0.25) scheduler.NetStats(); time.sleep(0.25) diff --git a/res/themes/3.5inchThemeSystem/background.png b/res/themes/3.5inchThemeSystem/background.png new file mode 100644 index 00000000..8acb66d6 Binary files /dev/null and b/res/themes/3.5inchThemeSystem/background.png differ diff --git a/res/themes/3.5inchThemeSystem/preview.png b/res/themes/3.5inchThemeSystem/preview.png new file mode 100644 index 00000000..bc4e5720 Binary files /dev/null and b/res/themes/3.5inchThemeSystem/preview.png differ diff --git a/res/themes/3.5inchThemeSystem/theme.yaml b/res/themes/3.5inchThemeSystem/theme.yaml new file mode 100644 index 00000000..db826e5f --- /dev/null +++ b/res/themes/3.5inchThemeSystem/theme.yaml @@ -0,0 +1,233 @@ +--- +author: "@mathoudebine" +display: + DISPLAY_ORIENTATION: portrait + DISPLAY_RGB_LED: 0, 0, 255 +static_images: + BACKGROUND: + PATH: background.png + X: 0 + Y: 0 + WIDTH: 320 + HEIGHT: 480 +STATS: + CPU: + PERCENTAGE: + INTERVAL: 1 + TEXT: + SHOW: true + SHOW_UNIT: true + X: 235 + Y: 35 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 30 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + GRAPH: + SHOW: true + X: 155 + Y: 70 + WIDTH: 150 + HEIGHT: 15 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 0, 0, 255 + BAR_OUTLINE: false + BACKGROUND_COLOR: 0, 0, 0 + FREQUENCY: + INTERVAL: 5 + TEXT: + SHOW: true + SHOW_UNIT: true + X: 154 + Y: 95 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 30 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + TEMPERATURE: + INTERVAL: 5 + TEXT: + SHOW: true + SHOW_UNIT: true + X: 140 + Y: 35 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 30 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + FAN_SPEED: + INTERVAL: 5 + TEXT: + SHOW: true + SHOW_UNIT: True + X: 155 + Y: 380 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + GPU: + INTERVAL: 1 + PERCENTAGE: + GRAPH: + SHOW: true + X: 155 + Y: 190 + WIDTH: 150 + HEIGHT: 15 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 0, 0, 255 + BAR_OUTLINE: false + BACKGROUND_COLOR: 40, 40, 40 + TEXT: + SHOW: true + SHOW_UNIT: true + X: 235 + Y: 155 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 30 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + MEMORY: + TEXT: + SHOW: true + SHOW_UNIT: true + X: 204 + Y: 215 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 23 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + TEMPERATURE: + TEXT: + SHOW: true + SHOW_UNIT: true + X: 140 + Y: 155 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 30 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + SYSTEM: + INTERVAL: 5 + FAN_SPEED: + TEXT: + SHOW: true + SHOW_UNIT: false + X: 155 + Y: 415 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + TEMPERATURE: + TEXT: + SHOW: true + SHOW_UNIT: True + X: 170 + Y: 445 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + MEMORY: + INTERVAL: 5 + VIRTUAL: + GRAPH: + SHOW: true + X: 155 + Y: 300 + WIDTH: 150 + HEIGHT: 15 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 0, 0, 255 + BAR_OUTLINE: false + BACKGROUND_COLOR: 0, 0, 0 + USED: + SHOW: true + SHOW_UNIT: true + X: 170 + Y: 330 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 32 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + PERCENT_TEXT: + SHOW: true + SHOW_UNIT: true + X: 235 + Y: 265 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + DISK: + INTERVAL: 10 + USED: + GRAPH: + SHOW: false + X: 155 + Y: 345 + WIDTH: 150 + HEIGHT: 15 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 0, 0, 255 + BAR_OUTLINE: false + BACKGROUND_COLOR: 0, 0, 0 + TEXT: + SHOW: false + SHOW_UNIT: true + X: 204 + Y: 411 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 23 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + TOTAL: + TEXT: + SHOW: false + SHOW_UNIT: true + X: 204 + Y: 381 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 23 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + FREE: + TEXT: + SHOW: false + SHOW_UNIT: true + X: 204 + Y: 441 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 23 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + DATE: + INTERVAL: 1 + DAY: + TEXT: + SHOW: true + X: 155 + Y: 6 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 12 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + WIDTH: 90 + ANCHOR: lm + HOUR: + TEXT: + SHOW: true + X: 250 + Y: 6 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 12 + FONT_COLOR: 255, 255, 255 + BACKGROUND_IMAGE: background.png + WIDTH: 64 + ANCHOR: lm diff --git a/res/themes/3.5inchThemeSystem/theme_example.png b/res/themes/3.5inchThemeSystem/theme_example.png new file mode 100644 index 00000000..bc4e5720 Binary files /dev/null and b/res/themes/3.5inchThemeSystem/theme_example.png differ diff --git a/res/themes/default.yaml b/res/themes/default.yaml index a915bcb6..70cd5bb4 100644 --- a/res/themes/default.yaml +++ b/res/themes/default.yaml @@ -43,16 +43,26 @@ STATS: SHOW: False LINE_GRAPH: SHOW: False + FAN_PERCENT: + INTERVAL: 0 + TEXT: + SHOW: false + GRAPH: + SHOW: false + RADIAL: + SHOW: false + LINE_GRAPH: + SHOW: false FAN_SPEED: INTERVAL: 0 TEXT: - SHOW: False + SHOW: false GRAPH: - SHOW: False + SHOW: false RADIAL: - SHOW: False + SHOW: false LINE_GRAPH: - SHOW: False + SHOW: false GPU: INTERVAL: 0 PERCENTAGE: @@ -122,6 +132,35 @@ STATS: SHOW: False LINE_GRAPH: SHOW: False + SYSTEM: + INTERVAL: 0 + FAN_PERCENT: + TEXT: + SHOW: false + GRAPH: + SHOW: false + RADIAL: + SHOW: false + LINE_GRAPH: + SHOW: false + FAN_SPEED: + TEXT: + SHOW: false + GRAPH: + SHOW: false + RADIAL: + SHOW: false + LINE_GRAPH: + SHOW: false + TEMPERATURE: + TEXT: + SHOW: false + GRAPH: + SHOW: false + RADIAL: + SHOW: false + LINE_GRAPH: + SHOW: false MEMORY: INTERVAL: 0 SWAP: diff --git a/res/themes/theme_example.yaml b/res/themes/theme_example.yaml index 677e3f09..c6b2e81d 100644 --- a/res/themes/theme_example.yaml +++ b/res/themes/theme_example.yaml @@ -427,6 +427,80 @@ STATS: AXIS_FONT_SIZE: 10 # BACKGROUND_COLOR: 0, 0, 0 BACKGROUND_IMAGE: background.png + FAN_PERCENT: + # In seconds. Longer intervals cause this to refresh more slowly. + # Setting to lower values will display near real time data, + # but may cause significant CPU usage or the display not to update properly + INTERVAL: 5 + TEXT: + SHOW: False + SHOW_UNIT: True + X: 154 + Y: 13 + # Text sensors may vary in size and create "ghosting" effects where old value stay displayed under the new one. + # To avoid this use one of these 2 methods (or both): + # - either use a monospaced font (fonts with "mono" in name, see res/fonts/ for available fonts) + # - or force a static width/height for the text field. Be sure to have enough space for the longest value that can be displayed (e.g. "100%" for a percentage) + # WIDTH: 200 # Uncomment to force a static width + # HEIGHT: 50 # Uncomment to force static height + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 23 + FONT_COLOR: 255, 255, 255 + # BACKGROUND_COLOR: 132, 154, 165 + BACKGROUND_IMAGE: background.png + ALIGN: left # left / center / right + ANCHOR: lt # Check https://pillow.readthedocs.io/en/stable/handbook/text-anchors.html + GRAPH: + SHOW: False + X: 115 + Y: 71 + WIDTH: 178 + HEIGHT: 13 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 255, 0, 0 + BAR_OUTLINE: False + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + RADIAL: + SHOW: False + X: 100 + Y: 110 + RADIUS: 40 + WIDTH: 10 + MIN_VALUE: 0 + MAX_VALUE: 100 + ANGLE_START: 120 + ANGLE_END: 60 + ANGLE_STEPS: 20 + ANGLE_SEP: 5 + CLOCKWISE: True + BAR_COLOR: 0, 255, 0 + SHOW_TEXT: True + SHOW_UNIT: True + FONT: roboto-mono/RobotoMono-Bold.ttf + FONT_SIZE: 13 + FONT_COLOR: 200, 200, 200 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + LINE_GRAPH: + SHOW: False + X: 300 + Y: 220 + WIDTH: 133 + HEIGHT: 70 + MIN_VALUE: 0 + MAX_VALUE: 3000 + HISTORY_SIZE: 10 + AUTOSCALE: True + LINE_COLOR: 61, 184, 225 + LINE_WIDTH: 2 + AXIS: True + AXIS_COLOR: 255, 135, 0 + AXIS_FONT: roboto/Roboto-Black.ttf + AXIS_FONT_SIZE: 10 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png GPU: # In seconds. Longer intervals cause this to refresh more slowly. # Setting to lower values will display near real time data, @@ -891,6 +965,195 @@ STATS: AXIS_FONT_SIZE: 10 # BACKGROUND_COLOR: 0, 0, 0 BACKGROUND_IMAGE: background.png + SYSTEM: + # In seconds. Longer intervals cause this to refresh more slowly. + # Setting to lower values will display near real time data, + # but may cause significant CPU usage or the display not to update properly + # Note: refresh interval is common to all GPU sensors + INTERVAL: 1 + FAN_SPEED: + TEXT: + SHOW: true + SHOW_UNIT: false + X: 155 + Y: 415 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + GRAPH: + SHOW: False + X: 115 + Y: 71 + WIDTH: 178 + HEIGHT: 13 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 255, 0, 0 + BAR_OUTLINE: False + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + RADIAL: + SHOW: False + X: 100 + Y: 110 + RADIUS: 40 + WIDTH: 10 + MIN_VALUE: 0 + MAX_VALUE: 100 + ANGLE_START: 120 + ANGLE_END: 60 + ANGLE_STEPS: 20 + ANGLE_SEP: 5 + CLOCKWISE: True + BAR_COLOR: 0, 255, 0 + SHOW_TEXT: True + SHOW_UNIT: True + FONT: roboto-mono/RobotoMono-Bold.ttf + FONT_SIZE: 13 + FONT_COLOR: 200, 200, 200 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + LINE_GRAPH: + SHOW: False + X: 300 + Y: 220 + WIDTH: 133 + HEIGHT: 70 + MIN_VALUE: 0 + MAX_VALUE: 100 + HISTORY_SIZE: 10 + AUTOSCALE: False + LINE_COLOR: 61, 184, 225 + LINE_WIDTH: 2 + AXIS: True + AXIS_COLOR: 255, 135, 0 + AXIS_FONT: roboto/Roboto-Black.ttf + AXIS_FONT_SIZE: 10 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + FAN_PERCENT: + TEXT: + SHOW: true + SHOW_UNIT: false + X: 155 + Y: 415 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + GRAPH: + SHOW: False + X: 115 + Y: 71 + WIDTH: 178 + HEIGHT: 13 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 255, 0, 0 + BAR_OUTLINE: False + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + RADIAL: + SHOW: False + X: 100 + Y: 110 + RADIUS: 40 + WIDTH: 10 + MIN_VALUE: 0 + MAX_VALUE: 100 + ANGLE_START: 120 + ANGLE_END: 60 + ANGLE_STEPS: 20 + ANGLE_SEP: 5 + CLOCKWISE: True + BAR_COLOR: 0, 255, 0 + SHOW_TEXT: True + SHOW_UNIT: True + FONT: roboto-mono/RobotoMono-Bold.ttf + FONT_SIZE: 13 + FONT_COLOR: 200, 200, 200 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + LINE_GRAPH: + SHOW: False + X: 300 + Y: 220 + WIDTH: 133 + HEIGHT: 70 + MIN_VALUE: 0 + MAX_VALUE: 100 + HISTORY_SIZE: 10 + AUTOSCALE: False + LINE_COLOR: 61, 184, 225 + LINE_WIDTH: 2 + AXIS: True + AXIS_COLOR: 255, 135, 0 + AXIS_FONT: roboto/Roboto-Black.ttf + AXIS_FONT_SIZE: 10 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + TEMPERATURE: + TEXT: + SHOW: true + SHOW_UNIT: True + X: 170 + Y: 445 + FONT: jetbrains-mono/JetBrainsMono-Bold.ttf + FONT_SIZE: 28 + FONT_COLOR: 255, 255, 255 + BACKGROUND_COLOR: 67, 100, 116 + GRAPH: + SHOW: False + X: 115 + Y: 71 + WIDTH: 178 + HEIGHT: 13 + MIN_VALUE: 0 + MAX_VALUE: 100 + BAR_COLOR: 255, 0, 0 + BAR_OUTLINE: False + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + RADIAL: + SHOW: False + X: 100 + Y: 110 + RADIUS: 40 + WIDTH: 10 + MIN_VALUE: 0 + MAX_VALUE: 100 + ANGLE_START: 120 + ANGLE_END: 60 + ANGLE_STEPS: 20 + ANGLE_SEP: 5 + CLOCKWISE: True + BAR_COLOR: 0, 255, 0 + SHOW_TEXT: True + SHOW_UNIT: True + FONT: roboto-mono/RobotoMono-Bold.ttf + FONT_SIZE: 13 + FONT_COLOR: 200, 200, 200 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png + LINE_GRAPH: + SHOW: False + X: 300 + Y: 220 + WIDTH: 133 + HEIGHT: 70 + MIN_VALUE: 0 + MAX_VALUE: 100 + HISTORY_SIZE: 10 + AUTOSCALE: False + LINE_COLOR: 61, 184, 225 + LINE_WIDTH: 2 + AXIS: True + AXIS_COLOR: 255, 135, 0 + AXIS_FONT: roboto/Roboto-Black.ttf + AXIS_FONT_SIZE: 10 + # BACKGROUND_COLOR: 0, 0, 0 + BACKGROUND_IMAGE: background.png MEMORY: # In seconds. Longer intervals cause this to refresh more slowly. # Setting to lower values will display near real time data, diff --git a/theme-editor.py b/theme-editor.py index bec917c2..84443733 100755 --- a/theme-editor.py +++ b/theme-editor.py @@ -112,8 +112,12 @@ def refresh_theme(): stats.CPU.temperature() if config.THEME_DATA['STATS']['CPU']['FAN_SPEED'].get("INTERVAL", 0) > 0: stats.CPU.fan_speed() + if config.THEME_DATA['STATS']['CPU']['FAN_PERCENT'].get("INTERVAL", 0) > 0: + stats.CPU.fan_percent() if config.THEME_DATA['STATS']['GPU'].get("INTERVAL", 0) > 0: stats.Gpu.stats() + if config.THEME_DATA['STATS']['SYSTEM'].get("INTERVAL", 0) > 0: + stats.System.stats() if config.THEME_DATA['STATS']['MEMORY'].get("INTERVAL", 0) > 0: stats.Memory.stats() if config.THEME_DATA['STATS']['DISK'].get("INTERVAL", 0) > 0: