mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 16:56:54 +00:00
98_WOL: Big update of WOL. Module now uses Blockingcall. By using the new attribute useUdpBroadcast you can specify a Broardcastadress wher the Magicattribute is sent. When using 0 as interal you can switch checking for the device off
git-svn-id: https://svn.fhem.de/fhem/trunk@7623 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
3af5d03f65
commit
a5f2aea0f1
@ -22,7 +22,9 @@ package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
use IO::Socket;
|
||||
use Blocking;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
################################################################################
|
||||
sub WOL_Initialize($) {
|
||||
my ($hash) = @_;
|
||||
@ -30,7 +32,8 @@ sub WOL_Initialize($) {
|
||||
$hash->{SetFn} = "WOL_Set";
|
||||
$hash->{DefFn} = "WOL_Define";
|
||||
$hash->{UndefFn} = "WOL_Undef";
|
||||
$hash->{AttrList} = "interval shutdownCmd sysCmd ".
|
||||
$hash->{AttrFn} = "WOL_Attr";
|
||||
$hash->{AttrList} = "interval shutdownCmd sysCmd useUdpBroadcast ".
|
||||
$readingFnAttributes;
|
||||
}
|
||||
################################################################################
|
||||
@ -47,32 +50,21 @@ sub WOL_Set($@) {
|
||||
if ($v eq "on") {
|
||||
readingsSingleUpdate($hash, "active", $v, 1);
|
||||
Log3 $hash, 3, "[$name] waking $name with MAC $hash->{MAC} IP $hash->{IP} ";
|
||||
WOL_GetUpdate( { 'HASH' => $hash } );
|
||||
} elsif ($v eq "off") {
|
||||
readingsSingleUpdate($hash, "active", $v, 1);
|
||||
my $cmd = AttrVal($name, "shutdownCmd", "");
|
||||
if ($cmd eq "") {
|
||||
Log3 $hash, 3, "[$name] no shutdown command given (see shutdownCmd attribute)!";
|
||||
} else {
|
||||
$cmd = SemicolonEscape($cmd);
|
||||
Log3 $hash, 3, "[$name] shutdownCmd: $cmd executed";
|
||||
my $ret = AnalyzeCommandChain(undef, $cmd);
|
||||
Log3 ($hash, 3, "[$name]" . $ret) if($ret);
|
||||
return undef;
|
||||
}
|
||||
$cmd = SemicolonEscape($cmd);
|
||||
Log3 $hash, 3, "[$name] shutdownCmd: $cmd executed";
|
||||
my $ret = AnalyzeCommandChain(undef, $cmd);
|
||||
Log3 ($hash, 3, "[$name]" . $ret) if($ret);
|
||||
} elsif ($v eq "refresh") {
|
||||
;
|
||||
WOL_UpdateReadings( { 'HASH' => $hash } );
|
||||
}
|
||||
|
||||
WOL_UpdateReadings($hash);
|
||||
return undef if($v eq "refresh");
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
InternalTimer(gettimeofday()+60, "WOL_UpdateReadings", $hash, 0);
|
||||
|
||||
my $active = ReadingsVal($hash->{NAME}, "active", "nF");
|
||||
if ($active eq "on") {
|
||||
WOL_GetUpdate($hash);
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
@ -102,7 +94,7 @@ sub WOL_Define($$) {
|
||||
if(!($mode =~ m/^(BOTH|EW|UDP)$/));
|
||||
|
||||
return "invalid repeat<$repeat> - use 999"
|
||||
if(!($repeat =~ m/^[0-9]{3,3}$/i));
|
||||
if(!($repeat =~ m/^[0-9]{1,3}$/i));
|
||||
|
||||
$hash->{NAME} = $name;
|
||||
$hash->{MAC} = $mac;
|
||||
@ -110,8 +102,6 @@ sub WOL_Define($$) {
|
||||
$hash->{REPEAT} = $repeat;
|
||||
$hash->{MODE} = $mode;
|
||||
|
||||
$hash->{INTERVAL} = AttrVal($hash->{NAME}, "interval", 900);
|
||||
|
||||
readingsSingleUpdate($hash, "packet_via_EW", "none",0);
|
||||
readingsSingleUpdate($hash, "packet_via_UDP", "none",0);
|
||||
readingsSingleUpdate($hash, "state", "none",0);
|
||||
@ -119,7 +109,7 @@ sub WOL_Define($$) {
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
|
||||
WOL_UpdateReadings($hash);
|
||||
WOL_SetNextTimer($hash, 10);
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
@ -127,49 +117,96 @@ sub WOL_Undef($$) {
|
||||
|
||||
my ($hash, $arg) = @_;
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
myRemoveInternalTimer("ping", $hash);
|
||||
myRemoveInternalTimer("wake", $hash);
|
||||
BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_UpdateReadings($) {
|
||||
my ($myHash) = @_;
|
||||
|
||||
my $hash = myGetHashIndirekt($myHash, (caller(0))[3]);
|
||||
return if (!defined($hash));
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
|
||||
my $blockingFn = "WOL_Ping";
|
||||
my $arg = $hash->{NAME}."|".$hash->{IP};
|
||||
my $finishFn = "WOL_PingDone";
|
||||
my $timeout = 3;
|
||||
my $abortFn = "WOL_PingAbort";
|
||||
|
||||
if (!(exists($hash->{helper}{RUNNING_PID}))) {
|
||||
$hash->{helper}{RUNNING_PID} =
|
||||
BlockingCall($blockingFn, $arg, $finishFn, $timeout, $abortFn, $hash);
|
||||
} else {
|
||||
Log3 $hash, 3, "[$name] Blocking Call running no new started";
|
||||
WOL_SetNextTimer($hash);
|
||||
}
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_Ping($){
|
||||
my ($string) = @_;
|
||||
my ($name, $ip) = split("\\|", $string);
|
||||
my $hash = $defs{$name};
|
||||
|
||||
my $ping = "ping -c 1 -w 2 $ip";
|
||||
my $res = qx ($ping);
|
||||
$res = "" if (!defined($res));
|
||||
|
||||
Log3 $hash, 5, "[$name] executing: $ping";
|
||||
|
||||
my $erreichbar = !($res =~ m/100%/);
|
||||
my $return = "$name|$erreichbar";
|
||||
return $return;
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_PingDone($){
|
||||
my ($string) = @_;
|
||||
my ($name, $erreichbar) = split("\\|", $string);
|
||||
my $hash = $defs{$name};
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
|
||||
if ($erreichbar) {
|
||||
Log3 $hash, 5, "[$name] ping succesful - state = on";
|
||||
readingsBulkUpdate ($hash, "isRunning", "true");
|
||||
readingsBulkUpdate ($hash, "state", "on");
|
||||
} else {
|
||||
Log3 $hash, 5, "[$name] ping not succesful - state = off";
|
||||
readingsBulkUpdate ($hash, "isRunning", "false");
|
||||
readingsBulkUpdate ($hash, "state", "off");
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
|
||||
delete($hash->{helper}{RUNNING_PID});
|
||||
|
||||
WOL_SetNextTimer($hash);
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_PingAbort($){
|
||||
my ($hash) = @_;
|
||||
$hash->{INTERVAL} = AttrVal($hash->{NAME}, "interval", 900);
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
my $ip = $hash->{IP};
|
||||
delete($hash->{helper}{RUNNING_PID});
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
|
||||
my $ping = "ping -c 1 -w 2 $ip";
|
||||
my $res = qx ($ping);
|
||||
$res = "" if (!defined($res));
|
||||
|
||||
Log3 $hash, 5, "[$name] executing: $ping";
|
||||
Log3 $hash, 5, "[$name] result of ping:$res";
|
||||
|
||||
if ( $res =~ m/100%/) {
|
||||
Log3 $hash, 5, "[$name] ping not succesful - state = on";
|
||||
readingsBulkUpdate ($hash, "isRunning", "false");
|
||||
readingsBulkUpdate ($hash, "state", "off");
|
||||
} else {
|
||||
Log3 $hash, 5, "[$name] ping succesful - state = on";
|
||||
readingsBulkUpdate ($hash, "isRunning", "true");
|
||||
readingsBulkUpdate ($hash, "state", "on");
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "WOL_UpdateReadings", $hash, 0);
|
||||
Log3 $hash->{NAME}, 3, "BlockingCall for ".$hash->{NAME}." was aborted";
|
||||
WOL_SetNextTimer($hash);
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_GetUpdate($) {
|
||||
my ($hash) = @_;
|
||||
my ($myHash) = @_;
|
||||
|
||||
my $hash = myGetHashIndirekt($myHash, (caller(0))[3]);
|
||||
return if (!defined($hash));
|
||||
|
||||
my $active = ReadingsVal($hash->{NAME}, "active", "nF");
|
||||
if ($active eq "on") {
|
||||
WOL_wake($hash);
|
||||
if ($hash->{REPEAT} > 0) {
|
||||
InternalTimer(gettimeofday()+$hash->{REPEAT}, "WOL_GetUpdate", $hash, 0);
|
||||
myRemoveInternalTimer("wake", $hash);
|
||||
myInternalTimer ("wake", gettimeofday()+$hash->{REPEAT}, "WOL_GetUpdate", $hash, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,29 +218,31 @@ sub WOL_wake($){
|
||||
my $mac = $hash->{MAC};
|
||||
my $host = $hash->{IP};
|
||||
|
||||
$host = '255.255.255.255' if (!defined $host);
|
||||
$host = AttrVal($name, "useUdpBroadcast",$host);
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
|
||||
Log3 $hash, 4, "[$name] keeping $name with MAC $mac IP $host busy";
|
||||
|
||||
if ($hash->{MODE} eq "BOTH" || $hash->{MODE} eq "EW" ) {
|
||||
if ($hash->{MODE} ~~ ["BOTH", "EW" ] ) {
|
||||
WOL_by_ew ($hash, $mac);
|
||||
readingsBulkUpdate ($hash, "packet_via_EW", $mac);
|
||||
}
|
||||
if ($hash->{MODE} eq "BOTH" || $hash->{MODE} eq "UDP" ) {
|
||||
if ($hash->{MODE} ~~ ["BOTH", "UDP"] ) {
|
||||
WOL_by_udp ($hash, $mac, $host);
|
||||
readingsBulkUpdate ($hash, "packet_via_UDP", $host);
|
||||
}
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
}
|
||||
################################################################################
|
||||
# method to wakevia lan, taken from Net::Wake package
|
||||
# method to wake via lan, taken from Net::Wake package
|
||||
sub WOL_by_udp {
|
||||
my ($hash, $mac_addr, $host, $port) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
# use the discard service if $port not passed in
|
||||
if (! defined $host) { $host = '255.255.255.255' }
|
||||
if (! defined $port || $port !~ /^\d+$/ ) { $port = 9 }
|
||||
if (!defined $port || $port !~ /^\d+$/ ) { $port = 9 }
|
||||
|
||||
my $sock = new IO::Socket::INET(Proto=>'udp') or die "socket : $!";
|
||||
if(!$sock) {
|
||||
@ -211,6 +250,7 @@ sub WOL_by_udp {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$host = '192.168.2.255';
|
||||
my $ip_addr = inet_aton($host);
|
||||
my $sock_addr = sockaddr_in($port, $ip_addr);
|
||||
$mac_addr =~ s/://g;
|
||||
@ -254,6 +294,45 @@ sub WOL_by_ew($$) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_SetNextTimer($;$) {
|
||||
my ($hash, $int) = @_;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
$int = AttrVal($hash->{NAME}, "interval", 900) if not defined $int;
|
||||
if ($int != 0) {
|
||||
Log3 $hash, 5, "[$name] WOL_SetNextTimer to $int";
|
||||
myRemoveInternalTimer("ping", $hash);
|
||||
myInternalTimer ("ping", gettimeofday() + $int, "WOL_UpdateReadings", $hash, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
################################################################################
|
||||
sub WOL_Attr($$$) {
|
||||
my ($cmd, $name, $attrName, $attrVal) = @_;
|
||||
|
||||
my $hash = $defs{$name};
|
||||
|
||||
if ($attrName eq "useUdpBroadcast") {
|
||||
if(!($attrVal =~ m/^([0-9]{1,3}([.-]|$)){4}$/i)) {
|
||||
Log3 $hash, 3, "[$name] invalid Broadcastadress<$attrVal> - use ddd.ddd.ddd.ddd";
|
||||
}
|
||||
}
|
||||
|
||||
if ($attrName eq "interval") {
|
||||
RemoveInternalTimer($hash);
|
||||
|
||||
# when deleting the interval we trigger an update in one second
|
||||
my $int = ($cmd eq "del") ? 1 : $attrVal;
|
||||
if ($int != 0) {
|
||||
# restart timer with new interval
|
||||
WOL_SetNextTimer($hash, $int);
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@ -338,7 +417,10 @@ So, for example a Buffalo NAS can be kept awake.
|
||||
attr wol shutdownCmd "/bin/echo "Teatime" > /dev/console" # shell command
|
||||
</PRE>
|
||||
<li><code>attr <name> interval <seconds></code></a>
|
||||
<br>defines the time between two checks by a <i>ping</i> if state of <name> is <i>on</i></li>
|
||||
<br>defines the time between two checks by a <i>ping</i> if state of <name> is <i>on</i> By using 0 as parametr for interval you can switch off checking the device.</li>
|
||||
<li><code>attr <name> useUdpBroadcast <<broardcastAdress>></code>
|
||||
<br>When using UDP then the magic packet can be send to one of the broardcastAdresses (x.x.x.255, x.x.255.255, x.255.255.255) instead of the target host address.
|
||||
Try using this, when you are trying to wake up a machine in your own subnet and the wakekup with the target adress is instable or doesn't work.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user