mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-20 07:16:03 +00:00
74_Unifi: Added support for Controller v3 (v4 already supported).
git-svn-id: https://svn.fhem.de/fhem/trunk@9130 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
e167ccfec5
commit
aab2d16cc2
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# 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.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- feature: 74_Unifi: - Added support for Controller v3 (v4 already supported)
|
||||||
- change: 74_Unifi: - changed get-Name from 'clientDetails' to 'clientData'
|
- change: 74_Unifi: - changed get-Name from 'clientDetails' to 'clientData'
|
||||||
- changed start from defFn to NotifyFn
|
- changed start from defFn to NotifyFn
|
||||||
- added 'get clientData' selection by client-ID
|
- added 'get clientData' selection by client-ID
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# $Id: 74_Unifi.pm 2015-08-24 07:10 - rapster - rapster at x0e dot de $
|
# $Id: 74_Unifi.pm 2015-08-24 23:00 - rapster - rapster at x0e dot de $
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
@ -42,23 +42,27 @@ sub Unifi_Define($$) {
|
|||||||
);
|
);
|
||||||
$hash->{httpParams} = {
|
$hash->{httpParams} = {
|
||||||
hash => $hash,
|
hash => $hash,
|
||||||
timeout => 5,
|
timeout => 8,
|
||||||
method => "POST",
|
method => "POST",
|
||||||
noshutdown => 0,
|
noshutdown => 0,
|
||||||
ignoreredirects => 1,
|
ignoreredirects => 1,
|
||||||
loglevel => 5,
|
loglevel => 5,
|
||||||
sslargs => { SSL_verify_mode => 'SSL_VERIFY_NONE' },
|
sslargs => { SSL_verify_mode => 'SSL_VERIFY_NONE' },
|
||||||
header => "Content-Type: application/json;charset=UTF-8"
|
header => ($hash->{version} == 3) ? undef : "Content-Type: application/json;charset=UTF-8"
|
||||||
};
|
};
|
||||||
$hash->{loginParams} = {
|
$hash->{loginParams} = {
|
||||||
%{$hash->{httpParams}},
|
%{$hash->{httpParams}},
|
||||||
url => $hash->{url}."api/login",
|
|
||||||
data => "{'username':'".$a[4]."', 'password':'".$a[5]."'}",
|
|
||||||
cookies => ($hash->{loginParams}->{cookies}) ? $hash->{loginParams}->{cookies} : '',
|
cookies => ($hash->{loginParams}->{cookies}) ? $hash->{loginParams}->{cookies} : '',
|
||||||
callback => \&Unifi_Login_Receive
|
callback => \&Unifi_Login_Receive
|
||||||
};
|
};
|
||||||
|
if($hash->{version} == 3) {
|
||||||
|
$hash->{loginParams}->{url} = $hash->{url}."login";
|
||||||
|
$hash->{loginParams}->{data} = "login=login&username=".Unifi_Urlencode($a[4])."&password=".Unifi_Urlencode($a[5]);
|
||||||
|
}else {
|
||||||
|
$hash->{loginParams}->{url} = $hash->{url}."api/login";
|
||||||
|
$hash->{loginParams}->{data} = "{'username':'".$a[4]."', 'password':'".$a[5]."'}";
|
||||||
|
}
|
||||||
|
|
||||||
# Don't use old cookies when user, pw or url changed
|
|
||||||
if($oldLoginData && $oldLoginData ne $hash->{loginParams}->{data}.$hash->{url}) {
|
if($oldLoginData && $oldLoginData ne $hash->{loginParams}->{data}.$hash->{url}) {
|
||||||
$hash->{loginParams}->{cookies} = '';
|
$hash->{loginParams}->{cookies} = '';
|
||||||
readingsSingleUpdate($hash,"state","disconnected",1);
|
readingsSingleUpdate($hash,"state","disconnected",1);
|
||||||
@ -216,11 +220,8 @@ sub Unifi_DoUpdate($@) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($hash->{STATE} ne 'connected') {
|
if ($hash->{STATE} ne 'connected') {
|
||||||
if($manual) {
|
readingsSingleUpdate($hash,"state","disconnected",1) if($hash->{STATE} ne 'disconnected');
|
||||||
Log3 $name, 3, "$name: DoUpdate - Manual Updates only allowed while connected, End now...";
|
|
||||||
} else {
|
|
||||||
Unifi_Login_Send($hash)
|
Unifi_Login_Send($hash)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Unifi_GetClients_Send($hash);
|
Unifi_GetClients_Send($hash);
|
||||||
# Do more...
|
# Do more...
|
||||||
@ -255,37 +256,63 @@ sub Unifi_Login_Receive($) {
|
|||||||
if ($err ne "") {
|
if ($err ne "") {
|
||||||
Log3 $name, 5, "$name: Login_Receive - Error while requesting ".$param->{url}." - $err";
|
Log3 $name, 5, "$name: Login_Receive - Error while requesting ".$param->{url}." - $err";
|
||||||
}
|
}
|
||||||
elsif ($data ne "") {
|
elsif ($data ne "" && $hash->{version} == 3) {
|
||||||
if ($param->{code} == 200 || $param->{code} == 400) {
|
if ($data =~ /Invalid username or password/si) {
|
||||||
|
Log3 $name, 1, "$name: Login_Receive - Login Failed! Invalid username or password! Will try again after interval... ";
|
||||||
|
} else {
|
||||||
|
Log3 $name, 5, "$name: Login_Receive - Login Failed! Version 3 should not deliver data on successfull login. Will try again after interval... ";
|
||||||
|
}
|
||||||
|
readingsSingleUpdate($hash,"state","disconnected",1) if($hash->{STATE} ne "disconnected");
|
||||||
|
InternalTimer(time()+$hash->{interval}, 'Unifi_Login_Send', $hash, 0);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
elsif ($data ne "" || $hash->{version} == 3) { # v3 Login is empty if login is successfully
|
||||||
|
if ($param->{code} == 200 || $param->{code} == 400 || $param->{code} == 401 || ($hash->{version} == 3 && ($param->{code} == 302 || $param->{code} == 200))) {
|
||||||
|
if($hash->{version} != 3) {
|
||||||
eval {
|
eval {
|
||||||
$data = decode_json($data);
|
$data = decode_json($data);
|
||||||
1;
|
1;
|
||||||
} or do {
|
} or do {
|
||||||
my $e = $@;
|
my $e = $@;
|
||||||
Log3 $name, 5, "$name: Login_Receive - Failed to decode returned json object! Will try again after interval... - error:$e";
|
Log3 $name, 5, "$name: Login_Receive - Failed to decode returned json object! Will try again after interval... - error:$e";
|
||||||
|
readingsSingleUpdate($hash,"state","disconnected",1) if($hash->{STATE} ne "disconnected");
|
||||||
InternalTimer(time()+$hash->{interval}, 'Unifi_Login_Send', $hash, 0);
|
InternalTimer(time()+$hash->{interval}, 'Unifi_Login_Send', $hash, 0);
|
||||||
return undef;
|
return undef;
|
||||||
};
|
};
|
||||||
if ($data->{meta}->{rc} eq "ok") {
|
}
|
||||||
Log3 $name, 5, "$name: Login_Receive - Login successfully! - state:'$data->{meta}->{rc}'";
|
if ($hash->{version} == 3 || $data->{meta}->{rc} eq "ok") { # v3 has no rc-state
|
||||||
|
Log3 $name, 5, "$name: Login_Receive - state=ok || version=3";
|
||||||
$param->{cookies} = '';
|
$param->{cookies} = '';
|
||||||
for (split("\r\n",$param->{httpheader})) {
|
for (split("\r\n",$param->{httpheader})) {
|
||||||
if(/^Set-Cookie/) {
|
if(/^Set-Cookie/) {
|
||||||
s/Set-Cookie:\s(.*?);.*/Cookie: $1/;
|
s/Set-Cookie:\s(.*?);.*/Cookie: $1/;
|
||||||
$param->{cookies} .= $_.'\r\n';
|
$param->{cookies} .= $_.(($hash->{version} == 3) ? '' : '\r\n'); #v3 has only one cookie and no header at all
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log3 $name, 5, "$name: Login_Receive - Received-cookies:$param->{cookies}";
|
|
||||||
|
|
||||||
|
if($param->{cookies} ne '') {
|
||||||
|
Log3 $name, 5, "$name: Login_Receive - Login successfully! $param->{cookies}";
|
||||||
readingsSingleUpdate($hash,"state","connected",1);
|
readingsSingleUpdate($hash,"state","connected",1);
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
Unifi_DoUpdate($hash);
|
Unifi_DoUpdate($hash);
|
||||||
|
}else {
|
||||||
|
Log3 $name, 5, "$name: Login_Receive - Something went wrong, login seems ok but no cookies received. Will try again after interval...";
|
||||||
|
readingsSingleUpdate($hash,"state","disconnected",1) if($hash->{STATE} ne "disconnected");
|
||||||
|
InternalTimer(time()+$hash->{interval}, 'Unifi_Login_Send', $hash, 0);
|
||||||
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (defined($data->{meta}->{msg})) {
|
if (defined($data->{meta}->{msg})) {
|
||||||
my $loglevel = ($data->{meta}->{msg} eq 'api.err.Invalid') ? 1 : 5;
|
if ($data->{meta}->{msg} eq 'api.err.Invalid') {
|
||||||
Log3 $name, $loglevel, "$name: Login_Receive - Login Failed! - state:'$data->{meta}->{rc}' - msg:'$data->{meta}->{msg}'";
|
Log3 $name, 1, "$name: Login_Receive - Login Failed! Invalid username or password!"
|
||||||
|
." - state:'$data->{meta}->{rc}' - msg:'$data->{meta}->{msg}' - Will try again after interval...";
|
||||||
|
} elsif ($data->{meta}->{msg} eq 'api.err.LoginRequired') {
|
||||||
|
Log3 $name, 1, "$name: Login_Receive - Login Failed! This error while login indicates that you use wrong <version> or"
|
||||||
|
." have to define <version> in your fhem definition. - Will try again after interval...";
|
||||||
|
}else {
|
||||||
|
Log3 $name, 5, "$name: Login_Receive - Login Failed! - state:'$data->{meta}->{rc}' - msg:'$data->{meta}->{msg}'";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log3 $name, 5, "$name: Login_Receive - Login Failed (without message)! - state:'$data->{meta}->{rc}'";
|
Log3 $name, 5, "$name: Login_Receive - Login Failed (without message)! - state:'$data->{meta}->{rc}'";
|
||||||
}
|
}
|
||||||
@ -298,7 +325,7 @@ sub Unifi_Login_Receive($) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log3 $name, 5, "$name: Login_Receive - Connect/Login to Unifi-Controller failed! Will try again after interval...";
|
Log3 $name, 5, "$name: Login_Receive - Connect/Login to Unifi-Controller failed! Will try again after interval...";
|
||||||
readingsSingleUpdate($hash,"state","disconnected",1) if($hash->{READINGS}->{state}->{VAL} ne "disconnected");
|
readingsSingleUpdate($hash,"state","disconnected",1) if($hash->{STATE} ne "disconnected");
|
||||||
InternalTimer(time()+$hash->{interval}, 'Unifi_Login_Send', $hash, 0);
|
InternalTimer(time()+$hash->{interval}, 'Unifi_Login_Send', $hash, 0);
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -311,7 +338,7 @@ sub Unifi_GetClients_Send($) {
|
|||||||
my $param = {
|
my $param = {
|
||||||
%{$hash->{httpParams}},
|
%{$hash->{httpParams}},
|
||||||
url => $hash->{url}."api/s/$hash->{siteID}/stat/sta",
|
url => $hash->{url}."api/s/$hash->{siteID}/stat/sta",
|
||||||
header => $hash->{loginParams}->{cookies}.$hash->{httpParams}->{header},
|
header => ($hash->{version} == 3) ? $hash->{loginParams}->{cookies} : $hash->{loginParams}->{cookies}.$hash->{httpParams}->{header},
|
||||||
callback => \&Unifi_GetClients_Receive
|
callback => \&Unifi_GetClients_Receive
|
||||||
};
|
};
|
||||||
HttpUtils_NonblockingGet($param);
|
HttpUtils_NonblockingGet($param);
|
||||||
@ -327,7 +354,7 @@ sub Unifi_GetClients_Receive($) {
|
|||||||
Log3 $name, 5, "$name: GetClients_Receive - Error while requesting ".$param->{url}." - $err";
|
Log3 $name, 5, "$name: GetClients_Receive - Error while requesting ".$param->{url}." - $err";
|
||||||
}
|
}
|
||||||
elsif ($data ne "") {
|
elsif ($data ne "") {
|
||||||
if ($param->{code} == 200 || $param->{code} == 401 || $param->{code} == 400) {
|
if ($param->{code} == 200 || $param->{code} == 400 || $param->{code} == 401) {
|
||||||
eval {
|
eval {
|
||||||
$data = decode_json($data);
|
$data = decode_json($data);
|
||||||
1;
|
1;
|
||||||
@ -360,8 +387,7 @@ sub Unifi_GetClients_Receive($) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (defined($data->{meta}->{msg})) {
|
if (defined($data->{meta}->{msg})) {
|
||||||
Log3 $name, 5, "$name: GetClients_Receive - Failed! - state:'$data->{meta}->{rc}' - msg:'$data->{meta}->{msg}'";
|
if ($data->{meta}->{msg} eq 'api.err.LoginRequired') {
|
||||||
if($data->{meta}->{msg} eq 'api.err.LoginRequired') {
|
|
||||||
Log3 $name, 5, "$name: GetClients_Receive - LoginRequired detected...";
|
Log3 $name, 5, "$name: GetClients_Receive - LoginRequired detected...";
|
||||||
if($hash->{STATE} ne 'disconnected') {
|
if($hash->{STATE} ne 'disconnected') {
|
||||||
Log3 $name, 5, "$name: GetClients_Receive - I am the first who detected LoginRequired. Do re-login...";
|
Log3 $name, 5, "$name: GetClients_Receive - I am the first who detected LoginRequired. Do re-login...";
|
||||||
@ -370,6 +396,14 @@ sub Unifi_GetClients_Receive($) {
|
|||||||
Unifi_DoUpdate($hash);
|
Unifi_DoUpdate($hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elsif ($data->{meta}->{msg} eq "api.err.NoSiteContext" || ($hash->{version} == 3 && $data->{meta}->{msg} eq "api.err.InvalidObject")) {
|
||||||
|
Log3 $name, 1, "$name: GetClients_Receive - Failed! - state:'$data->{meta}->{rc}' - msg:'$data->{meta}->{msg}'"
|
||||||
|
." - This error indicates that the <siteID> in your definition is wrong."
|
||||||
|
." Try to modify your definition with <sideID> = default. Will try again after interval...";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3 $name, 5, "$name: GetClients_Receive - Failed! - state:'$data->{meta}->{rc}' - msg:'$data->{meta}->{msg}'";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log3 $name, 5, "$name: GetClients_Receive - Failed (without message)! - state:'$data->{meta}->{rc}'";
|
Log3 $name, 5, "$name: GetClients_Receive - Failed (without message)! - state:'$data->{meta}->{rc}'";
|
||||||
}
|
}
|
||||||
@ -383,11 +417,26 @@ sub Unifi_GetClients_Receive($) {
|
|||||||
}
|
}
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
sub Unifi_Urlencode($) {
|
||||||
|
my ($s) = @_;
|
||||||
|
$s =~ s/ /+/g;
|
||||||
|
$s =~ s/([^A-Za-z0-9\+-])/sprintf("%%%02X", ord($1))/seg;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
sub Unifi_Urldecode($) {
|
||||||
|
my ($s) = @_;
|
||||||
|
$s =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
||||||
|
$s =~ s/\+/ /g;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
### KNOWN RESPONSES ###
|
### KNOWN RESPONSES ###
|
||||||
# { "data" : [ ] , "meta" : { "msg" : "api.err.Invalid" , "rc" : "error"}}
|
# { "data" : [ ] , "meta" : { "msg" : "api.err.Invalid" , "rc" : "error"}} //Invalid Login credentials in v4, in v3 the login-html-page is returned
|
||||||
# { "data" : [ ] , "meta" : { "rc" : "ok"}}
|
# { "data" : [ ] , "meta" : { "rc" : "ok"}}
|
||||||
# { "data" : [ ] , "meta" : { "msg" : "api.err.NoSiteContext" , "rc" : "error"}}
|
# { "data" : [ ] , "meta" : { "msg" : "api.err.InvalidObject" , "rc" : "error"}} //Wrong siteID in v3
|
||||||
# { "data" : [ ] , "meta" : { "msg" : "api.err.LoginRequired" , "rc" : "error"}}
|
# { "data" : [ ] , "meta" : { "msg" : "api.err.NoSiteContext" , "rc" : "error"}} //Wrong siteID in v4
|
||||||
|
# { "data" : [ ] , "meta" : { "msg" : "api.err.LoginRequired" , "rc" : "error"}} //Login Required / cookie is invalid / Unifi v4 is used wiith controller v3
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
@ -441,19 +490,22 @@ The device will be still connected, even it is in PowerSave-Mode. (In this mode
|
|||||||
</ul>
|
</ul>
|
||||||
[<interval>]:
|
[<interval>]:
|
||||||
<ul>
|
<ul>
|
||||||
<code>optional: interval to fetch the information from the unifi-api. <br>
|
<code>(optional without <siteID> and <version>)<br>
|
||||||
|
Interval to fetch the information from the unifi-api. <br>
|
||||||
default: 30 seconds</code><br>
|
default: 30 seconds</code><br>
|
||||||
</ul>
|
</ul>
|
||||||
[<siteID>]:
|
[<siteID>]:
|
||||||
<ul>
|
<ul>
|
||||||
<code>optional: You can find the site-ID by selecting the site in the UniFi web interface.<br>
|
<code>(optional without <version>)<br>
|
||||||
e.g. (https://localhost:8443/manage/s/foobar) siteId = 'foobar'.<br>
|
You can find the site-ID by selecting the site in the UniFi web interface.<br>
|
||||||
default: 'default'</code><br>
|
e.g. https://192.168.12.13:8443/manage/s/foobar the siteId you must use is: foobar.<br>
|
||||||
|
default: default</code><br>
|
||||||
</ul>
|
</ul>
|
||||||
[<version>]:
|
[<version>]:
|
||||||
<ul>
|
<ul>
|
||||||
<code>optional: Your unifi-controller version.<br>
|
<code>(optional if you use unifi v4)<br>
|
||||||
This is not used at the moment, both v3.x and v4.x controller are supported.<br>
|
Unifi-controller version. <br>
|
||||||
|
Version must be specified if version is not 4. At the moment version 3 and 4 are supported.<br>
|
||||||
default: 4</code><br>
|
default: 4</code><br>
|
||||||
</ul> <br>
|
</ul> <br>
|
||||||
<br>
|
<br>
|
||||||
@ -470,8 +522,7 @@ The device will be still connected, even it is in PowerSave-Mode. (In this mode
|
|||||||
<h4>Set</h4>
|
<h4>Set</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>set <name> update</code><br>
|
<li><code>set <name> update</code><br>
|
||||||
Makes immediately a manual update. </li><br>
|
Makes immediately a manual update. </li>
|
||||||
Note: Manual updates are only possible while unifi-controller is connected and device is not disabled.
|
|
||||||
</ul><br>
|
</ul><br>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>set <name> clear <readings|clientData|all></code><br>
|
<li><code>set <name> clear <readings|clientData|all></code><br>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user