Neues Modul - 74_Unifi - Für den Ubiquiti Networks (UBNT) - Unifi Controller

Begonnen von rapster, 23 August 2015, 02:12:04

Vorheriges Thema - Nächstes Thema

Wuehler

Hallo,

die Ursache meines oben beschriebenes Performance-Problems kommt sehr wahrscheinlich daher, dass sowohl fhem als auch der Unifi-Controller auf demselben RasPi laufen. Das ist dann wohl doch etwas zu viel für den Kleinen als Abfragen-HTTP-Requests direkt hintereinander abzuschicken, durch den Unifi-Controller beantworten und die Antworten zu dekodieren. Da mich momentan nur die Clients interessieren bin ich mit dem Auskommentieren der anderen Aufrufe glücklich.

Da die Kinder aber immer öfter Besuch mit Handy-WLAN-Wünschen bekommen habe ich mir ein Voucher-Gast-WLAN eingerichtet. Jetzt wäre es Klasse, die Voucher-IDs per TelegramBot abfragen zu können.
Dazu habe ich auch schonmal ein wenig programmiert (als PERL- und Modul-Newebie nicht ganz so einfach :-), stoße aber beim Verstehen des Codes an meine Grenzen :-(
Mein Code dazu sieht aktuell folgendermaßen aus (zum Ausprobieren habe ich das Modul bei mir in MyUnifi umbenannt):

Voucher erzeugen:

sub MyUnifi_CreateVoucher_Send($) {
    my ($hash) = @_;
    my ($name,$self) = ($hash->{NAME},MyUnifi_Whoami());
    Log3 $name, 5, "$name ($self) - executed.";

    HttpUtils_NonblockingGet( {
                 %{$hash->{httpParams}},
        url      => $hash->{unifi}->{url}."cmd/hotspot",
        callback => \&MyUnifi_CreateVoucher_Cmd_Receive,
        data     => "{'cmd': 'create-voucher', 'expire': '120', 'n': '1', 'quota': '1', 'note': 'by FHEM'}",
    } );
    return undef;
}

sub MyUnifi_CreateVoucher_Cmd_Receive($) {
    my ($param, $err, $data) = @_;
    my ($name,$self,$hash) = ($param->{hash}->{NAME},MyUnifi_Whoami(),$param->{hash});
    Log3 $name, 5, "$name ($self) - executed.";

    if ($err ne "") {
        MyUnifi_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) - voucher_create_time:'$data->{data}[0]->{create_time}'";
                $hash->{CreatedVoucherTime}=$data->{data}[0]->{create_time};
            }
            else { MyUnifi_ReceiveFailure($hash,$data->{meta}); }
        } else {
            MyUnifi_ReceiveFailure($hash,{rc => $param->{code}, msg => "Failed with HTTP Code $param->{code}."});
        }
    }
    MyUnifi_GetCreatedVoucher_Send($hash);
    return undef;
}



Voucher auslesen:

sub MyUnifi_GetCreatedVoucher_Send($) {
    my ($hash) = @_;
    my ($name,$self) = ($hash->{NAME},MyUnifi_Whoami());
    Log3 $name, 5, "$name ($self) - executed.";

    HttpUtils_NonblockingGet( {
                 %{$hash->{httpParams}},
        method   => "GET",
        url      => $hash->{unifi}->{url}."stat/voucher",
        callback => \&MyUnifi_GetCreatedVoucher_Receive,
    } );
    return undef;
}
sub MyUnifi_GetCreatedVoucher_Receive($) {
    my ($param, $err, $data) = @_;
    my ($name,$self,$hash) = ($param->{hash}->{NAME},MyUnifi_Whoami(),$param->{hash});
    Log3 $name, 5, "$name ($self) - executed.";

    if ($err ne "") {
        MyUnifi_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}'";
                for my $h (@{$data->{data}}) {
                    if (defined($h->{create_time})) {
                        #$hash->{wlan_health} = $h;
                        if ($h->{create_time} eq $hash->{CreatedVoucherTime}) {
                            Log3 $name, 5, "$name ($self) - Treffer     -----:'$h->{code}'";
                            readingsBeginUpdate($hash);
                            readingsBulkUpdate($hash,"CreatedVoucherCode",$h->{code});
                            readingsEndUpdate($hash,1);
                        }
                    }
                }
            }
            else { MyUnifi_ReceiveFailure($hash,$data->{meta}); }
        } else {
            MyUnifi_ReceiveFailure($hash,{rc => $param->{code}, msg => "Failed with HTTP Code $param->{code}."});
        }
    }

    #MyUnifi_NextUpdateFn($hash,$self);
    return undef;
}


(plus Erweiterung der set-Methode)

Dabei habe ich gelernt, dass es aus Gründen der Vermeidung von Blockierung sinnvoller wäre, die Voucher-IDs in FHEM vorzuhalten (als Cache) und wenn der Cache z.B. nur noch 5 Voucher enthält ein paar auf einmal zu generieren und den Cache zu füllen. Bei jeder Auslieferung eines Vouchers müsste die entsprechende ID dann aus dem Cache gelöscht werden und evtl. erstmal für einen Tag (?) in eine Blacklist, so dass diese ID nicht mehrmals ausgeliefert wird.
Beim Auruf der Unifi-Api geholfen hat mir https://github.com/malle-pietje/UniFi-API-browser/blob/master/phpapi/class.unifi.php.

Wie wäre die Implementierung am sinnvollsten? Ggf. als Submodul? Es gibt jetzt schon recht viele Readings. Ausserdem ist der UseCase ggü. dem bisherigen "Überwachungs"-Case ein anderer und hat daher evtl. keine Update-Intervalle sondern steuert sich selbst nach Verbrauch.

Ein frohes neues Jahr wünscht der
Wühler

justme1968

ich bin gerade dabei ein unifi usg in betrieb zu nehmen und es kommen demnächst vermutlich noch ein paar unifi switches dazu.

das usg führt aktuell zu einem komischen verhalten im modul:
- es taucht als accesspoint auf, ich weiss noch nicht ob das sinnvoll ist
- ich habe readings für einen zusätzlichen ap mit der ip 192.168.1.1. das ist die default ip des usg die es aber nicht mehr hat
- alle lan clients tauchen jetzt mit reading auf, sind aber mehr oder weniger zufällig einem der wlan ap zugeordnet.
  nicht dem usg

ich glaube hier gibt es noch optimierungsbedarf bzw. anpassungen wenn nicht nur wlan aps am unifi controller hängen.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rapster

Das stimmt allerdings Andre :-)
Würde mir gerne ein möglichst vollständiges (ohne PW...) Dumper($defs{unifi}) von dir anschauen,
allerdings vermute ich dass hier nicht alles der usg dabei sein wird und separat abgefragt werden muss.

Unschön die usg mit in das unifi-device aufzunehmen,
es sollte dann auch gleich das Aufteilen des Moduls in mehrere Geräte gemacht werden.

Bin allerdings die letzten Wochen schon kaum zum schlafen gekommen :-)
Hoffe (denke) dass es allerdings in Kürze? ruhiger wird und ich mal wieder mehr zu fhem komme!

Falls du allerdings an dem Modul Optimierungen durchführen willst, oder Patches damit es schneller geht, gerne :-)

Gruß Claudiu



Hauswart

1. Installation:
KNX, Tasmota (KNX), Sonos, Unifi

2. Installation:
HM-CFG-USB, Unifi (, SIGNALduino 868, MySensors, SIGNALduino 433)

justme1968

du kannst z.b. die unifi connected/disconnected mit einem PRESENCE function {ReadingsVal(...) eq 'connected'} in ein PRESENCE devicvice übernehmen.

aktuell noch mit einem kleinen BlockingCall overhead der eigentlich nicht nötig ist. das ist aber nicht kritisch.

gruss
andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Hauswart

Zitat von: justme1968 am 09 Januar 2017, 14:17:03
du kannst z.b. die unifi connected/disconnected mit einem PRESENCE function {ReadingsVal(...) eq 'connected'} in ein PRESENCE devicvice übernehmen.
Danke dir. Habe es nur schnell testen können, aber erhalte eine Fehlermeldung:
define Unifi_test PRESENCE function {ReadingsVal("UniFi","NameDevice") eq "connected"}
ergibt einen Error und eine Fehlermeldung im Log...

1. Installation:
KNX, Tasmota (KNX), Sonos, Unifi

2. Installation:
HM-CFG-USB, Unifi (, SIGNALduino 868, MySensors, SIGNALduino 433)

Markus Bloch

Bitte versuch mal:

define Unifi_test PRESENCE function {ReadingsVal("UniFi","NameDevice","") eq "connected"}
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Papaloewe


Hauswart

Zitat von: Markus Bloch am 09 Januar 2017, 15:49:52
Bitte versuch mal:

define Unifi_test PRESENCE function {ReadingsVal("UniFi","NameDevice","") eq "connected"}
Funktioniert nun auch bei mir. Vielen Dank. Wie setze ich bei Abwesenheit "absent"? Bisher liefert er lediglich "error", klar weil die Funktion nicht erfüllt ist, aber keine 0 zurückgibt.
1. Installation:
KNX, Tasmota (KNX), Sonos, Unifi

2. Installation:
HM-CFG-USB, Unifi (, SIGNALduino 868, MySensors, SIGNALduino 433)

Markus Bloch

z.B. so:

define Unifi_test PRESENCE function {ReadingsVal("UniFi","NameDevice","") eq "connected" ? 1 : 0}
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Hauswart

Zitat von: Markus Bloch am 10 Januar 2017, 08:38:28
z.B. so:

define Unifi_test PRESENCE function {ReadingsVal("UniFi","NameDevice","") eq "connected" ? 1 : 0}
Funktioniert perfekt! Danke.
1. Installation:
KNX, Tasmota (KNX), Sonos, Unifi

2. Installation:
HM-CFG-USB, Unifi (, SIGNALduino 868, MySensors, SIGNALduino 433)

Markus Bloch

Ich werde in den nächsten Tagen eine Änderung machen, so dass man PRESENCE auf Events binden kann.

Damit soll PRESENCE um folgende Syntax erweitert werden:

define <NAME> PRESENCE event <absent-Regexp> <present-Regexp>

Sobald die jeweilige Regexp auf ein entsprechendes Event matcht, wird der Status entsprechend in PRESENCE geändert. Optional würde dann noch eine Funktion hinzukommen in der man ein Timeout definieren kann analog zu den Thresholds bei den herkömlichen Modis (absence-/presenceThreshold).

Viele Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Hauswart

1. Installation:
KNX, Tasmota (KNX), Sonos, Unifi

2. Installation:
HM-CFG-USB, Unifi (, SIGNALduino 868, MySensors, SIGNALduino 433)

Markus Bloch

Ist intuitiver ohne in Perl abtauchen zu müssen. Funktional wäre es gleich
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Pippowicz

Hi,

vielleicht hilft es ja jemandem wenn es Verbindungsprobleme mit einen UniFi Controller auf einem Raspi gibt ;)

Ich probiere hier schon seit Stunden den UniFi Controller in meine FHEM Installation einzubinden. Trotz aller Ansätze
aus dem Thread hier hat es nicht geklappt. Abhilfe schaffte letztendlich dann doch ein Setzen des Timeouts in der
74_Unifi.pm.

Das war auch so im Thread hier erwähnt, allerdings braucht der Raspi anscheinen teilweise mehr als die dort
vorgeschlagenen 5 Sekunden. Eine Erhöhung des Werts auf 10 funktioniert hier einwandfrei.

(Hardware: Controller auf einen Raspi 3, FHEM auf einem zweiten Raspi)

Grüße, Chris