Unifi UAP Presence via Shell Script, SSH & mca-dump

Begonnen von Gimbel, 27 Januar 2018, 17:29:53

Vorheriges Thema - Nächstes Thema

Gimbel

Hintergrund

Ich habe die Presence Erkennung zunächt mit dem 74_Unifi Modul ausprobiert, dabei aber festgestellt, dass das Pollen der API den Unifi-Controller (läuft bei mir mit auf dem RPI auf dem auch Fhem läuft) recht ressourcen-intensiv ist. Ein Intervall unter 60 Sekunden war damit nicht machbar.
Auch der Umstand, dass man die Absence erst ca. 10 Minuten später (liegt nicht am Modul, sondern an Unifi bzw. deren API) mitbekommt war nicht wirklich praktikabel.

Daher ein neuer Ansatz:

Die meißten Unifi APs haben, wenn man sich per SSH verbindet einen Befehl mit an Board mca-dump der ein Json mit Informationen über die verbundenen Clients zurückliefert, hier z. B. die Parameter eines Clients.


{
"auth_time": 4294967226,
"authorized": true,
"ccq": 941,
"dhcpend_time": 4880,
"dhcpstart_time": 3880,
"hostname": "iPhone-von-abc",
"idletime": 3,
"ip": "10.12.0.99",
"is_11n": true,
"mac": "12:12:34:34:78:ab",
"noise": -111,
"rssi": 31,
"rx_bytes": 95689054,
"rx_mcast": 0,
"rx_packets": 338403,
"rx_rate": 39000,
"rx_retries": 0,
"serialno": "00:00:00:00:00:00",
"signal": -80,
"state": 15,
"state_ht": true,
"state_pwrmgt": false,
"tx_bytes": 81889256,
"tx_packets": 273157,
"tx_power": 38,
"tx_rate": 58500,
"tx_retries": 67718,
"uptime": 90111,
"vlan_id": 0
},

Neben den Informationen über die Clients bekommt man auch noch die benachbarten SSIDs etc.

Erste Tests

Schaltet man das Wlan im Client aus, dann verschwindet er sofort aus dieser Liste, nach dem Einschalten ist er direkt wieder da.

Leider verhält es sich beim physischem Verlassen des Wlan-Bereichs anders. Erste Tests* zeigen ein Verschwinden aus der Liste nach ca. 5 Minuten, beim erneuten Betreten des Wlans dauert es ca. 25 bis 45 Sekunden wenn sich das iPhone im Standby befindet. Einmal den Home-Button betätigt, scheint sich das iPhone sofort mit dem Wlan zu verbinden und es ist direkt in der Liste enthalten.
*getestet mit einem alten iPhone 3GS und einem Unifi AP AC In-Wall FW 3.9.3.7537

Meine Intention war es eigentlich automatisch das Licht einzuschalten, wenn ich nach Hause komme, dafür ist es leider etwas zu langsam, dann evtl. doch eher ein Bewegungsmelder :).

Analyse

Trotzdem sind über diese Daten interessante Anwenungen denkbar, z. B. wenn man mehrere APs hat, kann man herausfinden mit welchem AP ein Client verbunden ist und z. B. sagen auf welchem Stockwerk sich ein Nutzer befindet. Es ist zuindest etwas schneller und ressourcen-schonender als die Methode über die Unifi API zu gehen. Ein Polling im 3 Sekunden Intervall hat den AP in der CPU- und Speicher-Auslastung nicht merklich beeinflusst.




Zum selber machen

Ist jetzt noch keine saubere Lösung, eher ein Proof of Concept.

1. SSH Zugang per Ssh-Key zum Unifi AP
Den braucht ihr um euch später per Shellskript auf dem AP ohne eingabe eines Passwortes einloggen könnt.

Erstellt euch ein Ssh-Key ohne Passphrase falls ihr noch keinen habt. Testen werdet ihr das Skript wahrscheinlich unter einem anderen User z. B. pi, da später der User fhem das Shellskript ausführt, braucht der fhem User auch einen Ssh-Key. In meinem Fall habe ich die Tests unter dem pi User gemacht und dann für den fehm User einen 2. Key erstellt.

Um die Public-Keys dem AP bekannt zu machen, könnt ihr dieser Anleitung folgen:
https://help.ubnt.com/hc/en-us/articles/235247068-UniFi-Add-Custom-SSH-Keys-to-Your-UniFi-Devices

Bei mir auf einem Linux (raspian) ist die im Link erwähnte Datei hier zu finden: /var/lib/unifi/sites/default

Die Datei mit 2 Keys sieht dann so aus:

config.system_cfg.1=sshd.auth.key.1.status=enabled
config.system_cfg.2=sshd.auth.key.1.value=AAAAB3Nz...NUzUj/zrZkdiw9ZZGn
config.system_cfg.3=sshd.auth.key.1.type=ssh-rsa
config.system_cfg.4=sshd.auth.key.2.status=enabled
config.system_cfg.5=sshd.auth.key.2.value=AAAAB2Gmk...kjsi82SJjow9ZZGjn
config.system_cfg.6=sshd.auth.key.2.type=ssh-rsa


Ihr könnt im Unifi Controller nach dem speichern der Datei eine Provisionierung starten um die Config auf den AP zu schreiben, mitlerweile gibt es dafür auch einen eigenen Knopf im Controller, Geräte/[AP-wählen]/Konfiguration/Gerät verwalten/Provisionierung erzwingen

Testet die Verbindung mit ssh admin@10.12.0.30 Username (kann man im Unifi-Controller Einstellungen/Zone/Geräte-Zugangsdaten/SSH-Zugangsdaten einsehen) und IP des Unifi-APs bitte anpassen. Im Controller könnt ihr auch das Ssh-Passwort einsehen.

2. Das Shell-Skript


#!/bin/bash
ssh -o StrictHostKeyChecking=no admin@10.12.0.30 'mca-dump | grep -c "iPhone-von-abc"';


Dieses legt ihr an einem Ort der Wahl ab und gebt ihm Ausführuns-Rechte für die entsprechenden User.

Erklärung: der Befehl mca-dump | grep -c "iPhone-von-abc" nimmt die Ausgabe von mca-dump und filtert (grep) die Zeichenkette iPhone-von-abc heraus. Die Angabe -c bewirkt, dass die Anzahl der Vorkommen gezält werden. Ist der Hostname also in der mca-dump Ausgabe vorhanden wird 1 zurückgegeben, anderfalls 0. Zufällig ist das genau, dass was die Presence Ergennung via Shell-Skript benötigt. Längerfristig müsste man das anders lösen, aber für die ersten Tests reicht das so aus.

Ihr könnt natürlich auch nach eurer MAC-oder IP-Adresse filtern.

Als Ausbaustufe könnte man dem Shell-Skript aus Fhem übergeben nach was gefiltert werden soll.


#!/bin/bash
#echo "Filter for: $1"
ssh -o StrictHostKeyChecking=no admin@10.12.0.30 'mca-dump | grep -c $1';

noch nicht getestet, falls man sehr viele Personen/Geräte auswerten will macht es ggf. Sinn die Ausgabe von mca-dump lokal mit Perl, Python oder Node zu verarbeiten.

Hinweis: bei Problemen hat mir das Logfile weitergeholfen, das Presence Modul erwartet als Rückgabe nur 0 oder 1, wenn ihr aber zum debuggen ein paar echo-Befehle o.ä. mit einbaut, dann schlägt die Erkennung zwar fehl, aber im Logfile könnt ihr diese sehen.

3. Die Presence-Konfiguraion


define Presence_Abc PRESENCE shellscript "/home/pi/.fhem/customConfig/presence.sh iPhone-von-abc"        5 5
#define <name>      PRESENCE shellscript "<path>                                  [<arg1>] [<argN>].." [ <check-interval (Def. 30s)> [ <present-check-interval> ] ]
attr Presence_Abc room Anwesenheit
attr Presence_Abc event-on-change-reading state

define Presence_Abc_NotifyA notify Presence_Abc:absent set Kuechenlicht_Schalter off
define Presence_Abc_NotifyP notify Presence_Abc:present set Kuechenlicht_Schalter on



Viel Spaß beim ausprobieren.

PS. zum Testen bzw. Simulieren das ein Client den Wlan Bereich verlässt, kann man die Sendeleistung des APs auf minimal stellen und dann ein Smartphone verwenden und es z. B. in einen sehr dickwandigen Topf legen (ein Bräter o.ä.) dann noch ein Zimmer dazwischen, das hat bei mir gereicht um dem Wlan den gar auszumachen.

timmmmmey

Hi Gimbel,

die Idee ist definitiv ressourcensparender. Habe ähnliches bei meinem Asus AC-68U gemacht. Da wurde nur leider jeder SSH-Login ins Log geschrieben... :(

Vielleicht noch zwei Anmerkungen, die mir beim Nachbau aufgefallen sind und anderen vielleicht auch passieren könnten:
1. bei mehren APs/MeshNodes muss die Abfrage pro Knoten erfolgen
2. Nicht alle Geräte haben einen Hostnamen bei mir. Insbesondere ein iPhone ist immer ohne Namen im Output. Ich gehe daher über die mac-Adresse und matche die direkt case-invariant (-i Option).

Viele Grüße
Tim