# $Id$ package main; use strict; use warnings; use Data::Dumper; my $SYSSTAT_hasSysStatistics = 1; my $SYSSTAT_hasSNMP = 1; my %SYSSTAT_diskTypes = ( ".1.3.6.1.2.1.25.2.1.1" => 'Other', ".1.3.6.1.2.1.25.2.1.2" => 'Ram', ".1.3.6.1.2.1.25.2.1.3" => 'VirtualMemory', ".1.3.6.1.2.1.25.2.1.4" => 'FixedDisk', ".1.3.6.1.2.1.25.2.1.5" => 'RemovableDisk', ".1.3.6.1.2.1.25.2.1.6" => 'FloppyDisk', ".1.3.6.1.2.1.25.2.1.7" => 'CompactDisk', ".1.3.6.1.2.1.25.2.1.8" => 'RamDisk', ".1.3.6.1.2.1.25.2.1.9" => 'FlashMemory', ".1.3.6.1.2.1.25.2.1.10" => 'NetworkDisk', ); sub SYSSTAT_Initialize($) { my ($hash) = @_; eval "use Sys::Statistics::Linux::LoadAVG"; $SYSSTAT_hasSysStatistics = 0 if($@); eval "use Sys::Statistics::Linux::DiskUsage"; $SYSSTAT_hasSysStatistics = 0 if($@); eval "use Net::SNMP"; $SYSSTAT_hasSNMP = 0 if($@); $hash->{DefFn} = "SYSSTAT_Define"; $hash->{UndefFn} = "SYSSTAT_Undefine"; $hash->{GetFn} = "SYSSTAT_Get"; $hash->{AttrFn} = "SYSSTAT_Attr"; $hash->{AttrList} = "disable:1 disabledForIntervals raspberrycpufreq:1 raspberrytemperature:0,1,2 synologytemperature:0,1,2 stat:1 uptime:1,2 ssh_user "; $hash->{AttrList} .= " snmp:1 mibs:textField-long snmpVersion:1,2 snmpCommunity" if( $SYSSTAT_hasSNMP ); $hash->{AttrList} .= " filesystems showpercent"; $hash->{AttrList} .= " useregex:1" if( $SYSSTAT_hasSysStatistics ); $hash->{AttrList} .= " $readingFnAttributes"; } ##################################### sub SYSSTAT_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); return "Usage: define SYSSTAT [interval [interval_fs [host]]]" if(@a < 2); my $interval = 60; if(int(@a)>=3) { $interval = $a[2]; } if( $interval < 60 ) { $interval = 60; } my $interval_fs = $interval * 60; if(int(@a)>=4) { $interval_fs = $a[3]; } if( $interval_fs < $interval ) { $interval_fs = $interval; } if( $interval_fs == $interval ) { $interval_fs = undef; } my $host = $a[4] if(int(@a)>=5);; delete( $hash->{INTERVAL_FS} ); delete( $hash->{HOST} ); $hash->{"HAS_Sys::Statistics"} = $SYSSTAT_hasSysStatistics; $hash->{"HAS_Net::SNMP"} = $SYSSTAT_hasSNMP; $hash->{STATE} = "Initialized"; $hash->{INTERVAL} = $interval; $hash->{INTERVAL_FS} = $interval_fs if( defined( $interval_fs ) ); $hash->{HOST} = $host if( defined( $host ) ); $hash->{interval_fs} = $interval_fs; SYSSTAT_InitSys( $hash ) if( $SYSSTAT_hasSysStatistics ); SYSSTAT_InitSNMP( $hash ) if( $SYSSTAT_hasSNMP ); RemoveInternalTimer($hash); InternalTimer(gettimeofday()+$hash->{INTERVAL}, "SYSSTAT_GetUpdate", $hash, 0); return undef; } sub SYSSTAT_InitSys($) { my ($hash) = @_; return if( !$SYSSTAT_hasSysStatistics ); if( defined($hash->{HOST}) ) { my $cmd = qx(which ssh); chomp( $cmd ); my $user = AttrVal($hash->{NAME}, "ssh_user", undef ); $cmd .= ' '; $cmd .= $user."\@" if( defined($user) ); $cmd .= $hash->{HOST}." df -kP 2>/dev/null"; $hash->{loadavg} = Sys::Statistics::Linux::LoadAVG->new; $hash->{diskusage} = Sys::Statistics::Linux::DiskUsage->new( cmd => { path => '', df => $cmd } ); } else { $hash->{loadavg} = Sys::Statistics::Linux::LoadAVG->new; $hash->{diskusage} = Sys::Statistics::Linux::DiskUsage->new; } } sub SYSSTAT_InitSNMP($) { my ($hash) = @_; my $name = $hash->{NAME}; delete( $hash->{session} ); return if( !$SYSSTAT_hasSNMP ); my $host = "localhost"; my $community = "public"; $host = $hash->{HOST} if( defined($hash->{HOST} ) ); my ( $session, $error ) = Net::SNMP->session( -hostname => $host, -community => AttrVal($name,"snmpCommunity","public"), -port => 161, -version => AttrVal($name,"snmpVersion",1), ); if( $error ) { Log3 $name, 2, "$name: $error"; } elsif ( !defined($session) ) { Log3 $name, 2, "$name: can't connect to host $host"; } else { $session->timeout(3); $hash->{session} = $session; } } sub SYSSTAT_Undefine($$) { my ($hash, $arg) = @_; RemoveInternalTimer($hash); return undef; } sub SYSSTAT_Get($@) { my ($hash, @a) = @_; my $name = $a[0]; return "$name: get needs at least one parameter" if(@a < 2); my $cmd= $a[1]; if($cmd eq "filesystems") { my $ret; if( $hash->{USE_SNMP} && defined($hash->{session}) ) { my $types = SYSSTAT_readOIDs($hash,".1.3.6.1.2.1.25.2.3.1.2"); my $response = SYSSTAT_readOIDs($hash,".1.3.6.1.2.1.25.2.3.1.3"); foreach my $oid ( sort { ($a =~/\.(\d+)$/)[0] <=> ($b =~/\.(\d+)$/)[0]} keys %$response ) { $ret .= "\n" if( $ret ); my $id = ($oid =~/\.(\d+)$/)[0]; $ret .= $id ." <= ". $response->{$oid} ." (". $SYSSTAT_diskTypes{$types->{".1.3.6.1.2.1.25.2.3.1.2.$id"}} .")"; } $ret = " => \n$ret" if( $ret ); } elsif(defined($hash->{diskusage})) { my $filesystems = $hash->{diskusage}->get; $ret = " <= "; foreach my $filesystem (keys %$filesystems ) { $ret .= "\n" if( $ret ); $ret .= $filesystem ." <= ". $filesystems->{$filesystem}->{mountpoint}; } } return $ret; } elsif( $cmd eq "update" ) { $hash->{LOCAL} = 1; SYSSTAT_GetUpdate( $hash ); delete $hash->{LOCAL}; return; } return "Unknown argument $cmd, choose one of update:noArg filesystems:noArg"; } sub SYSSTAT_Attr($$$) { my ($cmd, $name, $attrName, $attrVal) = @_; $attrVal= "" unless defined($attrVal); my $orig = $attrVal; $attrVal = "1" if($attrName eq "snmp"); $attrVal = "1" if($attrName eq "useregex"); $attrVal = "1" if($attrName eq "showpercent"); $attrVal = "1" if($attrName eq "raspberrycpufreq"); my $hash = $defs{$name}; if( $attrName eq "filesystems") { my @filesystems = split(",",$attrVal); @{$hash->{filesystems}} = @filesystems; } elsif( $attrName eq "ssh_user") { $attr{$name}{$attrName} = $attrVal; SYSSTAT_InitSys( $hash ) if( $SYSSTAT_hasSysStatistics ); } elsif( $attrName eq "snmpVersion" && $SYSSTAT_hasSNMP ) { $hash->{$attrName} = $attrVal; SYSSTAT_InitSNMP( $hash ); } elsif( $attrName eq "snmpCommunity" && $SYSSTAT_hasSNMP ) { $hash->{$attrName} = $attrVal; SYSSTAT_InitSNMP( $hash ); } elsif ($attrName eq "snmp" && $SYSSTAT_hasSNMP ) { if( $cmd eq "set" && $attrVal ne "0" ) { $hash->{USE_SNMP} = $attrVal; SYSSTAT_InitSNMP( $hash ); } else { delete $hash->{USE_SNMP}; } } if( $cmd eq "set" ) { if( $orig ne $attrVal ) { $attr{$name}{$attrName} = $attrVal; return $attrName ." set to ". $attrVal; } } return; } sub SYSSTAT_getLoadAVG($); sub SYSSTAT_getPiTemp($); sub SYSSTAT_getUptime($); sub SYSSTAT_GetUpdate($) { my ($hash) = @_; my $name = $hash->{NAME}; if(!$hash->{LOCAL}) { RemoveInternalTimer($hash); InternalTimer(gettimeofday()+$hash->{INTERVAL}, "SYSSTAT_GetUpdate", $hash, 0); return if( IsDisabled($name) > 0 ); } my $load = SYSSTAT_getLoadAVG( $hash ); readingsBeginUpdate($hash); my $state = undef; $state = $load->{state} if( defined($load->{state}) ); $state = $load->{avg_1} . " " . $load->{avg_5} . " " . $load->{avg_15} if( !$state && defined($load->{avg_1}) ); readingsBulkUpdate($hash,"state",$state); readingsBulkUpdate($hash,"load",$load->{avg_1}); my $do_diskusage = 1; if( defined($hash->{INTERVAL_FS} ) ) { $do_diskusage = 0; $hash->{interval_fs} -= $hash->{INTERVAL}; if( $hash->{interval_fs} <= 0 ) { $do_diskusage = 1; $hash->{interval_fs} += $hash->{INTERVAL_FS}; } } if( $do_diskusage && $#{$hash->{filesystems}} >= 0 ) { if( $hash->{USE_SNMP} && defined($hash->{session}) ) { my $showpercent = AttrVal($name, "showpercent", "") ne ""; my @snmpoids = (); for my $id (@{$hash->{filesystems}}) { push @snmpoids, sprintf( ".1.3.6.1.2.1.25.2.3.1.3.%i", $id ); push @snmpoids, sprintf( ".1.3.6.1.2.1.25.2.3.1.4.%i", $id ) if( !$showpercent ); push @snmpoids, sprintf( ".1.3.6.1.2.1.25.2.3.1.5.%i", $id ); push @snmpoids, sprintf( ".1.3.6.1.2.1.25.2.3.1.6.%i", $id ); } my $response = SYSSTAT_readOIDs($hash,\@snmpoids); if( $response ) { for my $id (@{$hash->{filesystems}}) { my $unit = $response->{sprintf( ".1.3.6.1.2.1.25.2.3.1.4.%i", $id )}; my $free = $response->{sprintf( ".1.3.6.1.2.1.25.2.3.1.5.%i", $id )} - $response->{sprintf( ".1.3.6.1.2.1.25.2.3.1.6.%i", $id )}; if( $showpercent ) { $free = 100 * $response->{sprintf( ".1.3.6.1.2.1.25.2.3.1.6.%i", $id )} / $response->{sprintf( ".1.3.6.1.2.1.25.2.3.1.5.%i", $id )}; $free = sprintf( "%.1f", $free ); } else { $free *= $unit; } my $name = $response->{sprintf( ".1.3.6.1.2.1.25.2.3.1.3.%i", $id )}; if( $name =~ m/^([[:alpha:]]:\\)/ ) { $name = $1; $name =~ s.\\./.g; } else { $name =~ s/ //g; } readingsBulkUpdate($hash,$name,$free); } } } elsif( defined($hash->{diskusage} ) ) { my $usage = $hash->{diskusage}->get; my $type = 'free'; if( AttrVal($name, "showpercent", "") ne "" ) { $type = 'usageper'; } if( AttrVal($name, "useregex", "") eq "" ) { for my $filesystem (@{$hash->{filesystems}}) { my $fs = $usage->{$filesystem}; readingsBulkUpdate($hash,$fs->{mountpoint},$fs->{$type}); } } else { for my $filesystem (@{$hash->{filesystems}}) { foreach my $key (keys %$usage) { if( $key =~ /$filesystem/ ) { my $fs = $usage->{$key}; readingsBulkUpdate($hash,$fs->{mountpoint},$fs->{$type}); } } } } } } if( AttrVal($name, "raspberrytemperature", 0) > 0 ) { my $temp = SYSSTAT_getPiTemp($hash); if( $temp > 0 && $temp < 200 ) { if( AttrVal($name, "raspberrytemperature", 0) eq 2 ) { $temp = sprintf( "%.1f", (3 * ReadingsVal($name,"temperature",$temp) + $temp ) / 4 ); } readingsBulkUpdate($hash,"temperature",$temp); } } elsif( AttrVal($name, "synologytemperature", 0) > 0 ) { my $temp = SYSSTAT_getSynoTemp($hash); if( $temp && $temp > 0 && $temp < 200 ) { if( AttrVal($name, "synologytemperature", 0) eq 2 ) { $temp = sprintf( "%.1f", (3 * ReadingsVal($name,"temperature",$temp) + $temp ) / 4 ); } readingsBulkUpdate($hash,"temperature",$temp); } } if( $hash->{USE_SNMP} && defined($hash->{session}) ) { if( my $mibs = AttrVal($name, "mibs", undef) ) { my @snmpoids; foreach my $entry (split(/[ ,\n]/, $mibs)) { next if( !$entry ); my($mib,undef) = split(':', $entry ); next if( !$mib ); push @snmpoids, $mib; } my $response = SYSSTAT_readOIDs($hash,\@snmpoids); foreach my $entry (split(/[ ,\n]/, $mibs)) { next if( !$entry ); my($mib,$reading) = split(':', $entry ); next if( !$mib ); next if( !$reading ); my $result = $response->{$mib}; readingsBulkUpdate($hash,$reading,$result); } } } if( AttrVal($name, "raspberrycpufreq", 0) > 0 ) { my $freq = SYSSTAT_getPiFreq($hash); readingsBulkUpdate($hash,"cpufreq",$freq); } if( AttrVal($name, "stat", 0) > 0 ) { my @percent = SYSSTAT_getStat($hash); if( @percent ) { #my($user,$nice,$system,$idle,$iowait,$irq,$softirq,$steal,$guest,$guest_nice) = @percent; readingsBulkUpdate($hash,"user", $percent[0]); readingsBulkUpdate($hash,"system", $percent[2]); readingsBulkUpdate($hash,"idle", $percent[3]); readingsBulkUpdate($hash,"iowait", $percent[4]); } } if( AttrVal($name, "uptime", 0) > 0 ) { my $uptime = SYSSTAT_getUptime($hash); readingsBulkUpdate($hash,"uptime",$uptime); } readingsEndUpdate($hash,defined($hash->{LOCAL} ? 0 : 1)); } sub SYSSTAT_getLoadAVG($ ) { my ($hash) = @_; my $name = $hash->{NAME}; if( $hash->{USE_SNMP} && defined($hash->{session}) ) { my @snmpoids = ( ".1.3.6.1.4.1.2021.10.1.3.1", ".1.3.6.1.4.1.2021.10.1.3.2", ".1.3.6.1.4.1.2021.10.1.3.3" ); my $response = SYSSTAT_readOIDs($hash,\@snmpoids); if( !$response ) { my $response = SYSSTAT_readOIDs($hash,".1.3.6.1.2.1.25.3.3.1.2"); my $avg = ""; my %lavg = (); my $load = 0; foreach my $key (keys %$response) { $avg .= "," if( $avg ne "" ); $avg .= $response->{$key}; $load += $response->{$key} / 100; } $lavg{avg_1} = $load if( $avg ne "" ); $lavg{state} = $avg if( $avg ne "" ); return \%lavg; } my %lavg = (); $lavg{avg_1} = $response->{".1.3.6.1.4.1.2021.10.1.3.1"}; $lavg{avg_5} = $response->{".1.3.6.1.4.1.2021.10.1.3.2"}; $lavg{avg_15} = $response->{".1.3.6.1.4.1.2021.10.1.3.3"}; return \%lavg; } return undef if( !defined($hash->{loadavg}) ); if( defined($hash->{HOST}) ) { no strict; no warnings 'redefine'; local *Sys::Statistics::Linux::LoadAVG::get = sub { my $self = shift; my $class = ref $self; my $file = $self->{files}; my %lavg = (); my $cmd = qx(which ssh); chomp( $cmd ); my $user = AttrVal($hash->{NAME}, "ssh_user", undef ); $cmd .= ' '; $cmd .= $user."\@" if( defined($user) ); $cmd .= $hash->{HOST}." cat /proc/loadavg 2>/dev/null"; my $fh; if( open($fh, "$cmd|" ) ) { ( $lavg{avg_1} , $lavg{avg_5} , $lavg{avg_15} ) = (split /\s+/, <$fh>)[0..2]; close($fh); } return \%lavg; }; return $hash->{loadavg}->get; } return $hash->{loadavg}->get; } sub SYSSTAT_readOIDs($$) { my ($hash,$snmpoids) = @_; my $name = $hash->{NAME}; return undef if( !defined($hash->{session}) ); my $response; if( ref($snmpoids) eq "ARRAY" ) { $response = $hash->{session}->get_request( @{$snmpoids} ); Log3 $name, 4, "$name: got empty result from snmp query ".$hash->{session}->error() if( !$response ); } else { $response = $hash->{session}->get_next_request($snmpoids); my @snmpoids = (); my @nextid = keys %$response; while ( @nextid && $nextid[0] && $nextid[0] =~ m/^$snmpoids/ ) { push( @snmpoids, $nextid[0] ); $response = $hash->{session}->get_next_request( $nextid[0] ); @nextid = keys %$response; } $response = $hash->{session}->get_request( @snmpoids ); #Log3 $name, 4, "$name: got empty result from snmp query ".$hash->{session}->error() if( !$response ); } return $response; } sub SYSSTAT_readCmd($$$) { my ($hash,$command,$default) = @_; my $value = $default; if( defined($hash->{HOST}) ) { my $cmd = qx(which ssh); chomp( $cmd ); my $user = AttrVal($hash->{NAME}, "ssh_user", undef ); $cmd .= ' '; $cmd .= $user."\@" if( defined($user) ); $cmd .= $hash->{HOST}." $command 2>/dev/null"; if( open(my $fh, "$cmd|" ) ) { $value = <$fh>; close($fh); } } else { if( open( my $fh, "$command|" ) ) { $value = <$fh>; close($fh); } } return $value; } sub SYSSTAT_readFile($$$) { my ($hash,$filename,$default) = @_; my $value = $default; if( defined($hash->{HOST}) ) { my $cmd = qx(which ssh); chomp( $cmd ); my $user = AttrVal($hash->{NAME}, "ssh_user", undef ); $cmd .= ' '; $cmd .= $user."\@" if( defined($user) ); $cmd .= $hash->{HOST}." cat ". $filename ." 2>/dev/null"; if( open(my $fh, "$cmd|" ) ) { $value = <$fh>; close($fh); } } else { if( open( my $fh, '<', $filename ) ) { $value = <$fh>; close($fh); } } return $value; } sub SYSSTAT_getPiTemp($) { my ($hash) = @_; my $temp = SYSSTAT_readFile($hash,"/sys/class/thermal/thermal_zone0/temp",-1); return $temp / 1000; } sub SYSSTAT_getSynoTemp($) { my ($hash) = @_; my $temp = -1; if( $hash->{USE_SNMP} && defined($hash->{session}) ) { my @snmpoids = ( ".1.3.6.1.4.1.6574.1.2.0" ); my $response = SYSSTAT_readOIDs($hash,\@snmpoids); $temp = $response->{".1.3.6.1.4.1.6574.1.2.0"}; } return $temp; } sub SYSSTAT_getPiFreq($) { my ($hash) = @_; my $freq = SYSSTAT_readFile($hash,"/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",0); return $freq / 1000; } sub SYSSTAT_getUptime($) { my ($hash) = @_; my $name = $hash->{NAME}; if( $hash->{USE_SNMP} && defined($hash->{session}) ) { my @snmpoids = ( ".1.3.6.1.2.1.25.1.1.0" ); my $response = SYSSTAT_readOIDs($hash,\@snmpoids); my $uptime = $response->{".1.3.6.1.2.1.25.1.1.0"}; if( AttrVal($name, "uptime", 0) == 2 ) { if( $uptime && $uptime =~ m/(\d+)\s\D+,\s(\d+):(\d+):(\d+)/ ) { my $days = $1?$1:0; my $hours = $2; my $minutes = $3; my $seconds = $4; $uptime = $days * 24; $uptime += $hours; $uptime *= 60; $uptime += $minutes; $uptime *= 60; $uptime += $seconds; } } return $uptime; } my $uptime = SYSSTAT_readFile($hash,"/proc/uptime",""); if($uptime) { $uptime = $1 if ( $uptime && $uptime =~ /^\s*([0-9.]+)\s+([0-9.]+)/ ); if( AttrVal($name, "uptime", 0) != 2 ) { # cut off partial seconds $uptime = int( $uptime ); my $seconds = $uptime % 60; $uptime = int($uptime / 60); my $minutes = $uptime % 60; $uptime = int($uptime / 60); my $hours = $uptime % 24; my $days = int($uptime / 24); $uptime = sprintf( "%d days, %d:%.2d", $days, $hours, $minutes); Log3 $name, 4, "$name: uptime returned :$uptime: via proc-uptime file "; # JVI } # fallback if by any reason parsing /proc/uptime does not work } else { my $uptime = SYSSTAT_readCmd($hash,"uptime",0); ############# match uptime time statement with the different formats seen on linux # examples # 18:52:21 up 26 days, 21:08, 2 users, load average: 0.04, 0.03, 0.05 # 18:52:21 up 26 days, 55 min, 1 user, load average: 0.05, 0.05, 0.05 # 18:52:21 up 55 min, 1 user, load average: 0.05, 0.05, 0.05 # 18:52:21 up 21:08, 1 user, load average: 0.05, 0.05, 0.05 # # complex expression to match only the time parts of the uptime result # $1 is complete up time information of uptime result # $2 is # days part of the uptime # $3 just the # from the "# days"" part or nothing if no days are given # $4 is complete hour/minutes or # min information # $5 is hours part if hours:min are given # $6 is minutes part if hours:min are given # $7 is minutes if # min is given $uptime = $1 if ( $uptime && $uptime =~ m/[[:alpha:]]{2}\s*(((\d*)\s*[[:alnum:]]*,?)?\s+((\d+):(\d+)|(\d+)\s+[[:alpha:]]+in[[:alpha:]]*)),?/ ); $uptime = "0 days, $uptime" if( $uptime && !$2); if( AttrVal($name, "uptime", 0) == 2 ) { my $days = $3?$3:0; my $hours = $5?$5:0; my $minutes = $6?$6:$7; $uptime = $days * 24; $uptime += $hours; $uptime *= 60; $uptime += $minutes; $uptime *= 60; } Log3 $name, 4, "$name: uptime returned :$uptime: via cmdline "; # JVI } return $uptime; } sub SYSSTAT_getStat($) { my ($hash) = @_; my $name = $hash->{NAME}; if( $hash->{USE_SNMP} && defined($hash->{session}) ) { my @snmpoids = ( ".1.3.6.1.4.1.2021.11.9.0", ".1.3.6.1.4.1.2021.11.10.0", ".1.3.6.1.4.1.2021.11.11.0" ); my $response = SYSSTAT_readOIDs($hash,\@snmpoids); my @percent = ( $response->{".1.3.6.1.4.1.2021.11.9.0"}, # user undef, $response->{".1.3.6.1.4.1.2021.11.10.0"}, # system $response->{".1.3.6.1.4.1.2021.11.11.0"} ); # idle return @percent; } my $line = SYSSTAT_readFile($hash,"/proc/stat",""); #my($user,$nice,$system,$idle,$iowait,$irq,$softirq,$steal,$guest,$guest_nice) = split( " ", $Line ); my($dummy,@values) = split( " ", $line ); if( !defined($hash->{values}) ) { $hash->{values} = \@values; return undef; } else { my @diff = map { $values[$_] - $hash->{values}->[$_] } 0 .. $#values; $hash->{values} = \@values; my $sum = 0; $sum += $_ for @diff; my @percent = map { int($diff[$_]*1000 / $sum)/10 } 0 .. $#values; return @percent; } } 1; =pod =item device =begin html

SYSSTAT

    Provides system statistics for the host FHEM runs on or a remote Linux system that is reachable by preconfigured passwordless ssh access.

    Notes:
    • This module needs Sys::Statistics::Linux on Linux.
      It can be installed with 'cpan install Sys::Statistics::Linux'
      or on debian with 'apt-get install libsys-statistics-linux-perl'
    • To monitor a target by snmp Net::SNMP hast to be installed.
    • To plot the load values the following code can be used:
        define sysstatlog FileLog /usr/local/FHEM/var/log/sysstat-%Y-%m.log sysstat
        attr sysstatlog nrarchive 1
        define svg_sysstat SVG sysstatlog:sysstat:CURRENT
        attr wl_sysstat label "Load Min: $data{min1}, Max: $data{max1}, Aktuell: $data{currval1}"
        attr wl_sysstat room System
        
    • to match the root filesystem (mount point '/') in diskusage plots use '#FileLog 4:/\x3a:0:' or '#FileLog 4:\s..\s:0:' and not '#FileLog 4:/:0:' as the later will match all mount points
    • .
    Define
      define <name> SYSSTAT [<interval> [<interval_fs>] [<host>]]

      Defines a SYSSTAT device.

      The load is updated every <interval> seconds. The default and minimum is 60.

      The diskusage is updated every <interval_fs> seconds. The default is <interval>*60 and the minimum is 60. <interval_fs> is only aproximated and works best if <interval_fs> is an integral multiple of <interval>.

      If <host> is given it has to be accessible by ssh without the need for a password. Examples:
        define sysstat SYSSTAT
        define sysstat SYSSTAT 300
        define sysstat SYSSTAT 60 600

    Readings
    • load
      the 1 minute load average (for windows targets monitored by snmp aproximated value
    • state
      the 1, 5 and 15 minute load averages (or windows targets monitored by snmp the per cpu utilization)
    • user,system,idle,iowait
      respective percentage of systemutilization (linux targets only)
    • <mountpoint>
      free bytes for <mountpoint>

    Get
      get <name> <value>

      where value is one of

    • filesystems
      Lists the filesystems that can be monitored.

    Attributes
    • disable
      keep timers running but disable collection of statistics.
    • filesystems
      List of comma separated filesystems (not mountpoints) that should be monitored.
      Examples:
        attr sysstat filesystems /dev/md0,/dev/md2
        attr sysstat filesystems /dev/.*
        attr sysstat filesystems 1,3,5
    • disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM...
    • mibs
      space separated list of <mib>:<reding> pairs that sould be polled.
    • showpercent
      If set the usage is shown in percent. If not set the remaining free space in bytes is shown.
    • snmp
      1 -> use snmp to monitor load, uptime and filesystems (including physical and virtual memory)
    • stat
      1 -> monitor user,system,idle and iowait percentage of system utilization (available only for linux targets)
    • raspberrytemperature
      If set and > 0 the raspberry pi on chip termal sensor is read.
      If set to 2 a geometric average over the last 4 values is created.
    • synologytemperature
      If set and > 0 the main temperaure of a synology diskstation is read. requires snmp.
      If set to 2 a geometric average over the last 4 values is created.
    • raspberrycpufreq
      If set and > 0 the raspberry pi on chip termal sensor is read.
    • uptime
      If set and > 0 the system uptime is read.
      If set to 2 the uptime is displayed in seconds.
    • useregex
      If set the entries of the filesystems list are treated as regex.
    • ssh_user
      The username for ssh remote access.
    • snmpVersion
    • snmpCommunity
    • readingFnAttributes
=end html =begin html_DE

SYSSTAT

    Das Modul stellt Systemstatistiken für den Rechner, auf dem FHEM läuft bzw. für ein entferntes Linux System, das per vorkonfiguriertem ssh Zugang ohne Passwort erreichbar ist, zur Vefügung.

    Notes:
    • Dieses Modul benötigt Sys::Statistics::Linux für Linux.
      Es kann mit 'cpan install Sys::Statistics::Linux'
      bzw. auf Debian mit 'apt-get install libsys-statistics-linux-perl' installiert werden.
    • Um einen Zielrechner mit snmp zu überwachen, muss Net::SNMP installiert sein.
    • Um die Lastwerte zu plotten, kann der folgende Code verwendet werden:
        define sysstatlog FileLog /usr/local/FHEM/var/log/sysstat-%Y-%m.log sysstat
        attr sysstatlog nrarchive 1
        define svg_sysstat SVG sysstatlog:sysstat:CURRENT
        attr wl_sysstat label "Load Min: $data{min1}, Max: $data{max1}, Aktuell: $data{currval1}"
        attr wl_sysstat room System
        
    • Um das Wurzel-Dateisystem (Mountpunkt '/') bei Plots der Plattennutzung zu erhalten, sollte dieser Code '#FileLog 4:/\x3a:0:' bzw. '#FileLog 4:\s..\s:0:' und nicht dieser Code '#FileLog 4:/:0:' verwendet werden, da der letztere alle Mountpunkte darstellt.
    • .
    Define
      define <name> SYSSTAT [<interval> [<interval_fs>] [<host>]]

      definiert ein SYSSTAT Device.

      Die (Prozessor)last wird alle <interval> Sekunden aktualisiert. Standard bzw. Minimum ist 60.

      Die Plattennutzung wird alle <interval_fs> Sekunden aktualisiert. Standardwert ist <interval>*60 und Minimum ist 60. <interval_fs> wird nur angenähert und funktioniert am Besten, wenn <interval_fs> ein ganzzahliges Vielfaches von <interval> ist.

      Wenn <host> angegeben wird, muss der Zugang per ssh ohne Passwort möglich sein.

      Beispiele:
        define sysstat SYSSTAT
        define sysstat SYSSTAT 300
        define sysstat SYSSTAT 60 600

    Readings
    • load
      die durchschnittliche (Prozessor)last der letzten 1 Minute (für Windows Rechner mit snmp angenähertem Wert)
    • state
      die durchschnittliche (Prozessor)last der letzten 1, 5 und 15 Minuten (für Windows Rechner die Nutzung pro CPU via snmp ermittelt)
    • user, system, idle, iowait
      den Prozentsatz der entsprechenden Systemlast (nur für Linux Systeme)
    • <mountpoint>
      Anzahl der freien Bytes für <mountpoint>

    Get
      get <name> <value>

      Werte für value sind

    • filesystems
      zeigt die Dateisysteme an, die überwacht werden können.

    Attributes
    • disable
      lässt die Timer weiterlaufen, aber stoppt die Speicherung der Daten.
    • filesystems
      Liste mit Komma getrennten Dateisystemen (nicht Mountpunkten) die überwacht werden sollen.
      Beispiele:
        attr sysstat filesystems /dev/md0,/dev/md2
        attr sysstat filesystems /dev/.*
        attr sysstat filesystems 1,3,5
    • mibs
      Leerzeichen getrennte Liste aus <mib>:<reding> Paaren die abgefragt werden sollen.
    • showpercent
      Wenn gesetzt, wird die Nutzung in Prozent angegeben. Wenn nicht gesetzt, wird der verfübare Platz in Bytes angezeigt.
    • snmp
      1 -> snmp wird verwendet, um Last, Einschaltzeit und Dateisysteme (inkl. physikalischem und virtuellem Speicher) zu überwachen
    • stat
      1 -> überwacht Prozentsatz der user, system, idle und iowait Last (nur auf Linux Systemen verfügbar)
    • raspberrytemperature
      Wenn gesetzt und > 0 wird der Temperatursensor auf dem Raspberry Pi ausgelesen.
      Wenn Wert 2 ist, wird ein geometrischer Durchschnitt der letzten 4 Werte dargestellt.
    • synologytemperature
      Wenn gesetzt und > 0 wird die Temperatur einer Synology Diskstation ausgelesen (erfordert snmp).
      Wenn Wert 2 ist, wird ein geometrischer Durchschnitt der letzten 4 Werte dargestellt.
    • raspberrycpufreq
      Wenn gesetzt und > 0 wird die Raspberry Pi CPU Frequenz ausgelesen.
    • uptime
      Wenn gesetzt und > 0 wird die Betriebszeit (uptime) des Systems ausgelesen.
      Wenn Wert 2 ist, wird die Betriebszeit (uptime) in Sekunden angezeigt.
    • useregex
      Wenn Wert gesetzt, werden die Einträge der Dateisysteme als regex behandelt.
    • ssh_user
      Der Username für den ssh Zugang auf dem entfernten Rechner.
    • snmpVersion
    • snmpCommunity
    • readingFnAttributes
=end html_DE =cut