FHEM Forum

FHEM => Automatisierung => DOIF => Thema gestartet von: Torxgewinde am 31 Oktober 2023, 21:20:03

Titel: [gelöst] uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: Torxgewinde am 31 Oktober 2023, 21:20:03
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?
Titel: Aw: uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: Damian am 31 Oktober 2023, 22:44:19
Definiere es im Perlmodus - das könnte das Problem lösen. Im FHEM-Modus wird Selbsttriggerung per default unterbunden.
Titel: Aw: uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: Torxgewinde am 01 November 2023, 07:34:12
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!
Titel: Aw: [gelöst] uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: Damian am 01 November 2023, 11:07:48
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.
Titel: Aw: [gelöst] uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: Torxgewinde am 01 November 2023, 19:03:13
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)
Titel: Aw: [gelöst] uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: Damian am 01 November 2023, 20:06:52
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.


Titel: Aw: [gelöst] uiTable aktualisiert Cards nicht, nutze "readingsBulkUpdate()" etc.
Beitrag von: mumpitzstuff am 18 November 2023, 22:24:46
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...