Hallo,
Ich habe einen Systemmonitor der generell funktioniert, aber es werden die Charts nicht aktualisiert. Wenn ich die Seite neu lade, werden die Werte korrekt angezeigt. Ich denke es liegt vielleicht daran, dass ich direkt die Perl-Funktionen wie readingsBulkUpdate() etc. nutze. Das Flag für Events bei readingsEndUpdate($hash, 1); ist auf 1...
defmod Hardwaremonitor.doif DOIF ([+:01])\
{\
use Time::HiRes;;\
my $start_time = gettimeofday();;\
\
my $hash = $defs{"$SELF"};;\
readingsBeginUpdate($hash);;\
\
##This is too slow:\
##my $BATT_STATE = qx(cat /sys/class/power_supply/BAT0/status);;\
##my $BATT_CAPACITY_DESIGN = qx(cat /sys/class/power_supply/BAT0/charge_full_design);;\
##my $BATT_CAPACITY_FULL = qx(cat /sys/class/power_supply/BAT0/charge_full);;\
##my $BATT_CHARGE_NOW = qx(cat /sys/class/power_supply/BAT0/charge_now);;\
##my $BATT_CYCLES = qx(cat /sys/class/power_supply/BAT0/cycle_count);;\
##my $BATT_CURRENT = qx(cat /sys/class/power_supply/BAT0/current_now);;\
##my $BATT_CHARGE_SYSTEM = qx(cat /sys/class/power_supply/BAT0/capacity);;\
\
my $my_read_file = sub {\
my ($filename) = @_;;\
my $fh;;\
return "Error with $filename: $!" unless open($fh, '<', $filename);;\
my $data = do { local $/;; <$fh> };;\
close($fh);;\
return $data;;\
};;\
\
my $BATT_STATE = $my_read_file->('/sys/class/power_supply/BAT0/status');;\
my $BATT_CAPACITY_DESIGN = $my_read_file->('/sys/class/power_supply/BAT0/charge_full_design');;\
my $BATT_CAPACITY_FULL = $my_read_file->('/sys/class/power_supply/BAT0/charge_full');;\
my $BATT_CHARGE_NOW = $my_read_file->('/sys/class/power_supply/BAT0/charge_now');;\
my $BATT_CYCLES = $my_read_file->('/sys/class/power_supply/BAT0/cycle_count');;\
my $BATT_CURRENT = $my_read_file->('/sys/class/power_supply/BAT0/current_now');;\
my $BATT_CHARGE_SYSTEM = $my_read_file->('/sys/class/power_supply/BAT0/capacity');;\
my $MEM_INFO = $my_read_file->('/proc/meminfo');;\
my $MY_STATUS = $my_read_file->("/proc/$$/status");;\
my $eth0_rx_bytes = $my_read_file->('/sys/class/net/eth0/statistics/rx_bytes');;\
my $eth0_tx_bytes = $my_read_file->('/sys/class/net/eth0/statistics/tx_bytes');;\
my $cpu_temp = $my_read_file->('/sys/class/thermal/thermal_zone0/temp') / 1000;;\
my $currentStats = $my_read_file->('/proc/stat');;\
my $previousStats = ReadingsVal("$SELF", ".cpustat", undef);;\
\
my $BATT_CHARGE_CALCULATED = int(100 * $BATT_CHARGE_NOW / $BATT_CAPACITY_FULL);;\
my ($MemTotal) = $MEM_INFO =~ /^MemTotal:\s+(\d+)\s+kB/m;;\
my ($MemFree) = $MEM_INFO =~ /^MemFree:\s+(\d+)\s+kB/m;;\
my ($MemAvailable) = $MEM_INFO =~ /^MemAvailable:\s+(\d+)\s+kB/m;;\
my ($VmSize) = $MY_STATUS =~ /^VmSize:\s+(\d+)\s+kB/m;;\
\
readingsBulkUpdate($hash, "BATT_STATE", $BATT_STATE);;\
readingsBulkUpdate($hash, "BATT_CAPACITY_DESIGN", $BATT_CAPACITY_DESIGN);;\
readingsBulkUpdate($hash, "BATT_CAPACITY_FULL", $BATT_CAPACITY_FULL);;\
readingsBulkUpdate($hash, "BATT_CHARGE_NOW", $BATT_CHARGE_NOW);;\
readingsBulkUpdate($hash, "BATT_CYCLES", $BATT_CYCLES);;\
readingsBulkUpdate($hash, "BATT_CURRENT", $BATT_CURRENT);;\
readingsBulkUpdate($hash, "BATT_CHARGE_CALCULATED", $BATT_CHARGE_CALCULATED);;\
readingsBulkUpdate($hash, "BATT_CHARGE_SYSTEM", $BATT_CHARGE_SYSTEM);;\
readingsBulkUpdate($hash, "MemTotal", $MemTotal);;\
readingsBulkUpdate($hash, "MemFree", $MemFree);;\
readingsBulkUpdate($hash, "MemAvailable", $MemAvailable);;\
readingsBulkUpdate($hash, "eth0_rx_bytes", $eth0_rx_bytes);;\
readingsBulkUpdate($hash, "eth0_tx_bytes", $eth0_tx_bytes);;\
readingsBulkUpdate($hash, "cpu_temp", $cpu_temp);;\
readingsBulkUpdate($hash, "VmSize", $VmSize);;\
readingsBulkUpdate($hash, ".cpustat", $currentStats);;\
\
##just extract cpu, cpu0, cpu1 .. cpuN as array\
my @cpus = map { (split " ", $_)[0] } grep { /cpu/ } split "\n", $currentStats;;\
\
##iterate over all cpus in /proc/stat\
foreach my $cpu (@cpus) {\
##skip if no previous stats to compare to\
last unless ($previousStats);;\
\
## algorithm from https://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux\
## converted to perl & FHEM\
## verified with: "taskset -c 0 stress-ng --cpu 1 --cpu-load 100" for each CPU\
my $currentLine = (grep { /$cpu / } split("\n", $currentStats))[0];;\
my ($cpul, $user, $nice, $system, $idle, $iowait, $irq, $softirq, $steal, $guest, $guest_nice) = split(" ", $currentLine);;\
my $previousLine = (grep { /$cpu / } split("\n", $previousStats))[0];;\
my ($prevcpul, $prevuser, $prevnice, $prevsystem, $previdle, $previowait, $previrq, $prevsoftirq, $prevsteal, $prevguest, $prevguest_nice) = split(" ", $previousLine);;\
\
my $PrevIdle = $previdle + $previowait;;\
my $Idle = $idle + $iowait;;\
my $PrevNonIdle = $prevuser + $prevnice + $prevsystem + $previrq + $prevsoftirq + $prevsteal;;\
my $NonIdle = $user + $nice + $system + $irq + $softirq + $steal;;\
my $PrevTotal = $PrevIdle + $PrevNonIdle;;\
my $Total = $Idle + $NonIdle;;\
my $totald = $Total - $PrevTotal;;\
my $idled = $Idle - $PrevIdle;;\
\
my $CPU_Percentage = ($totald - $idled) / $totald * 100;;\
\
readingsBulkUpdate($hash, $cpu, $CPU_Percentage);;\
}\
\
my $runtime = (gettimeofday() - $start_time) * 1000;;\
readingsBulkUpdate($hash, "runtime", "$runtime ms");;\
readingsEndUpdate($hash, 1);;\
}
attr Hardwaremonitor.doif alias Hardwaremonitor
attr Hardwaremonitor.doif do always
attr Hardwaremonitor.doif event_Readings VmSize_MB:[$SELF:VmSize]/1024,\
MemTotal_MB:[$SELF:MemTotal]/1024
attr Hardwaremonitor.doif group Hardwaremonitor
attr Hardwaremonitor.doif icon icoSYSTEM
attr Hardwaremonitor.doif room Server
attr Hardwaremonitor.doif stateFormat Battery: BATT_CHARGE_SYSTEM %, Memory available: mem_available_percent
attr Hardwaremonitor.doif uiTable {\
package ui_Table;;\
}\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([[$SELF:cpu:col7d],[$SELF:cpu0:col7d],[$SELF:cpu1:col7d]],"CPU Last","it_cpu",0,100,120,0,["cpu,yellow","cpu0,green","cpu1,red"],undef,"0,,,",",1,,,,1,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:VmSize_MB:col7d],"FHEM-Speichernutzung (VmSize=".[$SELF:VmSize]."kB)","it_memory",0,[$SELF:MemTotal_MB],120,0,"MB",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:BATT_CHARGE_CALCULATED:col7d],"Batterieladezustand","measure_battery_75",0,100,0,120,"%",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:cpu_temp:col7d],"CPU Temperatur","temp_temperature",20,100,120,0,"°C",undef,"0,,,",",1,,,,,600",undef,undef)
attr Hardwaremonitor.doif userReadings mem_available_percent:Mem.* {\
my $avail = ReadingsNum($name, "MemAvailable", -1);;\
my $total = ReadingsNum($name, "MemTotal", -1);;\
return round(100*$avail/$total, 0)."%";;\
}
Sie sieht es aus:
Bildschirmfoto_2023-10-31_21-10-09.png
Testweise setze ich einen der CPU-Kerne auf 100% Last und würde erwarten, dass es im Chart nach ein/zwei Minuten auch von alleine sichtbar ist.
taskset -c 0 stress-ng --cpu 1 --cpu-load 100
In der Konsole vom Browser passiert auch wohl was, aber die Charts bleiben einfach stehen:
Bildschirmfoto_2023-10-31_21-15-06.png
Hat jemand eine Idee?
Definiere es im Perlmodus - das könnte das Problem lösen. Im FHEM-Modus wird Selbsttriggerung per default unterbunden.
Ah, super und danke für den Wink in die richtige Richtung, es läuft nun wie gewünscht.
Da in diesem Fall nur ein Timer der Auslöser ist, habe ich das sicherlich nicht immer ganz einfache Attribut selftrigger (https://fhem.de/commandref_DE.html#DOIF_selftrigger) auf den nicht ganz unkritischen Wert "all" gesetzt. Den Perl-Modus möchte ich mir später auch nochmal genauer anschauen, der hat ja auch so Einiges zu bieten.
Hier nochmal das ganze Device, falls es jemand auch gebrauchen kann. Das Besondere ist, dass Werte für RAM, CPU und Akkufüllstand schnell und einfach aus "/sys" und "/proc" geholt werden. Der Laufzeitunterschied zu einer Lösung die ein paar qx() Kommnados ausführt, war es wert die Sache in Perl zu lösen. Auch ist die CPU-Last-Berechnung in Prozent mir lieber als "load", auch wenn es ein wenig weitere Rechnerei ist.
defmod Hardwaremonitor.doif DOIF ([+:01])\
{\
use Time::HiRes;;\
my $start_time = gettimeofday();;\
\
my $hash = $defs{"$SELF"};;\
readingsBeginUpdate($hash);;\
\
##This is too slow:\
##my $BATT_STATE = qx(cat /sys/class/power_supply/BAT0/status);;\
##my $BATT_CAPACITY_DESIGN = qx(cat /sys/class/power_supply/BAT0/charge_full_design);;\
##my $BATT_CAPACITY_FULL = qx(cat /sys/class/power_supply/BAT0/charge_full);;\
##my $BATT_CHARGE_NOW = qx(cat /sys/class/power_supply/BAT0/charge_now);;\
##my $BATT_CYCLES = qx(cat /sys/class/power_supply/BAT0/cycle_count);;\
##my $BATT_CURRENT = qx(cat /sys/class/power_supply/BAT0/current_now);;\
##my $BATT_CHARGE_SYSTEM = qx(cat /sys/class/power_supply/BAT0/capacity);;\
\
my $my_read_file = sub {\
my ($filename) = @_;;\
my $fh;;\
return "Error with $filename: $!" unless open($fh, '<', $filename);;\
my $data = do { local $/;; <$fh> };;\
close($fh);;\
return $data;;\
};;\
\
my $BATT_STATE = $my_read_file->('/sys/class/power_supply/BAT0/status');;\
my $BATT_CAPACITY_DESIGN = $my_read_file->('/sys/class/power_supply/BAT0/charge_full_design');;\
my $BATT_CAPACITY_FULL = $my_read_file->('/sys/class/power_supply/BAT0/charge_full');;\
my $BATT_CHARGE_NOW = $my_read_file->('/sys/class/power_supply/BAT0/charge_now');;\
my $BATT_CYCLES = $my_read_file->('/sys/class/power_supply/BAT0/cycle_count');;\
my $BATT_CURRENT = $my_read_file->('/sys/class/power_supply/BAT0/current_now');;\
my $BATT_CHARGE_SYSTEM = $my_read_file->('/sys/class/power_supply/BAT0/capacity');;\
my $MEM_INFO = $my_read_file->('/proc/meminfo');;\
my $MY_STATUS = $my_read_file->("/proc/$$/status");;\
my $eth0_rx_bytes = $my_read_file->('/sys/class/net/eth0/statistics/rx_bytes');;\
my $eth0_tx_bytes = $my_read_file->('/sys/class/net/eth0/statistics/tx_bytes');;\
my $cpu_temp = $my_read_file->('/sys/class/thermal/thermal_zone0/temp') / 1000;;\
my $currentStats = $my_read_file->('/proc/stat');;\
my $previousStats = ReadingsVal("$SELF", ".cpustat", undef);;\
\
my $BATT_CHARGE_CALCULATED = int(100 * $BATT_CHARGE_NOW / $BATT_CAPACITY_FULL);;\
my ($MemTotal) = $MEM_INFO =~ /^MemTotal:\s+(\d+)\s+kB/m;;\
my ($MemFree) = $MEM_INFO =~ /^MemFree:\s+(\d+)\s+kB/m;;\
my ($MemAvailable) = $MEM_INFO =~ /^MemAvailable:\s+(\d+)\s+kB/m;;\
my ($VmSize) = $MY_STATUS =~ /^VmSize:\s+(\d+)\s+kB/m;;\
\
readingsBulkUpdate($hash, "BATT_STATE", $BATT_STATE);;\
readingsBulkUpdate($hash, "BATT_CAPACITY_DESIGN", $BATT_CAPACITY_DESIGN);;\
readingsBulkUpdate($hash, "BATT_CAPACITY_FULL", $BATT_CAPACITY_FULL);;\
readingsBulkUpdate($hash, "BATT_CHARGE_NOW", $BATT_CHARGE_NOW);;\
readingsBulkUpdate($hash, "BATT_CYCLES", $BATT_CYCLES);;\
readingsBulkUpdate($hash, "BATT_CURRENT", $BATT_CURRENT);;\
readingsBulkUpdate($hash, "BATT_CHARGE_CALCULATED", $BATT_CHARGE_CALCULATED);;\
readingsBulkUpdate($hash, "BATT_CHARGE_SYSTEM", $BATT_CHARGE_SYSTEM);;\
readingsBulkUpdate($hash, "MemTotal", $MemTotal);;\
readingsBulkUpdate($hash, "MemFree", $MemFree);;\
readingsBulkUpdate($hash, "MemAvailable", $MemAvailable);;\
readingsBulkUpdate($hash, "eth0_rx_bytes", $eth0_rx_bytes);;\
readingsBulkUpdate($hash, "eth0_tx_bytes", $eth0_tx_bytes);;\
readingsBulkUpdate($hash, "cpu_temp", $cpu_temp);;\
readingsBulkUpdate($hash, "VmSize", $VmSize);;\
readingsBulkUpdate($hash, ".cpustat", $currentStats);;\
\
##just extract cpu, cpu0, cpu1 .. cpuN as array\
my @cpus = map { (split " ", $_)[0] } grep { /cpu/ } split "\n", $currentStats;;\
\
##iterate over all cpus in /proc/stat\
foreach my $cpu (@cpus) {\
##skip if no previous stats to compare to\
last unless ($previousStats);;\
\
## algorithm from https://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux\
## converted to perl & FHEM\
## verified with: "taskset -c 0 stress-ng --cpu 1 --cpu-load 100" for each CPU\
my $currentLine = (grep { /$cpu / } split("\n", $currentStats))[0];;\
my ($cpul, $user, $nice, $system, $idle, $iowait, $irq, $softirq, $steal, $guest, $guest_nice) = split(" ", $currentLine);;\
my $previousLine = (grep { /$cpu / } split("\n", $previousStats))[0];;\
my ($prevcpul, $prevuser, $prevnice, $prevsystem, $previdle, $previowait, $previrq, $prevsoftirq, $prevsteal, $prevguest, $prevguest_nice) = split(" ", $previousLine);;\
\
my $PrevIdle = $previdle + $previowait;;\
my $Idle = $idle + $iowait;;\
my $PrevNonIdle = $prevuser + $prevnice + $prevsystem + $previrq + $prevsoftirq + $prevsteal;;\
my $NonIdle = $user + $nice + $system + $irq + $softirq + $steal;;\
my $PrevTotal = $PrevIdle + $PrevNonIdle;;\
my $Total = $Idle + $NonIdle;;\
my $totald = $Total - $PrevTotal;;\
my $idled = $Idle - $PrevIdle;;\
\
my $CPU_Percentage = ($totald - $idled) / $totald * 100;;\
\
readingsBulkUpdate($hash, $cpu, $CPU_Percentage);;\
}\
\
my $runtime = (gettimeofday() - $start_time) * 1000;;\
readingsBulkUpdate($hash, "runtime", "$runtime ms");;\
readingsEndUpdate($hash, 1);;\
}
attr Hardwaremonitor.doif alias Hardwaremonitor
attr Hardwaremonitor.doif do always
attr Hardwaremonitor.doif event_Readings VmSize_MB:[$SELF:VmSize]/1024,\
MemTotal_MB:[$SELF:MemTotal]/1024
attr Hardwaremonitor.doif group Hardwaremonitor
attr Hardwaremonitor.doif icon icoSYSTEM
attr Hardwaremonitor.doif room Server
attr Hardwaremonitor.doif selftrigger all
attr Hardwaremonitor.doif stateFormat Battery: BATT_CHARGE_SYSTEM %, Memory available: mem_available_percent
attr Hardwaremonitor.doif uiTable {\
package ui_Table;;\
}\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([[$SELF:cpu:col7d],[$SELF:cpu0:col7d],[$SELF:cpu1:col7d]],"CPU Last","it_cpu",0,100,120,0,["cpu,yellow","cpu0,green","cpu1,red"],undef,"0,,,",",1,,,,1,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:VmSize_MB:col7d],"FHEM-Speichernutzung (VmSize=".[$SELF:VmSize]."kB)","it_memory",0,[$SELF:MemTotal_MB],120,0,"MB",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:BATT_CHARGE_CALCULATED:col7d],"Batterieladezustand","measure_battery_75",0,100,0,120,"%",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:cpu_temp:col7d],"CPU Temperatur","temp_temperature",20,100,120,0,"°C",undef,"0,,,",",1,,,,,600",undef,undef)
attr Hardwaremonitor.doif userReadings mem_available_percent:Mem.* {\
my $avail = ReadingsNum($name, "MemAvailable", -1);;\
my $total = ReadingsNum($name, "MemTotal", -1);;\
return round(100*$avail/$total, 0)."%";;\
}
Danke!
Zitat von: Torxgewinde am 01 November 2023, 07:34:12Den Perl-Modus möchte ich mir später auch nochmal genauer anschauen, der hat ja auch so Einiges zu bieten.
Das wäre doch eine gut Gelegenheit dazu. Da du ja ohnehin alles in Perl programmiert hast, brauchst du nur aus
defmod Hardwaremonitor.doif DOIF ([+:01])\
{\
...
defmod Hardwaremonitor.doif DOIF {[+:01];\
\
zu machen.
Dann hast du einen Perl-Block mit dem Timer als Trigger drin, Diverse Attribute wie do und selftrigger entfallen. Statt readingsBulkUpdate und co. kannst du folgende Funktionen nutzen: https://wiki.fhem.de/wiki/DOIF/Perl-Modus#Setzen_mehrerer_Readings_des_eigenen_DOIF-Devices_in_einem_Eventblock
Der Block ist in einem eigenen Namensraum gekapselt, daher muss man beim Aufruf fremder Funktionen :: voranstellen.
Nochmal Danke! Es hat sogar Spaß gemacht zu sehen wie einfach das ist! Klappt im Perl-Modus auch wunderbar:
defmod Hardwaremonitor.doif DOIF # Definitions of locally used functions\
subs {\
# read a file and return its content\
sub my_read_file($) {\
my ($filename) = @_;;\
my $fh;;\
return "Error with $filename: $!" unless open($fh, '<', $filename);;\
my $data = do { local $/;; <$fh> };;\
close($fh);;\
return $data;;\
}\
}\
\
# Block to be executed at startup and every sharp minute\
init {[+:01];;\
use Time::HiRes;;\
my $start_time = gettimeofday();;\
set_Reading_Begin();;\
\
my $BATT_STATE = my_read_file('/sys/class/power_supply/BAT0/status');;\
my $BATT_CAPACITY_DESIGN = my_read_file('/sys/class/power_supply/BAT0/charge_full_design');;\
my $BATT_CAPACITY_FULL = my_read_file('/sys/class/power_supply/BAT0/charge_full');;\
my $BATT_CHARGE_NOW = my_read_file('/sys/class/power_supply/BAT0/charge_now');;\
my $BATT_CYCLES = my_read_file('/sys/class/power_supply/BAT0/cycle_count');;\
my $BATT_CURRENT = my_read_file('/sys/class/power_supply/BAT0/current_now');;\
my $BATT_CHARGE_SYSTEM = my_read_file('/sys/class/power_supply/BAT0/capacity');;\
my $MEM_INFO = my_read_file('/proc/meminfo');;\
my $MY_STATUS = my_read_file("/proc/$$/status");;\
my $eth0_rx_bytes = my_read_file('/sys/class/net/eth0/statistics/rx_bytes');;\
my $eth0_tx_bytes = my_read_file('/sys/class/net/eth0/statistics/tx_bytes');;\
my $cpu_temp = my_read_file('/sys/class/thermal/thermal_zone0/temp') / 1000;;\
my $currentStats = my_read_file('/proc/stat');;\
my $previousStats = [$SELF:.cpustat,undef];;\
\
my $BATT_CHARGE_CALCULATED = int(100 * $BATT_CHARGE_NOW / $BATT_CAPACITY_FULL);;\
my ($MemTotal) = $MEM_INFO =~ /^MemTotal:\s+(\d+)\s+kB/m;;\
my ($MemFree) = $MEM_INFO =~ /^MemFree:\s+(\d+)\s+kB/m;;\
my ($MemAvailable) = $MEM_INFO =~ /^MemAvailable:\s+(\d+)\s+kB/m;;\
my ($VmSize) = $MY_STATUS =~ /^VmSize:\s+(\d+)\s+kB/m;;\
\
set_Reading_Update("BATT_STATE", $BATT_STATE);;\
set_Reading_Update("BATT_CAPACITY_DESIGN", $BATT_CAPACITY_DESIGN);;\
set_Reading_Update("BATT_CAPACITY_FULL", $BATT_CAPACITY_FULL);;\
set_Reading_Update("BATT_CHARGE_NOW", $BATT_CHARGE_NOW);;\
set_Reading_Update("BATT_CYCLES", $BATT_CYCLES);;\
set_Reading_Update("BATT_CURRENT", $BATT_CURRENT);;\
set_Reading_Update("BATT_CHARGE_CALCULATED", $BATT_CHARGE_CALCULATED);;\
set_Reading_Update("BATT_CHARGE_SYSTEM", $BATT_CHARGE_SYSTEM);;\
set_Reading_Update("MemTotal", $MemTotal);;\
set_Reading_Update("MemFree", $MemFree);;\
set_Reading_Update("MemAvailable", $MemAvailable);;\
set_Reading_Update("eth0_rx_bytes", $eth0_rx_bytes);;\
set_Reading_Update("eth0_tx_bytes", $eth0_tx_bytes);;\
set_Reading_Update("cpu_temp", $cpu_temp);;\
set_Reading_Update("VmSize", $VmSize);;\
set_Reading_Update(".cpustat", $currentStats);;\
\
##just extract cpu, cpu0, cpu1 .. cpuN as array\
my @cpus = map { (split " ", $_)[0] } grep { /cpu/ } split "\n", $currentStats;;\
\
##iterate over all cpus in /proc/stat\
foreach my $cpu (@cpus) {\
##skip if no previous stats to compare to\
last unless ($previousStats);;\
\
## algorithm from https://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux\
## converted to perl & FHEM\
## verified with: "taskset -c 0 stress-ng --cpu 1 --cpu-load 100" for each CPU\
my $currentLine = (grep { /$cpu / } split("\n", $currentStats))[0];;\
my ($cpul, $user, $nice, $system, $idle, $iowait, $irq, $softirq, $steal, $guest, $guest_nice) = split(" ", $currentLine);;\
my $previousLine = (grep { /$cpu / } split("\n", $previousStats))[0];;\
my ($prevcpul, $prevuser, $prevnice, $prevsystem, $previdle, $previowait, $previrq, $prevsoftirq, $prevsteal, $prevguest, $prevguest_nice) = split(" ", $previousLine);;\
\
my $PrevIdle = $previdle + $previowait;;\
my $Idle = $idle + $iowait;;\
my $PrevNonIdle = $prevuser + $prevnice + $prevsystem + $previrq + $prevsoftirq + $prevsteal;;\
my $NonIdle = $user + $nice + $system + $irq + $softirq + $steal;;\
my $PrevTotal = $PrevIdle + $PrevNonIdle;;\
my $Total = $Idle + $NonIdle;;\
my $totald = $Total - $PrevTotal;;\
my $idled = $Idle - $PrevIdle;;\
\
my $CPU_Percentage = ($totald - $idled) / $totald * 100;;\
\
set_Reading_Update($cpu, $CPU_Percentage);;\
}\
\
my $runtime = (gettimeofday() - $start_time) * 1000;;\
set_Reading_Update("runtime", "$runtime ms");;\
set_Reading_End(1);;\
}
attr Hardwaremonitor.doif alias Hardwaremonitor
attr Hardwaremonitor.doif event_Readings VmSize_MB:[$SELF:VmSize]/1024,\
MemTotal_MB:[$SELF:MemTotal]/1024,\
mem_available_percent:round(100*[$SELF:MemAvailable]/[$SELF:MemTotal],0)
attr Hardwaremonitor.doif group Hardwaremonitor
attr Hardwaremonitor.doif icon icoSYSTEM
attr Hardwaremonitor.doif room Server
attr Hardwaremonitor.doif stateFormat Battery: BATT_CHARGE_SYSTEM %, Memory available: mem_available_percent %
attr Hardwaremonitor.doif uiTable {\
package ui_Table;;\
}\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([[$SELF:cpu:col7d],[$SELF:cpu0:col7d],[$SELF:cpu1:col7d]],"CPU Last","it_cpu",0,100,120,0,["cpu,yellow","cpu0,green","cpu1,red"],undef,"0,,,",",1,,,,1,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:VmSize_MB:col7d],"FHEM-Speichernutzung (VmSize=".[$SELF:VmSize]."kB)","it_memory",0,[$SELF:MemTotal_MB],120,0,"MB",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:BATT_CHARGE_CALCULATED:col7d],"Batterieladezustand","measure_battery_75",0,100,0,120,"%",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:cpu_temp:col7d],"CPU Temperatur","temp_temperature",20,100,120,0,"°C",undef,"0,,,",",1,,,,,600",undef,undef)
Schön, dass es Spaß gemacht hat. Im Perl-Modus bist du viel flexibler, FHEM-Modus ist etwas für Anfänger, die mit if-then-else auskommen.
Das kannst du glatt als Codeschnipsel im entsprechenden Unterforum mit Bild posten, da es von allgemeinem Interesse sein dürfte.
Wirklich sehr schön, ich musste bei mir lediglich die Dateipfade etwas anpassen, dann ging es auf Anhieb. Vielen Dank!
defmod doif_Hardwaremonitor DOIF subs {\
sub my_read_file($) {\
my ($filename) = @_;;\
my $fh;;\
return "Error with $filename: $!" unless open($fh, '<', $filename);;\
my $data = do { local $/;; <$fh> };;\
close($fh);;\
return $data;;\
}\
}\
\
init {[+:01];;\
use Time::HiRes;;\
my $start_time = gettimeofday();;\
set_Reading_Begin();;\
\
my $BATT_STATUS = my_read_file('/sys/class/power_supply/BAT0/status');;\
my $BATT_CAPACITY_DESIGN = my_read_file('/sys/class/power_supply/BAT0/energy_full_design');;\
my $BATT_CAPACITY_FULL = my_read_file('/sys/class/power_supply/BAT0/energy_full');;\
my $BATT_CHARGE_NOW = my_read_file('/sys/class/power_supply/BAT0/energy_now');;\
my $BATT_CYCLES = my_read_file('/sys/class/power_supply/BAT0/cycle_count');;\
my $BATT_CURRENT = my_read_file('/sys/class/power_supply/BAT0/power_now');;\
my $BATT_CHARGE_SYSTEM = my_read_file('/sys/class/power_supply/BAT0/capacity');;\
my $MEM_INFO = my_read_file('/proc/meminfo');;\
my $MY_STATUS = my_read_file("/proc/$$/status");;\
my $eth0_rx_bytes = my_read_file('/sys/class/net/enp0s25/statistics/rx_bytes');;\
my $eth0_tx_bytes = my_read_file('/sys/class/net/enp0s25/statistics/tx_bytes');;\
my $cpu_temp = my_read_file('/sys/class/thermal/thermal_zone0/temp') / 1000;;\
my $currentStats = my_read_file('/proc/stat');;\
my $previousStats = [$SELF:.cpustat,undef];;\
\
my $BATT_CHARGE_CALCULATED = int(100 * $BATT_CHARGE_NOW / $BATT_CAPACITY_FULL);;\
my ($MemTotal) = $MEM_INFO =~ /^MemTotal:\s+(\d+)\s+kB/m;;\
my ($MemFree) = $MEM_INFO =~ /^MemFree:\s+(\d+)\s+kB/m;;\
my ($MemAvailable) = $MEM_INFO =~ /^MemAvailable:\s+(\d+)\s+kB/m;;\
my ($MemBuffers) = $MEM_INFO =~ /^Buffers:\s+(\d+)\s+kB/m;;\
my ($MemCached) = $MEM_INFO =~ /^Cached:\s+(\d+)\s+kB/m;;\
my ($MemSReclaimable) = $MEM_INFO =~ /^SReclaimable:\s+(\d+)\s+kB/m;;\
my ($MemShmem) = $MEM_INFO =~ /^Shmem:\s+(\d+)\s+kB/m;;\
my $MemUsed = $MemTotal - $MemFree - $MemBuffers - $MemCached - $MemSReclaimable + $MemShmem;; \
my ($VmSize) = $MY_STATUS =~ /^VmSize:\s+(\d+)\s+kB/m;;\
\
set_Reading_Update("BATT_STATUS", $BATT_STATUS);;\
set_Reading_Update("BATT_CAPACITY_DESIGN", $BATT_CAPACITY_DESIGN);;\
set_Reading_Update("BATT_CAPACITY_FULL", $BATT_CAPACITY_FULL);;\
set_Reading_Update("BATT_CHARGE_NOW", $BATT_CHARGE_NOW);;\
set_Reading_Update("BATT_CYCLES", $BATT_CYCLES);;\
set_Reading_Update("BATT_CURRENT", $BATT_CURRENT);;\
set_Reading_Update("BATT_CHARGE_CALCULATED", $BATT_CHARGE_CALCULATED);;\
set_Reading_Update("BATT_CHARGE_SYSTEM", $BATT_CHARGE_SYSTEM);;\
set_Reading_Update("MemTotal", $MemTotal);;\
set_Reading_Update("MemTotal_MB", int($MemTotal / 1024));;\
set_Reading_Update("MemFree", $MemFree);;\
set_Reading_Update("MemAvailable", $MemAvailable);;\
set_Reading_Update("MemUsed", $MemUsed);;\
set_Reading_Update("MemUsed_MB", int($MemUsed / 1024));;\
set_Reading_Update("MemBuffers", $MemBuffers);;\
set_Reading_Update("MemCached", $MemCached);;\
set_Reading_Update("MemSReclaimable", $MemSReclaimable);;\
set_Reading_Update("MemShmem", $MemShmem);;\
set_Reading_Update("mem_available_percent", ::round(100 * ($MemTotal - $MemUsed) / $MemTotal, 0));;\
set_Reading_Update("eth0_rx_bytes", $eth0_rx_bytes);;\
set_Reading_Update("eth0_tx_bytes", $eth0_tx_bytes);;\
set_Reading_Update("cpu_temp", $cpu_temp);;\
set_Reading_Update("VmSize", $VmSize);;\
set_Reading_Update("VmSize_MB", int($VmSize / 1024));;\
set_Reading_Update(".cpustat", $currentStats);;\
\
##just extract cpu, cpu0, cpu1 .. cpuN as array\
my @cpus = map { (split " ", $_)[0] } grep { /cpu/ } split "\n", $currentStats;;\
\
##iterate over all cpus in /proc/stat\
foreach my $cpu (@cpus) {\
##skip if no previous stats to compare to\
last unless ($previousStats);;\
\
## algorithm from https://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux\
## converted to perl & FHEM\
## verified with: "taskset -c 0 stress-ng --cpu 1 --cpu-load 100" for each CPU\
my $currentLine = (grep { /$cpu / } split("\n", $currentStats))[0];;\
my ($cpul, $user, $nice, $system, $idle, $iowait, $irq, $softirq, $steal, $guest, $guest_nice) = split(" ", $currentLine);;\
my $previousLine = (grep { /$cpu / } split("\n", $previousStats))[0];;\
my ($prevcpul, $prevuser, $prevnice, $prevsystem, $previdle, $previowait, $previrq, $prevsoftirq, $prevsteal, $prevguest, $prevguest_nice) = split(" ", $previousLine);;\
\
my $PrevIdle = $previdle + $previowait;;\
my $Idle = $idle + $iowait;;\
my $PrevNonIdle = $prevuser + $prevnice + $prevsystem + $previrq + $prevsoftirq + $prevsteal;;\
my $NonIdle = $user + $nice + $system + $irq + $softirq + $steal;;\
my $PrevTotal = $PrevIdle + $PrevNonIdle;;\
my $Total = $Idle + $NonIdle;;\
my $totald = $Total - $PrevTotal;;\
my $idled = $Idle - $PrevIdle;;\
\
my $CPU_Percentage = ($totald - $idled) / $totald * 100;;\
\
set_Reading_Update($cpu, $CPU_Percentage);;\
}\
\
my $runtime = (gettimeofday() - $start_time) * 1000;;\
set_Reading_Update("runtime", "$runtime ms");;\
set_Reading_End(1);;\
}
attr doif_Hardwaremonitor alias Hardwaremonitor
attr doif_Hardwaremonitor icon icoSYSTEM
attr doif_Hardwaremonitor room SYSTEM
attr doif_Hardwaremonitor stateFormat Temperatur: cpu_temp °C, Memory available: mem_available_percent %
attr doif_Hardwaremonitor uiTable {\
package ui_Table;;\
}\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([[$SELF:cpu:col7d],[$SELF:cpu0:col7d],[$SELF:cpu1:col7d],[$SELF:cpu2:col7d],[$SELF:cpu3:col7d]],"CPU Last","it_cpu",0,100,120,0,["cpu,white","cpu0,yellow","cpu1,orange","cpu2,deeppink","cpu3,red"],undef,"0,,,",",1,,,,1,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:MemUsed_MB:col7d],"FHEM-Speichernutzung (Used=".[$SELF:MemUsed_MB]."MB)","it_memory",0,[$SELF:MemTotal_MB],120,0,"MB",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:BATT_CHARGE_CALCULATED:col7d],"Batterieladezustand","measure_battery_75",0,100,0,120,"%",undef,"0,,,",",1,,,,,600",undef,undef)\
\
## card ($collect,$header,$icon,$min,$max,$minColor,$maxColor,$unit,$func,$decfont,$size,$model,$lightness,\
## $collect2,$min2,$max2,$minColor2,$maxColor2,$unit2,$func2,$decfont2)\
card([$SELF:cpu_temp:col7d],"CPU Temperatur","temp_temperature",20,100,120,0,"°C",undef,"0,,,",",1,,,,,600",undef,undef)
Ich habe noch einmal etwas am benutzten Speicher gebastelt und für mich passt es so besser...