diff --git a/fhem/FHEM/74_UnifiSwitch.pm b/fhem/FHEM/74_UnifiSwitch.pm index e160d9758..5b60b702b 100755 --- a/fhem/FHEM/74_UnifiSwitch.pm +++ b/fhem/FHEM/74_UnifiSwitch.pm @@ -34,6 +34,7 @@ use strict; use warnings; use POSIX; use JSON qw(decode_json); +use JSON qw(encode_json); ### Forward declarations ####################################################{ sub UnifiSwitch_Initialize($$); @@ -55,7 +56,8 @@ sub UnifiSwitch_Initialize($$) { $hash->{AttrFn} = "UnifiSwitch_Attr"; $hash->{SetFn} = "UnifiSwitch_Set"; $hash->{GetFn} = "UnifiSwitch_Get"; - $hash->{AttrList} = $readingFnAttributes; + $hash->{AttrList} = "portProfileDisableID ". + $readingFnAttributes; # TODO: notwendig? $hash->{Match} = "^UnifiSwitch"; # TODO ATTR wird nicht übernommen @@ -94,9 +96,19 @@ sub UnifiSwitch_Undef($$){ } sub UnifiSwitch_Attr(@){ - my @a = @_; - return undef; + my ($cmd,$name,$attr_name,$attr_value) = @_; + my $hash = $defs{$name}; + + #if($cmd eq "set") { + # if($attr_name eq "portProfileDisableID") { + # } + #} + #elsif($cmd eq "del") { + # if($attr_name eq "portProfileDisableID") { + # } + #} + return undef; } @@ -111,78 +123,88 @@ sub UnifiSwitch_Set($@){ # Log3 $name, 5, "$name: set called with $setName but device is disabled!" if($setName ne "?"); # return undef; #} - if($setName !~ /clear|poeMode/) { - return "Unknown argument $setName, choose one of " - ."clear:all,readings poeMode "; #TODO: PortNamen sowie die Modes als Auswahl anhängen - } else { - Log3 $name, 4, "$name: set $setName"; - if ($setName eq 'poeMode') { - return "usage: $setName " if( !$setVal ); - my $apRef; - my $ap = $hash->{usw}; - return "switch has no poe-ports!" if( !$ap->{port_table} ); - $apRef = $ap; - if( $setVal !~ m/\d+/ ) { - for my $port (@{$apRef->{port_table}}) { - next if( $port->{name} !~ $setVal ); - $setVal = $port->{port_idx}; - last; - } - } - return "port-ID musst be numeric" if( $setVal !~ m/\d+/ ); - return "port musst be in [1..". scalar @{$apRef->{port_table}} ."] " if( $setVal < 1 || $setVal > scalar @{$apRef->{port_table}} ); - return "switch '$apRef->{name}' has no port $setVal" if( !defined(@{$apRef->{port_table}}[$setVal-1] ) ); - return "port $setVal of switch '$apRef->{name}' is not poe capable" if( !@{$apRef->{port_table}}[$setVal-1]->{port_poe} ); + my $portProfileDisableID=AttrVal($name,"portProfileDisableID",undef); + my $isPortprofileID = undef; + $isPortprofileID ="disablePort" if (defined $portProfileDisableID); + if($setName !~ /clear|poeMode|disablePort/) { + return "Unknown argument $setName, choose one of " + ."clear:all,readings poeMode ".$isPortprofileID; #TODO: PortNamen sowie die Modes als Auswahl anhängen + } else { + Log3 $name, 4, "$name: set $setName"; + my $apRef = $hash->{usw}; + if( $setVal !~ m/\d+/ ) { #falls der Portname angegeben wurde, diesen in eine ID umwandeln. + for my $port (@{$apRef->{port_table}}) { + next if( $port->{name} !~ $setVal ); + $setVal = $port->{port_idx}; + last; + } + } + my $port_overrides = $apRef->{port_overrides}; + my $idx; + my $i = 0; + for my $entry (@{$port_overrides}) { + if( defined $entry->{port_idx}){ + if($entry->{port_idx} eq $setVal) { + $idx = $i; + #last; + } + } + else{ + splice(@{$port_overrides},$i,1); #manchmal kommen Einträge ohne ID hinzu. Dies führt bei vielen Overrides zu einem Fehler, da mehr Overrides als Ports vorhanden sein können. Hier wird aufgeräumt. + } + ++$i; + } + if( !defined($idx) ) { + push @{$port_overrides}, {port_idx => $setVal+0}; + $idx = scalar @{$port_overrides}; + } + return "port-ID musst be numeric" if( $setVal !~ m/\d+/ ); + return "switch has no ports!" if( !$apRef->{port_table} ); + return "port musst be in [1..". scalar @{$apRef->{port_table}} ."] " if( $setVal < 1 || $setVal > scalar @{$apRef->{port_table}} ); + return "switch '$apRef->{name}' has no port $setVal" if( !defined(@{$apRef->{port_table}}[$setVal-1] ) ); + + if( $setName eq 'disablePort' ) { + $port_overrides->[$idx]{portconf_id} = $portProfileDisableID; + IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); + }elsif ($setName eq 'poeMode') { + return "usage: $setName " if( !$setVal ); + return "port $setVal of switch '$apRef->{name}' is not poe capable" if( !@{$apRef->{port_table}}[$setVal-1]->{port_poe} ); - my $port_overrides = $apRef->{port_overrides}; - my $idx; - my $i = 0; - for my $entry (@{$port_overrides}) { - if( defined $entry->{port_idx} && ($entry->{port_idx} eq $setVal) ) { - $idx = $i; - last; - } - ++$i; - } - if( !defined($idx) ) { - push @{$port_overrides}, {port_idx => $setVal+0}; - $idx = scalar @{$port_overrides}; - } - if( $setVal2 eq 'off' ) { - $port_overrides->[$idx]{poe_mode} = "off"; - IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); + if( $setVal2 eq 'off' ) { + $port_overrides->[$idx]{poe_mode} = "off"; + IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); - } elsif( $setVal2 eq 'auto' || $setVal2 eq 'poe+' ) { - #return "port $setVal not auto poe capable" if( @{$apRef->{port_table}}[$setVal-1]->{poe_caps} & 0x03 ) ; - $port_overrides->[$idx]{poe_mode} = "auto"; - IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides ); + } elsif( $setVal2 eq 'auto' || $setVal2 eq 'poe+' ) { + #return "port $setVal not auto poe capable" if( @{$apRef->{port_table}}[$setVal-1]->{poe_caps} & 0x03 ) ; + $port_overrides->[$idx]{poe_mode} = "auto"; + IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides ); - } elsif( $setVal2 eq 'passive' ) { - #return "port $setVal not passive poe capable" if( @{$apRef->{port_table}}[$setVal-1]->{poe_caps} & 0x04 ) ; - $port_overrides->[$idx]{poe_mode} = "pasv24"; - IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); + } elsif( $setVal2 eq 'passive' ) { + #return "port $setVal not passive poe capable" if( @{$apRef->{port_table}}[$setVal-1]->{poe_caps} & 0x04 ) ; + $port_overrides->[$idx]{poe_mode} = "pasv24"; + IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); - } elsif( $setVal2 eq 'passthrough' ) { - #return "port $setVal not passthrough poe capable" if( @{$apRef->{port_table}}[$setVal-1]->{poe_caps} & 0x08 ) ; - $port_overrides->[$idx]{poe_mode} = "passthrough"; - IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); + } elsif( $setVal2 eq 'passthrough' ) { + #return "port $setVal not passthrough poe capable" if( @{$apRef->{port_table}}[$setVal-1]->{poe_caps} & 0x08 ) ; + $port_overrides->[$idx]{poe_mode} = "passthrough"; + IOWrite($hash, "Unifi_DeviceRestJson_Send", $apRef->{device_id}, $port_overrides); - } elsif( $setVal2 eq 'restart' ) {#TODO: Was wir hier gemacht? Funktioniert das noch? - IOWrite($hash, "Unifi_ApJson_Send", $apRef->{device_id}, {cmd => 'power-cycle', mac => $apRef->{mac}, port_idx => $setVal}); + } elsif( $setVal2 eq 'restart' ) {#TODO: Was wir hier gemacht? Funktioniert das noch? + IOWrite($hash, "Unifi_ApJson_Send", $apRef->{device_id}, {cmd => 'power-cycle', mac => $apRef->{mac}, port_idx => $setVal}); - } else { - return "unknwon poe mode $setVal2"; - } - }elsif ($setName eq 'clear') { - if ($setVal eq 'readings' || $setVal eq 'all') { - for (keys %{$hash->{READINGS}}) { - delete $hash->{READINGS}->{$_} if($_ ne 'state'); - } - } - } - } - return undef; + }else { + return "unknwon poe mode $setVal2"; + } + }elsif ($setName eq 'clear') { + if ($setVal eq 'readings' || $setVal eq 'all') { + for (keys %{$hash->{READINGS}}) { + delete $hash->{READINGS}->{$_} if($_ ne 'state'); + } + } + } + } + return undef; } @@ -197,8 +219,8 @@ sub UnifiSwitch_Get($@){ Log3 $name, 5, "$name: get called with $getName."; } - if($getName !~ /poeState/) { - return "Unknown argument $getName, choose one of poeState"; + if($getName !~ /poeState|portOverrides/) { + return "Unknown argument $getName, choose one of poeState:noArg portOverrides:noArg"; } elsif ($getName eq 'poeState') { my $poeState; @@ -209,12 +231,12 @@ sub UnifiSwitch_Get($@){ $poeState .= "\n" if( $poeState ); $poeState .= sprintf( "%-20s (mac:%-17s, id:%s)\n", $apRef->{name}, $apRef->{mac}, $apRef->{device_id} ); $poeState .= sprintf( " %2s %-15s", "id", "name" ); - $poeState .= sprintf( " %s %s %-6s %-4s %-10s", "", "on", "mode", "", "class" ); + $poeState .= sprintf( " %s %-6s %-4s %s %-10s", " ", "on", "mode", " ", "class" ); $poeState .= "\n"; for my $port (@{$apRef->{port_table}}) { #next if( !$port->{port_poe} ); $poeState .= sprintf( " %2i %-15s", $port->{port_idx}, $port->{name} ); - $poeState .= sprintf( " %s %s %-6s %-4s %-10s", $port->{poe_caps}, $port->{poe_enable}, $port->{poe_mode}, defined($port->{poe_good})?($port->{poe_good}?"good":""):"", defined($port->{poe_class})?$port->{poe_class}:"" ) if( $port->{port_poe} ); + $poeState .= sprintf( " %s %-6s %-4s %s %-10s", $port->{poe_caps}, $port->{poe_enable}, $port->{poe_mode}, defined($port->{poe_good})?($port->{poe_good}?"good":""):"", defined($port->{poe_class})?$port->{poe_class}:"" ) if( $port->{port_poe} ); $poeState .= sprintf( " %5.2fW %5.2fV %5.2fmA", $port->{poe_power}?$port->{poe_power}:0, $port->{poe_voltage}, $port->{poe_current}?$port->{poe_current}:0 ) if( $port->{port_poe} ); $poeState .= "\n"; } @@ -223,6 +245,29 @@ sub UnifiSwitch_Get($@){ $poeState .= "====================================================\n"; return $poeState; } + elsif ($getName eq 'portOverrides') { + my $portOverrides; + my $apRef = $hash->{usw}; + next if( $apRef->{type} ne 'usw' ); + next if( !$apRef->{port_table} ); + next if( $getVal && $getVal ne $apRef->{mac} && $getVal ne $apRef->{device_id} && $apRef->{name} !~ $getVal ); + $portOverrides .= "\n" if( $portOverrides ); + $portOverrides .= sprintf( "%-20s (mac:%-17s, id:%s)\n", $apRef->{name}, $apRef->{mac}, $apRef->{device_id} ); + $portOverrides .= sprintf( " %2s %-15s", "id", "name" ); + $portOverrides .= sprintf( " %-10s %-25s", "poe_mode", "PortConfigID" ); + $portOverrides .= "\n"; + for my $port (@{$apRef->{port_overrides}}) { + if(defined $port->{port_idx}){ + $portOverrides .= sprintf( " %2i %-15s", $port->{port_idx}, $port->{name}?$port->{name}:"" ); + $portOverrides .= sprintf( " %-10s %-25s", $port->{poe_mode}?$port->{poe_mode}:"", $port->{portconf_id}?$port->{portconf_id}:""); + $portOverrides .= "\n"; + } + } + + $portOverrides = "====================================================\n". $portOverrides; + $portOverrides .= "====================================================\n"; + return $portOverrides; + } return undef; } @@ -272,6 +317,9 @@ sub UnifiSwitch_Parse($$) { } } } + + + readingsEndUpdate($hash,1); } Log3 $name, 5, "$name ($self) - return: ".$hash->{NAME}; @@ -346,6 +394,10 @@ You can use the readings or set features to control your unifi-switch.
  • set <name> poeMode <port> <off|auto|passive|passthrough|restart>
    Set PoE mode for <port>.
  • +
    +
  • set <name> disablePort <port>
    + Only visible when Attr portProfileDisableID is set.
    + Set the PortProfile from Attr portProfileDisableID for <port>.
  • Get

    @@ -353,9 +405,24 @@ You can use the readings or set features to control your unifi-switch.
  • get <name> poeState
    Show more details about the ports of the switch.

  • +
  • get <name> portOverrides
    + Show more details about the portOverrides of the switch.
  • +
    + + +

    Attributes

    +
      +
    • attr portProfileDisableID
      + Quick Workaround for special purposes: Must contain the ID off the disable-PortConfig. Then set disablePort can be used.
      + The ID can be found with get portOverrides.
      + To enable the port the UnifiController-Software must be used.
    • +
      +
    • readingFnAttributes
    • +
    +

    Readings