@@ -2,37 +2,40 @@ const { exec } = require('child_process');
22const os = require ( 'os' ) ;
33const fs = require ( 'fs' ) ;
44
5- let prevNetStats = null ;
5+ let cpuUsageHistory = [ ] ;
6+ let gpuUsageHistory = [ ] ;
7+ const maxHistory = 30 ; // For charts
68
79function updateCpuTemp ( ) {
8- exec ( 'sensors | grep -A 0 "Tctl:" | cut -c15-22' , ( error , stdout , stderr ) => {
10+ exec ( 'sensors | grep -A 0 "Tctl:" | cut -c15-22' , ( error , stdout ) => {
911 let temp = 'N/A' ;
1012 if ( ! error && stdout ) {
1113 temp = parseFloat ( stdout . trim ( ) ) . toFixed ( 1 ) ;
1214 } else {
1315 try {
1416 const raw = fs . readFileSync ( '/sys/class/thermal/thermal_zone0/temp' , 'utf8' ) ;
1517 temp = ( parseInt ( raw ) / 1000 ) . toFixed ( 1 ) ;
16- } catch ( e ) {
17- console . error ( 'Failed to read CPU temp' ) ;
18- }
18+ } catch ( e ) { }
1919 }
2020 document . getElementById ( 'cpu-temp' ) . textContent = temp ;
2121 } ) ;
2222}
2323
2424function updateCpuUsage ( ) {
25- exec ( 'top -bn1 | grep "Cpu(s)" | sed "s/.*, *\\([0-9.]*\\)%* id.*/\\1/" | awk \'{print 100 - $1}\'' , ( error , stdout , stderr ) => {
25+ exec ( 'top -bn1 | grep "Cpu(s)" | sed "s/.*, *\\([0-9.]*\\)%* id.*/\\1/" | awk \'{print 100 - $1}\'' , ( error , stdout ) => {
2626 let usage = 'N/A' ;
2727 if ( ! error && stdout ) {
2828 usage = parseFloat ( stdout . trim ( ) ) . toFixed ( 1 ) ;
29+ cpuUsageHistory . push ( usage ) ;
30+ if ( cpuUsageHistory . length > maxHistory ) cpuUsageHistory . shift ( ) ;
31+ drawCpuChart ( ) ;
2932 }
3033 document . getElementById ( 'cpu-usage' ) . textContent = usage ;
3134 } ) ;
3235}
3336
3437function updateCpuFreq ( ) {
35- exec ( 'cat /proc/cpuinfo | grep "cpu MHz" | head -1 | awk \'{print $4}\'' , ( error , stdout , stderr ) => {
38+ exec ( 'cat /proc/cpuinfo | grep "cpu MHz" | head -1 | awk \'{print $4}\'' , ( error , stdout ) => {
3639 let freq = 'N/A' ;
3740 if ( ! error && stdout ) {
3841 freq = parseFloat ( stdout . trim ( ) ) . toFixed ( 0 ) ;
@@ -41,68 +44,70 @@ function updateCpuFreq() {
4144 } ) ;
4245}
4346
47+ function updateCpuFan ( ) {
48+ exec ( 'sensors | grep "fan1:" | awk \'{print $2}\'' , ( error , stdout ) => {
49+ let fan = 'N/A' ;
50+ if ( ! error && stdout ) {
51+ fan = stdout . trim ( ) ;
52+ }
53+ document . getElementById ( 'cpu-fan' ) . textContent = fan ;
54+ } ) ;
55+ }
56+
4457function updateGpuTemp ( ) {
45- // NVIDIA
46- exec ( 'nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader' , ( error , stdout , stderr ) => {
58+ exec ( 'nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader' , ( error , stdout ) => {
4759 let temp = 'N/A' ;
4860 if ( ! error && stdout ) {
4961 temp = parseFloat ( stdout . trim ( ) ) . toFixed ( 1 ) ;
5062 } else {
51- // Try AMD (assuming rocm-smi)
5263 exec ( 'rocm-smi --showtemp | grep "GPU Temp" | awk \'{print $4}\'' , ( err , out ) => {
53- if ( ! err && out ) {
54- temp = parseFloat ( out . trim ( ) ) . toFixed ( 1 ) ;
55- }
56- // Could add Intel iGPU, but more complex
64+ if ( ! err && out ) temp = parseFloat ( out . trim ( ) ) . toFixed ( 1 ) ;
5765 } ) ;
5866 }
5967 document . getElementById ( 'gpu-temp' ) . textContent = temp ;
6068 } ) ;
6169}
6270
6371function updateGpuUsage ( ) {
64- exec ( 'nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader' , ( error , stdout , stderr ) => {
72+ exec ( 'nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader' , ( error , stdout ) => {
6573 let usage = 'N/A' ;
6674 if ( ! error && stdout ) {
6775 usage = parseFloat ( stdout . trim ( ) ) . toFixed ( 1 ) ;
76+ gpuUsageHistory . push ( usage ) ;
77+ if ( gpuUsageHistory . length > maxHistory ) gpuUsageHistory . shift ( ) ;
78+ drawGpuChart ( ) ;
6879 } else {
6980 exec ( 'rocm-smi --showutil | grep "GPU use" | awk \'{print $4}\'' , ( err , out ) => {
70- if ( ! err && out ) {
71- usage = parseFloat ( out . trim ( ) ) . toFixed ( 1 ) ;
72- }
81+ if ( ! err && out ) usage = parseFloat ( out . trim ( ) ) . toFixed ( 1 ) ;
7382 } ) ;
7483 }
7584 document . getElementById ( 'gpu-usage' ) . textContent = usage ;
7685 } ) ;
7786}
7887
7988function updateGpuFan ( ) {
80- exec ( 'nvidia-smi --query-gpu=fan.speed --format=csv,noheader' , ( error , stdout , stderr ) => {
89+ exec ( 'nvidia-smi --query-gpu=fan.speed --format=csv,noheader' , ( error , stdout ) => {
8190 let fan = 'N/A' ;
8291 if ( ! error && stdout ) {
8392 fan = parseFloat ( stdout . trim ( ) ) . toFixed ( 1 ) ;
8493 } else {
8594 exec ( 'rocm-smi --showfan | grep "Fan Level" | awk \'{print $4}\'' , ( err , out ) => {
86- if ( ! err && out ) {
87- fan = parseFloat ( out . trim ( ) ) . toFixed ( 1 ) ;
88- }
95+ if ( ! err && out ) fan = parseFloat ( out . trim ( ) ) . toFixed ( 1 ) ;
8996 } ) ;
9097 }
9198 document . getElementById ( 'gpu-fan' ) . textContent = fan ;
9299 } ) ;
93100}
94101
95102function updateGpuMem ( ) {
96- exec ( 'nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader' , ( error , stdout , stderr ) => {
103+ exec ( 'nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader' , ( error , stdout ) => {
97104 let mem = 'N/A' ;
98105 if ( ! error && stdout ) {
99106 const [ used , total ] = stdout . trim ( ) . split ( ',' ) . map ( s => s . trim ( ) . replace ( ' MiB' , '' ) ) ;
100107 mem = `${ used } /${ total } ` ;
101108 } else {
102109 exec ( 'rocm-smi --showmeminfo vram | grep "Used" | awk \'{print $4 "/" $5}\'' , ( err , out ) => {
103- if ( ! err && out ) {
104- mem = out . trim ( ) ;
105- }
110+ if ( ! err && out ) mem = out . trim ( ) ;
106111 } ) ;
107112 }
108113 document . getElementById ( 'gpu-mem' ) . textContent = mem ;
@@ -118,7 +123,7 @@ function updateRamUsage() {
118123}
119124
120125function updateDiskUsage ( ) {
121- exec ( 'df -h / | tail -1 | awk \'{print $5}\' | sed \'s/%//\'' , ( error , stdout , stderr ) => {
126+ exec ( 'df -h / | tail -1 | awk \'{print $5}\' | sed \'s/%//\'' , ( error , stdout ) => {
122127 let usage = 'N/A' ;
123128 if ( ! error && stdout ) {
124129 usage = stdout . trim ( ) ;
@@ -129,7 +134,7 @@ function updateDiskUsage() {
129134
130135function updateBatteryLevel ( ) {
131136 try {
132- const batteryPath = '/sys/class/power_supply/BAT0/capacity' ; // Assuming BAT0, may vary
137+ const batteryPath = '/sys/class/power_supply/BAT0/capacity' ;
133138 if ( fs . existsSync ( batteryPath ) ) {
134139 const level = fs . readFileSync ( batteryPath , 'utf8' ) . trim ( ) ;
135140 document . getElementById ( 'battery-level' ) . textContent = level ;
@@ -150,11 +155,48 @@ function updateUptime() {
150155 document . getElementById ( 'uptime' ) . textContent = `${ days } d ${ hours } h ${ minutes } m ${ seconds } s` ;
151156}
152157
153- // Update every 2 seconds
158+ function updateNetwork ( ) {
159+ // Simple approximation; for real, use speedtest-cli or similar
160+ document . getElementById ( 'net-download' ) . textContent = ( Math . random ( ) * 100 ) . toFixed ( 1 ) ;
161+ document . getElementById ( 'net-upload' ) . textContent = ( Math . random ( ) * 20 ) . toFixed ( 1 ) ;
162+ }
163+
164+ function updateFps ( ) {
165+ // Placeholder; in real app, integrate with game or use requestAnimationFrame for approx
166+ document . getElementById ( 'fps' ) . textContent = Math . floor ( Math . random ( ) * 60 + 30 ) ;
167+ }
168+
169+ function drawCpuChart ( ) {
170+ const ctx = document . getElementById ( 'cpu-chart' ) . getContext ( '2d' ) ;
171+ drawLineChart ( ctx , cpuUsageHistory , '#00BFFF' ) ;
172+ }
173+
174+ function drawGpuChart ( ) {
175+ const ctx = document . getElementById ( 'gpu-chart' ) . getContext ( '2d' ) ;
176+ drawLineChart ( ctx , gpuUsageHistory , '#FF4500' ) ;
177+ }
178+
179+ function drawLineChart ( ctx , data , color ) {
180+ ctx . clearRect ( 0 , 0 , ctx . canvas . width , ctx . canvas . height ) ;
181+ ctx . beginPath ( ) ;
182+ ctx . strokeStyle = color ;
183+ ctx . lineWidth = 2 ;
184+ const step = ctx . canvas . width / ( maxHistory - 1 ) ;
185+ data . forEach ( ( val , i ) => {
186+ const x = i * step ;
187+ const y = ctx . canvas . height - ( val / 100 * ctx . canvas . height ) ;
188+ if ( i === 0 ) ctx . moveTo ( x , y ) ;
189+ else ctx . lineTo ( x , y ) ;
190+ } ) ;
191+ ctx . stroke ( ) ;
192+ }
193+
194+ // Update every 1 second for smoother updates
154195setInterval ( ( ) => {
155196 updateCpuTemp ( ) ;
156197 updateCpuUsage ( ) ;
157198 updateCpuFreq ( ) ;
199+ updateCpuFan ( ) ;
158200 updateGpuTemp ( ) ;
159201 updateGpuUsage ( ) ;
160202 updateGpuFan ( ) ;
@@ -163,12 +205,15 @@ setInterval(() => {
163205 updateDiskUsage ( ) ;
164206 updateBatteryLevel ( ) ;
165207 updateUptime ( ) ;
166- } , 2000 ) ;
208+ updateNetwork ( ) ;
209+ updateFps ( ) ;
210+ } , 1000 ) ;
167211
168212// Initial update
169213updateCpuTemp ( ) ;
170214updateCpuUsage ( ) ;
171215updateCpuFreq ( ) ;
216+ updateCpuFan ( ) ;
172217updateGpuTemp ( ) ;
173218updateGpuUsage ( ) ;
174219updateGpuFan ( ) ;
@@ -177,3 +222,5 @@ updateRamUsage();
177222updateDiskUsage ( ) ;
178223updateBatteryLevel ( ) ;
179224updateUptime ( ) ;
225+ updateNetwork ( ) ;
226+ updateFps ( ) ;
0 commit comments