diff --git a/fhem/CHANGED b/fhem/CHANGED index 165d32b44..3c2262517 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,6 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. - SVN + - feature: new module 42_SYSMON.pm added (hexenmeister) - feature: YAMAHA_AVR: new readings for radio stations, current title and more. see commandref for more details. - feature: new module 32_withings.pm added (justme1968) diff --git a/fhem/FHEM/42_SYSMON.pm b/fhem/FHEM/42_SYSMON.pm new file mode 100644 index 000000000..6a96d393c --- /dev/null +++ b/fhem/FHEM/42_SYSMON.pm @@ -0,0 +1,1833 @@ +################################################################ +# +# Copyright notice +# +# (c) 2013 Alexander Schulz +# +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The GNU General Public License can be found at +# http://www.gnu.org/copyleft/gpl.html. +# A copy is found in the textfile GPL.txt and important notices to the license +# from the author is found in LICENSE.txt distributed with these scripts. +# +# This script is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# This copyright notice MUST APPEAR in all copies of the script! +# +################################################################ + +# $Id$ + +package main; + +use strict; +use warnings; + +my $VERSION = "1.2.1"; + +use constant { + DATE => "date", + UPTIME => "uptime", + UPTIME_TEXT => "uptime_text", + FHEMUPTIME => "fhemuptime", + FHEMUPTIME_TEXT => "fhemuptime_text", + IDLETIME => "idletime", + IDLETIME_TEXT => "idletime_text" +}; + +use constant { + CPU_FREQ => "cpu_freq", + CPU_TEMP => "cpu_temp", + CPU_TEMP_AVG => "cpu_temp_avg", + LOADAVG => "loadavg" +}; + +use constant { + RAM => "ram", + SWAP => "swap" +}; + +use constant { + ETH0 => "eth0", + WLAN0 => "wlan0", + DIFF_SUFFIX => "_diff" +}; + +use constant FS_PREFIX => "~ "; +#use constant FS_PREFIX_N => "fs_"; + +sub +SYSMON_Initialize($) +{ + my ($hash) = @_; + + Log 5, "SYSMON Initialize"; + + $hash->{DefFn} = "SYSMON_Define"; + $hash->{UndefFn} = "SYSMON_Undefine"; + $hash->{GetFn} = "SYSMON_Get"; + $hash->{SetFn} = "SYSMON_Set"; + $hash->{AttrFn} = "SYSMON_Attr"; + $hash->{AttrList} = "filesystems network-interfaces user-defined disable:0,1 ". + $readingFnAttributes; +} +### attr NAME user-defined osUpdates:1440:Aktualisierungen:cat ./updates.txt [,:::] + +sub +SYSMON_Define($$) +{ + my ($hash, $def) = @_; + + logF($hash, "Define", "$def"); + + my @a = split("[ \t][ \t]*", $def); + + return "Usage: define SYSMON [M1 [M2 [M3 [M4]]]]" if(@a < 2); + + if(int(@a)>=3) + { + my @na = @a[2..scalar(@a)-1]; + SYSMON_setInterval($hash, @na); + } else { + SYSMON_setInterval($hash, undef); + } + + $hash->{STATE} = "Initialized"; + + $hash->{DEF_TIME} = time() unless defined($hash->{DEF_TIME}); + + SYSMON_updateCurrentReadingsMap($hash); + + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL_BASE}, "SYSMON_Update", $hash, 0); + + #$hash->{LOCAL} = 1; + #SYSMON_Update($hash); #-> so nicht. hat im Startvorgang gelegentlich (oft) den Server 'aufgehaengt' + #delete $hash->{LOCAL}; + + return undef; +} + +sub +SYSMON_setInterval($@) +{ + my ($hash, @a) = @_; + + my $interval = 60; + $hash->{INTERVAL_BASE} = $interval; + + my $p1=1; + my $p2=1; + my $p3=1; + my $p4=10; + + if(defined($a[0]) && int($a[0]) eq $a[0]) {$p1 = $a[0];} + if(defined($a[1]) && int($a[1]) eq $a[1]) {$p2 = $a[1];} else {$p2 = $p1;} + if(defined($a[2]) && int($a[2]) eq $a[2]) {$p3 = $a[2];} else {$p3 = $p1;} + if(defined($a[3]) && int($a[3]) eq $a[3]) {$p4 = $a[3];} else {$p4 = $p1*10;} + + $hash->{INTERVAL_MULTIPLIERS} = $p1." ".$p2." ".$p3." ".$p4; +} + + +my $cur_readings_map; +sub +SYSMON_updateCurrentReadingsMap($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + my $rMap; + + # Map aktueller Namen erstellen + + # Feste Werte + $rMap->{+DATE} = "Date"; + if(SYSMON_isCPUFreqRPiBBB($hash)) { + #$rMap->{"cpu_freq"} = "CPU Frequenz"; + $rMap->{"cpu_freq"} = "CPU frequency"; + } + if(SYSMON_isCPUTempRPi($hash) || SYSMON_isCPUTempBBB($hash)) { + #$rMap->{+CPU_TEMP} = "CPU Temperatur"; + #$rMap->{"cpu_temp_avg"} = "Durchschnittliche CPU Temperatur"; + $rMap->{+CPU_TEMP} = "CPU temperature"; + $rMap->{"cpu_temp_avg"} = "Average CPU temperature"; + } + #$rMap->{"fhemuptime"} = "Betriebszeit FHEM"; + #$rMap->{"fhemuptime_text"} = "Betriebszeit FHEM"; + #$rMap->{"idletime"} = "Leerlaufzeit"; + #$rMap->{"idletime_text"} = "Leerlaufzeit"; + #$rMap->{"loadavg"} = "Durchschnittliche Auslastung"; + #$rMap->{"ram"} = "RAM"; + #$rMap->{"swap"} = "Swap"; + #$rMap->{"uptime"} = "Betriebszeit"; + #$rMap->{"uptime_text"} = "Betriebszeit"; + $rMap->{"fhemuptime"} = "System up time"; + $rMap->{"fhemuptime_text"} = "FHEM up time"; + $rMap->{"idletime"} = "Idle time"; + $rMap->{"idletime_text"} = "Idle time"; + $rMap->{"loadavg"} = "Load average"; + $rMap->{"ram"} = "RAM"; + $rMap->{"swap"} = "swap"; + $rMap->{"uptime"} = "System up time"; + $rMap->{"uptime_text"} = "System up time"; + + # Filesystems [:[:]] + my $filesystems = AttrVal($name, "filesystems", undef); + if(defined $filesystems) { + my @filesystem_list = split(/,\s*/, trim($filesystems)); + foreach (@filesystem_list) { + my($fName, $fDef, $nComment) = split(/:/, $_); + if(defined $nComment) { + $rMap->{$fName} = $nComment; + } else { + if(defined $fDef) { + # Benannte + $rMap->{$fName} = "Filesystem ".$fDef; + } else { + # Unbenannte + $rMap->{$fName} = "Mount point ".$fName; + } + } + } + } else { + $rMap->{"root"} = "Filesystem /"; + } + + # Networkadapters: [:[:]] + my $networkadapters = AttrVal($name, "network-interfaces", undef); + if(defined $networkadapters) { + my @networkadapters_list = split(/,\s*/, trim($networkadapters)); + foreach (@networkadapters_list) { + my($nName, $nDef, $nComment) = split(/:/, $_); + if(defined $nComment) { + $rMap->{$nName} = $nComment; + $rMap->{$nName."_diff"} = $nComment." (diff)"; + } else { + if(defined $nDef) { + # Benannte + $rMap->{$nName} = "Network ".$nDef; + $rMap->{$nName."_diff"} = "Network ".$nDef." (diff)"; + } else { + # Unbenannte + $rMap->{$nName} = "Network adapter ".$nName; + $rMap->{$nName."_diff"} = "Network adapter ".$nName." (diff)"; + } + } + } + } + + # User defined + my $userdefined = AttrVal($name, "user-defined", undef); + if(defined $userdefined) { + my @userdefined_list = split(/,\s*/, trim($userdefined)); + foreach (@userdefined_list) { + # ::: + my($uName, $uInterval, $uComment, $uCmd) = split(/:/, $_); + if(defined $uComment) { + # Nur gueltige + $rMap->{$uName} = $uComment; + } + } + } + + $cur_readings_map = $rMap; + return $rMap; +} + +sub +SYSMON_getObsoleteReadingsMap($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + + my $rMap; + + # alle READINGS durchgehen + my @cKeys=keys (%{$defs{$name}{READINGS}}); + foreach my $aName (@cKeys) { + if(defined ($aName)) { + # alles hinzufuegen, was nicht in der Aktuellen Liste ist + if(!$cur_readings_map->{$aName}) { + $rMap->{$aName} = 1; + } + } + } + + return $rMap; +} + +sub +SYSMON_Undefine($$) +{ + my ($hash, $arg) = @_; + + logF($hash, "Undefine", ""); + + RemoveInternalTimer($hash); + return undef; +} + +sub +SYSMON_Get($@) +{ + my ($hash, @a) = @_; + + my $name = $a[0]; + + if(@a < 2) + { + logF($hash, "Get", "@a: get needs at least one parameter"); + return "$name: get needs at least one parameter"; + } + + my $cmd= $a[1]; + + logF($hash, "Get", "@a"); + + if($cmd eq "update") + { + #$hash->{LOCAL} = 1; + SYSMON_Update($hash, 1); + #delete $hash->{LOCAL}; + return undef; + } + + if($cmd eq "list") { + my $map = SYSMON_obtainParameters($hash, 1); + my $ret = ""; + foreach my $name (keys %{$map}) { + my $value = $map->{$name}; + $ret = "$ret\n".sprintf("%-20s %s", $name, $value); + } + return $ret; + } + + if($cmd eq "version") + { + return $VERSION; + } + + if($cmd eq "interval_base") + { + return $hash->{INTERVAL_BASE}; + } + + if($cmd eq "interval_multipliers") + { + return $hash->{INTERVAL_MULTIPLIERS}; + } + + return "Unknown argument $cmd, choose one of list:noArg update:noArg interval_base:noArg interval_multipliers:noArg version:noArg"; +} + +sub +SYSMON_Set($@) +{ + my ($hash, @a) = @_; + + my $name = $a[0]; + + if(@a < 2) + { + logF($hash, "Set", "@a: set needs at least one parameter"); + return "$name: set needs at least one parameter"; + } + + my $cmd= $a[1]; + + logF($hash, "Set", "@a"); + + if($cmd eq "interval_multipliers") + { + if(@a < 3) { + logF($hash, "Set", "$name: not enought parameters"); + return "$name: not enought parameters"; + } + + my @na = @a[2..scalar(@a)-1]; + SYSMON_setInterval($hash, @na); + return $cmd ." set to ".($hash->{INTERVAL_MULTIPLIERS}); + } + + if($cmd eq "clean") { + # Nicht mehr benoetigte Readings loeschen + my $omap = SYSMON_getObsoleteReadingsMap($hash); + foreach my $aName (keys %{$omap}) { + delete $defs{$name}{READINGS}{$aName}; + } + return; + } + + if($cmd eq "clear") + { + my $subcmd = my $cmd= $a[2]; + if(defined $subcmd) { + delete $defs{$name}{READINGS}{$subcmd}; + return; + } + + return "missing parameter. use clear "; + } + + return "Unknown argument $cmd, choose one of interval_multipliers clean:noArg clear"; +} + +sub +SYSMON_Attr($$$) +{ + my ($cmd, $name, $attrName, $attrVal) = @_; + + Log 5, "SYSMON Attr: $cmd $name $attrName $attrVal"; + + $attrVal= "" unless defined($attrVal); + my $orig = AttrVal($name, $attrName, ""); + + if( $cmd eq "set" ) {# set, del + if( $orig ne $attrVal ) { + + my $hash = $main::defs{$name}; + if($attrName eq "disable") + { + RemoveInternalTimer($hash); + if($attrVal ne "0") + { + InternalTimer(gettimeofday()+$hash->{INTERVAL_BASE}, "SYSMON_Update", $hash, 0); + } + #$hash->{LOCAL} = 1; + SYSMON_Update($hash); + #delete $hash->{LOCAL}; + } + + $attr{$name}{$attrName} = $attrVal; + + SYSMON_updateCurrentReadingsMap($hash); + + #return $attrName ." set to ". $attrVal; + return undef; + } + } + return; +} + +my $u_first_mark = undef; + +sub +SYSMON_Update($@) +{ + my ($hash, $refresh_all) = @_; + + logF($hash, "Update", ""); + + my $name = $hash->{NAME}; + + if(!$hash->{LOCAL}) { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL_BASE}, "SYSMON_Update", $hash, 1); + } + + readingsBeginUpdate($hash); + + if( AttrVal($name, "disable", "") eq "1" ) + { + logF($hash, "Update", "disabled"); + $hash->{STATE} = "Inactive"; + } else { + # Beim ersten mal alles aktualisieren! + if(!$u_first_mark) { + $u_first_mark = 1; + $refresh_all = 1; + } + + # Parameter holen + my $map = SYSMON_obtainParameters($hash, $refresh_all); + + $hash->{STATE} = "Active"; + #my $state = $map->{LOADAVG}; + #readingsBulkUpdate($hash,"state",$state); + + foreach my $aName (keys %{$map}) { + my $value = $map->{$aName}; + # Nur aktualisieren, wenn ein gueltiges Value vorliegt + if(defined $value) { + readingsBulkUpdate($hash,$aName,$value); + } + + } + + # Nicht mehr benoetigte Readings loeschen + my $omap = SYSMON_getObsoleteReadingsMap($hash); + foreach my $aName (keys %{$omap}) { + delete $defs{$name}{READINGS}{$aName}; + } + + } + + readingsEndUpdate($hash,defined($hash->{LOCAL} ? 0 : 1)); +} + +sub +SYSMON_obtainParameters($$) +{ + my ($hash, $refresh_all) = @_; + my $name = $hash->{NAME}; + + my $map; + + my $base=0; + my $im = "1 1 1 10"; + # Wenn wesentliche Parameter nicht definiert sind, soll ktualisierung immer vorgenommen werden + if((defined $hash->{INTERVAL_BASE}) && (defined $hash->{INTERVAL_MULTIPLIERS})) { + $base = $hash->{INTERVAL_BASE}; + $im = $hash->{INTERVAL_MULTIPLIERS}; + } + + my $ref = int(time()/$base); + my ($m1, $m2, $m3, $m4) = split(/\s+/, $im); + + # immer aktualisieren: uptime, uptime_text, fhemuptime, fhemuptime_text, idletime, idletime_text + $map = SYSMON_getUptime($hash, $map); + $map = SYSMON_getFHEMUptime($hash, $map); + + if($m1 gt 0) { # Nur wenn > 0 + # M1: cpu_freq, cpu_temp, cpu_temp_avg, loadavg + if($refresh_all || ($ref % $m1) eq 0) { + #Log 3, "SYSMON -----------> DEBUG: read CPU-Temp"; + if(SYSMON_isCPUTempRPi($hash)) { # Rasp + $map = SYSMON_getCPUTemp_RPi($hash, $map); + } + if (SYSMON_isCPUTempBBB($hash)) { + $map = SYSMON_getCPUTemp_BBB($hash, $map); + } + if(SYSMON_isCPUFreqRPiBBB($hash)) { + $map = SYSMON_getCPUFreq($hash, $map); + } + $map = SYSMON_getLoadAvg($hash, $map); + } + } + + if($m2 gt 0) { # Nur wenn > 0 + # M2: ram, swap + if($refresh_all || ($ref % $m2) eq 0) { + $map = SYSMON_getRamAndSwap($hash, $map); + } + } + + if($m3 gt 0) { # Nur wenn > 0 + # M3: eth0, eth0_diff, wlan0, wlan0_diff + my $update_ns = ($refresh_all || ($ref % $m3) eq 0); + #if($refresh_all || ($ref % $m3) eq 0) { + my $networks = AttrVal($name, "network-interfaces", undef); + if($update_ns) { + if(defined $networks) { + my @networks_list = split(/,\s*/, trim($networks)); + foreach (@networks_list) { + $map = SYSMON_getNetworkInfo($hash, $map, $_); + } + } else { + # Wenn nichts definiert, werden Default-Werte verwendet + if(SYSMON_isFB($hash)) { + $map = SYSMON_getNetworkInfo($hash, $map, "ath0"); + $map = SYSMON_getNetworkInfo($hash, $map, "ath1"); + $map = SYSMON_getNetworkInfo($hash, $map, "cpmac0"); + $map = SYSMON_getNetworkInfo($hash, $map, "dsl"); + $map = SYSMON_getNetworkInfo($hash, $map, "eth0"); + $map = SYSMON_getNetworkInfo($hash, $map, "guest"); + $map = SYSMON_getNetworkInfo($hash, $map, "hotspot"); + $map = SYSMON_getNetworkInfo($hash, $map, "lan"); + $map = SYSMON_getNetworkInfo($hash, $map, "vdsl"); + } else { + $map = SYSMON_getNetworkInfo($hash, $map, ETH0); + $map = SYSMON_getNetworkInfo($hash, $map, WLAN0); + } + } + } + } + + if($m4 gt 0) { # Nur wenn > 0 + # M4: Filesystem-Informationen + my $update_fs = ($refresh_all || ($ref % $m4) eq 0); + my $filesystems = AttrVal($name, "filesystems", undef); + if($update_fs) { + if(defined $filesystems) + { + my @filesystem_list = split(/,\s*/, trim($filesystems)); + foreach (@filesystem_list) + { + $map = SYSMON_getFileSystemInfo($hash, $map, $_); + } + } else { + $map = SYSMON_getFileSystemInfo($hash, $map, "root:/"); + } + } else { + # Workaround: Damit die Readings zw. den Update-Punkten nicht geloescht werden, werden die Schluessel leer angelegt + # Wenn noch keine Update notwendig, dan einfach alte Schluessel (mit undef als Wert) angeben, + # damit werden die Readings in der Update-Methode nicht geloescht. + # Die ggf. notwendige Loeschung findet nur bei tatsaechlichen Update statt. + my @cKeys=keys (%{$defs{$name}{READINGS}}); + foreach my $aName (@cKeys) { + #if(defined ($aName) && (index($aName, FS_PREFIX) == 0 || index($aName, FS_PREFIX_N) == 0)) { + if(defined ($aName) && (index($aName, FS_PREFIX) == 0 )) { + $map->{$aName} = undef; + } + } + } + } + + #Log 3, "SYSMON >>> USER_DEFINED >>>>>>>>>>>>>>> START"; + my $userdefined = AttrVal($name, "user-defined", undef); + if(defined $userdefined) { + my @userdefined_list = split(/,\s*/, trim($userdefined)); + foreach (@userdefined_list) { + # ::: + my $ud = $_; + my($uName, $uInterval, $uComment, $uCmd) = split(/:/, $ud); + logF($hash, "User-Defined Reading", "[$uName][$uInterval][$uComment][$uCmd]"); + if(defined $uCmd) { # Also, wenn alle Parameter vorhanden + my $iInt = int($uInterval); + if($iInt>0) { + my $update_ud = ($refresh_all || ($ref % $iInt) eq 0); + if($update_ud) { + $map = SYSMON_getUserDefined($hash, $map, $uName, $uCmd); + } + } + } + } + } + + return $map; +} + +#------------------------------------------------------------------------------ +# Liest Benutzerdefinierte Eintraege +#------------------------------------------------------------------------------ +sub +SYSMON_getUserDefined($$$$) +{ + my ($hash, $map, $uName, $uCmd) = @_; + logF($hash, "SYSMON_getUserDefined", "Name=[$uName] Cmd=[$uCmd]"); + + my $out_str = SYSMON_execute($hash, $uCmd); + $map->{$uName} = $out_str; + + return $map; +} + +#------------------------------------------------------------------------------ +# leifert Zeit seit dem Systemstart +#------------------------------------------------------------------------------ +sub +SYSMON_getUptime($$) +{ + my ($hash, $map) = @_; + + #my $uptime_str = qx(cat /proc/uptime ); + my $uptime_str = SYSMON_execute($hash, "cat /proc/uptime"); + my ($uptime, $idle) = split(/\s+/, trim($uptime_str)); + my $idle_percent = $idle/$uptime*100; + + $map->{+UPTIME}=sprintf("%d",$uptime); + #$map->{+UPTIME_TEXT} = sprintf("%d days, %02d hours, %02d minutes, %02d seconds",SYSMON_decode_time_diff($uptime)); + $map->{+UPTIME_TEXT} = sprintf("%d days, %02d hours, %02d minutes",SYSMON_decode_time_diff($uptime)); + + $map->{+IDLETIME}=sprintf("%d %.2f %%",$idle, $idle_percent); + $map->{+IDLETIME_TEXT} = sprintf("%d days, %02d hours, %02d minutes",SYSMON_decode_time_diff($idle)).sprintf(" (%.2f %%)",$idle_percent); + #$map->{+IDLETIME_PERCENT} = sprintf ("%.2f %",$idle_percent); + + return $map; +} + +#------------------------------------------------------------------------------ +# leifert Zeit seit FHEM-Start +#------------------------------------------------------------------------------ +sub +SYSMON_getFHEMUptime($$) +{ + my ($hash, $map) = @_; + + if(defined ($hash->{DEF_TIME})) { + my $fhemuptime = time()-$hash->{DEF_TIME}; + $map->{+FHEMUPTIME} = sprintf("%d",$fhemuptime); + $map->{+FHEMUPTIME_TEXT} = sprintf("%d days, %02d hours, %02d minutes",SYSMON_decode_time_diff($fhemuptime)); + } + + return $map; +} + +#------------------------------------------------------------------------------ +# leifert CPU-Auslastung +#------------------------------------------------------------------------------ +sub +SYSMON_getLoadAvg($$) +{ + my ($hash, $map) = @_; + + #my $la_str = qx(cat /proc/loadavg ); + my $la_str = SYSMON_execute($hash, "cat /proc/loadavg"); + my ($la1, $la5, $la15, $prc, $lastpid) = split(/\s+/, trim($la_str)); + + $map->{+LOADAVG}="$la1 $la5 $la15"; + #$map->{"load"}="$la1"; + #$map->{"load5"}="$la5"; + #$map->{"load15"}="$la15"; + + return $map; +} + +#------------------------------------------------------------------------------ +# leifert CPU Temperature (Raspberry Pi) +#------------------------------------------------------------------------------ +sub +SYSMON_getCPUTemp_RPi($$) +{ + + my ($hash, $map) = @_; + my $val = SYSMON_execute($hash, "cat /sys/class/thermal/thermal_zone0/temp 2>&1"); + $val = int($val); + my $val_txt = sprintf("%.2f", $val/1000); + $map->{+CPU_TEMP}="$val_txt"; + my $t_avg = sprintf( "%.1f", (3 * ReadingsVal($hash->{NAME},CPU_TEMP_AVG,$val_txt) + $val_txt ) / 4 ); + $map->{+CPU_TEMP_AVG}="$t_avg"; + return $map; +} + +#------------------------------------------------------------------------------ +# leifert CPU Temperature (BeagleBone Black) +#------------------------------------------------------------------------------ +sub +SYSMON_getCPUTemp_BBB($$) +{ + my ($hash, $map) = @_; + my $val = SYSMON_execute($hash, "cat /sys/class/hwmon/hwmon0/device/temp1_input 2>&1"); + $val = int($val); + my $val_txt = sprintf("%.2f", $val/1000); + $map->{+CPU_TEMP}="$val_txt"; + my $t_avg = sprintf( "%.1f", (3 * ReadingsVal($hash->{NAME},CPU_TEMP_AVG,$val_txt) + $val_txt ) / 4 ); + $map->{+CPU_TEMP_AVG}="$t_avg"; + return $map; +} + +#------------------------------------------------------------------------------ +# leifert CPU Frequenz (Raspberry Pi, BeagleBone Black) +#------------------------------------------------------------------------------ +sub +SYSMON_getCPUFreq($$) +{ + my ($hash, $map) = @_; + my $val = SYSMON_execute($hash, "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>&1"); + $val = int($val); + my $val_txt = sprintf("%d", $val/1000); + $map->{+CPU_FREQ}="$val_txt"; + return $map; +} + +#------------------------------------------------------------------------------ +# Liefert Werte fuer RAM und SWAP (Gesamt, Verwendet, Frei). +#------------------------------------------------------------------------------ +sub SYSMON_getRamAndSwap($$) +{ + my ($hash, $map) = @_; + + #my @speicher = qx(free -m); + my @speicher = SYSMON_execute($hash, "free"); + + shift @speicher; + my ($fs_desc, $total, $used, $free, $shared, $buffers, $cached) = split(/\s+/, trim($speicher[0])); + shift @speicher; + my ($fs_desc2, $total2, $used2, $free2, $shared2, $buffers2, $cached2) = split(/\s+/, trim($speicher[0])); + + if($fs_desc2 ne "Swap:") + { + shift @speicher; + ($fs_desc2, $total2, $used2, $free2, $shared2, $buffers2, $cached2) = split(/\s+/, trim($speicher[0])); + } + + my $ram; + my $swap; + #my $percentage_ram; + #my $percentage_swap; + + $total = $total / 1024; + $used = $used / 1024; + $free = $free / 1024; + $buffers = $buffers / 1024; + $cached = $cached / 1024; + + $ram = sprintf("Total: %.2f MB, Used: %.2f MB, %.2f %%, Free: %.2f MB", $total, ($used - $buffers - $cached), (($used - $buffers - $cached) / $total * 100), ($free + $buffers + $cached)); + + $map->{+RAM} = $ram; + + # wenn kein swap definiert ist, ist die Groesse (total2) gleich Null. Dies wuerde eine Exception (division by zero) ausloesen + if($total2 > 0) + { + $total2 = $total2 / 1024; + $used2 = $used2 / 1024; + $free2 = $free2 / 1024; + + $swap = sprintf("Total: %.2f MB, Used: %.2f MB, %.2f %%, Free: %.2f MB", $total2, $used2, ($used2 / $total2 * 100), $free2); + } + else + { + $swap = "n/a" + } + + $map->{+SWAP} = $swap; + + return $map; +} + +#------------------------------------------------------------------------------ +# Liefert Fuellstand fuer das angegebene Dateisystem (z.B. '/dev/root', '/dev/sda1' (USB stick)). +# Eingabeparameter: HASH; MAP; FS-Bezeichnung +#------------------------------------------------------------------------------ +sub SYSMON_getFileSystemInfo ($$$) +{ + my ($hash, $map, $fs) = @_; + + # Neue Syntax: benannte Filesystems: : + my($fName, $fDef, $fComment) = split(/:/, $fs); + if(defined $fDef) { + $fs = $fDef; + } + + my $disk = "df ".$fs." -m 2>&1"; # in case of failure get string from stderr + + #my @filesystems = qx($disk); + my @filesystems = SYSMON_execute($hash, $disk); + + shift @filesystems; + if (index($filesystems[0], $fs) >= 0) # check if filesystem available -> gives failure on console + { + my ($fs_desc, $total, $used, $available, $percentage_used, $mnt_point) = split(/\s+/, $filesystems[0]); + $percentage_used =~ /^(.+)%$/; + $percentage_used = $1; + my $out_txt = "Total: ".$total." MB, Used: ".$used." MB, ".$percentage_used." %, Available: ".$available." MB at ".$mnt_point; + if(defined $fDef) { + $map->{$fName} = $out_txt; + } else { + $map->{+FS_PREFIX.$mnt_point} = $out_txt; + } + } else { + if(defined $fDef) { + $map->{$fName} = "not available"; + } else { + $map->{+FS_PREFIX.$fs} = "not available"; + } + } + + return $map; +} + +#------------------------------------------------------------------------------ +# Liefert Netztwerkinformationen +# Parameter: HASH; MAP; DEVICE (eth0 or wlan0) +#------------------------------------------------------------------------------ +sub SYSMON_getNetworkInfo ($$$) +{ + my ($hash, $map, $device) = @_; + + my($nName, $nDef) = split(/:/, $device); + if(!defined $nDef) { + $nDef = $nName; + } + $device = $nDef; + + # in case of network not present get failure from stderr (2>&1) + my $cmd="ifconfig ".$device." 2>&1"; + + #my @dataThroughput = qx($cmd); + my @dataThroughput = SYSMON_execute($hash, $cmd); + + # check if network available + if (index($dataThroughput[0], 'Fehler') < 0 && index($dataThroughput[0], 'error') < 0) + { + my $dataThroughput = undef; + foreach (@dataThroughput) { + if(index($_, 'RX bytes') >= 0) { + $dataThroughput = $_; + } + } + + if(defined $dataThroughput) { + # remove RX bytes or TX bytes from string + $dataThroughput =~ s/RX bytes://; + $dataThroughput =~ s/TX bytes://; + $dataThroughput = trim($dataThroughput); + + @dataThroughput = split(/ /, $dataThroughput); # return of split is array + } + + my $rxRaw = 0; + $rxRaw = $dataThroughput[0] / 1024 / 1024 if(defined $dataThroughput[0]); + my $txRaw = 0; + $txRaw = $dataThroughput[4] / 1024 / 1024 if(defined $dataThroughput[4]); + my $rx = sprintf ("%.2f", $rxRaw); + my $tx = sprintf ("%.2f", $txRaw); + my $totalRxTx = $rx + $tx; + + my $out_txt = "RX: ".$rx." MB, TX: ".$tx." MB, Total: ".$totalRxTx." MB"; + $map->{$nName} = $out_txt; + + my $lastVal = ReadingsVal($hash->{NAME},$device,"RX: 0 MB, TX: 0 MB, Total: 0 MB"); + my ($d0, $o_rx, $d1, $d2, $o_tx, $d3, $d4, $o_tt, $d5) = split(/\s+/, trim($lastVal)); + + my $d_rx = $rx-$o_rx; + if($d_rx<0) {$d_rx=0;} + my $d_tx = $tx-$o_tx; + if($d_tx<0) {$d_tx=0;} + my $d_tt = $totalRxTx-$o_tt; + if($d_tt<0) {$d_tt=0;} + my $out_txt_diff = "RX: ".sprintf ("%.2f", $d_rx)." MB, TX: ".sprintf ("%.2f", $d_tx)." MB, Total: ".sprintf ("%.2f", $d_tt)." MB"; + $map->{$nName.DIFF_SUFFIX} = $out_txt_diff; + } else { + $map->{$nName} = "not available"; + $map->{$nName.DIFF_SUFFIX} = "not available"; + } + + return $map; +} + +#------------------------------------------------------------------------------ +# Systemparameter als HTML-Tabelle ausgeben +# Parameter: Name des SYSMON-Geraetes (muss existieren), dessen Daten zur Anzeige gebracht werden sollen. +# (optional) Liste der anzuzeigenden Werte (ReadingName[:Comment:[Postfix]],...) +# Beispiel: define sysv weblink htmlCode {SYSMON_ShowValuesHTML('sysmon', ('date:Datum', 'cpu_temp:CPU Temperatur: °C', 'cpu_freq:CPU Frequenz: MHz'))} +#------------------------------------------------------------------------------ +sub SYSMON_ShowValuesHTML ($;@) +{ + my ($name, @data) = @_; + my $hash = $main::defs{$name}; + SYSMON_updateCurrentReadingsMap($hash); +log 3, "SYSMON $>name, @data<"; + my @dataDescription = @data; + if(!defined @data) { + # Array mit anzuzeigenden Parametern (Prefix, Name (in Map), Postfix) + @dataDescription = (DATE, + CPU_TEMP.":".$cur_readings_map->{+CPU_TEMP}.":"." °C", + CPU_FREQ.":".$cur_readings_map->{+CPU_FREQ}.":"." MHz", + UPTIME_TEXT, FHEMUPTIME_TEXT, LOADAVG, RAM, SWAP); + + # network-interfaces + my $networks = AttrVal($name, "network-interfaces", undef); + if(defined $networks) { + my @networks_list = split(/,\s*/, trim($networks)); + foreach (@networks_list) { + my($nName, $nDef, $nComment) = split(/:/, $_); + push(@dataDescription, $nName); + } + } + + # named filesystems + my $filesystems = AttrVal($name, "filesystems", undef); + if(defined $filesystems) { + my @filesystem_list = split(/,\s*/, trim($filesystems)); + foreach (@filesystem_list) { + my($fName, $fDef, $fComment) = split(/:/, $_); + push(@dataDescription, $fName); + } + } + + # User defined + my $userdefined = AttrVal($name, "user-defined", undef); + if(defined $userdefined) { + my @userdefined_list = split(/,\s*/, trim($userdefined)); + foreach (@userdefined_list) { + # ::: + my($uName, $uInterval, $uComment, $uCmd) = split(/:/, $_); + push(@dataDescription, $uName); + } + } + } + + my $map = SYSMON_obtainParameters($hash, 1); + + my $div_class=""; + + my $htmlcode = "
"; + + # oben definierte Werte anzeigen + foreach (@dataDescription) { + my($rName, $rComment, $rPostfix) = split(/:/, $_); + if(!defined $rComment) { + $rComment = $cur_readings_map->{$rName}; + } + my $rVal = $map->{$rName}; + if($rName eq DATE) { + # Datum anzeigen + $rVal = strftime("%d.%m.%Y %H:%M:%S", localtime()); + } + $htmlcode .= ""; + } + + # nur Default (also alles anzeigen) + if(!defined @data) { + ## network-interfaces + #my $networks = AttrVal($name, "network-interfaces", undef); + #if(defined $networks) { + # my @networks_list = split(/,\s*/, trim($networks)); + # foreach (@networks_list) { + # my($nName, $nDef, $nComment) = split(/:/, $_); + # my $nComment = $cur_readings_map->{$nName}; + # my $nVal = $map->{$nName}; + # $htmlcode .= ""; + # } + #} + + # File systems + foreach my $aName (sort keys %{$map}) { + if(defined ($aName) && index($aName, FS_PREFIX) == 0) { + $aName =~ /^~ (.+)/; + $htmlcode .= ""; + } + } + + ## named filesystems + #my $filesystems = AttrVal($name, "filesystems", undef); + #if(defined $filesystems) { + # my @filesystem_list = split(/,\s*/, trim($filesystems)); + # foreach (@filesystem_list) { + # my($fName, $fDef, $fComment) = split(/:/, $_); + # my $fComment = $cur_readings_map->{$fName}; + # my $fVal = $map->{$fName}; + # $htmlcode .= ""; + # } + #} + } + + $htmlcode .= "
".$rComment.": ".$rVal.$rPostfix."
".$nComment.": ".$nVal."
File System: ".$1." ".$map->{$aName}."
".$fComment.": ".$fVal."

"; + + return $htmlcode; +} + +my $sys_cpu_temp_rpi = undef; +sub +SYSMON_isCPUTempRPi($) { + my ($hash) = @_; + if(!defined $sys_cpu_temp_rpi) { + $sys_cpu_temp_rpi = int(SYSMON_execute($hash, "[ -f /sys/class/thermal/thermal_zone0/temp ] && echo 1 || echo 0")); + } + + return $sys_cpu_temp_rpi; +} + +my $sys_cpu_temp_bbb = undef; +sub +SYSMON_isCPUTempBBB($) { + my ($hash) = @_; + if(!defined $sys_cpu_temp_bbb) { + $sys_cpu_temp_bbb = int(SYSMON_execute($hash, "[ -f /sys/class/hwmon/hwmon0/device/temp1_input ] && echo 1 || echo 0")); + } + + return $sys_cpu_temp_bbb; +} + +my $sys_cpu_freq_rpi_bbb = undef; +sub +SYSMON_isCPUFreqRPiBBB($) { + my ($hash) = @_; + if(!defined $sys_cpu_freq_rpi_bbb) { + $sys_cpu_freq_rpi_bbb = int(SYSMON_execute($hash, "[ -f /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq ] && echo 1 || echo 0")); + } + + return $sys_cpu_freq_rpi_bbb; +} + +my $sys_fb = undef; +sub +SYSMON_isFB($) { + my ($hash) = @_; + if(!defined $sys_fb) { + $sys_fb = int(SYSMON_execute($hash, "[ -f /usr/bin/ctlmgr_ctl ] && echo 1 || echo 0")); + } + return $sys_fb; +} + +sub +SYSMON_execute($$) +{ + my ($hash, $cmd) = @_; + return qx($cmd); +} + +#------------------------------------------------------------------------------ +# Uebersetzt Sekunden (Dauer) in Tage/Stunden/Minuten/Sekunden +#------------------------------------------------------------------------------ +sub SYSMON_decode_time_diff($) +{ + my $s = shift; + + my $d = int($s/86400); + $s -= $d*86400; + my $h = int($s/3600); + $s -= $h*3600; + my $m = int($s/60); + $s -= $m*60; + + return ($d,$h,$m,$s); +} + +#------------------------------------------------------------------------------ +# Logging: Funkrionsaufrufe +# Parameter: HASH, Funktionsname, Message +#------------------------------------------------------------------------------ +sub logF($$$) +{ + my ($hash, $fname, $msg) = @_; + #Log 5, "SYSMON $fname (".$hash->{NAME}."): $msg"; + Log 5, "SYSMON $fname $msg"; +} + +sub trim($) +{ + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +1; + +=pod +=begin html + + + +

SYSMON

+
    +This module provides statistics about the system running FHEM server. Only Linux-based systems are supported. Some information are hardware specific and are not available on any platform. So far, this module has been tested on the following systems: Raspberry Pi (Debian Wheezy) BeagleBone Black, Fritz box 7390 (no CPU data). +

    + Define +

    + define SYSMON [<M1>[ <M2>[ <M3>[ <M4>]]]]
    +
    + +This statement creates a new SYSMON instance. The parameters M1 to M4 define the refresh interval for various Readings (statistics). The parameters are to be understood as multipliers for the time defined by INTERVAL_BASE. Because this time is fixed at 60 seconds, the Mx-parameter can be considered as time intervals in minutes.
    +If one (or more) of the multiplier is set to zero, the corresponding readings is deactivated. +
    +
    + The parameters are responsible for updating the readings according to the following scheme: +
      +
    • M1: (Default: 1)
      + cpu_freq, cpu_temp, cpu_temp_avg, loadavg

      +
    • +
    • M2: (Default: M1)
      + ram, swap
      +
    • +
    • M3: (Default: M1)
      + eth0, eth0_diff, wlan0, wlan0_diff

      +
    • +
    • M4: (Default: 10*M1)
      + Filesystem informations

      +
    • +
    • The following parameters are always updated with the base interval (regardless of the Mx-parameter):
      + fhemuptime, fhemuptime_text, idletime, idletime_text, uptime, uptime_text

      +
    • +
    +
    + + Readings: +

    +
      +
    • cpu_freq
      + CPU frequency +
    • +
      +
    • cpu_temp
      + CPU temperature +
    • +
      +
    • cpu_temp_avg
      + Average of the CPU temperature, formed over the last 4 values. +
    • +
      +
    • fhemuptime
      + Time (in seconds) since the start of FHEM server. +
    • +
      +
    • fhemuptime_text
      + Time since the start of the FHEM server: human-readable output (text representation). +
    • +
      +
    • idletime
      + Time spent by the system since the start in the idle mode (period of inactivity). +
    • +
      +
    • idletime_text
      + The inactivity time of the system since system start in human readable form. +
    • +
      +
    • loadavg
      + System load (load average): 1 minute, 5 minutes and 15 minutes. +
    • +
      +
    • ram
      + memory usage. +
    • +
      +
    • swap
      + swap usage. +
    • +
      +
    • uptime
      + System uptime. +
    • +
      +
    • uptime_text
      + System uptime (human readable). +
    • +
      +
    • Network statistics
      + Statistics for the specified network interface about the data volumes transferred and the difference since the previous measurement. +
      + Examples:
      + Amount of the transmitted data via interface eth0.
      + eth0: RX: 940.58 MB, TX: 736.19 MB, Total: 1676.77 MB
      + Change of the amount of the transferred data in relation to the previous call (for eth0).
      + eth0_diff: RX: 0.66 MB, TX: 0.06 MB, Total: 0.72 MB
      +
    • +
      +
    • File system information
      + Usage of the desired file systems.
      + Example:
      + fs_root: Total: 7340 MB, Used: 3573 MB, 52 %, Available: 3425 MB at / +
    • +
      +
      +
    • user defined
      + These Readings provide output of commands, which are passed to the operating system. +
    • +
      +
      +
    + + Sample output:
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      cpu_freq
      900
      2013-11-27 00:05:36
      cpu_temp
      49.77
      2013-11-27 00:05:36
      cpu_temp_avg
      49.7
      2013-11-27 00:05:36
      eth0
      RX: 2954.22 MB, TX: 3469.21 MB, Total: 6423.43 MB
      2013-11-27 00:05:36
      eth0_diff
      RX: 6.50 MB, TX: 0.23 MB, Total: 6.73 MB
      2013-11-27 00:05:36
      fhemuptime
      11231
      2013-11-27 00:05:36
      fhemuptime_text  
      0 days, 03 hours, 07 minutes
      2013-11-27 00:05:36
      idletime
      931024 88.35 %
      2013-11-27 00:05:36
      idletime_text
      10 days, 18 hours, 37 minutes (88.35 %)
      2013-11-27 00:05:36
      loadavg
      0.14 0.18 0.22
      2013-11-27 00:05:36
      ram
      Total: 485 MB, Used: 140 MB, 28.87 %, Free: 345 MB
      2013-11-27 00:05:36
      swap
      n/a
      2013-11-27 00:05:36
      uptime
      1053739
      2013-11-27 00:05:36
      uptime_text
      12 days, 04 hours, 42 minutes
      2013-11-27 00:05:36
      wlan0
      RX: 0.00 MB, TX: 0.00 MB, Total: 0 MB
      2013-11-27 00:05:36
      wlan0_diff
      RX: 0.00 MB, TX: 0.00 MB, Total: 0.00 MB
      2013-11-27 00:05:36
      fs_root
      Total: 7404 MB, Used: 3533 MB, 50 %, Available: 3545 MB at /
      2013-11-27 00:05:36
      fs_boot
      Total: 56 MB, Used: 19 MB, 33 %, Available: 38 MB at /boot
      2013-11-27 00:05:36
      fs_usb1
      Total: 30942 MB, Used: 6191 MB, 21 %, Available: 24752 MB at /media/usb1  
      2013-11-27 00:05:36
      +

    + + Get:

    +
      +
    • interval
      + Lists the specified polling intervalls. +
    • +
      +
    • list
      + Lists all readings. +
    • +
      +
    • update
      + Refresh all readings. +
    • +
      +
    • version
      + Displays the version of SYSMON module. +
    • +
      +

    + + Set:

    +
      +
    • interval_multipliers
      + Defines update intervals (as in the definition of the device). +
    • +
      +
    • clean
      + Clears user-definable Readings. After an update (manual or automatic) new readings are generated.
      +
    • +
      +
    • clear <reading name>
      + Deletes the Reading entry with the given name. After an update this entry is possibly re-created (if defined). This mechanism allows the selective deleting unnecessary custom entries.
      +
    • +
      +

    + + Attributes:

    +
      +
    • filesystems <reading name>[:<mountpoint>[:<comment>]],...
      + Specifies the file system to be monitored (a comma-separated list).
      + Reading-name is used in the display and logging, the mount point is the basis of the evaluation, comment is relevant to the HTML display (see SYSMON_ShowValuesHTML)
      + Examples:
      + /boot,/,/media/usb1
      + fs_boot:/boot,fs_root:/:Root,fs_usb1:/media/usb1:USB-Stick
      +
    • +
      +
    • network-interfaces <name>[:<interface>[:<comment>]],...
      + Comma-separated list of network interfaces that are to be monitored. Each entry consists of the Reading-name, the name of the Netwerk adapter and a comment for the HTML output (see SYSMON_ShowValuesHTML). If no colon is used, the value is used simultaneously as a Reading-name and interface name.
      + Example ethernet:eth0:Ethernet,wlan:wlan0:WiFi
      +
    • +
      +
    • user-defined <readingsName>:<Interval_Minutes>:<Comment>:<Cmd>,...
      + This comma-separated list defines user defined Readings with the following data: Reading name, refresh interval (in minutes), a Comment, and operating system command. +
      The os commands are executed according to the specified Intervals and are noted as Readings with the specified name. Comments are used for the HTML output (see SYSMON_ShowValuesHTML).. +
      All parameter parts are required! +
      It is important that the specified commands are executed quickly, because at this time the entire FHEM server is blocked!
      + If results of the long-running operations required, these should be set up as a CRON job and store results as a text file.

      + Example: Display of package updates for the operating system:
      + cron-Job:
      + apt-get upgrade --dry-run| perl -ne '/(\d*)\s[upgraded|aktualisiert]\D*(\d*)\D*install|^ \S+.*/ and print "$1 aktualisierte, $2 neue Pakete"' 2>/dev/null > /opt/fhem/data/updatestatus.txt +
      + uder-defined attribute
      sys_updates:1440:System Aktualisierungen:cat /opt/fhem/data/updatestatus.txt
      + the number of available updates is daily recorded as 'sys_updates'. +
    • +
      +
    • disable
      + Possible values: 0 and 1. '1' means that the update is stopped. +
    • +
      +

    + + Plots:

    +
      + predefined gplot files:
      +
        + + mySMRAM.gplot
        + mySMCPUTemp.gplot
        + mySMFS_Root.gplot
        + mySMFS_usb1.gplot
        + mySMLoad.gplot
        + mySMNetworkEth0.gplot
        + mySMNetworkEth0t.gplot
        +
        +
      +

    + + HTML output method (see Weblink): SYSMON_ShowValuesHTML(<SYSMON-Instance>[,<Liste>])

    +
      + The module provides a function that returns selected Readings as HTML.
      + As a parameter the name of the defined SYSMON device is expected.
      + The second parameter is optional and specifies a list of readings to be displayed in the format <ReadingName>[:<Comment>[:<Postfix>]].
      + ReadingName is the Name of desired Reading, Comment is used as the display name and postfix is displayed after eihentlichen value (such as units or as MHz can be displayed).
      + If no Comment is specified, an internally predefined description is used.
      + If no list specified, a predefined selection is used (all values are displayed).

      + define sysv1 weblink htmlCode {SYSMON_ShowValuesHTML('sysmon')}
      + define sysv2 weblink htmlCode {SYSMON_ShowValuesHTML('sysmon', ('date:Datum', 'cpu_temp:CPU Temperatur: °C', 'cpu_freq:CPU Frequenz: MHz'))} +

    + + Examples:

    +
      + + # Modul-Definition
      + define sysmon SYSMON 1 1 1 10
      + #attr sysmon event-on-update-reading cpu_temp,cpu_temp_avg,cpu_freq,eth0_diff,loadavg,ram,^~ /.*usb.*,~ /$
      + attr sysmon event-on-update-reading cpu_temp,cpu_temp_avg,cpu_freq,eth0_diff,loadavg,ram,fs_.*
      + attr sysmon filesystems fs_boot:/boot,fs_root:/:Root,fs_usb1:/media/usb1:USB-Stick
      + attr sysmon network-interfaces eth0:eth0:Ethernet,wlan0:wlan0:WiFi
      + attr sysmon group RPi
      + attr sysmon room 9.03_Tech
      +
      + # Log
      + define FileLog_sysmon FileLog ./log/sysmon-%Y-%m.log sysmon
      + attr FileLog_sysmon group RPi
      + attr FileLog_sysmon logtype mySMCPUTemp:Plot,text
      + attr FileLog_sysmon room 9.03_Tech
      +
      + # Visualisierung: CPU-Temperatur
      + define wl_sysmon_temp SVG FileLog_sysmon:mySMCPUTemp:CURRENT
      + attr wl_sysmon_temp group RPi
      + attr wl_sysmon_temp label "CPU Temperatur: Min $data{min2}, Max $data{max2}, Last $data{currval2}"
      + attr wl_sysmon_temp room 9.03_Tech
      +
      + # Visualisierung: Netzwerk-Datenübertragung fü eth0
      + define wl_sysmon_eth0 SVG FileLog_sysmon:mySMNetworkEth0:CURRENT
      + attr wl_sysmon_eth0 group RPi
      + attr wl_sysmon_eth0 label "Netzwerk-Traffic eth0: $data{min1}, Max: $data{max1}, Aktuell: $data{currval1}"
      + attr wl_sysmon_eth0 room 9.03_Tech
      +
      + # Visualisierung: CPU-Auslastung (load average)
      + define wl_sysmon_load SVG FileLog_sysmon:mySMLoad:CURRENT
      + attr wl_sysmon_load group RPi
      + attr wl_sysmon_load label "Load Min: $data{min1}, Max: $data{max1}, Aktuell: $data{currval1}"
      + attr wl_sysmon_load room 9.03_Tech
      +
      + # Visualisierung: RAM-Nutzung
      + define wl_sysmon_ram SVG FileLog_sysmon:mySMRAM:CURRENT
      + attr wl_sysmon_ram group RPi
      + attr wl_sysmon_ram label "RAM-Nutzung Total: $data{max1}, Min: $data{min2}, Max: $data{max2}, Aktuell: $data{currval2}"
      + attr wl_sysmon_ram room 9.03_Tech
      +
      + # Visualisierung: Dateisystem: Root-Partition
      + define wl_sysmon_fs_root SVG FileLog_sysmon:mySMFS_Root:CURRENT
      + attr wl_sysmon_fs_root group RPi
      + attr wl_sysmon_fs_root label "Root Partition Total: $data{max1}, Min: $data{min2}, Max: $data{max2}, Aktuell: $data{currval2}"
      + attr wl_sysmon_fs_root room 9.03_Tech
      +
      + # Visualisierung: Dateisystem: USB-Stick
      + define wl_sysmon_fs_usb1 SVG FileLog_sysmon:mySMFS_usb1:CURRENT
      + attr wl_sysmon_fs_usb1 group RPi
      + attr wl_sysmon_fs_usb1 label "USB1 Total: $data{max1}, Min: $data{min2}, Max: $data{max2}, Aktuell: $data{currval2}"
      + attr wl_sysmon_fs_usb1 room 9.03_Tech
      +
      + # Anzeige der Readings zum Einbinden in ein 'Raum'.
      + define SysValues weblink htmlCode {SYSMON_ShowValuesHTML('sysmon')}
      + attr SysValues group RPi
      + attr SysValues room 9.03_Tech
      +
      +
    + +
+ + +=end html +=begin html_DE + + +

SYSMON

+
    + Dieses Modul liefert diverse Informationen und Statistiken zu dem System, auf dem FHEM-Server ausgeführt wird. + Es werden nur Linux-basierte Systeme unterstützt. Manche Informationen sind hardwarespezifisch und sind daher nicht auf jeder Plattform + verfügbar. + Bis jetzt wurde dieses Modul auf folgenden Systemen getestet: Raspberry Pi (Debian Wheezy), BeagleBone Black, FritzBox 7390 (keine CPU-Daten). +

    + Define +

    + define SYSMON [<M1>[ <M2>[ <M3>[ <M4>]]]]
    +
    + Diese Anweisung erstellt eine neue SYSMON-Instanz. + Die Parameter M1 bis M4 legen die Aktualisierungsintervale für verschiedenen Readings (Statistiken) fest. + Die Parameter sind als Multiplikatoren für die Zeit, die durch INTERVAL_BASE definiert ist, zu verstehen. + Da diese Zeit fest auf 60 Sekunden gesetzt ist, können die Mx-Parameters als Zeitintervalle in Minuten angesehen werden.
    + Wird einer (oder mehrere) Multiplikator auf Null gesetzt werden, wird das entsprechende Readings deaktiviert.
    +
    + Die Parameter sind für die Aktualisierung der Readings nach folgender Schema zuständig: +
      +
    • M1: (Default-Wert: 1)
      + cpu_freq, cpu_temp, cpu_temp_avg, loadavg

      +
    • +
    • M2: (Default-Wert: M1)
      + ram, swap
      +
    • +
    • M3: (Default-Wert: M1)
      + eth0, eth0_diff, wlan0, wlan0_diff

      +
    • +
    • M4: (Default-Wert: 10*M1)
      + Filesystem-Informationen

      +
    • +
    • folgende Parameter werden immer anhand des Basisintervalls (unabhängig von den Mx-Parameters) aktualisiert:
      + fhemuptime, fhemuptime_text, idletime, idletime_text, uptime, uptime_text

      +
    • +
    +
    + + Readings: +

    +
      +
    • cpu_freq
      + CPU-Frequenz +
    • +
      +
    • cpu_temp
      + CPU-Temperatur +
    • +
      +
    • cpu_temp_avg
      + Durchschnitt der CPU-Temperatur, gebildet über die letzten 4 Werte. +
    • +
      +
    • fhemuptime
      + Zeit (in Sekunden) seit dem Start des FHEM-Servers. +
    • +
      +
    • fhemuptime_text
      + Zeit seit dem Start des FHEM-Servers: Menschenlesbare Ausgabe (texttuelle Darstellung). +
    • +
      +
    • idletime
      + Zeit (in Sekunden und in Prozent), die das System (nicht der FHEM-Server!) + seit dem Start in dem Idle-Modus verbracht hat. Also die Zeit der Inaktivität. +
    • +
      +
    • idletime_text
      + Zeit der Inaktivität des Systems seit dem Systemstart in menschenlesbarer Form. +
    • +
      +
    • loadavg
      + Ausgabe der Werte für die Systemauslastung (load average): 1 Minute-, 5 Minuten- und 15 Minuten-Werte. +
    • +
      +
    • ram
      + Ausgabe der Speicherauslastung. +
    • +
      +
    • swap
      + Benutzung und Auslastung der SWAP-Datei (bzw. Partition). +
    • +
      +
    • uptime
      + Zeit (in Sekenden) seit dem Systemstart. +
    • +
      +
    • uptime_text
      + Zeit seit dem Systemstart in menschenlesbarer Form. +
    • +
      +
    • Netzwerkinformationen
      + Informationen zu den über die angegebene Netzwerkschnittstellen übertragene Datenmengen + und der Differenz zu der vorherigen Messung. +
      + Beispiele:
      + Menge der übertragenen Daten über die Schnittstelle eth0.
      + eth0: RX: 940.58 MB, TX: 736.19 MB, Total: 1676.77 MB
      + Änderung der übertragenen Datenmenge in Bezug auf den vorherigen Aufruf (für eth0).
      + eth0_diff: RX: 0.66 MB, TX: 0.06 MB, Total: 0.72 MB
      +
    • +
      +
    • Dateisysteminformationen
      + Informationen zu der Größe und der Belegung der gewünschten Dateisystemen.
      + Seit Version 1.1.0 können Dateisysteme auch benannt werden (s.u.).
      + In diesem Fall werden für die diese Readings die angegebenen Namen verwendet.
      + Dies soll die Übersicht verbessern und die Erstellung von Plots erleichten.
      + Beispiel:
      + fs_root: Total: 7340 MB, Used: 3573 MB, 52 %, Available: 3425 MB at / +
    • +
      +
      +
    • Benutzerdefinierte Einträge
      + Diese Readings sind Ausgaben der Kommanden, die an das Betriebssystem übergeben werden. + Die entsprechende Angaben werden im Attribut user-defined vorgenommen. +
    • +
      +
      +
    + + Beispiel-Ausgabe:
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      cpu_freq
      900
      2013-11-27 00:05:36
      cpu_temp
      49.77
      2013-11-27 00:05:36
      cpu_temp_avg
      49.7
      2013-11-27 00:05:36
      eth0
      RX: 2954.22 MB, TX: 3469.21 MB, Total: 6423.43 MB
      2013-11-27 00:05:36
      eth0_diff
      RX: 6.50 MB, TX: 0.23 MB, Total: 6.73 MB
      2013-11-27 00:05:36
      fhemuptime
      11231
      2013-11-27 00:05:36
      fhemuptime_text  
      0 days, 03 hours, 07 minutes
      2013-11-27 00:05:36
      idletime
      931024 88.35 %
      2013-11-27 00:05:36
      idletime_text
      10 days, 18 hours, 37 minutes (88.35 %)
      2013-11-27 00:05:36
      loadavg
      0.14 0.18 0.22
      2013-11-27 00:05:36
      ram
      Total: 485 MB, Used: 140 MB, 28.87 %, Free: 345 MB
      2013-11-27 00:05:36
      swap
      n/a
      2013-11-27 00:05:36
      uptime
      1053739
      2013-11-27 00:05:36
      uptime_text
      12 days, 04 hours, 42 minutes
      2013-11-27 00:05:36
      wlan0
      RX: 0.00 MB, TX: 0.00 MB, Total: 0 MB
      2013-11-27 00:05:36
      wlan0_diff
      RX: 0.00 MB, TX: 0.00 MB, Total: 0.00 MB
      2013-11-27 00:05:36
      fs_root
      Total: 7404 MB, Used: 3533 MB, 50 %, Available: 3545 MB at /
      2013-11-27 00:05:36
      fs_boot
      Total: 56 MB, Used: 19 MB, 33 %, Available: 38 MB at /boot
      2013-11-27 00:05:36
      fs_usb1
      Total: 30942 MB, Used: 6191 MB, 21 %, Available: 24752 MB at /media/usb1  
      2013-11-27 00:05:36
      +

    + + Get:

    +
      +
    • interval
      + Listet die bei der Definition angegebene Polling-Intervalle auf. +
    • +
      +
    • list
      + Gibt alle Readings aus. +
    • +
      +
    • update
      + Aktualisiert alle Readings. Alle Werte werden neu abgefragt. +
    • +
      +
    • version
      + Zeigt die Version des SYSMON-Moduls. +
    • +
      +

    + + Set:

    +
      +
    • interval_multipliers
      + Definiert Multipliers (wie bei der Definition des Gerätes). +
    • +
      +
    • clean
      + Löscht benutzerdefinierbare Readings. Nach einem Update (oder nach der automatischen Aktualisierung) werden neue Readings generiert.
      +
    • +
      +
    • clear <reading name>
      + Löscht den Reading-Eintrag mit dem gegebenen Namen. Nach einem Update (oder nach der automatischen Aktualisierung) + wird dieser Eintrag ggf. neu erstellt (falls noch definiert). Dieses Mechanismus erlaubt das gezielte Löschen nicht mehr benötigter + benutzerdefinierten Einträge.
      +
    • +
      +

    + + Attributes:

    +
      +
    • filesystems <reading name>[:<mountpoint>[:<comment>]],...
      + Gibt die zu überwachende Dateisysteme an. Es wird eine kommaseparierte Liste erwartet.
      + Reading-Name wird bei der Anzeige und Logging verwendet, Mount-Point ist die Grundlage der Auswertung, + Kommentar ist relevant für die HTML-Anzeige (s. SYSMON_ShowValuesHTML)
      + Beispiel: /boot,/,/media/usb1
      + oder: fs_boot:/boot,fs_root:/:Root,fs_usb1:/media/usb1:USB-Stick
      + Im Sinne der besseren Übersicht sollten zumindest Name und MountPoint angegeben werden. +
    • +
      +
    • network-interfaces <name>[:<interface>[:<comment>]],...
      + Kommaseparierte Liste der Netzwerk-Interfaces, die überwacht werden sollen. + Jeder Eintrag besteht aus dem Reading-Namen, dem Namen + des Netwerk-Adapters und einem Kommentar für die HTML-Anzeige (s. SYSMON_ShowValuesHTML). Wird kein Doppelpunkt verwendet, + wird der Wert gleichzeitig als Reading-Name und Interface-Name verwendet.
      + Beispiel ethernet:eth0:Ethernet,wlan:wlan0:WiFi
      +
    • +
      +
    • user-defined <readingsName>:<Interval_Minutes>:<Comment>:<Cmd>,...
      + Diese kommaseparierte Liste definiert Einträge mit jeweils folgenden Daten: + Reading-Name, Aktualisierungsinterval in Minuten, Kommentar und Betriebssystem-Commando. +
      Die BS-Befehle werden entsprechend des angegebenen Intervalls ausgeführt und als Readings mit den angegebenen Namen vermerkt. + Kommentare werden für die HTML-Ausgaben (s. SYSMON_ShowValuesHTML) benötigt. +
      Alle Parameter sind nicht optional! +
      Es ist wichtig, dass die angegebenen Befehle schnell ausgeführt werden, denn in dieser Zeit wird der gesamte FHEM-Server blockiert! +
      Werden Ergebnisse der lang laufenden Operationen benötigt, sollten diese z.B als CRON-Job eingerichtet werden + und in FHEM nur die davor gespeicherten Ausgaben visualisiert.

      + Beispiel: Anzeige der vorliegenden Paket-Aktualisierungen für das Betriebssystem:
      + In einem cron-Job wird folgendes täglich ausgeführt:
      + apt-get upgrade --dry-run| perl -ne '/(\d*)\s[upgraded|aktualisiert]\D*(\d*)\D*install|^ \S+.*/ and print "$1 aktualisierte, $2 neue Pakete"' 2>/dev/null > /opt/fhem/data/updatestatus.txt +
      + Das Attribute uder-defined wird auf
      sys_updates:1440:System Aktualisierungen:cat /opt/fhem/data/updatestatus.txt
      gesetzt. + Danach wird die Anzahl der verfügbaren Aktualisierungen täglich als Reading 'sys_updates' protokolliert. +
    • +
      +
    • disable
      + Mögliche Werte: 0,1. Bei 1 wird die Aktualisierung gestoppt. +
    • +
      +

    + + Plots:

    +
      + Für dieses Modul sind bereits einige gplot-Dateien vordefiniert:
      +
        + + mySMRAM.gplot
        + mySMCPUTemp.gplot
        + mySMFS_Root.gplot
        + mySMFS_usb1.gplot
        + mySMLoad.gplot
        + mySMNetworkEth0.gplot
        + mySMNetworkEth0t.gplot
        +
        +
      +

    + + HTML-Ausgabe-Methode (für ein Weblink): SYSMON_ShowValuesHTML(<SYSMON-Instanz>[,<Liste>])

    +
      + Das Modul definiert eine Funktion, die ausgewählte Readings in HTML-Format ausgibt.
      + Als Parameter wird der Name des definierten SYSMON-Geräts erwartet.
      + Der zweite Parameter ist optional und gibt eine Liste der anzuzeigende Readings + im Format <ReadingName>[:<Comment>[:<Postfix>]] an.
      + Dabei gibt ReadingName den anzuzeigenden Reading an, der Wert aus Comment wird als der Anzeigename verwendet + und Postfix wird nach dem eihentlichen Wert angezeigt (so können z.B. Einheiten wie MHz angezeigt werden).
      + Falls kein Comment angegeben ist, wird eine intern vordefinierte Beschreibung angegeben. + Bei benutzerdefinierbaren Readings wird ggf. Comment aus der Definition verwendet.
      + Wird keine Liste angegeben, wird eine vordefinierte Auswahl verwendet (alle Werte).

      + define sysv1 weblink htmlCode {SYSMON_ShowValuesHTML('sysmon')}
      + define sysv2 weblink htmlCode {SYSMON_ShowValuesHTML('sysmon', ('date:Datum', 'cpu_temp:CPU Temperatur: °C', 'cpu_freq:CPU Frequenz: MHz'))} +

    + + Beispiele:

    +
      + + # Modul-Definition
      + define sysmon SYSMON 1 1 1 10
      + #attr sysmon event-on-update-reading cpu_temp,cpu_temp_avg,cpu_freq,eth0_diff,loadavg,ram,^~ /.*usb.*,~ /$
      + attr sysmon event-on-update-reading cpu_temp,cpu_temp_avg,cpu_freq,eth0_diff,loadavg,ram,fs_.*
      + attr sysmon filesystems fs_boot:/boot,fs_root:/:Root,fs_usb1:/media/usb1:USB-Stick
      + attr sysmon network-interfaces eth0:eth0:Ethernet,wlan0:wlan0:WiFi
      + attr sysmon group RPi
      + attr sysmon room 9.03_Tech
      +
      + # Log
      + define FileLog_sysmon FileLog ./log/sysmon-%Y-%m.log sysmon
      + attr FileLog_sysmon group RPi
      + attr FileLog_sysmon logtype mySMCPUTemp:Plot,text
      + attr FileLog_sysmon room 9.03_Tech
      +
      + # Visualisierung: CPU-Temperatur
      + define wl_sysmon_temp SVG FileLog_sysmon:mySMCPUTemp:CURRENT
      + attr wl_sysmon_temp group RPi
      + attr wl_sysmon_temp label "CPU Temperatur: Min $data{min2}, Max $data{max2}, Last $data{currval2}"
      + attr wl_sysmon_temp room 9.03_Tech
      +
      + # Visualisierung: Netzwerk-Datenübertragung fü eth0
      + define wl_sysmon_eth0 SVG FileLog_sysmon:mySMNetworkEth0:CURRENT
      + attr wl_sysmon_eth0 group RPi
      + attr wl_sysmon_eth0 label "Netzwerk-Traffic eth0: $data{min1}, Max: $data{max1}, Aktuell: $data{currval1}"
      + attr wl_sysmon_eth0 room 9.03_Tech
      +
      + # Visualisierung: CPU-Auslastung (load average)
      + define wl_sysmon_load SVG FileLog_sysmon:mySMLoad:CURRENT
      + attr wl_sysmon_load group RPi
      + attr wl_sysmon_load label "Load Min: $data{min1}, Max: $data{max1}, Aktuell: $data{currval1}"
      + attr wl_sysmon_load room 9.03_Tech
      +
      + # Visualisierung: RAM-Nutzung
      + define wl_sysmon_ram SVG FileLog_sysmon:mySMRAM:CURRENT
      + attr wl_sysmon_ram group RPi
      + attr wl_sysmon_ram label "RAM-Nutzung Total: $data{max1}, Min: $data{min2}, Max: $data{max2}, Aktuell: $data{currval2}"
      + attr wl_sysmon_ram room 9.03_Tech
      +
      + # Visualisierung: Dateisystem: Root-Partition
      + define wl_sysmon_fs_root SVG FileLog_sysmon:mySMFS_Root:CURRENT
      + attr wl_sysmon_fs_root group RPi
      + attr wl_sysmon_fs_root label "Root Partition Total: $data{max1}, Min: $data{min2}, Max: $data{max2}, Aktuell: $data{currval2}"
      + attr wl_sysmon_fs_root room 9.03_Tech
      +
      + # Visualisierung: Dateisystem: USB-Stick
      + define wl_sysmon_fs_usb1 SVG FileLog_sysmon:mySMFS_usb1:CURRENT
      + attr wl_sysmon_fs_usb1 group RPi
      + attr wl_sysmon_fs_usb1 label "USB1 Total: $data{max1}, Min: $data{min2}, Max: $data{max2}, Aktuell: $data{currval2}"
      + attr wl_sysmon_fs_usb1 room 9.03_Tech
      +
      + # Anzeige der Readings zum Einbinden in ein 'Raum'.
      + define SysValues weblink htmlCode {SYSMON_ShowValuesHTML('sysmon')}
      + attr SysValues group RPi
      + attr SysValues room 9.03_Tech
      +
      +
    + +
+ +=end html_DE +=cut diff --git a/fhem/HISTORY b/fhem/HISTORY index 871e19ec7..227f8d5eb 100644 --- a/fhem/HISTORY +++ b/fhem/HISTORY @@ -536,4 +536,7 @@ - Fri Jul 26 2013 (A. Vogt alias baumrasen) - Added new module "WWO" + +- Mon Jan 13 2014 (A. Schulz alias hexenmeister) + - Added new module "SYSMON" \ No newline at end of file diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index 6c57525fe..9c515aefe 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -100,6 +100,7 @@ FHEM/38_CO20.pm justme1968 http://forum.fhem.de Sonstiges FHEM/40_RFXCOM.pm wherzig http://forum.fhem.de RFXTRX FHEM/41_OREGON.pm wherzig http://forum.fhem.de Sonstiges FHEM/42_RFXMETER.pm wherzig http://forum.fhem.de RFXTRX +FHEM/42_SYSMON.pm hexenmeister http://forum.fhem.de Unterstuetzende Dienste FHEM/43_RFXX10REC.pm wherzig http://forum.fhem.de RFXTRX FHEM/45_TRX.pm wherzig http://forum.fhem.de RFXTRX FHEM/46_TRX_ELSE.pm wherzig http://forum.fhem.de RFXTRX