Scene: Online/Offline via UniFi controller

riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Det var inte så enkelt att hitta ett vettigt sätt att kolla om sina enheter är hemma eller inte så nu har jag gjort en liten snurra som kollar med UniFi-controllern om enheterna är hemma. Kräver så klart att man använder Ubiquiti's produkter... och gör man inte det så är de väl värda att kika på :)

(Jag kör UniFi controller 5.6.19 som Docker-container samt vanliga Apache och PHP5 i en Synology NAS)


Redigera övre raderna och spara ner som index.php under i /unifi/ på en lämplig maskin som pratar PHP, hämta även UniFi-API-client och lägg den i /UniFi-API-client/ på samma maskin.

index.php

Code: Select all

<?php
header('Content-Type: application/json; charset=utf-8');

$controlleruser     = "root"; // the user name for access to the UniFi Controller
$controllerpassword = "SuperSecret :)"; // the password for access to the UniFi Controller
$controllerurl      = "https://22.22.11.11:8443"; // full url to the UniFi Controller, eg. "https://22.22.11.11:8443"
$site_id = "";
$controllerversion  = "5.5.20"; // the version of the Controller software, eg. "4.6.6" (must be at least 4.0.0)
$debug = false;

require_once("../UniFi-API-client/src/Client.php");

$unifiConnection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion);
//$set_debug_mode   = $unifi_connection->set_debug(true);
$loginresults     = $unifiConnection->login();
$unifiClients     = $unifiConnection->list_clients();

$result = array();

foreach ($unifiClients as $unifiClient) {
  $c = array();
  $c["mac"] = $unifiClient->mac;
  $c["name"] = $unifiClient->name;
  $c["vlan"] = $unifiClient->vlan;
  $c["ip"] = $unifiClient->ip;

  if ($unifiClient->is_wired == 1) {
    $c["network"] = "LAN";
    $c["ssid"] = null;
  } else {
    $c["network"] = "WiFi";
    $c["ssid"] = $unifiClient->essid;
  }

  $result[] = $c;
}
//echo json_encode($result, JSON_PRETTY_PRINT);
echo json_encode($result);
?>
https://github.com/Art-of-WiFi/UniFi-API-client

(Ett tips är att även ta hem UniFi-API-browser om man vill utforska APIet)

Nu ska du få ett JSON-svar om du surfar till /unifi/ ... om inte så är det något galet.

Skapa sedan upp en VD där "IP" pekar på din webbserver och port på webbporten.
Image

Lägg sedan till en eller flera labels som du namnsätter enligt: "lblMAC", alltså lbl följt av mac-adressen till enheten utan :
Exempelvis: lbl223344556677
Image


Som mainloop lägger du in följande kod:

Code: Select all

local doDebug = true
local sStatusOnline = "Online"
local sStatusOffline = "Offline"
local iSleepSeconds = 182

msgDebug = function (color, message)
  if doDebug then
    fibaro:debug("<span style='color: " .. color .. "'>" .. tostring(message) .. "</span>")
  end
end

tableLength = function (T)
   local c = 0
   for _ in pairs(T) do
     c = c + 1
   end
   return c
end

-- ------------------------------------------------------------------------------------------------------------------------
labels = {}
msgDebug("Orange", "Calling HC2 API for labels on device " .. tostring(fibaro:getSelfId()) )
local http = Net.FHttp("127.0.0.1", 11111)
local sResponse, status, err = http:GET("/api/devices/" .. tostring(fibaro:getSelfId()))
local jsonResponse = json.decode(sResponse)
for rowIndex, rowData in pairs(jsonResponse.properties.rows) do
  for buttonIndex, buttonData in pairs(rowData.elements) do
    msgDebug("Yellow", "Found label: " .. jsonResponse.properties.rows[rowIndex].elements[buttonIndex].name .. " (" .. jsonResponse.properties.rows[rowIndex].elements[buttonIndex].caption .. ")")
    labels[#labels+1] = jsonResponse.properties.rows[rowIndex].elements[buttonIndex].name
  end
end

msgDebug("Orange", "Calling UniFi API on " .. fibaro:getValue(fibaro:getSelfId(), 'IPAddress') )
local http = Net.FHttp(fibaro:getValue(fibaro:getSelfId(), 'IPAddress'), fibaro:getValue(fibaro:getSelfId(), 'TCPPort'))
local sResponse = http:GET("/unifi/")

local jsonResponse = json.decode(sResponse)
local jsonLength = tableLength(jsonResponse)


for p in pairs(labels) do
  msgDebug("Black", "")

  local label = labels[p]
  sLabel = "ui." .. label .. ".value"
  msgDebug("White", "Check device with label: " .. label)

  sValue = os.date("%Y-%m-%d %H:%M:%S") .. " / " .. sStatusOffline
  bOnline = false
  for r = 1, jsonLength do
    if (label ==  string.gsub("lbl" .. jsonResponse[r].mac, ":", "") ) then
      msgDebug("Green", "Online: " .. jsonResponse[r].mac .. " / " .. jsonResponse[r].name )
      sValue = tostring(os.date("%Y-%m-%d %H:%M:%S")) .. " / " .. sStatusOnline
      bOnline = true
    end
  end

  sCurrentValue = fibaro:getValue(fibaro:getSelfId(), sLabel)
  msgDebug("Orange", "Label, current value = " .. sCurrentValue)

  if bOnline then
    if string.find(sCurrentValue, sStatusOnline) then
      msgDebug("Gray", "Allready " .. sStatusOnline .. " status... no update!")
    else
      msgDebug("Yellow", sLabel .. " = " .. sValue)
      fibaro:call(fibaro:getSelfId(), "setProperty", sLabel, sValue)
    end
  else

    if string.find(sCurrentValue, sStatusOffline) then
      msgDebug("Gray", "Allready " .. sStatusOffline .. " status... no update!")
    else
      msgDebug("Yellow", sLabel .. " = " .. sValue)
      fibaro:call(fibaro:getSelfId(), "setProperty", sLabel, sValue)
    end
  end
end

-- ------------------------------------------------------------------------------------------------------------------------
msgDebug("Orange", "Done! Sleeping " .. tostring(iSleepSeconds) .. " seconds")
fibaro:sleep(iSleepSeconds * 1000)
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

Hej,
Jag håller på att försöka att få till Scenen och har lite frågor/funderingar

Har min Unifi controller liggande på /usr/local/UniFi på min server - ska man ha index.php och Unifi-API-client under /usr/local/UniFi på servern?

Får följande fel
[DEBUG] 23:49:32: Calling HC2 API for labels on device 234
[DEBUG] 23:49:32: Found label: lbl8cfXXXXXXXX (Lasse Galaxy S8 Plus)
[DEBUG] 23:49:32: Calling UniFi API on 192.168.0.5
[ERROR] 23:49:32: line 38: Expected value but found T_END at character 1
Last edited by Texan on 08 Nov 2017, 00:19, edited 1 time in total.
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote:Har min Unifi controller liggande på /usr/local/UniFi på min server - ska man ha index.php och Unifi-API-client under /usr/local/UniFi på servern?
Beror lite på... :)

UniFi-controllern kan finnas "vart som helst", jag kör min controller i docker på en NAS.
Sen kör min jag min Apache/PHP-server på en RPi.

Så, på min RPi har jag ungefär:

/var/www/html/UniFi-API-client <-- där har jag kört en "git clone" av https://github.com/Art-of-WiFi/UniFi-API-client.git
/var/www/html/unifi/index.php <-- där ligger innehållet i filen som jag postade tidigare.

Surfar man sen till http://rpi/unifi/ så ska man få ett json-resultat, får man inte det så är det något galet.
En bra felsökning är då att SSH'a in till RPi'n och köra:

Code: Select all

php /var/www/html/unifi/index.php
... det bör också resultera i ett JSON-svar ...
Robert
Medlem
Posts: 346
Joined: 17 Oct 2013, 22:40
11

Snyggt! Kan jag få nytta av när jag bygger om mitt nätverk i veckorna.

Skickat från min ZTE A2017G via Tapatalk
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

Kommit en bit på vägen...

När jag kör
php /var/www/html/unifi/index.php
Får jag följande
PHP Notice: Undefined property: stdClass::$name in /var/www/html/unifi/index.php on line 23
{"mac":"XX:XX:XX:XX:XX:XX","name":"","vlan":0,"ip":"192.168.0.48","network":"WiFi","ssid":"Cartier"}


Rad 23 i index.php ser ut så här
$c["name"] = $unifiClient->name;

Och tittar jag på Clients i controllers, så är name satt -i detta fal borde Gallaxy-S8 visas. Vad kan vara fel?




Hittade felet, satte ett Alias namn i controllers :)
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

Får nu följande fel

[DEBUG] 23:15:40: Calling HC2 API for labels on device 234
[DEBUG] 23:15:40: Found label: lbl8cfXXXXXXXX (Lasse Galaxy S8 Plus)
[DEBUG] 23:15:40: Calling UniFi API on 192.168.0.5
[ERROR] 23:15:40: line 38: Expected value but found invalid token at character 1
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote: [ERROR] 23:15:40: line 38: Expected value but found invalid token at character 1
Hur ser JSON-svaret ut om du surfar direkt till websidan? (eller kör den från en ssh-session)

Misstänker att det ligger en Warning eller liknande där...
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

riro wrote:
Texan wrote: [ERROR] 23:15:40: line 38: Expected value but found invalid token at character 1
Hur ser JSON-svaret ut om du surfar direkt till websidan? (eller kör den från en ssh-session)

Misstänker att det ligger en Warning eller liknande där...
När jag kör den från en ssh-session får jag följande olikheter

Står jag på /var/www/html/unifi

php /var/www/html/unifi/index.php
får jag tillbaka
[{"mac":"a4:XXXXXXXXXXX","name":"Chromecast","vlan":0,"ip":"192.168.0.64","network":"WiFi","ssid":"Cartier"}]


Och står jag på /var/www/html

php /var/www/html/unifi/index.php
får jag tillbaka
PHP Warning: require_once(../UniFi-API-client/src/Client.php): failed to open stream: No such file or directory in /var/www/html/unifi/index.php on line 11
PHP Fatal error: require_once(): Failed opening required '../UniFi-API-client/src/Client.php' (include_path='.:/usr/share/pear:/usr/share/php') in /var/www/html/unifi/index.php on line 11
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote:
riro wrote:
Texan wrote: [ERROR] 23:15:40: line 38: Expected value but found invalid token at character 1
Hur ser JSON-svaret ut om du surfar direkt till websidan? (eller kör den från en ssh-session)

Misstänker att det ligger en Warning eller liknande där...
När jag kör den från en ssh-session får jag följande olikheter

Står jag på /var/www/html/unifi

php /var/www/html/unifi/index.php
får jag tillbaka
[{"mac":"a4:XXXXXXXXXXX","name":"Chromecast","vlan":0,"ip":"192.168.0.64","network":"WiFi","ssid":"Cartier"}]


Och står jag på /var/www/html

php /var/www/html/unifi/index.php
får jag tillbaka
PHP Warning: require_once(../UniFi-API-client/src/Client.php): failed to open stream: No such file or directory in /var/www/html/unifi/index.php on line 11
PHP Fatal error: require_once(): Failed opening required '../UniFi-API-client/src/Client.php' (include_path='.:/usr/share/pear:/usr/share/php') in /var/www/html/unifi/index.php on line 11
Luktar rättigheter, eller avsaknad av det för webbservern ... kör du som root i ssh-sessionen?

Skickat från min SM-G950F via Tapatalk
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

Kör som root.
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

Surfar jag in på websidan - "https://minserver.se/unifi"

[{"mac":"a4:XXXXXXXXXXX","name":"Chromecast","vlan":0,"ip":"192.168.0.64","network":"WiFi","ssid":"Cartier"}]

Men skriver jag "https://192.168.0.5/unifi" så fungera det inte, vet inte om det ska vara så?
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote:Kör som root.
Då har Apache mest troligt inte rättigheter att läsa katalogen med UniFi-API-client ...

Visa SSH:

Code: Select all

ls -la /var/www/html/
Det borde visa lite skillnad på rättigheterna på /unifi/ och /Unifi-API-client/ ...
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

riro wrote:
Texan wrote:Kör som root.
Då har Apache mest troligt inte rättigheter att läsa katalogen med UniFi-API-client ...

Visa SSH:

Code: Select all

ls -la /var/www/html/
Det borde visa lite skillnad på rättigheterna på /unifi/ och /Unifi-API-client/ ...

drwxr-xr-x 3 root root 4096 Nov 9 11:58 UniFi-API-client
drwxr-xr-x 3 root root 4096 Nov 9 23:16 unify

Ändrade till full sökväg i index.php
require_once("/var/www/html/UniFi-API-client/src/Client.php");

När jag kör - php /var/www/html/unifi/index.php från hemma mappen så får jag tillbaka (vilket jag inte fick tidigare).
[{"mac":"8c:XXXXXXXXXX","name":"Galaxy-S8","vlan":0,"ip":"192.168.0.48"}]

Får följande fel..
[DEBUG] 23:52:17: Calling HC2 API for labels on device 234
[DEBUG] 23:52:17: Found label: lbl8cfXXXXXXXXX (Lasse Galaxy)
[DEBUG] 23:52:17: Calling UniFi API on 192.168.0.5
[ERROR] 23:52:17: line 38: Expected value but found invalid token at character 1

Är det några parametrar som måste ändras i mainloop eller skall den vara oförändrad?
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Det viktigaste är att få igång sidan via vanlig webbläsare först... sen kan du försöka få igång VDn

Skickat från min SM-G950F via Tapatalk
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote:Surfar jag in på websidan - "https://minserver.se/unifi"

[{"mac":"a4:XXXXXXXXXXX","name":"Chromecast","vlan":0,"ip":"192.168.0.64","network":"WiFi","ssid":"Cartier"}]

Men skriver jag "https://192.168.0.5/unifi" så fungera det inte, vet inte om det ska vara så?
En tanke, kör du verkligen endast med https på den servern?
Vet inte riktigt hur den hanterar certifikat... om du har möjlighet, prova kör med ren HTTP på port 80.

Sen går det att lägga på en debug-rad här så att man ser vad för data som kommer tillbaka:

Code: Select all

local sResponse = http:GET("/unifi/")
msgDebug("Red", sResponse)
local jsonResponse = json.decode(sResponse)
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

riro wrote:
Texan wrote:Surfar jag in på websidan - "https://minserver.se/unifi"

[{"mac":"a4:XXXXXXXXXXX","name":"Chromecast","vlan":0,"ip":"192.168.0.64","network":"WiFi","ssid":"Cartier"}]

Men skriver jag "https://192.168.0.5/unifi" så fungera det inte, vet inte om det ska vara så?
En tanke, kör du verkligen endast med https på den servern?
Vet inte riktigt hur den hanterar certifikat... om du har möjlighet, prova kör med ren HTTP på port 80.

Sen går det att lägga på en debug-rad här så att man ser vad för data som kommer tillbaka:

Code: Select all

local sResponse = http:GET("/unifi/")
msgDebug("Red", sResponse)
local jsonResponse = json.decode(sResponse)

Var lägger jag till debug raden, och behöver jag ändra "/unifi/" för att det ska fungera?
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote:Var lägger jag till debug raden, och behöver jag ändra "/unifi/" för att det ska fungera?
Du lägger den på rad 36, alltså så här (nej /unifi/ ska inte ändras):

Code: Select all

local doDebug = true
local sStatusOnline = "Online"
local sStatusOffline = "Offline"
local iSleepSeconds = 182

msgDebug = function (color, message)
  if doDebug then
    fibaro:debug("<span style='color: " .. color .. "'>" .. tostring(message) .. "</span>")
  end
end

tableLength = function (T)
   local c = 0
   for _ in pairs(T) do
     c = c + 1
   end
   return c
end

-- ------------------------------------------------------------------------------------------------------------------------
labels = {}
msgDebug("Orange", "Calling HC2 API for labels on device " .. tostring(fibaro:getSelfId()) )
local http = Net.FHttp("127.0.0.1", 11111)
local sResponse, status, err = http:GET("/api/devices/" .. tostring(fibaro:getSelfId()))
local jsonResponse = json.decode(sResponse)
for rowIndex, rowData in pairs(jsonResponse.properties.rows) do
  for buttonIndex, buttonData in pairs(rowData.elements) do
    msgDebug("Yellow", "Found label: " .. jsonResponse.properties.rows[rowIndex].elements[buttonIndex].name .. " (" .. jsonResponse.properties.rows[rowIndex].elements[buttonIndex].caption .. ")")
    labels[#labels+1] = jsonResponse.properties.rows[rowIndex].elements[buttonIndex].name
  end
end

msgDebug("Orange", "Calling UniFi API on " .. fibaro:getValue(fibaro:getSelfId(), 'IPAddress') )
local http = Net.FHttp(fibaro:getValue(fibaro:getSelfId(), 'IPAddress'), fibaro:getValue(fibaro:getSelfId(), 'TCPPort'))
local sResponse = http:GET("/unifi/")
msgDebug("Red", sResponse) -- Här är den nya raden :)
local jsonResponse = json.decode(sResponse)
local jsonLength = tableLength(jsonResponse)


for p in pairs(labels) do
  msgDebug("Black", "")

  local label = labels[p]
  sLabel = "ui." .. label .. ".value"
  msgDebug("White", "Check device with label: " .. label)

  sValue = os.date("%Y-%m-%d %H:%M:%S") .. " / " .. sStatusOffline
  bOnline = false
  for r = 1, jsonLength do
    if (label ==  string.gsub("lbl" .. jsonResponse[r].mac, ":", "") ) then
      msgDebug("Green", "Online: " .. jsonResponse[r].mac .. " / " .. jsonResponse[r].name )
      sValue = tostring(os.date("%Y-%m-%d %H:%M:%S")) .. " / " .. sStatusOnline
      bOnline = true
    end
  end

  sCurrentValue = fibaro:getValue(fibaro:getSelfId(), sLabel)
  msgDebug("Orange", "Label, current value = " .. sCurrentValue)

  if bOnline then
    if string.find(sCurrentValue, sStatusOnline) then
      msgDebug("Gray", "Allready " .. sStatusOnline .. " status... no update!")
    else
      msgDebug("Yellow", sLabel .. " = " .. sValue)
      fibaro:call(fibaro:getSelfId(), "setProperty", sLabel, sValue)
    end
  else

    if string.find(sCurrentValue, sStatusOffline) then
      msgDebug("Gray", "Allready " .. sStatusOffline .. " status... no update!")
    else
      msgDebug("Yellow", sLabel .. " = " .. sValue)
      fibaro:call(fibaro:getSelfId(), "setProperty", sLabel, sValue)
    end
  end
end

-- ------------------------------------------------------------------------------------------------------------------------
msgDebug("Orange", "Done! Sleeping " .. tostring(iSleepSeconds) .. " seconds")
fibaro:sleep(iSleepSeconds * 1000)
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

Fick det att fungera nu... tror jag
Fibaro1.png
Fibaro1.png (40.57 KiB) Viewed 23504 times
Tror inte min webbserver svara på förfrågningar från insidan (192.168.0.5) så jag skrev in min domänadress istället.
Fibaro2.png
riro
Medlem
Posts: 52
Joined: 27 Mar 2017, 11:02
7
Location: Falun
Contact:

Texan wrote:Fick det att fungera nu... tror jag
:)

Jag har själv inte använt det till något vettigt... så du får gärna hojta till om du kommer på ett bra användningsområde :lol:
User avatar
Texan
Medlem
Posts: 169
Joined: 25 Dec 2015, 15:07
8

riro wrote:
Texan wrote:Fick det att fungera nu... tror jag
:)

Jag har själv inte använt det till något vettigt... så du får gärna hojta till om du kommer på ett bra användningsområde :lol:

:D Tack för ditt tålamod och hjälpa mig att få igång det!

En funktion som jag kommer på är att kunna stänga/sätta på en lampa/enhet när en telefon blir synlig i nätet. Tyvärr så har jag ingen kunskap att få ihop en sådan lua scen, så om det är möjligt så vore jag tacksam.
Post Reply