hardwaremon 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Louis Hinchliffe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: hardwaremon
3
+ Version: 2.0.0
4
+ Summary: Hardware monitoring tool for CPU, RAM, and battery.
5
+ Author-email: Louis Hinchliffe <your.email@example.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Louis Hinchliffe
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: psutil
32
+ Requires-Dist: requests
33
+ Dynamic: license-file
34
+
35
+ # HardwareMon #
36
+
37
+
38
+ HardwareMon is a lightweight system monitoring tool designed to provide a detailed overview of your computer’s hardware and performance metrics. It can display CPU, memory, disk, GPU, battery, network, and peripheral information in real time. The project includes two main implementations: a Python version for Linux systems and a PowerShell version for Windows.
39
+
40
+ ## Features ##
41
+
42
+ HardwareMon gathers and presents information such as CPU usage, memory usage, disk activity, top running processes, GPU specifications and temperatures, battery status, and peripheral details. On Linux, the Python version uses the psutil library and native system commands to extract detailed system information. On Windows, the PowerShell version leverages CIM/WMI queries to report similar statistics.
43
+
44
+ The Linux version also includes a GUI mode built with Tkinter, offering a modern and configurable interface with light, dark, and hacker-style themes. To cycle themes, press F2. Graphs for CPU, memory, and disk usage are updated in real time, providing a quick visual snapshot of system performance.
45
+
46
+ ## Installation ##
47
+ Linux (Python version)
48
+
49
+ Ensure Python 3 and the psutil library are installed.
50
+
51
+ Clone the repository or download the Python script.
52
+
53
+ Run the script from a terminal:
54
+
55
+ ```
56
+ python3 hardware_mon.py
57
+ ```
58
+ ## Windows (PowerShell version) ##
59
+
60
+ Open PowerShell.
61
+
62
+ Run the script directly or use the provided .exe if available:
63
+
64
+ ```
65
+ .\hardware-info.ps1
66
+ ```
67
+
68
+ The Windows .exe was generated from the PowerShell script but is not maintained as actively as the source script. It may lack the latest bug fixes or features and is provided primarily for convenience.
69
+
70
+ # Notes #
71
+
72
+ The Windows version relies on CIM/WMI queries and may have limitations on certain hardware or older operating systems. The Linux Python version provides more extensive monitoring capabilities, including GPU lane and VRAM information for NVIDIA and AMD cards, as well as real-time graphical representations.
73
+
74
+ While the project can run as a standalone script or executable, it is recommended to use the scripts directly to ensure maximum compatibility and access to the latest updates.
75
+
76
+ The .sh script is also much more basic compared to the .py script on linux, since the .py script relies on Tkinter for graph drawings which Bash cannot use, and has not had as much attention compared to the .py version.
77
+
78
+ The .yml script only runs on the .py script.
79
+
80
+ # Contribution #
81
+
82
+ Contributions and suggestions are welcome. Please feel free to fork the repository and submit pull requests or report issues on the project’s issue tracker.
83
+
84
+ Made with ❤️ by Louis
@@ -0,0 +1,50 @@
1
+ # HardwareMon #
2
+
3
+
4
+ HardwareMon is a lightweight system monitoring tool designed to provide a detailed overview of your computer’s hardware and performance metrics. It can display CPU, memory, disk, GPU, battery, network, and peripheral information in real time. The project includes two main implementations: a Python version for Linux systems and a PowerShell version for Windows.
5
+
6
+ ## Features ##
7
+
8
+ HardwareMon gathers and presents information such as CPU usage, memory usage, disk activity, top running processes, GPU specifications and temperatures, battery status, and peripheral details. On Linux, the Python version uses the psutil library and native system commands to extract detailed system information. On Windows, the PowerShell version leverages CIM/WMI queries to report similar statistics.
9
+
10
+ The Linux version also includes a GUI mode built with Tkinter, offering a modern and configurable interface with light, dark, and hacker-style themes. To cycle themes, press F2. Graphs for CPU, memory, and disk usage are updated in real time, providing a quick visual snapshot of system performance.
11
+
12
+ ## Installation ##
13
+ Linux (Python version)
14
+
15
+ Ensure Python 3 and the psutil library are installed.
16
+
17
+ Clone the repository or download the Python script.
18
+
19
+ Run the script from a terminal:
20
+
21
+ ```
22
+ python3 hardware_mon.py
23
+ ```
24
+ ## Windows (PowerShell version) ##
25
+
26
+ Open PowerShell.
27
+
28
+ Run the script directly or use the provided .exe if available:
29
+
30
+ ```
31
+ .\hardware-info.ps1
32
+ ```
33
+
34
+ The Windows .exe was generated from the PowerShell script but is not maintained as actively as the source script. It may lack the latest bug fixes or features and is provided primarily for convenience.
35
+
36
+ # Notes #
37
+
38
+ The Windows version relies on CIM/WMI queries and may have limitations on certain hardware or older operating systems. The Linux Python version provides more extensive monitoring capabilities, including GPU lane and VRAM information for NVIDIA and AMD cards, as well as real-time graphical representations.
39
+
40
+ While the project can run as a standalone script or executable, it is recommended to use the scripts directly to ensure maximum compatibility and access to the latest updates.
41
+
42
+ The .sh script is also much more basic compared to the .py script on linux, since the .py script relies on Tkinter for graph drawings which Bash cannot use, and has not had as much attention compared to the .py version.
43
+
44
+ The .yml script only runs on the .py script.
45
+
46
+ # Contribution #
47
+
48
+ Contributions and suggestions are welcome. Please feel free to fork the repository and submit pull requests or report issues on the project’s issue tracker.
49
+
50
+ Made with ❤️ by Louis
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: hardwaremon
3
+ Version: 2.0.0
4
+ Summary: Hardware monitoring tool for CPU, RAM, and battery.
5
+ Author-email: Louis Hinchliffe <your.email@example.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Louis Hinchliffe
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: psutil
32
+ Requires-Dist: requests
33
+ Dynamic: license-file
34
+
35
+ # HardwareMon #
36
+
37
+
38
+ HardwareMon is a lightweight system monitoring tool designed to provide a detailed overview of your computer’s hardware and performance metrics. It can display CPU, memory, disk, GPU, battery, network, and peripheral information in real time. The project includes two main implementations: a Python version for Linux systems and a PowerShell version for Windows.
39
+
40
+ ## Features ##
41
+
42
+ HardwareMon gathers and presents information such as CPU usage, memory usage, disk activity, top running processes, GPU specifications and temperatures, battery status, and peripheral details. On Linux, the Python version uses the psutil library and native system commands to extract detailed system information. On Windows, the PowerShell version leverages CIM/WMI queries to report similar statistics.
43
+
44
+ The Linux version also includes a GUI mode built with Tkinter, offering a modern and configurable interface with light, dark, and hacker-style themes. To cycle themes, press F2. Graphs for CPU, memory, and disk usage are updated in real time, providing a quick visual snapshot of system performance.
45
+
46
+ ## Installation ##
47
+ Linux (Python version)
48
+
49
+ Ensure Python 3 and the psutil library are installed.
50
+
51
+ Clone the repository or download the Python script.
52
+
53
+ Run the script from a terminal:
54
+
55
+ ```
56
+ python3 hardware_mon.py
57
+ ```
58
+ ## Windows (PowerShell version) ##
59
+
60
+ Open PowerShell.
61
+
62
+ Run the script directly or use the provided .exe if available:
63
+
64
+ ```
65
+ .\hardware-info.ps1
66
+ ```
67
+
68
+ The Windows .exe was generated from the PowerShell script but is not maintained as actively as the source script. It may lack the latest bug fixes or features and is provided primarily for convenience.
69
+
70
+ # Notes #
71
+
72
+ The Windows version relies on CIM/WMI queries and may have limitations on certain hardware or older operating systems. The Linux Python version provides more extensive monitoring capabilities, including GPU lane and VRAM information for NVIDIA and AMD cards, as well as real-time graphical representations.
73
+
74
+ While the project can run as a standalone script or executable, it is recommended to use the scripts directly to ensure maximum compatibility and access to the latest updates.
75
+
76
+ The .sh script is also much more basic compared to the .py script on linux, since the .py script relies on Tkinter for graph drawings which Bash cannot use, and has not had as much attention compared to the .py version.
77
+
78
+ The .yml script only runs on the .py script.
79
+
80
+ # Contribution #
81
+
82
+ Contributions and suggestions are welcome. Please feel free to fork the repository and submit pull requests or report issues on the project’s issue tracker.
83
+
84
+ Made with ❤️ by Louis
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ hardwaremon.egg-info/PKG-INFO
6
+ hardwaremon.egg-info/SOURCES.txt
7
+ hardwaremon.egg-info/dependency_links.txt
8
+ hardwaremon.egg-info/entry_points.txt
9
+ hardwaremon.egg-info/requires.txt
10
+ hardwaremon.egg-info/top_level.txt
11
+ hardwaremonLINUX/HardwareMon.py
12
+ hardwaremonLINUX/__init__.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ hardwaremon = hardwaremon.HardwareMon:main
@@ -0,0 +1,2 @@
1
+ psutil
2
+ requests
@@ -0,0 +1 @@
1
+ hardwaremonLINUX
@@ -0,0 +1,1009 @@
1
+ from email.mime import text
2
+ from logging import root
3
+ import platform
4
+ import os
5
+ import time
6
+ import shutil
7
+ import re
8
+ import requests
9
+ import psutil
10
+ import tkinter.messagebox as messagebox
11
+
12
+
13
+ VERSION = "2.0.0"
14
+
15
+ MAX_POINTS = 60 # last 60 seconds
16
+
17
+ cpu_history = []
18
+ mem_history = []
19
+ disk_history = []
20
+
21
+
22
+ import requests
23
+
24
+ def check_for_updates():
25
+ repo = "louisboii747/HardwareMon"
26
+ url = f"https://api.github.com/repos/{repo}/releases/latest"
27
+
28
+ try:
29
+ response = requests.get(url, timeout=5)
30
+ if response.status_code == 200:
31
+ latest_version = response.json()["tag_name"].lstrip("v")
32
+ if latest_version != VERSION:
33
+ return f"Update available: v{latest_version}"
34
+ return None # No update
35
+ except Exception:
36
+ return None # Fail silently
37
+
38
+ def update_history():
39
+ cpu = psutil.cpu_percent(interval=None)
40
+ mem = psutil.virtual_memory().percent
41
+ disk = psutil.disk_usage('/').percent
42
+
43
+ cpu_history.append(cpu)
44
+ mem_history.append(mem)
45
+ disk_history.append(disk)
46
+
47
+ if len(cpu_history) > MAX_POINTS:
48
+ cpu_history.pop(0)
49
+ mem_history.pop(0)
50
+
51
+
52
+ def draw_graph(canvas, data, color, label):
53
+ canvas.delete("all")
54
+
55
+ width = int(canvas["width"])
56
+ height = int(canvas["height"])
57
+ padding = 10
58
+
59
+ if len(data) < 2:
60
+ return
61
+
62
+ max_val = 100 # percent-based graph
63
+ step_x = (width - 2 * padding) / (len(data) - 1)
64
+
65
+ points = []
66
+ for i, value in enumerate(data):
67
+ x = padding + i * step_x
68
+ y = height - padding - (value / max_val) * (height - 2 * padding)
69
+ points.extend([x, y])
70
+
71
+ canvas.create_line(points, fill=color, width=2, smooth=True)
72
+ canvas.create_text(
73
+ 5, 5,
74
+ anchor="nw",
75
+ text=f"{label}: {data[-1]:.1f}%",
76
+ fill=color,
77
+ font=("monospace", 10, "bold")
78
+ )
79
+
80
+
81
+ ALERTS = {
82
+ "cpu": 90,
83
+ "memory": 90,
84
+ "gpu_temp": 80,
85
+ "battery_low": 20
86
+ }
87
+
88
+ def check_alerts():
89
+ alerts = []
90
+ cpu = psutil.cpu_percent(interval=None)
91
+ if cpu > ALERTS["cpu"]:
92
+ alerts.append(f"⚠️ CPU Usage High: {cpu:.1f}%")
93
+
94
+ mem = psutil.virtual_memory().percent
95
+ if mem > ALERTS["memory"]:
96
+ alerts.append(f"⚠️ Memory Usage High: {mem:.1f}%")
97
+
98
+ temps = psutil.sensors_temperatures()
99
+ if temps:
100
+ for name, entries in temps.items():
101
+ for entry in entries:
102
+ if "gpu" in entry.label.lower() or "nvidia" in name.lower():
103
+ if entry.current > ALERTS["gpu_temp"]:
104
+ alerts.append(f"⚠️ GPU Temp High: {entry.current} °C")
105
+
106
+ bat = psutil.sensors_battery()
107
+ if bat and not bat.power_plugged and bat.percent < ALERTS["battery_low"]:
108
+ alerts.append(f"⚠️ Battery Low: {bat.percent:.1f}%")
109
+
110
+ return alerts
111
+
112
+
113
+ def gpu_info():
114
+ lines = ["=== GPU Information ==="]
115
+
116
+ try:
117
+ if platform.system() != "Linux":
118
+ return ["GPU info not implemented for this OS."]
119
+
120
+ # 1. Find ONLY dedicated AMD / NVIDIA GPUs
121
+ cmd = (
122
+ "lspci | grep -Ei "
123
+ "'(NVIDIA Corporation|Advanced Micro Devices, Inc.)' | "
124
+ "grep -E '(VGA|3D)' | "
125
+ "grep -vi 'APU'"
126
+ )
127
+ gpus = [l for l in os.popen(cmd).read().splitlines() if l]
128
+
129
+ if not gpus:
130
+ return ["No dedicated AMD or NVIDIA GPU found."]
131
+
132
+ for gpu in gpus:
133
+ lines.append(gpu)
134
+
135
+ # Extract PCI bus ID (e.g. 01:00.0)
136
+ bus_id = gpu.split()[0]
137
+
138
+ # 2. PCIe lane width (current + max)
139
+ pcie_info = os.popen(f"lspci -s {bus_id} -vv").read()
140
+ lane_match = re.search(
141
+ r"LnkSta:\s+Speed\s+[^,]+,\s+Width\s+x(\d+).*?\n.*?LnkCap:\s+Speed\s+[^,]+,\s+Width\s+x(\d+)",
142
+ pcie_info,
143
+ re.S
144
+ )
145
+
146
+ if lane_match:
147
+ current, maximum = lane_match.groups()
148
+ lines.append(f" PCIe: x{current} (max x{maximum})")
149
+ else:
150
+ lines.append(" PCIe: Unknown")
151
+
152
+ # 3. VRAM detection
153
+ if "NVIDIA" in gpu:
154
+ vram = os.popen(
155
+ "nvidia-smi --query-gpu=memory.total "
156
+ "--format=csv,noheader,nounits"
157
+ ).read().strip()
158
+ if vram:
159
+ lines.append(f" VRAM: {vram} MB")
160
+ else:
161
+ lines.append(" VRAM: Unknown")
162
+
163
+ elif "Advanced Micro Devices" in gpu:
164
+ vram = os.popen(
165
+ "grep -i 'VRAM' /var/log/Xorg.0.log 2>/dev/null | head -n1"
166
+ ).read().strip()
167
+ if vram:
168
+ lines.append(f" VRAM: {vram}")
169
+ else:
170
+ lines.append(" VRAM: Unknown (AMD userspace tools vary)")
171
+
172
+ return lines
173
+
174
+ except Exception as e:
175
+ return [f"GPU info error: {e}"]
176
+ mem = psutil.virtual_memory().percent
177
+ if mem > ALERTS["memory"]:
178
+ alerts = []
179
+ alerts.append(f"⚠️ Memory Usage High: {mem:.1f}%")
180
+
181
+ # GPU temp (if available)
182
+ temps = psutil.sensors_temperatures()
183
+ if temps:
184
+ for name, entries in temps.items():
185
+ for entry in entries:
186
+ if "gpu" in entry.label.lower() or "nvidia" in name.lower():
187
+ if entry.current > ALERTS["gpu_temp"]:
188
+ alerts = []
189
+ alerts.append(f"⚠️ GPU Temp High: {entry.current} °C")
190
+
191
+ # Battery
192
+ bat = psutil.sensors_battery()
193
+ if bat and not bat.power_plugged and bat.percent < ALERTS["battery_low"]:
194
+ alerts = []
195
+ alerts.append(f"⚠️ Battery Low: {bat.percent:.1f}%")
196
+
197
+ return alerts
198
+
199
+ def get_cpu_name():
200
+ if platform.system() == "Linux":
201
+ try:
202
+ with open("/proc/cpuinfo") as f:
203
+ for line in f:
204
+ if "model name" in line:
205
+ return line.split(":", 1)[1].strip()
206
+ except Exception:
207
+ pass
208
+ return platform.processor()
209
+
210
+ THEMES = {
211
+ "dark": {
212
+ "bg": "#111111",
213
+ "fg": "#e6e6e6",
214
+ "accent": "#4fc3f7"
215
+ },
216
+ "hacker": {
217
+ "bg": "#000000",
218
+ "fg": "#00ff00",
219
+ "accent": "#00cc00"
220
+ },
221
+ "red": {
222
+ "bg": "#2e0000",
223
+ "fg": "#ff4d4d",
224
+ "accent": "#ff1a1a"
225
+ },
226
+ "black on white": {
227
+ "bg": "#ffffff",
228
+ "fg": "#000000",
229
+ "accent": "#000000"
230
+ },
231
+ "blue": {
232
+ "bg": "#001f3f",
233
+ "fg": "#7FDBFF",
234
+ "accent": "#FFFFFF"
235
+ },
236
+ "purple": {
237
+ "bg": "#2e003e",
238
+ "fg": "#ff66ff",
239
+ "accent": "#ff1aff"
240
+ }
241
+ }
242
+
243
+
244
+
245
+
246
+ def apply_theme(root, text, theme_name):
247
+ theme = THEMES[theme_name]
248
+ root.configure(bg=theme["bg"])
249
+ text.configure(
250
+ bg=theme["bg"],
251
+ fg=theme["fg"],
252
+ insertbackground=theme["fg"] # caret color
253
+ )
254
+
255
+
256
+ current_theme = "dark" # default
257
+
258
+
259
+ def read_sys(path):
260
+ try:
261
+ with open(path) as f:
262
+ return f.read().strip()
263
+ except Exception:
264
+ return None
265
+
266
+ def battery_info():
267
+ lines = ["=== Battery Information ==="]
268
+ if not hasattr(psutil, "sensors_battery"):
269
+ return None
270
+ bat = psutil.sensors_battery()
271
+ if bat is None:
272
+ return None
273
+ percent = bat.percent
274
+ plugged = bat.power_plugged
275
+ secsleft = bat.secsleft
276
+ if secsleft == psutil.POWER_TIME_UNLIMITED:
277
+ time_str = "N/A"
278
+ elif secsleft == psutil.POWER_TIME_UNKNOWN:
279
+ time_str = "Unknown"
280
+ else:
281
+ hours, remainder = divmod(secsleft, 3600)
282
+ minutes, _ = divmod(remainder, 60)
283
+ time_str = f"{hours}h {minutes}m"
284
+ return f"{percent}% {'(Charging)' if plugged else '(Discharging)'} - Time left: {time_str}"
285
+ return lines
286
+
287
+ def clear_screen():
288
+ os.system('cls' if os.name == 'nt' else 'clear')
289
+
290
+
291
+ ## START SYSTEM SUMMARY ##
292
+
293
+ # ---------- Summary Function ----------
294
+ def system_summary():
295
+ lines = ["=== SYSTEM SUMMARY ==="]
296
+
297
+ cpu_name = get_cpu_name()
298
+ total_ram = round(psutil.virtual_memory().total / (1024**3), 1)
299
+ disk_total = round(psutil.disk_usage('/').total / (1024**3), 1)
300
+
301
+ # GPU name (simplified)
302
+ gpu_name = "Unknown"
303
+ if platform.system() == "Linux":
304
+ output = os.popen(
305
+ "lspci | grep -Ei '(VGA|3D)' | grep -Ei '(NVIDIA|AMD)'"
306
+ ).read().strip()
307
+ if output:
308
+ gpu_name = output.split(":")[-1].strip()
309
+
310
+ lines.append(f"CPU : {cpu_name}")
311
+ lines.append(f"GPU : {gpu_name}")
312
+ lines.append(f"RAM : {total_ram} GB")
313
+ lines.append(f"Disk : {disk_total} GB\n")
314
+
315
+ cpu = psutil.cpu_percent(interval=None)
316
+ mem = psutil.virtual_memory().percent
317
+ disk = psutil.disk_usage('/').percent
318
+
319
+ lines.append(f"CPU Usage : {cpu:.1f}%")
320
+ lines.append(f"Memory Usage: {mem:.1f}%")
321
+ lines.append(f"Disk Usage : {disk:.1f}%")
322
+
323
+ return lines
324
+
325
+ # ---------- Full Sections ---------- #
326
+
327
+ SECTIONS = [
328
+ system_summary
329
+ ]
330
+
331
+
332
+ ## END System Summary ##
333
+
334
+
335
+
336
+ def system_info():
337
+ lines = ["=== System Information ==="]
338
+ try:
339
+ uptime_seconds = time.time() - psutil.boot_time()
340
+ info = [
341
+ f"OS/Kernel Version: {platform.system()} {platform.release()}",
342
+ f"Architecture: {platform.machine()}",
343
+ f"CPU: {get_cpu_name()}",
344
+ f"CPU Frequency: {psutil.cpu_freq().current:.2f} MHz",
345
+ f"CPU Cores: {psutil.cpu_count(logical=False)}",
346
+ f"Threads: {psutil.cpu_count(logical=True)}",
347
+ f"Memory: {round(psutil.virtual_memory().total / (1024**3), 2)} GB",
348
+ f"Disk: {round(psutil.disk_usage('/').total / (1024**3), 2)} GB",
349
+ f"Uptime: {uptime_seconds / 3600:.2f} hours",
350
+ f"User: {os.getlogin()}",
351
+ f"Display Size: {shutil.get_terminal_size().columns}x{shutil.get_terminal_size().lines}",
352
+ f"Filesystem: {platform.system()}"
353
+ f"Resizable Bar: {'Supported' if os.path.exists('/sys/bus/pci/devices/0000:00:01.0/resizable_bar') else 'Not Supported'}"
354
+
355
+ ]
356
+
357
+ io = psutil.disk_io_counters()
358
+ if io:
359
+ info.append(
360
+ f"Disk Activity: {io.read_bytes / (1024**2):.2f} MB read, "
361
+ f"{io.write_bytes / (1024**2):.2f} MB written"
362
+ )
363
+
364
+ bat = battery_info()
365
+ info.append(f"Battery: {bat if bat else 'N/A'}")
366
+
367
+ return info
368
+
369
+ except Exception as e:
370
+ return [f"System info error: {e}"]
371
+
372
+
373
+ ## END System Info ##
374
+
375
+ def swap_memory():
376
+ lines = ["=== Swap Memory ==="]
377
+ swap = psutil.swap_memory()
378
+ lines.append(f"Swap: {round(swap.total / (1024**3), 2)} GB, Used: {round(swap.used / (1024**3), 2)} GB ({swap.percent}%)")
379
+ return lines
380
+
381
+
382
+
383
+
384
+
385
+ def memory_temperature():
386
+ lines = ["=== Memory Temperature ==="]
387
+ temps = psutil.sensors_temperatures()
388
+ if not temps:
389
+ return ["===Memory temperature sensors not available"]
390
+
391
+ for name, entries in temps.items():
392
+ for entry in entries:
393
+ if "memory" in entry.label.lower() or "ram" in name.lower():
394
+ if entry.label:
395
+ lines.append(f"{entry.label}: {entry.current} °C")
396
+ else:
397
+ lines.append(f"{name}: {entry.current} °C")
398
+
399
+ return lines if len(lines) > 1 else ["===No Memory temperature data found==="]
400
+
401
+
402
+ def gpu_info():
403
+ lines = ["=== GPU Information ==="]
404
+
405
+ try:
406
+ if platform.system() != "Linux":
407
+ return ["GPU info not implemented for this OS."]
408
+
409
+ # 1. Find ONLY dedicated AMD / NVIDIA GPUs
410
+ cmd = (
411
+ "lspci | grep -Ei "
412
+ "'(NVIDIA Corporation|Advanced Micro Devices, Inc.)' | "
413
+ "'(VGA|3D)' | "
414
+ "'(APU)' -vi"
415
+ "grep -E '(VGA|3D)' | "
416
+ "grep -vi 'APU'"
417
+ )
418
+ gpus = [l for l in os.popen(cmd).read().splitlines() if l]
419
+
420
+ if not gpus:
421
+ return ["No dedicated AMD or NVIDIA GPU found."]
422
+
423
+ for gpu in gpus:
424
+ lines.append(gpu)
425
+
426
+ # Extract PCI bus ID (e.g. 01:00.0)
427
+ bus_id = gpu.split()[0]
428
+
429
+ # 2. PCIe lane width (current + max)
430
+ pcie_info = os.popen(f"lspci -s {bus_id} -vv").read()
431
+ lane_match = re.search(
432
+ r"LnkSta:\s+Speed\s+[^,]+,\s+Width\s+x(\d+).*?\n.*?LnkCap:\s+Speed\s+[^,]+,\s+Width\s+x(\d+)",
433
+ pcie_info,
434
+ re.S
435
+ )
436
+
437
+ if lane_match:
438
+ current, maximum = lane_match.groups()
439
+ lines.append(f" PCIe: x{current} (max x{maximum})")
440
+ else:
441
+ lines.append(" PCIe: Unknown")
442
+
443
+ # 3. VRAM detection
444
+ if "NVIDIA" in gpu:
445
+ vram = os.popen(
446
+ "nvidia-smi --query-gpu=memory.total "
447
+ "--format=csv,noheader,nounits"
448
+ ).read().strip()
449
+ if vram:
450
+ lines.append(f" VRAM: {vram} MB")
451
+ else:
452
+ lines.append(" VRAM: Unknown")
453
+
454
+ elif "Advanced Micro Devices" in gpu:
455
+ vram = os.popen(
456
+ "grep -i 'VRAM' /var/log/Xorg.0.log 2>/dev/null | head -n1"
457
+ ).read().strip()
458
+ if vram:
459
+ lines.append(f" VRAM: {vram}")
460
+ else:
461
+ lines.append(" VRAM: Unknown (AMD userspace tools vary)")
462
+
463
+ return lines
464
+
465
+ except Exception as e:
466
+ return [f"GPU info error: {e}"]
467
+
468
+
469
+
470
+
471
+
472
+ def intel_gpu_info():
473
+ lines = ["=== Intel GPU Information ==="]
474
+ try:
475
+ if platform.system() == "Linux":
476
+ intel_gpu_output = os.popen("lspci | grep -i 'intel' | grep -i 'vga\\|3d\\|2d'").read()
477
+ gpus = intel_gpu_output.strip().split("\n")
478
+ if not gpus or gpus == ['']:
479
+ return ["No Intel GPU information found."]
480
+ for gpu in gpus:
481
+ lines.append(gpu)
482
+ else:
483
+ lines.append("Intel GPU info not implemented for this OS.")
484
+ except Exception as e:
485
+ lines.append(f"Intel GPU info error: {e}")
486
+ return lines
487
+
488
+
489
+ def cpu_mem_bar():
490
+ cpu = psutil.cpu_percent(interval=None)
491
+ lines = ["=== CPU and Memory Usage ==="]
492
+ mem = psutil.virtual_memory().percent
493
+ width = 50
494
+ cpu_bar = "#" * int(cpu / 100 * width)
495
+ mem_bar = "#" * int(mem / 100 * width)
496
+ lines.append(f"CPU: [{cpu_bar:<{width}}] {cpu:.1f}%")
497
+ lines.append(f"MEM: [{mem_bar:<{width}}] {mem:.1f}%")
498
+ return lines
499
+
500
+
501
+ def network_info():
502
+ net = psutil.net_io_counters(pernic=True)
503
+ lines = ["=== Network Interfaces ==="]
504
+ for iface, data in net.items():
505
+ lines.append(f"{iface:10}: Sent={data.bytes_sent / (1024**2):6.2f} MB | Recv={data.bytes_recv / (1024**2):6.2f} MB")
506
+ return lines
507
+
508
+
509
+
510
+ def top_processes(n=5):
511
+ procs = [(p.info["name"], p.info["cpu_percent"], p.info["memory_percent"])
512
+ for p in psutil.process_iter(["name", "cpu_percent", "memory_percent"])]
513
+ procs.sort(key=lambda x: (x[1], x[2]), reverse=True)
514
+ lines = [f"=== Top {n} Processes ==="]
515
+ for name, cpu, mem in procs[:n]:
516
+ lines.append(f"{name[:25]:25} | CPU: {cpu:5.1f}% | MEM: {mem:5.1f}%")
517
+ return lines
518
+
519
+
520
+
521
+
522
+ def motherboard_info():
523
+ if platform.system() == "Linux":
524
+ lines = ["=== Motherboard Information ==="]
525
+ base_path = "/sys/devices/virtual/dmi/id/"
526
+ info = {
527
+ "Manufacturer": read_sys(base_path + "board_vendor"),
528
+ "Product Name": read_sys(base_path + "board_name"),
529
+ "Version": read_sys(base_path + "board_version"),
530
+ "Serial Number": read_sys(base_path + "board_serial"),
531
+
532
+ }
533
+ for key , value in info.items():
534
+ lines.append(f"{key}: {value if value else 'N/A'}")
535
+
536
+ return lines
537
+
538
+
539
+
540
+
541
+ def fan_info():
542
+ lines = ["=== Fan Sensors ==="]
543
+ hwmon_base = "/sys/class/hwmon"
544
+
545
+ if not os.path.exists(hwmon_base):
546
+ return ["Fan sensors not available"]
547
+
548
+ for hw in os.listdir(hwmon_base):
549
+ hw_path = os.path.join(hwmon_base, hw)
550
+ name = read_sys(os.path.join(hw_path, "name")) or hw
551
+
552
+ for file in os.listdir(hw_path):
553
+ if file.startswith("fan") and file.endswith("_input"):
554
+ rpm = read_sys(os.path.join(hw_path, file))
555
+ if rpm and rpm.isdigit():
556
+ lines.append(f"{name} {file}: {rpm} RPM")
557
+
558
+ return lines if len(lines) > 1 else ["==No fans detected==="]
559
+
560
+
561
+
562
+
563
+ def partition_info():
564
+ lines = ["=== Partition Information ==="]
565
+ for part in psutil.disk_partitions(all=False):
566
+ lines.append(f"{part.device} mounted on {part.mountpoint} - Type: {part.fstype}")
567
+ return lines
568
+
569
+
570
+ def drive_info():
571
+ lines = ["=== Drive Information ==="]
572
+ for part in psutil.disk_partitions(all=False):
573
+ try:
574
+ usage = psutil.disk_usage(part.mountpoint)
575
+ except (PermissionError, FileNotFoundError):
576
+ continue
577
+
578
+ lines.append(
579
+ f"{part.mountpoint:15} "
580
+ f"{usage.used // (1024**3):4} / "
581
+ f"{usage.total // (1024**3):4} GB "
582
+ f"({usage.percent:5.1f}%)"
583
+ )
584
+
585
+ return lines
586
+
587
+
588
+ def gpu_temperature():
589
+ lines = ["=== GPU Temperature ==="]
590
+ temps = psutil.sensors_temperatures()
591
+ if not temps:
592
+ return ["GPU temperature sensors not available"]
593
+
594
+ for name, entries in temps.items():
595
+ for entry in entries:
596
+ if "gpu" in entry.label.lower() or "nvidia" in name.lower() or "amdgpu" in name.lower():
597
+ if entry.label:
598
+ lines.append(f"{entry.label}: {entry.current} °C")
599
+ else:
600
+ lines.append(f"{name}: {entry.current} °C")
601
+
602
+ return lines if len(lines) > 1 else ["===No GPU temperature data found==="]
603
+
604
+
605
+ def memory_temperature():
606
+ lines = ["=== Memory Temperature ==="]
607
+ temps = psutil.sensors_temperatures()
608
+ if not temps:
609
+ return ["Memory temperature sensors not available"]
610
+
611
+ for name, entries in temps.items():
612
+ for entry in entries:
613
+ if "memory" in entry.label.lower() or "ram" in name.lower():
614
+ if entry.label:
615
+ lines.append(f"{entry.label}: {entry.current} °C")
616
+ else:
617
+ lines.append(f"{name}: {entry.current} °C")
618
+
619
+ return lines if len(lines) > 1 else ["===No Memory temperature data found==="]
620
+
621
+
622
+ def cpu_temperature():
623
+ lines = ["=== CPU Core Temperatures ==="]
624
+ temps = psutil.sensors_temperatures()
625
+
626
+ if not temps:
627
+ return ["CPU temperature sensors not available"]
628
+
629
+ for name, entries in temps.items():
630
+ if "core" not in name.lower():
631
+ continue
632
+
633
+ for entry in entries:
634
+ if entry.label and "core" in entry.label.lower():
635
+ lines.append(f"{entry.label}: {entry.current} °C")
636
+
637
+ if len(lines) == 1:
638
+ return ["CPU core temperature sensors not found"]
639
+
640
+ return lines
641
+
642
+
643
+ def keyboard_info():
644
+ lines = ["=== Keyboard Information ==="]
645
+ try:
646
+ if platform.system() == "Linux":
647
+ lsusb_output = os.popen("lsusb | grep -i 'keyboard'").read()
648
+ keyboards = lsusb_output.strip().split("\n")
649
+ if not keyboards or keyboards == ['']:
650
+ return ["===No keyboard information found.==="]
651
+ for kb in keyboards:
652
+ lines.append(kb)
653
+ else:
654
+ lines.append("===Keyboard info not implemented for this OS.===")
655
+ except Exception as e:
656
+ lines.append(f"Keyboard info error: {e}")
657
+ return lines
658
+
659
+
660
+ def mouse_info():
661
+ lines = ["=== Mouse Information ==="]
662
+ try:
663
+ if platform.system() == "Linux":
664
+ lsusb_output = os.popen("lsusb | grep -i 'mouse'").read()
665
+ mice = lsusb_output.strip().split("\n")
666
+ if not mice or mice == ['']:
667
+ return ["===No mouse information found.==="]
668
+ for mouse in mice:
669
+ lines.append(mouse)
670
+ else:
671
+ lines.append("===Mouse info not implemented for this OS.===")
672
+ except Exception as e:
673
+ lines.append(f"Mouse info error: {e}")
674
+ return lines
675
+
676
+
677
+ def os_info():
678
+ lines = ["=== Operating System Information ==="]
679
+ try:
680
+ if platform.system() == "Linux":
681
+ distro = ""
682
+ try:
683
+ with open("/etc/os-release") as f:
684
+ for line in f:
685
+ if line.startswith("PRETTY_NAME="):
686
+ distro = line.split("=")[1].strip().strip('"')
687
+ break
688
+ except Exception:
689
+ distro = "Unknown Linux Distro"
690
+ lines.append(f"Distribution: {distro}")
691
+ elif platform.system() == "Windows":
692
+ lines.append(f"Windows Version: {platform.version()}")
693
+ elif platform.system() == "Darwin":
694
+ mac_ver = platform.mac_ver()[0]
695
+ lines.append(f"macOS Version: {mac_ver}")
696
+ else:
697
+ lines.append("OS information not implemented for this OS.")
698
+ except Exception as e:
699
+ lines.append(f"OS info error: {e}")
700
+ return lines
701
+
702
+
703
+ def wifi_info():
704
+ lines = ["=== Wi-Fi Information ==="]
705
+ try:
706
+ if platform.system() == "Linux":
707
+ iwconfig_output = os.popen("iwconfig 2>/dev/null | grep 'ESSID'").read()
708
+ wifis = iwconfig_output.strip().split("\n")
709
+ if not wifis or wifis == ['']:
710
+ return ["===No Wi-Fi information found.==="]
711
+ for wifi in wifis:
712
+ lines.append(wifi)
713
+ else:
714
+ lines.append("===Wi-Fi info not implemented for this OS.===")
715
+ except Exception as e:
716
+ lines.append(f"Wi-Fi info error: {e}")
717
+ return lines
718
+
719
+
720
+ ## Print Lines ##
721
+ def main():
722
+ try:
723
+ while True:
724
+ clear_screen()
725
+ # System info
726
+ for line in system_info():
727
+ print(line)
728
+ # Swap memory
729
+ for line in [swap_memory()]:
730
+ print(line)
731
+ # Network
732
+ for line in network_info():
733
+ print(line)
734
+ # Top processes
735
+ for line in top_processes():
736
+ print(line)
737
+ # Drive info
738
+ for line in drive_info():
739
+ print(line)
740
+ # CPU and Memory bar
741
+ for line in [cpu_mem_bar()]:
742
+ print(line)
743
+ # CPU Temperature
744
+ for line in cpu_temperature():
745
+ print(line)
746
+ # Memory Temperature
747
+ for line in memory_temperature():
748
+ print(line)
749
+ # Fan Info
750
+ for line in fan_info():
751
+ print(line)
752
+ # GPU Info
753
+ for line in gpu_info():
754
+ print(line)
755
+ # Motherboard Info
756
+ for line in motherboard_info():
757
+ print(line)
758
+ # GPU Temperature
759
+ for line in gpu_temperature():
760
+ print(line)
761
+ # Battery Info
762
+ for line in [battery_info()]:
763
+ print(f"Battery: {line}")
764
+ # Memory Temperature
765
+ for line in memory_temperature():
766
+ print(line)
767
+ # OS Info
768
+ for line in os_info():
769
+ print(line)
770
+ # Keyboard Info
771
+ for line in keyboard_info():
772
+ print(line)
773
+ # Mouse Info
774
+ for line in mouse_info():
775
+ print(line)
776
+ # Wi-Fi Info
777
+ for line in wifi_info():
778
+ print(line)
779
+ # Partition Info
780
+ for line in partition_info():
781
+ print(line)
782
+ print("\nPress Ctrl+C to exit...")
783
+ time.sleep(1)
784
+ # Intel GPU Info
785
+ for line in intel_gpu_info():
786
+ print(line)
787
+
788
+
789
+ except KeyboardInterrupt:
790
+ print("\nExiting...")
791
+
792
+
793
+ current_theme = "dark"
794
+
795
+ # List of all section functions
796
+ SECTIONS = [
797
+ system_info,
798
+ swap_memory,
799
+ network_info,
800
+ top_processes,
801
+ cpu_mem_bar,
802
+ drive_info,
803
+ fan_info,
804
+ motherboard_info,
805
+ cpu_temperature,
806
+ gpu_info,
807
+ gpu_temperature,
808
+ memory_temperature,
809
+ os_info,
810
+ keyboard_info,
811
+ mouse_info,
812
+ wifi_info,
813
+ partition_info,
814
+ intel_gpu_info,
815
+
816
+ ]
817
+
818
+ def apply_theme(root, text, theme_name):
819
+ theme = THEMES[theme_name]
820
+ root.configure(bg=theme["bg"])
821
+ text.configure(bg=theme["bg"], fg=theme["fg"], insertbackground=theme["fg"])
822
+
823
+
824
+ # ---------- Summary ---------- #
825
+ def system_summary():
826
+ lines = ["=== SYSTEM SUMMARY ==="]
827
+
828
+ cpu_name = get_cpu_name()
829
+ total_ram = round(psutil.virtual_memory().total / (1024**3), 1)
830
+ disk_total = round(psutil.disk_usage('/').total / (1024**3), 1)
831
+
832
+ # GPU name (simplified)
833
+ gpu_name = "Unknown"
834
+ if platform.system() == "Linux":
835
+ output = os.popen(
836
+ "lspci | grep -Ei '(VGA|3D)' | grep -Ei '(NVIDIA|AMD)'"
837
+ ).read().strip()
838
+ if output:
839
+ gpu_name = output.split(":")[-1].strip()
840
+
841
+ lines.append(f"CPU : {cpu_name}")
842
+ lines.append(f"GPU : {gpu_name}")
843
+ lines.append(f"RAM : {total_ram} GB")
844
+ lines.append(f"Disk : {disk_total} GB\n")
845
+
846
+ cpu = psutil.cpu_percent(interval=None)
847
+ mem = psutil.virtual_memory().percent
848
+ disk = psutil.disk_usage('/').percent
849
+
850
+ lines.append(f"CPU Usage : {cpu:.1f}%")
851
+ lines.append(f"Memory Usage: {mem:.1f}%")
852
+ lines.append(f"Disk Usage : {disk:.1f}%")
853
+
854
+ return lines
855
+
856
+ # ---------- Full Sections Placeholder ----------
857
+ # Replace this with your actual SECTIONS list from your app
858
+ SECTIONS = [
859
+ system_info,
860
+ swap_memory,
861
+ network_info,
862
+ top_processes,
863
+ cpu_mem_bar,
864
+ drive_info,
865
+ fan_info,
866
+ motherboard_info,
867
+ cpu_temperature,
868
+ gpu_info,
869
+ gpu_temperature,
870
+ memory_temperature,
871
+ os_info,
872
+ keyboard_info,
873
+ mouse_info,
874
+ wifi_info,
875
+ partition_info,
876
+ intel_gpu_info
877
+ ]
878
+
879
+ import time
880
+
881
+ # Global cache for update messages
882
+ _last_update_check = 0
883
+ _update_msg_cache = None
884
+ UPDATE_CHECK_INTERVAL = 600 # seconds (10 minutes)
885
+
886
+ def check_for_updates_cached():
887
+ global _last_update_check, _update_msg_cache
888
+ now = time.time()
889
+
890
+ if now - _last_update_check > UPDATE_CHECK_INTERVAL:
891
+ _last_update_check = now
892
+ _update_msg_cache = check_for_updates() # your existing function
893
+
894
+ return _update_msg_cache
895
+
896
+
897
+ # ---------- GUI App ---------- #
898
+
899
+
900
+
901
+ import tkinter as tk
902
+ def gui_app():
903
+ root = tk.Tk()
904
+ root.title("HardwareMon")
905
+ root.geometry("800x600")
906
+
907
+ summary_mode = tk.BooleanVar(value=True)
908
+
909
+ # ---- Create widgets ---- #
910
+ version_label = tk.Label(root, text=f"HardwareMon v{VERSION}",
911
+ font=("monospace", 12, "bold"))
912
+ version_label.pack(anchor="ne", padx=10, pady=5)
913
+
914
+ text = tk.Text(root, font=("monospace", 11))
915
+ text.pack(fill="both", expand=True, padx=5, pady=5)
916
+
917
+ main_frame = tk.Frame(root)
918
+ main_frame.pack(pady=5, fill="x")
919
+
920
+ toggle_btn = tk.Button(main_frame, text="Show Full Stats")
921
+ toggle_btn.pack(pady=2)
922
+
923
+ cpu_canvas = tk.Canvas(main_frame, width=780, height=100)
924
+ cpu_canvas.pack(pady=2)
925
+ mem_canvas = tk.Canvas(main_frame, width=780, height=100)
926
+ mem_canvas.pack(pady=2)
927
+ disk_canvas = tk.Canvas(main_frame, width=780, height=100)
928
+ disk_canvas.pack(pady=2)
929
+
930
+ # ---- define functions ---- #
931
+ def apply_theme_gui(theme_name):
932
+ theme = THEMES[theme_name]
933
+ root.configure(bg=theme["bg"])
934
+ text.configure(bg=theme["bg"], fg=theme["fg"], insertbackground=theme["fg"])
935
+ version_label.configure(bg=theme["bg"], fg=theme["fg"])
936
+ toggle_btn.configure(bg=theme["bg"], fg=theme["fg"])
937
+ main_frame.configure(bg=theme["bg"])
938
+ cpu_canvas.configure(bg=theme["bg"])
939
+ mem_canvas.configure(bg=theme["bg"])
940
+ disk_canvas.configure(bg=theme["bg"])
941
+
942
+ def refresh_text():
943
+ scroll = text.yview()
944
+ text.delete("1.0", tk.END)
945
+ alerts = check_alerts()
946
+ update_msg = check_for_updates_cached()
947
+
948
+ if alerts:
949
+ version_label.config(text=" | ".join(alerts))
950
+ elif update_msg:
951
+ version_label.config(text=f"HardwareMon v{VERSION} → {update_msg}")
952
+ else:
953
+ version_label.config(text=f"HardwareMon v{VERSION}")
954
+
955
+ active_sections = [system_summary] if summary_mode.get() else SECTIONS
956
+ for section in active_sections:
957
+ lines = section()
958
+ for line in lines:
959
+ text.insert(tk.END, line + "\n")
960
+ text.insert(tk.END, "\n")
961
+
962
+ text.yview_moveto(scroll[0])
963
+
964
+ update_history()
965
+ draw_graph(cpu_canvas, cpu_history, THEMES[current_theme]["accent"], "CPU")
966
+ draw_graph(mem_canvas, mem_history, THEMES[current_theme]["accent"], "Memory")
967
+ draw_graph(disk_canvas, disk_history, THEMES[current_theme]["accent"], "Disk")
968
+
969
+ def toggle_view():
970
+ summary_mode.set(not summary_mode.get())
971
+ toggle_btn.config(text="Show Full Stats" if summary_mode.get() else "Show Summary")
972
+ refresh_text()
973
+
974
+ toggle_btn.config(command=toggle_view)
975
+
976
+ def switch_theme(event=None):
977
+ global current_theme
978
+ theme_names = list(THEMES.keys())
979
+ next_index = (theme_names.index(current_theme) + 1) % len(theme_names)
980
+ current_theme = theme_names[next_index]
981
+ apply_theme_gui(current_theme)
982
+ refresh_text()
983
+
984
+ root.bind("<F2>", lambda e: toggle_view())
985
+ root.bind("<F3>", switch_theme)
986
+
987
+ apply_theme_gui(current_theme)
988
+ refresh_text()
989
+
990
+ def update_loop():
991
+ refresh_text()
992
+ root.after(1000, update_loop)
993
+
994
+ update_loop()
995
+ root.mainloop()
996
+
997
+
998
+
999
+
1000
+
1001
+
1002
+ if __name__ == "__main__":
1003
+ check_for_updates()
1004
+ gui_app()
1005
+
1006
+ ## -- END GUI APP -- ##
1007
+
1008
+
1009
+ ## Made with <3 by Louis ##
File without changes
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=65.5.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "hardwaremon"
7
+ version = "2.0.0"
8
+ description = "Hardware monitoring tool for CPU, RAM, and battery."
9
+ readme = "README.md"
10
+ authors = [{name="Louis Hinchliffe", email="your.email@example.com"}]
11
+ license = {file="LICENSE"}
12
+ requires-python = ">=3.10"
13
+ dependencies = [
14
+ "psutil",
15
+ "requests",
16
+ ]
17
+
18
+ [project.scripts]
19
+ hardwaremon = "hardwaremon.HardwareMon:main" # if you have a main() function
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="HardwareMon",
5
+ version="2.0.0",
6
+ packages=find_packages(exclude=["test_hardwaremon*"]),
7
+ install_requires=[
8
+ "psutil",
9
+ "requests",
10
+ # add any other dependencies your project needs
11
+ ],
12
+ entry_points={
13
+ "console_scripts": [
14
+ "hardwaremon=HardwareMon.main:main", # adjust if your main file is different
15
+ ]
16
+ },
17
+ )