99 'mosquitto_local.service '
1010];
1111
12+ $ numTopProcesses = 10 ;
13+
14+ function getHardwareInfo ()
15+ {
16+ // Board-Name
17+ $ board = trim (@shell_exec ("cat /sys/class/dmi/id/board_name 2>/dev/null " ));
18+ if ($ board === '' ) {
19+ $ board = trim (@shell_exec ("cat /proc/device-tree/model 2>/dev/null " ));
20+ }
21+ if ($ board === '' ) {
22+ $ board = 'unbekannt ' ;
23+ }
24+
25+ // CPU-Kerne
26+ $ cpuCores = (int )@shell_exec ('nproc ' ) ?: 1 ;
27+
28+ // CPU-Temperatur (verschiedene Pfade möglich)
29+ $ temp = null ;
30+ $ paths = [
31+ '/sys/class/thermal/thermal_zone0/temp ' ,
32+ '/sys/devices/virtual/thermal/thermal_zone0/temp '
33+ ];
34+ foreach ($ paths as $ path ) {
35+ if (is_readable ($ path )) {
36+ $ raw = trim (file_get_contents ($ path ));
37+ if (is_numeric ($ raw )) {
38+ // Wert meist in Milligrad
39+ $ temp = round (((int )$ raw ) / 1000 , 1 );
40+ break ;
41+ }
42+ }
43+ }
44+ if ($ temp === null ) {
45+ // Fallback: vcgencmd (z.B. Raspberry Pi)
46+ $ vcgencmd = trim (@shell_exec ('which vcgencmd ' ));
47+ if ($ vcgencmd ) {
48+ $ out = trim (@shell_exec ('vcgencmd measure_temp 2>/dev/null ' ));
49+ if (preg_match ('/temp=([\d\.]+)/ ' , $ out , $ m )) {
50+ $ temp = (float )$ m [1 ];
51+ }
52+ }
53+ }
54+ if ($ temp === null ) {
55+ $ temp = 'unbekannt ' ;
56+ }
57+
58+ // Uptime
59+ $ uptime = 'unbekannt ' ;
60+ if (is_readable ('/proc/uptime ' )) {
61+ $ uptimeSeconds = (float )file_get_contents ('/proc/uptime ' );
62+ $ days = floor ($ uptimeSeconds / 86400 );
63+ $ hours = floor (($ uptimeSeconds % 86400 ) / 3600 );
64+ $ minutes = floor (($ uptimeSeconds % 3600 ) / 60 );
65+ $ seconds = floor ($ uptimeSeconds % 60 );
66+ $ uptime = sprintf ('%d Tage, %02d:%02d:%02d ' , $ days , $ hours , $ minutes , $ seconds );
67+ }
68+
69+ // Systemzeit
70+ $ systemTime = date ('d.m.Y, H:i:s ' );
71+
72+ return [
73+ 'board ' => [
74+ 'value ' => $ board ,
75+ 'unit ' => ''
76+ ],
77+ 'cpu_cores ' => [
78+ 'value ' => $ cpuCores ,
79+ 'unit ' => ''
80+ ],
81+ 'cpu_temp ' => [
82+ 'value ' => $ temp ,
83+ 'unit ' => is_numeric ($ temp ) ? '°C ' : ''
84+ ],
85+ 'uptime ' => [
86+ 'value ' => $ uptime ,
87+ 'unit ' => ''
88+ ],
89+ 'system_time ' => [
90+ 'value ' => $ systemTime ,
91+ 'unit ' => ''
92+ ]
93+ ];
94+ }
95+
96+ function getNetworkInfo ()
97+ {
98+ $ mac = 'unbekannt ' ;
99+ $ ip = 'unbekannt ' ;
100+ $ subnet = 'unbekannt ' ;
101+ $ gateway = 'unbekannt ' ;
102+ $ iface = null ;
103+
104+ // Ermittle Gateway und zugehörige Schnittstelle
105+ $ route = @shell_exec ("ip route | awk '/default/ {print \$3, \$5; exit}' " );
106+ if ($ route ) {
107+ list ($ gateway , $ iface ) = explode (' ' , trim ($ route ));
108+ }
109+
110+ if ($ iface ) {
111+ // MAC-Adresse mit ip-Befehl
112+ $ macInfo = @shell_exec ("ip link show $ iface | awk '/link \\// {print \$2; exit}' " );
113+ if ($ macInfo ) {
114+ $ mac = trim ($ macInfo );
115+ }
116+ // IP und Subnetz
117+ $ ipInfo = @shell_exec ("ip -o -f inet addr show $ iface | awk '{print \$4}' " );
118+ if ($ ipInfo ) {
119+ $ ipCidr = trim ($ ipInfo );
120+ if (strpos ($ ipCidr , '/ ' ) !== false ) {
121+ list ($ ip , $ cidr ) = explode ('/ ' , $ ipCidr );
122+ // Subnetz berechnen
123+ $ subnet = long2ip (-1 << (32 - (int )$ cidr ));
124+ }
125+ }
126+ }
127+
128+ return [
129+ 'interface ' => [
130+ 'value ' => $ iface ?? 'unbekannt ' ,
131+ 'unit ' => ''
132+ ],
133+ 'mac ' => [
134+ 'value ' => $ mac ,
135+ 'unit ' => ''
136+ ],
137+ 'ip ' => [
138+ 'value ' => $ ip ,
139+ 'unit ' => ''
140+ ],
141+ 'subnet ' => [
142+ 'value ' => $ subnet ,
143+ 'unit ' => ''
144+ ],
145+ 'gateway ' => [
146+ 'value ' => $ gateway ,
147+ 'unit ' => ''
148+ ]
149+ ];
150+ }
151+
152+ function getSoftwareInfo ()
153+ {
154+ $ version = 'unbekannt ' ;
155+ // $branch = 'unbekannt';
156+ $ commit = 'unbekannt ' ;
157+
158+ // Git-Verzeichnis bestimmen (eine Ebene höher als "web")
159+ $ repoDir = dirname (__DIR__ , 2 );
160+
161+ // Lese Versionsdatei (eine Ebene höher)
162+ $ versionFile = dirname (__DIR__ , 1 ) . '/version ' ;
163+ if (is_readable ($ versionFile )) {
164+ $ version = trim (file_get_contents ($ versionFile ));
165+ }
166+
167+ // // Ermittle aktuellen Git-Branch
168+ // $branchCmd = 'git -C ' . escapeshellarg($repoDir) . ' rev-parse --abbrev-ref HEAD 2>/dev/null';
169+ // $branchOut = trim(@shell_exec($branchCmd));
170+ // if ($branchOut !== '') {
171+ // $branch = $branchOut;
172+ // }
173+
174+ // Ermittle aktuellen Git-Commit
175+ $ commitFile = dirname (__DIR__ , 1 ) . '/lastcommit ' ;
176+ if (is_readable ($ commitFile )) {
177+ $ commit = trim (file_get_contents ($ commitFile ));
178+ }
179+
180+ return [
181+ 'version ' => [
182+ 'value ' => $ version ,
183+ 'unit ' => ''
184+ ],
185+ // 'git_branch' => [
186+ // 'value' => $branch,
187+ // 'unit' => ''
188+ // ],
189+ 'git_commit ' => [
190+ 'value ' => $ commit ,
191+ 'unit ' => ''
192+ ]
193+ ];
194+ }
195+
12196function getCpuLoad ()
13197{
14198 $ load = sys_getloadavg ();
15- $ cpuCores = (int )@shell_exec ('nproc ' ) ?: 1 ; // Fallback auf 1 Kern, falls nproc nicht verfügbar
199+ // Rückgabe der 1, 5 und 15 Minuten Last
200+
201+ // Lese die CPU-Zeile aus /proc/stat
202+ $ stat1 = explode (" " , preg_replace ('!\s+! ' , ' ' , trim (shell_exec ("head -n1 /proc/stat " ))));
203+ usleep (100000 ); // 100ms warten
204+ $ stat2 = explode (" " , preg_replace ('!\s+! ' , ' ' , trim (shell_exec ("head -n1 /proc/stat " ))));
205+
206+ // user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice
207+ $ fields = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ];
208+ $ cpu1 = $ cpu2 = 0 ;
209+ foreach ($ fields as $ i ) {
210+ $ cpu1 += isset ($ stat1 [$ i ]) ? (int )$ stat1 [$ i ] : 0 ;
211+ $ cpu2 += isset ($ stat2 [$ i ]) ? (int )$ stat2 [$ i ] : 0 ;
212+ }
213+ $ idle1 = isset ($ stat1 [4 ]) ? (int )$ stat1 [4 ] : 0 ;
214+ $ idle2 = isset ($ stat2 [4 ]) ? (int )$ stat2 [4 ] : 0 ;
215+
216+ $ totalDiff = $ cpu2 - $ cpu1 ;
217+ $ idleDiff = $ idle2 - $ idle1 ;
218+
219+ $ cpuPercent = $ totalDiff > 0 ? round ((1 - ($ idleDiff / $ totalDiff )) * 100 , 1 ) : 0 ;
16220
17221 return [
18- // '1min' => [
19- // 'value' => $load[0],
20- // 'unit' => ''
21- // ],
22- '1min_percent ' => [
23- 'value ' => round (($ load [0 ] / $ cpuCores ) * 100 , 1 ),
222+ 'used_percent ' => [
223+ 'value ' => $ cpuPercent ,
24224 'unit ' => '% '
25225 ],
26- // '5min' => [
27- // 'value' => $load[1],
28- // 'unit' => ''
29- // ],
30- '5min_percent ' => [
31- 'value ' => round (($ load [1 ] / $ cpuCores ) * 100 , 1 ),
32- 'unit ' => '% '
226+ 'load_1min ' => [
227+ 'value ' => $ load [0 ],
228+ 'unit ' => ''
33229 ],
34- // '15min ' => [
35- // 'value' => $load[2 ],
36- // 'unit' => ''
37- // ],
38- '15min_percent ' => [
39- 'value ' => round (( $ load [2 ] / $ cpuCores ) * 100 , 1 ) ,
40- 'unit ' => '% '
230+ ' load_5min ' => [
231+ 'value ' => $ load [1 ],
232+ 'unit ' => ''
233+ ],
234+ 'load_15min ' => [
235+ 'value ' => $ load [2 ],
236+ 'unit ' => ''
41237 ]
42238 ];
43239}
@@ -77,30 +273,30 @@ function getMemoryUsage()
77273 return false ;
78274}
79275
80- function getStorageUsage ( )
276+ function getPartitionUsage ( $ path , $ label )
81277{
82- $ diskTotal = @disk_total_space (" / " );
83- $ diskFree = @disk_free_space (" / " );
278+ $ diskTotal = @disk_total_space ($ path );
279+ $ diskFree = @disk_free_space ($ path );
84280 if ($ diskTotal === false || $ diskFree === false ) {
85281 return false ;
86282 }
87283 $ diskUsed = $ diskTotal - $ diskFree ;
88284 return [
89- ' used_percent ' => [
285+ $ label . ' _used_percent ' => [
90286 'value ' => round ($ diskUsed / $ diskTotal * 100 , 1 ),
91287 'unit ' => '% '
92288 ],
93- ' total ' => [
94- 'value ' => round ($ diskTotal / 1024 / 1024 / 1024 , 2 ),
95- 'unit ' => 'GB '
289+ $ label . ' _total ' => [
290+ 'value ' => round ($ diskTotal / 1024 / 1024 , 2 ),
291+ 'unit ' => 'MB '
96292 ],
97- ' used ' => [
98- 'value ' => round ($ diskUsed / 1024 / 1024 / 1024 , 2 ),
99- 'unit ' => 'GB '
293+ $ label . ' _used ' => [
294+ 'value ' => round ($ diskUsed / 1024 / 1024 , 2 ),
295+ 'unit ' => 'MB '
100296 ],
101- ' free ' => [
102- 'value ' => round ($ diskFree / 1024 / 1024 / 1024 , 2 ),
103- 'unit ' => 'GB '
297+ $ label . ' _free ' => [
298+ 'value ' => round ($ diskFree / 1024 / 1024 , 2 ),
299+ 'unit ' => 'MB '
104300 ]
105301 ];
106302}
@@ -116,6 +312,28 @@ function getServiceStatus($services)
116312 return $ result ;
117313}
118314
315+ function getTopCpuProcesses ($ limit )
316+ {
317+ // ps gibt: PID, Benutzer, CPU-Auslastung, Speicher, Befehl
318+ $ cmd = "ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head -n " . ($ limit + 1 );
319+ $ output = [];
320+ exec ($ cmd , $ output );
321+
322+ $ result = [];
323+ // Erste Zeile ist die Überschrift
324+ for ($ i = 1 ; $ i < count ($ output ); $ i ++) {
325+ // Spalten trennen (mehrere Leerzeichen)
326+ $ cols = preg_split ('/\s+/ ' , trim ($ output [$ i ]), 5 );
327+ if (count ($ cols ) === 5 ) {
328+ $ result [$ cols [4 ] . ' ( ' . $ cols [0 ] . ') ' ] = [
329+ 'value ' => (float )$ cols [2 ],
330+ 'unit ' => '% '
331+ ];
332+ }
333+ }
334+ return $ result ;
335+ }
336+
119337// API-Handler
120338if ($ _SERVER ['REQUEST_METHOD ' ] === 'POST ' ) {
121339 header ('Content-Type: application/json ' );
@@ -158,10 +376,16 @@ function getServiceStatus($services)
158376 if (php_sapi_name () !== 'cli ' && basename ($ _SERVER ['SCRIPT_FILENAME ' ]) === 'systeminfo_api.php ' ) {
159377 header ('Content-Type: application/json ' );
160378 echo json_encode ([
379+ 'hardwareInfo ' => getHardwareInfo (),
380+ 'networkInfo ' => getNetworkInfo (),
381+ 'softwareInfo ' => getSoftwareInfo (),
161382 'cpuLoad ' => getCpuLoad (),
162383 'memory ' => getMemoryUsage (),
163- 'storage ' => getStorageUsage (),
164- 'services ' => getServiceStatus ($ serviceList )
384+ 'top10CpuProcesses ' => getTopCpuProcesses ($ numTopProcesses ),
385+ 'services ' => getServiceStatus ($ serviceList ),
386+ 'storage (root) ' => getPartitionUsage ('/ ' , 'root ' ),
387+ 'storage (boot) ' => getPartitionUsage ('/boot ' , 'boot ' ),
388+ 'storage (ramdisk) ' => getPartitionUsage ('/var/www/html/openWB/ramdisk ' , 'ramdisk ' ),
165389 ]);
166390 exit ;
167391 }
0 commit comments