diff --git a/fhem/CHANGED b/fhem/CHANGED index 1624f099c..9b47a003f 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # 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. + - added: 37_dash_dhcp.pm: new module for amazon dash buttons - feature: 98_Hyperion: removed attribute hyperionAttrRestore default attributes just being added on define - added: 73_NUKIBridge,74_NUKIDevice: New Modules to control Nuki Smartlocks diff --git a/fhem/FHEM/37_dash_dhcp.pm b/fhem/FHEM/37_dash_dhcp.pm new file mode 100644 index 000000000..6c6752088 --- /dev/null +++ b/fhem/FHEM/37_dash_dhcp.pm @@ -0,0 +1,278 @@ + +# $Id$ + +package main; + +use strict; +use warnings; + +use IO::Socket::INET; + +sub +dash_dhcp_Initialize($) +{ + my ($hash) = @_; + + $hash->{ReadFn} = "dash_dhcp_Read"; + + $hash->{DefFn} = "dash_dhcp_Define"; + $hash->{NOTIFYDEV} = "global"; + $hash->{NotifyFn} = "dash_dhcp_Notify"; + $hash->{UndefFn} = "dash_dhcp_Undefine"; + #$hash->{SetFn} = "dash_dhcp_Set"; + #$hash->{GetFn} = "dash_dhcp_Get"; + $hash->{AttrFn} = "dash_dhcp_Attr"; + $hash->{AttrList} = "disable:1,0 disabledForIntervals allowed port $readingFnAttributes"; +} + +##################################### + +sub +dash_dhcp_Define($$) +{ + my ($hash, $def) = @_; + + my @a = split("[ \t][ \t]*", $def); + + return "Usage: define dash_dhcp" if(@a != 2); + + my $name = $a[0]; + $hash->{NAME} = $name; + + if( $init_done ) { + dash_dhcp_startListener($hash); + + } elsif( $hash->{STATE} ne "???" ) { + readingsSingleUpdate($hash, 'state', 'initialized', 1 ); + + } + + return undef; +} + +sub +dash_dhcp_Notify($$) +{ + my ($hash,$dev) = @_; + + return if($dev->{NAME} ne "global"); + return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}})); + + dash_dhcp_startListener($hash); + + return undef; +} + +sub +dash_dhcp_startListener($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + dash_dhcp_stopListener($hash); + + return undef if( IsDisabled($name) > 0 ); + + $hash->{PORT} = (getlogin eq 'root')?67:6767; + $hash->{PORT} = AttrVal($name, 'port', $hash->{PORT}); + Log3 $name, 4, "$name: using port $hash->{PORT}"; + + my $socket = IO::Socket::INET->new(LocalPort=>$hash->{PORT}, Proto=>'udp', Broadcast=>1, ReuseAddr=>1, ReusePort=>defined(&ReusePort)?1:0); + if($socket) { + readingsSingleUpdate($hash, 'state', 'listening', 1 ); + $hash->{LAST_CONNECT} = FmtDateTime( gettimeofday() ); + + $hash->{FD} = $socket->fileno(); + $hash->{CD} = $socket; # sysread / close won't work on fileno + $hash->{CONNECTS}++; + $selectlist{$name} = $hash; + + } else { + Log3 $name, 2, "$name: failed to open port $hash->{PORT} $@"; + + dash_dhcp_stopListener($hash); + InternalTimer(gettimeofday()+30, "dash_dhcp_startListener", $hash, 0); + + } +} +sub +dash_dhcp_stopListener($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + RemoveInternalTimer($hash); + + return if( !$hash->{CD} ); + + close($hash->{CD}) if($hash->{CD}); + delete($hash->{FD}); + delete($hash->{CD}); + delete($selectlist{$name}); + readingsSingleUpdate($hash, 'state', 'disconnected', 1 ); + Log3 $name, 3, "$name: Disconnected"; + $hash->{LAST_DISCONNECT} = FmtDateTime( gettimeofday() ); +} + +sub +dash_dhcp_Undefine($$) +{ + my ($hash, $arg) = @_; + + dash_dhcp_stopListener($hash); + + return undef; +} + +sub +dash_dhcp_Set($$@) +{ + my ($hash, $name, $cmd, @args) = @_; + + my $list = ""; + + return "Unknown argument $cmd, choose one of $list"; +} + +sub +dash_dhcp_Get($$@) +{ + my ($hash, $name, $cmd) = @_; + + my $list = ""; + + return "Unknown argument $cmd, choose one of $list"; +} + +sub +dash_dhcp_Parse($$;$) +{ + my ($hash,$data,$peerhost) = @_; + my $name = $hash->{NAME}; + + my $chaddr; + if (($data) =~ /^.*DHCPACK[^:]*([\da-z]{2}(:[\da-z]{2}){5}) .*/ ) { + $chaddr=$1; + + } else { + my ($op, $htype, $hlen, $hops, $xid, $secs, $flags ) = unpack( 'CCCCNnn', $data ); + #my $ciaddr = join '.', unpack('C4', substr($data, 12 ) ); + #my $yiaddr = join '.', unpack('C4', substr($data, 16 ) ); + #my $siaddr = join '.', unpack('C4', substr($data, 20 ) ); + #my $giaddr = join '.', unpack('C4', substr($data, 24 ) ); + $chaddr = join ':', unpack('(H2)*', substr($data, 28, $hlen ) ); + + } + + my $allowed = AttrVal($name, "allowed", undef ); + if( !$chaddr || $chaddr !~ m/[\da-z]{2}(:[\da-z]{2}){5}/i ) { + $chaddr = '' if( !$chaddr ); + Log3 $name, 2, "$name: invalid mac: $chaddr"; + + } elsif( !$allowed || ",$allowed," =~/,$chaddr,/ ) { + Log3 $name, 4, "$name: got $chaddr"; + + $chaddr =~ s/:/-/g; + readingsSingleUpdate( $hash, $chaddr, 'short', 1 ); + + } else { + Log3 $name, 4, "$name: ignoring $chaddr"; + + } + +} + +sub +dash_dhcp_Read($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + my $len; + my $buf; + + $len = $hash->{CD}->recv($buf, 1024); + if( !defined($len) || !$len ) { +Log 1, "!!!!!!!!!!"; + return; + } + + #$buf = pack('H*', '010106000597ee0e05b90000c0a8a10d000000000000000000000000005056a3e69700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633501030c0a646e732d7562756e7475370d011c02030f06770c2c2f1a792aff0000000000000000000000000000000000000000000000000000000000' ); + + dash_dhcp_Parse($hash, $buf, $hash->{CD}->peerhost); +} + +sub +dash_dhcp_Attr($$$) +{ + my ($cmd, $name, $attrName, $attrVal) = @_; + + my $orig = $attrVal; + + my $hash = $defs{$name}; + if( $attrName eq "disable" ) { + if( $cmd eq 'set' && $attrVal ne "0" ) { + dash_dhcp_stopListener($hash); + } else { + $attr{$name}{$attrName} = 0; + dash_dhcp_startListener($hash); + } + } elsif( $attrName eq "disabledForIntervals" ) { + delete $attr{$name}{$attrName}; + $attr{$name}{$attrName} = $attrVal if( $cmd eq 'set' ); + + dash_dhcp_startListener($hash); + + } elsif( $attrName eq "port" ) { + delete $attr{$name}{$attrName}; + $attr{$name}{$attrName} = $attrVal if( $cmd eq 'set' ); + + dash_dhcp_startListener($hash); + } + + if( $cmd eq 'set' ) { + if( $orig ne $attrVal ) { + $attr{$name}{$attrName} = $attrVal; + return $attrName ." set to ". $attrVal; + } + } + + return; +} + + +1; + +=pod +=item summary module for the amazon dash button +=item summary_DE Modul für den amazon dash button +=begin html + + +

dash_dhcp

+
+ +=end html +=cut diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index 1c5e68dc1..5b50b60f2 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -166,6 +166,7 @@ FHEM/36_Level.pm HCS http://forum.fhem.de Sonstige FHEM/36_WMBUS.pm kaihs http://forum.fhem.de Sonstige Systeme FHEM/37_SHC.pm rr2000 http://forum.fhem.de Sonstige Systeme FHEM/37_SHCdev.pm rr2000 http://forum.fhem.de Sonstige Systeme +FHEM/37_dash_dhcp.pm justme1968 http://forum.fhem.de Sonstige Systeme FHEM/37_fakeRoku.pm justme1968 http://forum.fhem.de Multimedia FHEM/37_harmony.pm justme1968 http://forum.fhem.de Multimedia FHEM/37_plex.pm justme1968 http://forum.fhem.de Multimedia