mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-04 23:46:35 +00:00
1745 lines
49 KiB
Perl
1745 lines
49 KiB
Perl
|
|
# $Id$
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Data::Dumper;
|
|
|
|
use JSON;
|
|
use Blocking;
|
|
|
|
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 Net::SNMP";
|
|
$SYSSTAT_hasSNMP = 0 if($@);
|
|
|
|
$hash->{ReadFn} = "SYSSTAT_Read";
|
|
|
|
$hash->{DefFn} = "SYSSTAT_Define";
|
|
$hash->{UndefFn} = "SYSSTAT_Undefine";
|
|
$hash->{ShutdownFn} = "SYSSTAT_Shutdown";
|
|
$hash->{NotifyFn} = "SYSSTAT_Notify";
|
|
$hash->{SetFn} = "SYSSTAT_Set";
|
|
$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 load:0 noSSH:1,0 ssh_user";
|
|
$hash->{AttrList} .= " snmp:1,0 mibs:textField-long snmpVersion:1,2 snmpCommunity" if( $SYSSTAT_hasSNMP );
|
|
$hash->{AttrList} .= " filesystems showpercent readings:textField-long readingsFormat:textField-long";
|
|
$hash->{AttrList} .= " useregex:1";
|
|
$hash->{AttrList} .= " $readingFnAttributes";
|
|
}
|
|
|
|
#####################################
|
|
|
|
sub
|
|
SYSSTAT_Define($$)
|
|
{
|
|
my ($hash, $def) = @_;
|
|
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
|
|
return "Usage: define <name> 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_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_InitSNMP( $hash ) if( $init_done );
|
|
SYSSTAT_Connect($hash) if( $init_done );
|
|
|
|
if( !$hash->{HOST} ) {
|
|
$hash->{helper}{has_proc_stat} = ( -r '/proc/stat' );
|
|
$hash->{helper}{has_proc_uptime} = ( -r '/proc/uptime' );
|
|
$hash->{helper}{has_proc_loadavg} = ( -r '/proc/loadavg' );
|
|
|
|
my $name = $hash->{NAME};
|
|
Log3 $name, 4, "$name: has_proc_stat: $hash->{helper}{has_proc_stat}";
|
|
Log3 $name, 4, "$name: has_proc_uptime: $hash->{helper}{has_proc_uptime}";
|
|
Log3 $name, 4, "$name: has_proc_loadavg: $hash->{helper}{has_proc_loadavg}";
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
sub
|
|
SYSSTAT_Disconnect($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
readingsSingleUpdate($hash, 'connection', 'disconnected', 1) if( $hash->{STATE} eq 'Started' ) ;
|
|
|
|
return if( !$hash->{FD} );
|
|
|
|
if( $hash->{PID} ) {
|
|
kill( 9, $hash->{PID} );
|
|
return;
|
|
}
|
|
|
|
close($hash->{FH}) if($hash->{FH});
|
|
delete($hash->{FH});
|
|
delete($hash->{FD});
|
|
delete($selectlist{$name});
|
|
|
|
$hash->{PARTIAL} ='';
|
|
|
|
$hash->{STATE} = "Disconnected";
|
|
Log3 $name, 3, "$name: Disconnected";
|
|
$hash->{LAST_DISCONNECT} = FmtDateTime( gettimeofday() );
|
|
}
|
|
sub
|
|
SYSSTAT_Connect($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
SYSSTAT_Disconnect($hash);
|
|
|
|
if( !$hash->{HOST} ) {
|
|
RemoveInternalTimer($hash);
|
|
InternalTimer(gettimeofday()+5, "SYSSTAT_GetUpdate", $hash, 0);
|
|
|
|
return;
|
|
|
|
} elsif( AttrVal($name, "noSSH", undef ) ) {
|
|
RemoveInternalTimer($hash);
|
|
InternalTimer(gettimeofday()+5, "SYSSTAT_GetUpdate", $hash, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
return undef if( AttrVal($name, "disable", undef ) );
|
|
|
|
my @queue = ();
|
|
$hash->{QUEUE} = \@queue;
|
|
|
|
$hash->{SENT} = 0;
|
|
$hash->{PARSED} = 0;
|
|
$hash->{PARTIAL} ='';
|
|
$hash->{STARTED} = 0;
|
|
|
|
my ($child, $parent);
|
|
if( socketpair($child, $parent, AF_UNIX, SOCK_STREAM, PF_UNSPEC) ) {
|
|
$child->autoflush(1);
|
|
$parent->autoflush(1);
|
|
|
|
my $pid = fhemFork();
|
|
|
|
if(!defined($pid)) {
|
|
close $parent;
|
|
close $child;
|
|
|
|
my $msg = "$name: Cannot fork: $!";
|
|
Log 1, $msg;
|
|
return $msg;
|
|
}
|
|
|
|
if( $pid ) {
|
|
close $parent;
|
|
$child->blocking(0);
|
|
|
|
$hash->{STATE} = "Started";
|
|
$hash->{CONNECTS}++;
|
|
|
|
$hash->{FH} = $child;
|
|
$hash->{FD} = fileno($child);
|
|
$hash->{PID} = $pid;
|
|
|
|
$selectlist{$name} = $hash;
|
|
|
|
SYSSTAT_Write( $hash, 'uname -a' );
|
|
|
|
RemoveInternalTimer($hash);
|
|
InternalTimer(gettimeofday()+5, "SYSSTAT_GetUpdate", $hash, 0);
|
|
|
|
} else {
|
|
close $child;
|
|
|
|
close STDIN;
|
|
close STDOUT;
|
|
close STDERR;
|
|
|
|
my $fn = $parent->fileno();
|
|
open(STDIN, "<&$fn") or die "can't redirect STDIN $!";
|
|
open(STDOUT, ">&$fn") or die "can't redirect STDOUT $!";
|
|
open(STDERR, ">&$fn") or die "can't redirect STDOUT $!";
|
|
|
|
#select STDIN; $| = 1;
|
|
#select STDOUT; $| = 1;
|
|
|
|
#STDIN->autoflush(1);
|
|
STDOUT->autoflush(1);
|
|
|
|
close $parent;
|
|
|
|
$ENV{PYTHONUNBUFFERED} = 1;
|
|
|
|
if( my $home = AttrVal($name, "home", undef ) ) {
|
|
$home = $ENV{'PWD'} if( $home eq 'PWD' );
|
|
$ENV{'HOME'} = $home;
|
|
Log3 $name, 2, "$name: setting \$HOME to $home";
|
|
}
|
|
|
|
my $cmd = qx(which ssh);
|
|
chomp( $cmd );
|
|
my $user = AttrVal($hash->{NAME}, "ssh_user", undef );
|
|
$cmd .= ' -q ';
|
|
$cmd .= $user."\@" if( defined($user) );
|
|
$cmd .= $hash->{HOST};
|
|
Log3 $name, 2, "$name: starting: $cmd";
|
|
|
|
exec split( ' ', $cmd ) or Log3 $name, 1, "exec failed";
|
|
|
|
POSIX::_exit(0);;
|
|
}
|
|
|
|
} else {
|
|
$hash->{STATE} = "Stopped";
|
|
Log3 $name, 3, "$name: socketpair failed";
|
|
InternalTimer(gettimeofday()+20, "SYSSTAT_Connect", $hash, 0);
|
|
}
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Write($$;$)
|
|
{
|
|
my ($hash,$cmd,$key) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
return undef if( !$hash->{FH} );
|
|
|
|
#FIXME: reconnect if QUEUE > xxx?
|
|
|
|
push @{$hash->{QUEUE}}, {cmd => $cmd, key => $key, };
|
|
return if( scalar @{$hash->{QUEUE}} > 1 );
|
|
|
|
Log3 $name, 4, "$name: sending: $cmd";
|
|
syswrite $hash->{FH}, "echo \">>>cmd start $hash->{SENT}<<<\"\n";
|
|
syswrite $hash->{FH}, "$cmd\n";
|
|
syswrite $hash->{FH}, "echo \">>>cmd end $hash->{SENT}<<<\"\n";
|
|
++$hash->{SENT};
|
|
|
|
return undef;
|
|
}
|
|
sub SYSSTAT_Parse($$$);
|
|
sub
|
|
SYSSTAT_Read($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
my $buf;
|
|
my $ret = sysread($hash->{FH}, $buf, 65536 );
|
|
my $err = int($!);
|
|
|
|
if( my $phash = $hash->{phash} ) {
|
|
|
|
if( $ret <= 0 ) {
|
|
$hash->{cleanup} = 1;
|
|
SYSSTAT_killChild( $hash );
|
|
return;
|
|
}
|
|
|
|
readingsBeginUpdate($phash);
|
|
my $key = $hash->{key};
|
|
my $cmd = $hash->{cmd};
|
|
$buf =~ s/\n$// if( $buf );
|
|
SYSSTAT_Parse($phash,$key?$key:$cmd,$buf);
|
|
readingsEndUpdate($phash, 1);
|
|
|
|
return;
|
|
}
|
|
|
|
if(!defined($ret) && $err == EWOULDBLOCK) {
|
|
return;
|
|
}
|
|
|
|
if(!defined($ret) || $ret <= 0) {
|
|
SYSSTAT_Disconnect( $hash );
|
|
delete $hash->{PID};
|
|
|
|
Log3 $name, 3, "$name: read: error during sysread: $!" if(!defined($ret));
|
|
Log3 $name, 3, "$name: read: end of file reached while sysread" if(defined($ret) && $ret <= 0);
|
|
|
|
InternalTimer(gettimeofday()+10, "SYSSTAT_Connect", $hash, 0);
|
|
return undef;
|
|
}
|
|
|
|
if( $buf =~ m/^(.*)?>>>cmd start (\d+)<<<\n(.*)\n>>>cmd end (\d+)<<<\n(.*)?/ ) {
|
|
$buf = $3;
|
|
$hash->{PARTIAL} = $5;
|
|
|
|
$hash->{STARTED} = 0;
|
|
|
|
} elsif( $buf =~ m/^>>>cmd start (\d+)<<<(.*)?/ ) {
|
|
$hash->{PARTIAL} = $2;
|
|
|
|
$hash->{STARTED} = 1;
|
|
return;
|
|
|
|
} elsif( $buf =~ m/(.*)>>>cmd end (\d+)<<<\n?$/ms ) {
|
|
$buf = $hash->{PARTIAL} . $1;
|
|
|
|
$hash->{STARTED} = 0;
|
|
|
|
} elsif( !$hash->{STARTED} ) {
|
|
return;
|
|
|
|
} else {
|
|
$hash->{PARTIAL} .= $buf;
|
|
return;
|
|
}
|
|
|
|
my $entry = shift @{$hash->{QUEUE}};
|
|
|
|
if( scalar @{$hash->{QUEUE}} ) {
|
|
my $cmd = $hash->{QUEUE}[0]->{cmd};
|
|
Log3 $name, 4, "$name: sending: $cmd";
|
|
syswrite $hash->{FH}, "echo \">>>cmd start $hash->{SENT}<<<\"\n";
|
|
syswrite $hash->{FH}, "$cmd\n";
|
|
syswrite $hash->{FH}, "echo \">>>cmd end $hash->{SENT}<<<\"\n";
|
|
++$hash->{SENT};
|
|
}
|
|
|
|
readingsBeginUpdate($hash);
|
|
my $key = $entry->{key};
|
|
my $cmd = $entry->{cmd};
|
|
$buf =~ s/\n$// if( $buf );
|
|
SYSSTAT_Parse($hash,$key?$key:$cmd,$buf);
|
|
readingsEndUpdate($hash, 1);
|
|
|
|
++$hash->{PARSED};
|
|
|
|
return undef;
|
|
}
|
|
sub
|
|
SYSSTAT_killChild($)
|
|
{
|
|
my ($chash) = @_;
|
|
my $name = $chash->{NAME};
|
|
|
|
kill( 9, $chash->{PID} );
|
|
|
|
if( !$chash->{cleanup} ) {
|
|
my $pname = $chash->{phash}->{NAME};
|
|
Log3 $pname, 2, "$pname: timeout reached, killing pid $chash->{PID} for cmd $chash->{cmd}";
|
|
}
|
|
|
|
RemoveInternalTimer($chash);
|
|
|
|
delete($defs{$name});
|
|
delete($selectlist{$name});
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Parse($$$)
|
|
{
|
|
my ($hash,$key,$data) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
return undef if( !$key ); #FIXME: reconnect ?
|
|
|
|
Log3 $name, 5, "$name: parsing: $key <- $data";
|
|
|
|
if( $key eq 'uname -a' && $data ) {
|
|
readingsSingleUpdate($hash, 'connection', 'connected', 1);
|
|
$hash->{STATE} = "Connected";
|
|
|
|
$hash->{uname} = $data;
|
|
|
|
SYSSTAT_Write( $hash, 'ls /proc/stat' );
|
|
SYSSTAT_Write( $hash, 'ls /proc/uptime' );
|
|
SYSSTAT_Write( $hash, 'ls /proc/loadavg' );
|
|
|
|
} elsif( $key eq 'ls /proc/stat' && $data ) {
|
|
$hash->{helper}{has_proc_stat} = $data =~ m'^/proc/stat' ? 1 : 0;
|
|
|
|
Log3 $name, 4, "$name: has_proc_stat: $hash->{helper}{has_proc_stat}";
|
|
|
|
} elsif( $key eq 'ls /proc/uptime' && $data ) {
|
|
$hash->{helper}{has_proc_uptime} = $data =~ m'^/proc/uptime' ? 1 : 0;
|
|
|
|
Log3 $name, 4, "$name: has_proc_uptime: $hash->{helper}{has_proc_uptime}";
|
|
|
|
} elsif( $key eq 'ls /proc/loadavg' && $data ) {
|
|
$hash->{helper}{has_proc_loadavg} = $data =~ m'^/proc/loadavg' ? 1 : 0;
|
|
|
|
Log3 $name, 4, "$name: has_proc_loadavg: $hash->{helper}{has_proc_loadavg}";
|
|
|
|
} elsif( $key =~ m/#reading:(.*)/ && $data ) {
|
|
my $reading = $1;
|
|
my $VALUE = $data;
|
|
|
|
if( my $value_format = $hash->{helper}{readingsFormat} ) {
|
|
if( ref($value_format) eq 'HASH' ) {
|
|
my $vf = "";
|
|
$vf = $value_format->{$reading} if( defined($reading) && exists($value_format->{$reading}) );
|
|
$vf = $value_format->{$reading.'.'.$VALUE} if( defined($reading) && exists($value_format->{$reading.'.'.$VALUE}) );
|
|
|
|
if( !ref($vf) && $vf =~ m/^{.*}$/s) {
|
|
eval $vf;
|
|
$VALUE = $data if( $@ );
|
|
Log3 $name, 2, "$name: $@" if( $@ );
|
|
|
|
}
|
|
|
|
} else {
|
|
Log3 $name, 2, "$name: readingsFormat is not a hash";
|
|
|
|
}
|
|
}
|
|
|
|
if( ref($VALUE) eq 'ARRAY' ) {
|
|
my $i = 1;
|
|
foreach my $value (@{$VALUE}) {
|
|
readingsBulkUpdate($hash, $reading.$i, $value);
|
|
++$i
|
|
}
|
|
} else {
|
|
readingsBulkUpdate($hash, $reading, $VALUE);
|
|
}
|
|
|
|
} elsif( $key eq 'cat /proc/loadavg' && $data ) {
|
|
my ($avg_1, $avg_5, $avg_15) = split( ' ', $data, 4 );
|
|
|
|
readingsBulkUpdate($hash, 'state', "$avg_1 $avg_5 $avg_15");
|
|
readingsBulkUpdate($hash, 'load', $avg_1);
|
|
|
|
} elsif( $key eq 'cat /proc/stat' && $data ) {
|
|
my(undef,@values) = split( ' ', $data, 12 );
|
|
pop @values;
|
|
if( !defined($hash->{helper}{proc_stat_old}) ) {
|
|
$hash->{helper}{proc_stat_old} = \@values;
|
|
return undef;
|
|
|
|
} else {
|
|
my @diff = map { $values[$_] - $hash->{helper}{proc_stat_old}->[$_] } 0 .. 4;
|
|
$hash->{helper}{proc_stat_old} = \@values;
|
|
|
|
my $sum = 0;
|
|
$sum += $_ for @diff;
|
|
|
|
my @percent = map { int($diff[$_]*1000 / $sum)/10 } 0 .. 4;
|
|
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]);
|
|
}
|
|
}
|
|
|
|
} elsif( $key eq 'cat /proc/uptime' && $data ) {
|
|
my ($uptime) = split(' ', $data, 2 );
|
|
|
|
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:%.2d", $days, $hours, $minutes, $seconds);
|
|
}
|
|
|
|
if( $hash->{BlockingResult} ) {
|
|
$hash->{BlockingResult}{uptime} = $uptime;
|
|
} else {
|
|
readingsBulkUpdate($hash,"uptime",$uptime);
|
|
}
|
|
|
|
} elsif( $key eq 'uptime' && $data ) {
|
|
if( $data =~ m/(([.,\d]+)\s([.,\d]+)\s([.,\d]+))$/ ) {
|
|
my $loadavg = $1;
|
|
$loadavg =~ s/, / /g;
|
|
$loadavg =~ s/,/./g;
|
|
SYSSTAT_Parse($hash, 'cat /proc/loadavg', $loadavg);
|
|
}
|
|
|
|
if( AttrVal($name, "uptime", 0) > 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
|
|
if( $data =~ m/[[:alpha:]]{2}\s*(((\d*)\s*[[:alnum:]]*,?)?\s+((\d+):(\d+)|(\d+)\s+[[:alpha:]]+in[[:alpha:]]*)),?/ ) {
|
|
my $days = $3?$3:0;
|
|
my $hours = $5?$5:0;
|
|
my $minutes = $6?$6:$7;
|
|
|
|
my $uptime = $days * 24;
|
|
$uptime += $hours;
|
|
$uptime *= 60;
|
|
$uptime += $minutes;
|
|
$uptime *= 60;
|
|
|
|
SYSSTAT_Parse($hash, 'cat /proc/uptime', $uptime);
|
|
return;
|
|
}
|
|
}
|
|
|
|
} elsif( $key eq '#freq1000' && $data ) {
|
|
readingsBulkUpdate($hash,"cpufreq",$data/1000);
|
|
|
|
} elsif( $key eq '#temp' && $data ) {
|
|
if( $data > 0 && $data < 200 ) {
|
|
if( AttrVal($name, "raspberrytemperature", 0) eq 2 ) {
|
|
$data = sprintf( "%.1f", (3 * ReadingsVal($name,"temperature",$data) + $data ) / 4 );
|
|
} elsif( AttrVal($name, "synologytemperature", 0) eq 2 ) {
|
|
$data = sprintf( "%.1f", (3 * ReadingsVal($name,"temperature",$data) + $data ) / 4 );
|
|
}
|
|
readingsBulkUpdate($hash, 'temperature', $data);
|
|
}
|
|
|
|
} elsif( $key eq '#temp1000' && $data ) {
|
|
SYSSTAT_Parse($hash, '#temp', $data/1000);
|
|
|
|
} elsif( $data && $key =~ m/#filesystems(:(.*))/ ) {
|
|
my $cl = $2;
|
|
my %filesystems = ();
|
|
foreach my $line (split(/\n/, $data)) {
|
|
next unless $line =~ /^(.+?)\s+(\d+\s+\d+\s+\d+\s.*)$/;
|
|
@{$filesystems{$1}}{qw(
|
|
total
|
|
used
|
|
free
|
|
usageper
|
|
mountpoint
|
|
)} = (split /\s+/, $2)[0..4];
|
|
|
|
$filesystems{$1}{usageper} =~ s/%//;
|
|
}
|
|
|
|
$hash->{helper}{filesystems} = \%filesystems;
|
|
|
|
if( $hash->{filesystems} ) {
|
|
my $usage = $hash->{helper}{filesystems};
|
|
|
|
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( $cl && $defs{$cl} ) {
|
|
|
|
my $ret;
|
|
foreach my $filesystem (sort { $a cmp $b } keys %{$hash->{helper}{filesystems}} ) {
|
|
$ret .= sprintf( "%30s %s\n", $filesystem, $hash->{helper}{filesystems}->{$filesystem}->{mountpoint} );
|
|
}
|
|
$ret = sprintf( "%30s %s", "<filesystem>", "<mountpoint>\n" ) .$ret if( $ret );
|
|
|
|
asyncOutput( $defs{$cl}, $ret ) if( $ret );
|
|
}
|
|
|
|
} else {
|
|
Log3 $name, 3, "$name: $key: $data";
|
|
|
|
}
|
|
}
|
|
|
|
|
|
sub
|
|
SYSSTAT_InitSNMP($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
delete( $hash->{session} );
|
|
|
|
return if( !$SYSSTAT_hasSNMP );
|
|
return if( !$hash->{USE_SNMP} );
|
|
|
|
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),
|
|
-translate => [ -timeticks => 0x0 ],
|
|
);
|
|
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;
|
|
|
|
my @snmpoids = ( '.1.3.6.1.2.1.1.1.0', '.1.3.6.1.2.1.1.5.0' );
|
|
my $response = SYSSTAT_readOIDs($hash,\@snmpoids);
|
|
$hash->{SystemDescription} = $response->{".1.3.6.1.2.1.1.1.0"};
|
|
$hash->{SystemName} = $response->{".1.3.6.1.2.1.1.5.0"};
|
|
}
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Undefine($$)
|
|
{
|
|
my ($hash, $arg) = @_;
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
|
|
|
|
SYSSTAT_Disconnect($hash);
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Shutdown($)
|
|
{
|
|
my ($hash) = @_;
|
|
|
|
RemoveInternalTimer($hash);
|
|
|
|
SYSSTAT_Disconnect($hash);
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Notify($$)
|
|
{
|
|
my ($hash,$dev) = @_;
|
|
|
|
return if($dev->{NAME} ne "global");
|
|
return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}}));
|
|
|
|
SYSSTAT_InitSNMP( $hash );
|
|
SYSSTAT_Connect($hash);
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Set($@)
|
|
{
|
|
my ($hash, $name, $cmd, $arg, @params) = @_;
|
|
return "$name: set needs at least one parameter" if( !$cmd );
|
|
|
|
if( $cmd eq 'reconnect' ) {
|
|
SYSSTAT_Connect( $hash );
|
|
return
|
|
|
|
} elsif( $cmd eq "raw" ) {
|
|
return "usage: raw <args>" if( !$arg );
|
|
|
|
SYSSTAT_Write( $hash, $arg. ' '. join(' ', @params ) );
|
|
return;
|
|
|
|
} elsif( $cmd eq "snmpDebug" ) {
|
|
if( defined($hash->{session}) ) {
|
|
$hash->{session}->debug($arg eq 'on' ? 0xff : 0x00 );
|
|
} else {
|
|
return 'no snmp session';
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
my $list = '';
|
|
$list .= 'raw:noArg reconnect:noArg' if( $hash->{HOST} );
|
|
$list .= ' snmpDebug:on,off,' if( $SYSSTAT_hasSNMP );
|
|
|
|
return "Unknown argument $cmd, choose one of $list";
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_Get($@)
|
|
{
|
|
my ($hash, $name, $cmd, $arg, @params) = @_;
|
|
return "$name: get needs at least one parameter" if( !$cmd );
|
|
|
|
if($cmd eq "filesystems") {
|
|
my $ret;
|
|
|
|
if( !$hash->{HOST} || $hash->{CONNECTS} ) {
|
|
SYSSTAT_getFilesystems($hash);
|
|
|
|
return undef;
|
|
|
|
} elsif( $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 .= sprintf( "%15s %s (%s)", $id, $response->{$oid}, $SYSSTAT_diskTypes{$types->{".1.3.6.1.2.1.25.2.3.1.2.$id"}} );
|
|
}
|
|
$ret = sprintf( "%15s %s", "<filesystem>", "<mountpoint>\n" ) .$ret if( $ret );
|
|
|
|
}
|
|
|
|
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 'disable') {
|
|
if( $cmd eq 'set' && $attrVal ne '0' ) {
|
|
$attr{$name}{$attrName} = $attrVal;
|
|
} else {
|
|
$hash->{STATE} = "Disabled";
|
|
RemoveInternalTimer($hash);
|
|
delete $attr{$name}{$attrName};
|
|
}
|
|
$hash->{$attrName} = $attrVal;
|
|
|
|
SYSSTAT_Connect($hash)
|
|
|
|
} elsif( $attrName eq 'noSSH') {
|
|
if( $cmd eq 'set' && $attrVal ne '0' ) {
|
|
$attr{$name}{$attrName} = $attrVal;
|
|
if( $hash->{HOST} ) {
|
|
SYSSTAT_Disconnect($hash);
|
|
delete $hash->{CONNECTS};
|
|
delete $hash->{helper}{has_proc_loadavg};
|
|
delete $hash->{helper}{has_proc_stat};
|
|
delete $hash->{helper}{has_proc_uptime};
|
|
}
|
|
|
|
} else {
|
|
SYSSTAT_Connect($hash);
|
|
|
|
}
|
|
|
|
} elsif( $attrName eq 'filesystems') {
|
|
my @filesystems = split(',',$attrVal);
|
|
@{$hash->{filesystems}} = @filesystems;
|
|
|
|
} elsif( $attrName eq 'ssh_user') {
|
|
$attr{$name}{$attrName} = $attrVal;
|
|
SYSSTAT_Connect( $hash ) if( $init_done );
|
|
|
|
} 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};
|
|
}
|
|
|
|
} elsif ($attrName eq 'readingsFormat' ) {
|
|
if( $cmd eq "set" ) {
|
|
my $attrVal = $attrVal;
|
|
|
|
my %specials= (
|
|
"%VALUE" => "1",
|
|
);
|
|
|
|
my $err = perlSyntaxCheck($attrVal, %specials);
|
|
return $err if($err);
|
|
|
|
if( $attrVal =~ m/^{.*}$/s && $attrVal =~ m/=>/ ) {
|
|
my $av = eval $attrVal;
|
|
if( $@ ) {
|
|
Log3 $hash->{NAME}, 2, "$hash->{NAME}: $@";
|
|
} else {
|
|
$attrVal = $av if( ref($av) eq "HASH" );
|
|
}
|
|
}
|
|
|
|
$hash->{helper}{$attrName} = $attrVal;
|
|
} else {
|
|
delete $hash->{helper}{$attrName};
|
|
}
|
|
}
|
|
|
|
if( $cmd eq 'set' ) {
|
|
if( $orig ne $attrVal ) {
|
|
$attr{$name}{$attrName} = $attrVal;
|
|
return "$attrName set to $attrVal";
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_getFilesystems($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
Log3 $name, 5, "$name: trying /proc/loadavg";
|
|
|
|
my $cl = '';
|
|
$cl = ":$hash->{CL}{NAME}" if( $hash->{CONNECTS} && $hash->{CL} );
|
|
|
|
if( !$hash->{HOST} || $hash->{CONNECTS} ) {
|
|
if( my $df = SYSSTAT_readCmd($hash, 'df -kP',"#filesystems$cl") ) {
|
|
my $interactive = !defined($hash->{'.updateTimestamp'});
|
|
readingsBeginUpdate($hash) if( $interactive );
|
|
SYSSTAT_Parse($hash, '#filesystems', $df) if( $df );
|
|
readingsEndUpdate($hash, 1) if( $interactive );
|
|
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
#Log3 $name, 2, "$name: filesystems error";
|
|
}
|
|
sub
|
|
SYSSTAT_getFilesystemsSNMP($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( $hash->{USE_SNMP} && defined($hash->{session}) ) {
|
|
my %filesystems = ();
|
|
|
|
my $showpercent = AttrVal($name, 'showpercent', '') ne '';
|
|
my @snmpoids = ();
|
|
for my $id (@{$hash->{filesystems}}) {
|
|
push @snmpoids, ".1.3.6.1.2.1.25.2.3.1.3.$id";
|
|
push @snmpoids, ".1.3.6.1.2.1.25.2.3.1.4.$id" if( !$showpercent );
|
|
push @snmpoids, ".1.3.6.1.2.1.25.2.3.1.5.$id";
|
|
push @snmpoids, ".1.3.6.1.2.1.25.2.3.1.6.$id";
|
|
}
|
|
my $response = SYSSTAT_readOIDs($hash,\@snmpoids);
|
|
if( $response ) {
|
|
for my $id (@{$hash->{filesystems}}) {
|
|
my $unit = $response->{".1.3.6.1.2.1.25.2.3.1.4.$id"};
|
|
my $free = $response->{".1.3.6.1.2.1.25.2.3.1.5.$id"} - $response->{".1.3.6.1.2.1.25.2.3.1.6.$id"};
|
|
|
|
if( $showpercent ) {
|
|
$free = 100 * $response->{".1.3.6.1.2.1.25.2.3.1.6.$id"} / $response->{".1.3.6.1.2.1.25.2.3.1.5.$id"};
|
|
$free = sprintf( '%.1f', $free );
|
|
} else {
|
|
$free *= $unit;
|
|
}
|
|
my $name = $response->{".1.3.6.1.2.1.25.2.3.1.3.$id"};
|
|
if( $name =~ m/^([[:alpha:]]:\\)/ ) {
|
|
$name = $1;
|
|
$name =~ s.\\./.g;
|
|
} else {
|
|
$name =~ s/ //g;
|
|
}
|
|
|
|
$hash->{BlockingResult}{$name} = $free;
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
Log3 $name, 2, "$name: snmp filesystems error";
|
|
}
|
|
|
|
sub SYSSTAT_getLoadAVG($);
|
|
sub SYSSTAT_getPiTemp($);
|
|
sub SYSSTAT_getUptime($);
|
|
sub
|
|
SYSSTAT_GetUpdate($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( AttrVal($name, "noSSH", undef) ) {
|
|
my @queue = ();
|
|
$hash->{QUEUE} = \@queue;
|
|
|
|
} elsif( $hash->{QUEUE} && scalar @{$hash->{QUEUE}} ) {
|
|
Log3 $name, 2, "$name: unanswered query in queue, reconnecting";
|
|
SYSSTAT_Connect($hash);
|
|
return;
|
|
}
|
|
|
|
if(!$hash->{LOCAL}) {
|
|
RemoveInternalTimer($hash);
|
|
InternalTimer(gettimeofday()+$hash->{INTERVAL}, 'SYSSTAT_GetUpdate', $hash, 0);
|
|
|
|
return if( IsDisabled($name) > 0 );
|
|
}
|
|
|
|
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( $hash->{LOCAL} ) {
|
|
$do_diskusage = 1;
|
|
}
|
|
}
|
|
|
|
if( !$hash->{HOST} || $hash->{CONNECTS} ) {
|
|
readingsBeginUpdate($hash);
|
|
|
|
SYSSTAT_getLoadAVG( $hash );
|
|
|
|
SYSSTAT_getFilesystems($hash) if( $do_diskusage && $#{$hash->{filesystems}} >= 0 );
|
|
|
|
SYSSTAT_getPiTemp($hash) if( AttrVal($name, 'raspberrytemperature', 0) > 0 );
|
|
SYSSTAT_getPiFreq($hash) if( AttrVal($name, 'raspberrycpufreq', 0) > 0 );
|
|
|
|
SYSSTAT_getStat($hash) if( AttrVal($name, 'stat', 0) > 0 );
|
|
|
|
SYSSTAT_getUptime($hash) if( AttrVal($name, 'uptime', 0) > 0 );
|
|
|
|
|
|
if( my $readings = AttrVal($name, 'readings', undef) ) {
|
|
foreach my $entry (split(/[\n]/, $readings)) {
|
|
next if( !$entry );
|
|
my($reading,$cmd) = split(':', $entry );
|
|
|
|
if( my $value = SYSSTAT_readCmd($hash, $cmd, "#reading:$reading") ) {
|
|
SYSSTAT_Parse($hash, "#reading:$reading", $value) if( $value );
|
|
}
|
|
}
|
|
}
|
|
|
|
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
|
}
|
|
|
|
if( $hash->{USE_SNMP} && defined($hash->{session}) ) {
|
|
$hash->{do_diskusage} = $do_diskusage;
|
|
$hash->{helper}{RUNNING_PID} = BlockingCall("SYSSTAT_BlockingCall", $hash, "SYSSTAT_BlockingDone", 300, "SYSSTAT_BlockingAborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
|
|
delete $hash->{do_diskusage};
|
|
}
|
|
}
|
|
sub
|
|
SYSSTAT_GetUpdateSNMP($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( !$hash->{USE_SNMP} || !defined($hash->{session}) ) {
|
|
return undef;
|
|
}
|
|
|
|
if(!$hash->{LOCAL}) {
|
|
return undef if( IsDisabled($name) > 0 );
|
|
}
|
|
|
|
SYSSTAT_getLoadAVGSNMP($hash) if( AttrVal($name, 'load', 1) > 0 );
|
|
|
|
SYSSTAT_getFilesystemsSNMP($hash) if( $hash->{do_diskusage} && $#{$hash->{filesystems}} >= 0 );
|
|
|
|
SYSSTAT_getSynoTempSNMP($hash) if( AttrVal($name, 'synologytemperature', 0) > 0 );
|
|
|
|
SYSSTAT_getStatSNMP($hash) if( AttrVal($name, 'stat', 0) > 0 );
|
|
SYSSTAT_getUptimeSNMP($hash) if( AttrVal($name, 'uptime', 0) > 0 );
|
|
|
|
SYSSTAT_getMIBS($hash);
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_getMIBS($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
my $mibs = AttrVal($name, 'mibs', undef);
|
|
return undef if( !$mibs );
|
|
|
|
my @snmpoids;
|
|
foreach my $entry (split(/[ ,\n]/, $mibs)) {
|
|
next if( !$entry );
|
|
my($mib,undef) = split(':', $entry );
|
|
next if( !$mib );
|
|
|
|
push @snmpoids, $mib;
|
|
}
|
|
|
|
return undef if( !@snmpoids );
|
|
|
|
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};
|
|
$hash->{BlockingResult}{$reading} = $result;
|
|
}
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_BlockingCall($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
$hash->{BlockingResult} = {};
|
|
|
|
SYSSTAT_GetUpdateSNMP($hash);
|
|
|
|
return "$name:".encode_json( $hash->{BlockingResult} );
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_BlockingDone($)
|
|
{
|
|
my ($string) = @_;
|
|
my ($name,$json) = split(":", $string, 2);
|
|
my $hash = $defs{$name};
|
|
|
|
Log3 $name, 4, "$name: BlockingCall finished: $hash->{helper}{RUNNING_PID}{fn}";
|
|
delete($hash->{helper}{RUNNING_PID});
|
|
|
|
#Log 1, $json;
|
|
|
|
my $decoded = decode_json( $json );
|
|
my $in_update = !defined($hash->{'.updateTimestamp'});
|
|
readingsBeginUpdate($hash) if( $in_update );
|
|
foreach my $key (keys %{$decoded}) {
|
|
my $reading = $key;
|
|
my $VALUE = $decoded->{$key};
|
|
|
|
if( my $value_format = $hash->{helper}{readingsFormat} ) {
|
|
if( ref($value_format) eq 'HASH' ) {
|
|
my $vf = "";
|
|
$vf = $value_format->{$reading} if( defined($reading) && exists($value_format->{$reading}) );
|
|
$vf = $value_format->{$reading.'.'.$VALUE} if( defined($reading) && exists($value_format->{$reading.'.'.$VALUE}) );
|
|
|
|
if( !ref($vf) && $vf =~ m/^{.*}$/s) {
|
|
eval $vf;
|
|
$VALUE = $decoded->{$key} if( $@ );
|
|
Log3 $name, 2, "$name: $@" if( $@ );
|
|
|
|
}
|
|
|
|
} else {
|
|
Log3 $name, 2, "$name: readingsFormat is not a hash";
|
|
|
|
}
|
|
}
|
|
|
|
readingsBulkUpdate($hash, $key, $VALUE);
|
|
}
|
|
readingsEndUpdate($hash, 1) if( $in_update );
|
|
}
|
|
sub
|
|
SYSSTAT_BlockingAborted($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
Log3 $name, 2, "$name: BlockingCall aborted: $hash->{helper}{RUNNING_PID}{fn}";
|
|
|
|
delete($hash->{helper}{RUNNING_PID});
|
|
}
|
|
|
|
sub SYSSTAT_readFile($$;$);
|
|
sub SYSSTAT_readCmd($$;$);
|
|
sub
|
|
SYSSTAT_getLoadAVG($ )
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( $hash->{helper}{has_proc_loadavg} ) {
|
|
Log3 $name, 5, "$name: trying /proc/loadavg";
|
|
|
|
my $loadavg = SYSSTAT_readFile($hash, '/proc/loadavg');
|
|
SYSSTAT_Parse($hash, 'cat /proc/loadavg', $loadavg) if( $loadavg );
|
|
return;
|
|
}
|
|
|
|
return if( $hash->{USE_SNMP} && defined($hash->{session}) );
|
|
|
|
Log3 $name, 5, "$name: trying uptime";
|
|
my $uptime = SYSSTAT_readCmd($hash, 'uptime');
|
|
SYSSTAT_Parse($hash, 'uptime', $uptime ) if( $uptime );
|
|
}
|
|
sub
|
|
SYSSTAT_getLoadAVGSNMP($ )
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
return if( $hash->{helper}{has_proc_loadavg} );
|
|
|
|
if( $hash->{USE_SNMP} && defined($hash->{session}) ) {
|
|
Log3 $name, 5, "$name: trying snmp load avg";
|
|
|
|
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;
|
|
foreach my $key (keys %{$response}) {
|
|
$avg .= ',' if( $avg );
|
|
$avg .= $response->{$key};
|
|
$load = 0 if( !$load );
|
|
$load += $response->{$key} / 100;
|
|
}
|
|
|
|
$hash->{BlockingResult}{state} = $avg if( defined($avg) );
|
|
$hash->{BlockingResult}{load} = $load if( defined($load) );
|
|
#readingsBulkUpdate($hash, 'state', $avg) if( $avg );
|
|
#readingsBulkUpdate($hash, 'load', $load) if( $load );
|
|
return undef;
|
|
}
|
|
|
|
my $avg_1 = $response->{'.1.3.6.1.4.1.2021.10.1.3.1'};
|
|
my $avg_5 = $response->{'.1.3.6.1.4.1.2021.10.1.3.2'};
|
|
my $avg_15 = $response->{'.1.3.6.1.4.1.2021.10.1.3.3'};
|
|
$hash->{BlockingResult}{state} = "$avg_1 $avg_5 $avg_15";
|
|
$hash->{BlockingResult}{load} = $avg_1;
|
|
#readingsBulkUpdate($hash, 'state', "$avg_1 $avg_5 $avg_15");
|
|
#readingsBulkUpdate($hash, 'load', $avg_1);
|
|
return undef;
|
|
}
|
|
|
|
Log3 $name, 2, "$name: snmp loadavg error";
|
|
}
|
|
|
|
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,$key) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( defined($hash->{HOST}) ) {
|
|
SYSSTAT_Write( $hash, $command, $key );
|
|
return undef;
|
|
|
|
} else {
|
|
if( my $pid = open( my $fh, '-|', $command ) ) {
|
|
if( 1 ) {
|
|
#non-blocking
|
|
my %chash = ();
|
|
$chash{NR} = $devcount++;
|
|
$chash{STATE} = $command;
|
|
$chash{TYPE} = $hash->{TYPE};
|
|
$chash{NAME} = "$name:cmd:$chash{NR}";
|
|
|
|
$chash{key} = $key;
|
|
$chash{cmd} = $command;
|
|
$chash{phash} = $hash;
|
|
|
|
$chash{TEMPORARY} = 1;
|
|
$attr{$chash{NAME}}{room} = 'hidden';
|
|
|
|
$chash{FH} = $fh;
|
|
$chash{FD} = fileno($fh);
|
|
$chash{PID} = $pid;
|
|
|
|
$defs{$chash{NAME}} = \%chash;
|
|
$selectlist{$chash{NAME}} = \%chash;
|
|
InternalTimer(gettimeofday()+5, 'SYSSTAT_killChild', \%chash, 0);
|
|
|
|
return undef;
|
|
|
|
} else {
|
|
#blocking FIXME: does not work if ssh is used somewhere else
|
|
my $value = `$command`;
|
|
return $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
sub
|
|
SYSSTAT_readFile($$;$)
|
|
{
|
|
my ($hash,$filename,$key) = @_;
|
|
|
|
my $value;
|
|
if( defined($hash->{HOST}) ) {
|
|
SYSSTAT_Write( $hash, "cat $filename", $key );
|
|
return undef;
|
|
|
|
} 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', '#temp1000');
|
|
SYSSTAT_Parse($hash, '#temp1000', $temp) if( $temp );
|
|
}
|
|
sub
|
|
SYSSTAT_getSynoTempSNMP($)
|
|
{
|
|
my ($hash) = @_;
|
|
|
|
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);
|
|
|
|
$hash->{BlockingResult}{temperature} = $response->{'.1.3.6.1.4.1.6574.1.2.0'};
|
|
}
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_getPiFreq($)
|
|
{
|
|
my ($hash) = @_;
|
|
|
|
my $freq = SYSSTAT_readFile($hash, '/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq', '#freq1000');
|
|
SYSSTAT_Parse($hash, '#freq1000', $freq) if( $freq );
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_getUptime($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( $hash->{helper}{has_proc_uptime} ) {
|
|
Log3 $name, 5, "$name: trying /proc/uptime";
|
|
|
|
my $uptime = SYSSTAT_readFile($hash, '/proc/uptime');
|
|
SYSSTAT_Parse($hash, 'cat /proc/uptime', $uptime) if( $uptime );
|
|
return;
|
|
}
|
|
}
|
|
sub
|
|
SYSSTAT_getUptimeSNMP($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
return if( $hash->{helper}{has_proc_uptime} );
|
|
|
|
if( $hash->{USE_SNMP} && defined($hash->{session}) ) {
|
|
Log3 $name, 5, "$name: trying snmp uptime";
|
|
|
|
my @snmpoids = ( '.1.3.6.1.2.1.1.3.0' );
|
|
|
|
my $response = SYSSTAT_readOIDs($hash,\@snmpoids);
|
|
|
|
my $uptime = $response->{'.1.3.6.1.2.1.1.3.0'};
|
|
if( defined($uptime) ) {
|
|
SYSSTAT_Parse($hash, 'cat /proc/uptime', $uptime/100);
|
|
return;
|
|
}
|
|
|
|
@snmpoids = ( '.1.3.6.1.2.1.25.1.1.0' );
|
|
|
|
$response = SYSSTAT_readOIDs($hash,\@snmpoids);
|
|
|
|
$uptime = $response->{'.1.3.6.1.2.1.25.1.1.0'};
|
|
if( defined($uptime) ) {
|
|
SYSSTAT_Parse($hash, 'cat /proc/uptime', $uptime/100);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
Log3 $name, 2, "$name: snmp uptime error";
|
|
}
|
|
|
|
sub
|
|
SYSSTAT_getStat($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
if( $hash->{helper}{has_proc_stat} ) {
|
|
Log3 $name, 5, "$name: trying /proc/stat";
|
|
|
|
my $line = SYSSTAT_readFile($hash, '/proc/stat');
|
|
SYSSTAT_Parse($hash, 'cat /proc/stat', $line) if( $line );
|
|
return;
|
|
}
|
|
|
|
return if( $hash->{USE_SNMP} && defined($hash->{session}) );
|
|
|
|
Log3 $name, 2, "$name: stat error";
|
|
}
|
|
sub
|
|
SYSSTAT_getStatSNMP($)
|
|
{
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
return if( $hash->{helper}{has_proc_stat} );
|
|
|
|
if( $hash->{USE_SNMP} && defined($hash->{session}) ) {
|
|
Log3 $name, 5, "$name: trying snmp stat";
|
|
|
|
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);
|
|
$hash->{BlockingResult}{user} = $response->{'.1.3.6.1.4.1.2021.11.9.0'};
|
|
$hash->{BlockingResult}{system} = $response->{'.1.3.6.1.4.1.2021.11.10.0'};
|
|
$hash->{BlockingResult}{idle} = $response->{'.1.3.6.1.4.1.2021.11.11.0'};
|
|
|
|
return;
|
|
}
|
|
|
|
Log3 $name, 2, "$name: snmp stat error";
|
|
}
|
|
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item device
|
|
=item summary system statistics for local and remote linux (and windows) systems
|
|
=item summary_DE Systemstatistiken für lokale und entfernte Linux (und Windows) Rechner
|
|
=begin html
|
|
|
|
<a name="SYSSTAT"></a>
|
|
<h3>SYSSTAT</h3>
|
|
<ul>
|
|
Provides system statistics for the host FHEM runs on or a remote Linux system that is reachable by preconfigured passwordless ssh access.<br><br>
|
|
|
|
Notes:
|
|
<ul>
|
|
<li>To monitor a target by snmp <code>Net::SNMP</code> hast to be installed.<br></li>
|
|
|
|
<li>To plot the load values the following code can be used:
|
|
<PRE>
|
|
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
|
|
</PRE></li>
|
|
<li>to match the root filesystem (mount point '/') in diskusage plots use
|
|
'<code>#FileLog 4:/\x3a:0:</code>' or '<code>#FileLog 4:\s..\s:0:</code>'
|
|
and <b>not</b> '<code>#FileLog 4:/:0:</code>' as the later will match all mount points</li>.
|
|
</ul>
|
|
|
|
<a name="SYSSTAT_Define"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> SYSSTAT [<interval> [<interval_fs>] [<host>]]</code><br>
|
|
<br>
|
|
|
|
Defines a SYSSTAT device.<br><br>
|
|
|
|
The load is updated every <interval> seconds. The default and minimum is 60.<br><br>
|
|
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>.<br><br>
|
|
|
|
If <host> is given it has to be accessible by ssh without the need for a password.
|
|
|
|
Examples:
|
|
<ul>
|
|
<code>define sysstat SYSSTAT</code><br>
|
|
<code>define sysstat SYSSTAT 300</code><br>
|
|
<code>define sysstat SYSSTAT 60 600</code><br>
|
|
</ul>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Readings"></a>
|
|
<b>Readings</b>
|
|
<ul>
|
|
<li>load<br>
|
|
the 1 minute load average (for windows targets monitored by snmp aproximated value</li>
|
|
<li>state<br>
|
|
the 1, 5 and 15 minute load averages (or windows targets monitored by snmp the per cpu utilization)</li>
|
|
<li>user,system,idle,iowait<br>
|
|
respective percentage of systemutilization (linux targets only)</li>
|
|
<li><mountpoint><br>
|
|
free bytes for <mountpoint></li>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Set"></a>
|
|
<b>Set</b>
|
|
<ul>
|
|
<code>set <name> <value></code>
|
|
<br><br>
|
|
where <code>value</code> is one of<br><br>
|
|
<li>raw <command><br>
|
|
Sends <command> to the remote system by ssh.<br>
|
|
<code>set <name> raw shutdown -h now</code></li>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Get"></a>
|
|
<b>Get</b>
|
|
<ul>
|
|
<code>get <name> <value></code>
|
|
<br><br>
|
|
where <code>value</code> is one of<br><br>
|
|
<li>filesystems<br>
|
|
Lists the filesystems that can be monitored.</li>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Attr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>noSSH<br>
|
|
</li>
|
|
<li>disable<br>
|
|
keep timers running but disable collection of statistics.</li>
|
|
<li>filesystems<br>
|
|
List of comma separated filesystems (not mountpoints) that should be monitored.<br>
|
|
Examples:
|
|
<ul>
|
|
<code>attr sysstat filesystems /dev/md0,/dev/md2</code><br>
|
|
<code>attr sysstat filesystems /dev/.*</code><br>
|
|
<code>attr sysstat filesystems 1,3,5</code><br>
|
|
</ul></li></lu>
|
|
<li>disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM...</li>
|
|
<li>mibs<br>
|
|
space separated list of <mib>:<reding> pairs that sould be polled.</li>
|
|
<li>readings<br>
|
|
Newline separated liste aus <reading>:<command> pairs should be executed.<br>
|
|
<pre>
|
|
attr <device> readings processes:ps ax | wc -l\
|
|
temperature:snmpwalk -c public -v 1 10.0.1.21 .1.3.6.1.4.1.6574.1.2.0 | grep -oE ..$
|
|
</pre>
|
|
</li>
|
|
<li>readingsFormat<br>
|
|
<pre>
|
|
attr <device> readings temperature:cat /sys/class/thermal/thermal*/temp\
|
|
temperatures:cat /sys/class/thermal/thermal*/temp\
|
|
frequency:cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
|
|
|
|
attr <device> readingsFormat { frequency => '{ $VALUE = [map {int($_ / 1000)} split("\n", $VALUE)] }',\
|
|
temperature => '{ $VALUE = [map {$_ / 1000} split("\n", $VALUE)] }',\
|
|
temperatures => '{ $VALUE =~ s/\n/ /g }' }
|
|
</pre>
|
|
</li>
|
|
<li>showpercent<br>
|
|
If set the usage is shown in percent. If not set the remaining free space in bytes is shown.</li>
|
|
<li>snmp<br>
|
|
1 -> use snmp to monitor load, uptime and filesystems (including physical and virtual memory)</li>
|
|
<li>stat<br>
|
|
1 -> monitor user,system,idle and iowait percentage of system utilization (available only for linux targets)</li>
|
|
<li>raspberrytemperature<br>
|
|
If set and > 0 the raspberry pi on chip termal sensor is read.<br>
|
|
If set to 2 a geometric average over the last 4 values is created.</li>
|
|
<li>synologytemperature<br>
|
|
If set and > 0 the main temperaure of a synology diskstation is read. requires snmp.<br>
|
|
If set to 2 a geometric average over the last 4 values is created.</li>
|
|
<li>raspberrycpufreq<br>
|
|
If set and > 0 the raspberry pi on chip termal sensor is read.</li>
|
|
<li>uptime<br>
|
|
If set and > 0 the system uptime is read.<br>
|
|
If set to 2 the uptime is displayed in seconds.</li>
|
|
<li>load<br>
|
|
If set and = 0 the system load is not read.</li>
|
|
<li>useregex<br>
|
|
If set the entries of the filesystems list are treated as regex.</li>
|
|
<li>ssh_user<br>
|
|
The username for ssh remote access.</li>
|
|
<li>snmpVersion</li>
|
|
<li>snmpCommunity</li>
|
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
|
</ul>
|
|
</ul>
|
|
|
|
=end html
|
|
|
|
=begin html_DE
|
|
|
|
<a name="SYSSTAT"></a>
|
|
<h3>SYSSTAT</h3>
|
|
<ul>
|
|
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.<br><br>
|
|
|
|
Notes:
|
|
<ul>
|
|
<li>Dieses Modul benötigt <code>Sys::Statistics::Linux</code> für Linux.<br>
|
|
Es kann mit '<code>cpan install Sys::Statistics::Linux</code>'<br>
|
|
bzw. auf Debian mit '<code>apt-get install libsys-statistics-linux-perl</code>'
|
|
installiert werden.</li>
|
|
|
|
<li>Um einen Zielrechner mit snmp zu überwachen, muss
|
|
<code>Net::SNMP</code> installiert sein.<br></li>
|
|
|
|
<li>Um die Lastwerte zu plotten, kann der folgende Code verwendet werden:
|
|
<pre>
|
|
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
|
|
</pre></li>
|
|
<li>Um das Wurzel-Dateisystem (Mountpunkt '/') bei Plots der Plattennutzung zu erhalten,
|
|
sollte dieser Code '<code>#FileLog 4:/\x3a:0:</code>' bzw. '<code>#FileLog 4:\s..\s:0:</code>'
|
|
und <b>nicht</b> dieser Code '<code>#FileLog 4:/:0:</code>' verwendet werden, da der letztere
|
|
alle Mountpunkte darstellt.</li>.
|
|
</ul>
|
|
|
|
<a name="SYSSTAT_Define"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> SYSSTAT [<interval> [<interval_fs>] [<host>]]</code><br>
|
|
<br>
|
|
|
|
definiert ein SYSSTAT Device.<br><br>
|
|
|
|
Die (Prozessor)last wird alle <interval> Sekunden aktualisiert. Standard bzw. Minimum ist 60.<br><br>
|
|
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.<br><br>
|
|
|
|
Wenn <host> angegeben wird, muss der Zugang per ssh ohne Passwort möglich sein.<br><br>
|
|
|
|
Beispiele:
|
|
<ul>
|
|
<code>define sysstat SYSSTAT</code><br>
|
|
<code>define sysstat SYSSTAT 300</code><br>
|
|
<code>define sysstat SYSSTAT 60 600</code>
|
|
</ul>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Readings"></a>
|
|
<b>Readings</b>
|
|
<ul>
|
|
<li>load<br>
|
|
die durchschnittliche (Prozessor)last der letzten 1 Minute (für Windows Rechner mit
|
|
snmp angenähertem Wert)</li>
|
|
<li>state<br>
|
|
die durchschnittliche (Prozessor)last der letzten 1, 5 und 15 Minuten (für Windows
|
|
Rechner die Nutzung pro CPU via snmp ermittelt)</li>
|
|
<li>user, system, idle, iowait<br>
|
|
den Prozentsatz der entsprechenden Systemlast (nur für Linux Systeme)</li>
|
|
<li><mountpoint><br>
|
|
Anzahl der freien Bytes für <mountpoint></li>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Set"></a>
|
|
<b>Set</b>
|
|
<ul>
|
|
<code>set <name> <value></code>
|
|
<br><br>
|
|
Werte für <code>value</code> sind<br><br>
|
|
<li>raw <command><br>
|
|
Sendet <command> per ssh and das entfernte System.<br>
|
|
<code>set <name> raw shutdown -h now</code></li>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Get"></a>
|
|
<b>Get</b>
|
|
<ul>
|
|
<code>get <name> <value></code>
|
|
<br><br>
|
|
Werte für <code>value</code> sind<br><br>
|
|
<li>filesystems<br>
|
|
zeigt die Dateisysteme an, die überwacht werden können.</li>
|
|
</ul><br>
|
|
|
|
<a name="SYSSTAT_Attr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>noSSH<br>
|
|
</li>
|
|
<li>disable<br>
|
|
lässt die Timer weiterlaufen, aber stoppt die Speicherung der Daten.</li>
|
|
<li>filesystems<br>
|
|
Liste mit Komma getrennten Dateisystemen (nicht Mountpunkten) die überwacht
|
|
werden sollen.<br>
|
|
Beispiele:
|
|
<ul>
|
|
<code>attr sysstat filesystems /dev/md0,/dev/md2</code><br>
|
|
<code>attr sysstat filesystems /dev/.*</code><br>
|
|
<code>attr sysstat filesystems 1,3,5</code><br>
|
|
</ul></li>
|
|
<li>mibs<br>
|
|
Leerzeichen getrennte Liste aus <mib>:<reding> Paaren die abgefragt werden sollen.</li>
|
|
<li>readings<br>
|
|
Newline getrennte Liste aus <reading>:<kommando> Paaren die ausgeführt werden sollen.<br>
|
|
<pre>
|
|
attr <device> readings processes:ps ax | wc -l\
|
|
temperature:snmpwalk -c public -v 1 10.0.1.21 .1.3.6.1.4.1.6574.1.2.0 | grep -oE ..$
|
|
</pre>
|
|
</li>
|
|
<li>readingsFormat<br>
|
|
<pre>
|
|
attr <device> readings temperature:cat /sys/class/thermal/thermal*/temp\
|
|
temperatures:cat /sys/class/thermal/thermal*/temp\
|
|
frequency:cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
|
|
|
|
attr <device> readingsFormat { frequency => '{ $VALUE = [map {int($_ / 1000)} split("\n", $VALUE)] }',\
|
|
temperature => '{ $VALUE = [map {$_ / 1000} split("\n", $VALUE)] }',\
|
|
temperatures => '{ $VALUE =~ s/\n/ /g }' }
|
|
</pre>
|
|
|
|
</li>
|
|
<li>showpercent<br>
|
|
Wenn gesetzt, wird die Nutzung in Prozent angegeben. Wenn nicht gesetzt, wird der verfübare
|
|
Platz in Bytes angezeigt.</li>
|
|
<li>snmp<br>
|
|
1 -> snmp wird verwendet, um Last, Einschaltzeit und Dateisysteme (inkl. physikalischem und
|
|
virtuellem Speicher) zu überwachen</li>
|
|
<li>stat<br>
|
|
1 -> überwacht Prozentsatz der user, system, idle und iowait Last
|
|
(nur auf Linux Systemen verfügbar)</li>
|
|
<li>raspberrytemperature<br>
|
|
Wenn gesetzt und > 0 wird der Temperatursensor auf dem Raspberry Pi ausgelesen.<br>
|
|
Wenn Wert 2 ist, wird ein geometrischer Durchschnitt der letzten 4 Werte dargestellt.</li>
|
|
<li>synologytemperature<br>
|
|
Wenn gesetzt und > 0 wird die Temperatur einer Synology Diskstation ausgelesen (erfordert snmp).<br>
|
|
Wenn Wert 2 ist, wird ein geometrischer Durchschnitt der letzten 4 Werte dargestellt.</li>
|
|
<li>raspberrycpufreq<br>
|
|
Wenn gesetzt und > 0 wird die Raspberry Pi CPU Frequenz ausgelesen.</li>
|
|
<li>uptime<br>
|
|
Wenn gesetzt und > 0 wird die Betriebszeit (uptime) des Systems ausgelesen.<br>
|
|
Wenn Wert 2 ist, wird die Betriebszeit (uptime) in Sekunden angezeigt.</li>
|
|
<li>load<br>
|
|
Wenn gesetzt und = 0 wird die last (load) des nicht Systems ausgelesen.</li>
|
|
<li>useregex<br>
|
|
Wenn Wert gesetzt, werden die Einträge der Dateisysteme als regex behandelt.</li>
|
|
<li>ssh_user<br>
|
|
Der Username für den ssh Zugang auf dem entfernten Rechner.</li>
|
|
<li>snmpVersion</li>
|
|
<li>snmpCommunity</li>
|
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
|
</ul>
|
|
</ul>
|
|
|
|
=end html_DE
|
|
=cut
|