From 39780a7c923c6b93ad3853078f0095e179e2ddff Mon Sep 17 00:00:00 2001 From: wuehler Date: Fri, 12 Jan 2018 20:39:58 +0000 Subject: [PATCH] 74_Unifi: added set commands to (un)block clients and en/disable WLANs git-svn-id: https://svn.fhem.de/fhem/trunk@15859 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 2 + fhem/FHEM/74_Unifi.pm | 190 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 188 insertions(+), 4 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index b30143998..756419d84 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # 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. + - feature: 74_Unifi: add new set commands to block/unblock clients, + enable/disable WLAN, new client-Reading essid - feature: structure: implement dynamic members via devspec (Forum #82604) - feature: new module 74_UnifiVideo for UnifiVideo integration (justme1968) - change: 93_DbLog: V3.6.2, new attribute "exportCacheAppend", minor fix in diff --git a/fhem/FHEM/74_Unifi.pm b/fhem/FHEM/74_Unifi.pm index 92ec8cc11..c5760b9b9 100644 --- a/fhem/FHEM/74_Unifi.pm +++ b/fhem/FHEM/74_Unifi.pm @@ -46,6 +46,12 @@ sub Unifi_ArchiveAlerts_Send($); sub Unifi_Cmd_Receive($); sub Unifi_ClientNames($@); sub Unifi_ApNames($@); +sub Unifi_BlockClient_Send($@); +sub Unifi_BlockClient_Receive($); +sub Unifi_UnblockClient_Send($@); +sub Unifi_UnblockClient_Receive($); +sub Unifi_WlanconfRest_Send($$@); +sub Unifi_WlanconfRest_Receive($); sub Unifi_NextUpdateFn($$); sub Unifi_ReceiveFailure($$); sub Unifi_CONNECTED($@); @@ -155,14 +161,16 @@ sub Unifi_Set($@) { my $clientNames = Unifi_ClientNames($hash); my $apNames = Unifi_ApNames($hash); + my $SSIDs = Unifi_SSIDs($hash); - if($setName !~ /archiveAlerts|restartAP|setLocateAP|unsetLocateAP|disconnectClient|update|clear|poeMode/) { + if($setName !~ /archiveAlerts|restartAP|setLocateAP|unsetLocateAP|disconnectClient|update|clear|poeMode|blockClient|unblockClient|enableWLAN|disableWLAN/) { return "Unknown argument $setName, choose one of update:noArg " ."clear:all,readings,clientData " .((defined $hash->{alerts_unarchived}[0] && scalar @{$hash->{alerts_unarchived}}) ? "archiveAlerts:noArg " : "") .(($apNames && Unifi_CONNECTED($hash)) ? "restartAP:all,$apNames setLocateAP:all,$apNames unsetLocateAP:all,$apNames " : "") .(($clientNames && Unifi_CONNECTED($hash)) ? "disconnectClient:all,$clientNames " : "") - ."poeMode"; + ."poeMode enableWLAN:$SSIDs disableWLAN:$SSIDs " + ."blockClient:$clientNames unblockClient:$clientNames"; } else { Log3 $name, 4, "$name: set $setName"; @@ -182,6 +190,56 @@ sub Unifi_Set($@) { Unifi_DisconnectClient_Send($hash,keys(%{$hash->{clients}})); } } + elsif ($setName eq 'blockClient') { + if ($setVal && $setVal ne 'all') { + $setVal = Unifi_ClientNames($hash,$setVal,'makeID'); + if (defined $hash->{clients}->{$setVal}) { + Unifi_BlockClient_Send($hash,$setVal); + } + else { + return "$hash->{NAME}: Unknown client '$setVal' in command '$setName', choose one of: all,$clientNames"; + } + } + elsif (!$setVal || $setVal eq 'all') { + Unifi_BlockClient_Send($hash,keys(%{$hash->{clients}})); + } + } + elsif ($setName eq 'unblockClient') { + if ($setVal && $setVal ne 'all') { + $setVal = Unifi_ClientNames($hash,$setVal,'makeID'); + if (defined $hash->{clients}->{$setVal}) { + Unifi_UnblockClient_Send($hash,$setVal); + } + else { + return "$hash->{NAME}: Unknown client '$setVal' in command '$setName', choose one of: all,$clientNames"; + } + } + elsif (!$setVal || $setVal eq 'all') { + Unifi_UnblockClient_Send($hash,keys(%{$hash->{clients}})); + } + } + elsif ($setName eq 'disableWLAN') { + my $wlan = Unifi_SSIDs($hash,$setVal,'makeID'); + if (defined $hash->{wlans}->{$wlan}) { + my $wlanconf = $hash->{wlans}->{$wlan}; + $wlanconf->{enabled}='false'; + Unifi_WlanconfRest_Send($hash,$wlan,$wlanconf); + } + else { + return "$hash->{NAME}: Unknown SSID '$setVal' in command '$setName', choose one of: all,$SSIDs"; + } + } + elsif ($setName eq 'enableWLAN') { + my $wlan = Unifi_SSIDs($hash,$setVal,'makeID'); + if (defined $hash->{wlans}->{$wlan}) { + my $wlanconf = $hash->{wlans}->{$wlan}; + $wlanconf->{enabled}='true'; + Unifi_WlanconfRest_Send($hash,$wlan,$wlanconf); + } + else { + return "$hash->{NAME}: Unknown SSID '$setVal' in command '$setName', choose one of: all,$SSIDs"; + } + } elsif ($setName eq 'poeMode') { return "usage: $setName " if( !$setVal3 ); my $apRef; @@ -648,7 +706,10 @@ sub Unifi_GetWlans_Receive($) { for my $h (@{$data->{data}}) { $hash->{wlans}->{$h->{_id}} = $h; - $hash->{wlans}->{$h->{_id}}->{x_passphrase} = '***'; # Don't show passphrase in list + #TODO: Passphrase ggf. verschlüsseln?! + #Ich musste diese Zeile rausnehmen, sonst ist das Json für enable/disableWLAN bei offenem WLAN (ohne Passphrase) falsch + #Aussternen geht nicht, sonst wird das PW unter Umständen darauf geändert. + #$hash->{wlans}->{$h->{_id}}->{x_passphrase} = '***'; # Don't show passphrase in list } } else { Unifi_ReceiveFailure($hash,$data->{meta}); } @@ -926,6 +987,7 @@ sub Unifi_SetClientReadings($) { readingsBulkUpdate($hash,$clientName."_last_seen",strftime "%Y-%m-%d %H:%M:%S",localtime($clientRef->{last_seen})); readingsBulkUpdate($hash,$clientName."_uptime",$clientRef->{uptime}); readingsBulkUpdate($hash,$clientName."_snr",$clientRef->{rssi}); + readingsBulkUpdate($hash,$clientName."_essid",$clientRef->{essid}); readingsBulkUpdate($hash,$clientName."_accesspoint",$apName); readingsBulkUpdate($hash,$clientName,'connected'); } @@ -1042,6 +1104,85 @@ sub Unifi_DisconnectClient_Receive($) { return undef; } ############################################################################### +sub Unifi_UnblockClient_Send($@) { + my ($hash,@clients) = @_; + my ($name,$self) = ($hash->{NAME},Unifi_Whoami()); + Log3 $name, 5, "$name ($self) - executed with count:'".scalar(@clients)."', ID:'".$clients[0]."'"; + + my $id = shift @clients; + HttpUtils_NonblockingGet( { + %{$hash->{httpParams}}, + url => $hash->{unifi}->{url}."cmd/stamgr", + callback => \&Unifi_UnblockClient_Receive, + clients => [@clients], + data => "{'mac': '".$hash->{clients}->{$id}->{mac}."', 'cmd': 'unblock-sta'}", + } ); + + return undef; +} +############################################################################### +sub Unifi_UnblockClient_Receive($) { + my ($param, $err, $data) = @_; + my ($name,$self,$hash) = ($param->{hash}->{NAME},Unifi_Whoami(),$param->{hash}); + Log3 $name, 5, "$name ($self) - executed."; + + if ($err ne "") { + Unifi_ReceiveFailure($hash,{rc => 'Error while requesting', msg => $param->{url}." - $err"}); + } + elsif ($data ne "") { + if ($param->{code} == 200 || $param->{code} == 400 || $param->{code} == 401) { + eval { $data = decode_json($data); 1; } or do { $data = { meta => {rc => 'error.decode_json', msg => $@} }; }; + + if ($data->{meta}->{rc} eq "ok") { + Log3 $name, 5, "$name ($self) - state:'$data->{meta}->{rc}'"; + } + else { Unifi_ReceiveFailure($hash,$data->{meta}); } + } else { + Unifi_ReceiveFailure($hash,{rc => $param->{code}, msg => "Failed with HTTP Code $param->{code}."}); + } + } + + if (scalar @{$param->{clients}}) { + Unifi_BlockClient_Send($hash,@{$param->{clients}}); + } + + return undef; +} +############################################################################### +sub Unifi_WlanconfRest_Send($$@) { + my ($hash,$id,$data) = @_; + my ($name,$self) = ($hash->{NAME},Unifi_Whoami()); + my $json = encode_json( $data ); + Log3 $name, 5, "$name ($self) - executed with $json."; + HttpUtils_NonblockingGet( { + %{$hash->{httpParams}}, + method => "PUT", + url => $hash->{unifi}->{url}."rest/wlanconf/".$id, + callback => \&Unifi_WlanconfRest_Receive, + aps => [], + data => $json, + } ); + return undef; +} + +sub Unifi_WlanconfRest_Receive($) { + my ($param, $err, $data) = @_; + my ($name,$self,$hash) = ($param->{hash}->{NAME},Unifi_Whoami(),$param->{hash}); + Log3 $name, 3, "$name ($self) - executed."; + + if ($err ne "") { + Unifi_ReceiveFailure($hash,{rc => 'Error while requesting', msg => $param->{url}." - $err"}); + } + elsif ($data ne "") { + if ($param->{code} == 200 || $param->{code} == 400 || $param->{code} == 401) { + eval { $data = decode_json($data); 1; } or do { $data = { meta => {rc => 'error.decode_json', msg => $@} }; }; + } else { + Unifi_ReceiveFailure($hash,{rc => $param->{code}, msg => "Failed with HTTP Code $param->{code}."}); + } + } + return undef; +} +############################################################################### sub Unifi_ApCmd_Send($$@) { #cmd: 'set-locate', 'unset-locate', 'restart' my ($hash,$cmd,@aps) = @_; @@ -1202,6 +1343,39 @@ sub Unifi_ClientNames($@) { } } ############################################################################### +sub Unifi_SSIDs($@){ + my ($hash,$ID,$W) = @_; + + my $wlanRef; + + if(defined $ID && defined $W && $W eq 'makeName') { # Return Name from ID + $wlanRef = $hash->{wlans}->{$ID}; + if (defined $wlanRef->{name} && $wlanRef->{name} =~ /^([\w\.\-]+)$/) { + $ID = $1; + } + return $ID; + } + elsif (defined $ID && defined $W && $W eq 'makeID') { # Return ID from Name + for (keys %{$hash->{wlans}}) { + $wlanRef = $hash->{wlans}->{$_}; + if (defined $wlanRef->{name} && $wlanRef->{name} eq $ID) { + $ID = $_; + last; + } + } + return $ID; + } + else { # Return all aps in a scalar + my $aps = ''; + for my $apID (keys %{$hash->{wlans}}) { + $aps .= Unifi_SSIDs($hash,$apID,'makeName').','; + } + $aps =~ s/.$//; + + return $aps; + } +} +############################################################################### sub Unifi_ApNames($@) { my ($hash,$ID,$W) = @_; @@ -1427,6 +1601,14 @@ Or you can use the other readings or set and get features to control your unifi- Stop 'locate' on one or all accesspoints.
  • set <name> poeMode <name|mac|id> <port> <off|auto|passive|passthrough|restart>
    Set PoE mode for <port>.
  • +
  • set <name> blockClient <clientname>
    + Block the <clientname>
  • +
  • set <name> unblockClient <clientname>
    + Unblocks the <clientname>
  • +
  • set <name> disableWLAN <ssid>
    + Disables WLAN with <ssid>
  • +
  • set <name> enableWLAN <ssid>
    + Enables WLAN with <ssid>
  • @@ -1478,7 +1660,7 @@ Or you can use the other readings or set and get features to control your unifi-

    Readings

      Note: All readings generate events. You can control this with these global attributes. -
    • Each client has 6 readings for connection-state, SNR, uptime, last_seen-time, connected-AP and hostname.
    • +
    • Each client has 7 readings for connection-state, SNR, uptime, last_seen-time, connected-AP, essid and hostname.
    • Each AP has 3 readings for state (can be 'ok' or 'error'), essid's and count of connected-clients.
    • The unifi-controller has 6 readings for event-count in configured 'timePeriod', unarchived-alert count, accesspoint count, overall wlan-state (can be 'ok', 'warning', or other?), connected user count and connected guest count.
    • The Unifi-device reading 'state' represents the connection-state to the unifi-controller (can be 'connected', 'disconnected', 'initialized' and 'disabled').