--[[
%% autostart
%% properties
%% globals
--]]
--------------------------------------------------
-- Scene : Ubiquiti Unifi
-- Author : Lazer
-- Version : 1.2
-- Date : April 2020
--------------------------------------------------
-- User variables
local URL = "https://192.168.x.x:443"
local username = "USERNMAE"
local password = "PASSWORD"
local intervalle = 10
local LAN_Devices = {
{
mac = "xx:xx:xx:xx:xx:xx", -- Smartphone 1
vg = "Unifi_Naam1WiFi"
},
{
mac = "xx:xx:xx:xx:xx:xx", -- Smartphone 2
vg = "Unifi_Naam2WiFi"
},
{
mac = "xx:xx:xx:xx:xx:xx", -- Smartphone 3
vg = "Unifi_Naam3WiFi"
}
}
-- System variables
local debug = false
local VG_Unifi_Cookie = "Unifi_Cookie" -- Global Variable used to store Cookie
--
-- Message() function
--
function Message(color, text)
if color and color ~= "" then
fibaro:debug('<span style="color:'..color..';">'..(text or '<i>nil</i>')..'</span>')
else
fibaro:debug(text or '<i>nil</i>')
end
end
--
-- Login function
--
function Login(command)
Message("fuchsia", "Login")
local httpClient = net.HTTPClient()
if debug then
Message("grey", URL .. "/api/login")
end
-- Login
httpClient:request(URL .. "/api/login", {
success = function(response)
if debug then
Message("gray", json.encode(response))
end
if response.status == 200 then
if response.data and response.data ~= "" then
local jsonTable = json.decode(response.data)
if jsonTable.meta and jsonTable.meta.rc and jsonTable.meta.rc == "ok" then
-- Get cookie
if response.headers and response.headers['Set-Cookie'] then
-- "Set-Cookie": "unifises=L1IADETuhsX6AwY44w72nCKftDOa1c1j; Path=\/; Secure; HttpOnly, csrf_token=b5y9pwpKD5dIcLqAxfHxUO2dQ6HUuvcL; Path=\/; Secure",
if debug then
Message("yellow", response.headers['Set-Cookie'])
end
-- Store cookie
Cookie = response.headers['Set-Cookie']
fibaro:setGlobal(VG_Unifi_Cookie, Cookie)
-- Execute given function as argument
if command and type(command) == "function" then
setTimeout(function() command() end, 0)
end
else
Message("red", "Error : missing Cookie in Response Headers")
end
else
Message("red", "Error : status = " .. tostring(response.status) .. " - rc = " .. (jsonTable.meta and jsonTable.meta.rc or "???") .. " - msg = " .. (jsonTable.meta and jsonTable.meta.msg or "???"))
end
else
Message("red", "Error : empty response")
end
else
Message("red", "Error : status=" .. tostring(response.status))
end
end,
error = function(err)
Message("red", 'httpClient:request() : Error : ' .. err)
end,
options = {
method = 'POST',
checkCertificate = false,
data = json.encode({username=username, password=password, strict=true})
-- data = '{"username":"'..username..'","password":"'..password..'","strict":true}'
}
})
end -- function
--
-- GetDevices function
--
function GetDevices()
Message("fuchsia", "GetDevices")
local httpClient = net.HTTPClient()
if debug then
Message("grey", URL .. "/api/s/UniFi_Noordwal/stat/sta")
end
-- Get list of connected devices
httpClient:request(URL .. "/api/s/UniFi_Noordwal/stat/sta", {
success = function(response)
if debug then
Message("gray", json.encode(response))
end
if response.status == 200 then -- HTTP 200 => OK
if response.data and response.data ~= "" then
local jsonTable = json.decode(response.data)
if jsonTable.meta and jsonTable.meta.rc and jsonTable.meta.rc == "ok" then
if jsonTable.data then
local count = #jsonTable.data
if debug then
Message("yellow", "Found " .. count .. " devices")
end
-- Browse devices
local i
for i=1, count do
if debug then
Message("blue", i.." hostname="..(jsonTable.data[i].hostname or "").." name="..(jsonTable.data[i].name or "").." mac="..(jsonTable.data[i].mac or "").." last_seen="..(jsonTable.data[i].last_seen or ""))
end
-- Look for device
local j
for j=1, #LAN_Devices do
if string.lower(LAN_Devices[j].mac or "") == string.lower(jsonTable.data[i].mac or "") then
local timestamp = fibaro:getGlobalValue(LAN_Devices[j].vg)
if timestamp ~= jsonTable.data[i].last_seen then
Message("green", "Found Host <b>"..(jsonTable.data[i].name or "").."</b> , MAC <b>"..(jsonTable.data[i].mac or "").."</b> , last seen <b>"..os.date('%d/%m/%Y %H:%M:%S', (jsonTable.data[i].last_seen or 0)).."</b>")
fibaro:setGlobal(LAN_Devices[j].vg, jsonTable.data[i].last_seen or 0);
end
break
end
end
end
else
Message("orange", "Warning : no device found")
end
else
Message("red", "Error : status = " .. tostring(response.status) .. " - rc = " .. (jsonTable.meta and jsonTable.meta.rc or "???") .. " - msg = " .. (jsonTable.meta and jsonTable.meta.msg or "???"))
end
else
Message("red", "Error : empty response")
end
elseif response.status == 401 then -- HTTP 401 => Unauthorized
-- Need to login and get new cookie
Message("orange", "Need to login and get new cookie")
Login()
return
else
if response.data and response.data ~= "" then
local jsonTable = json.decode(response.data)
Message("red", "Error : status = " .. tostring(response.status) .. " - rc = " .. (jsonTable.meta and jsonTable.meta.rc or "???") .. " - msg = " .. (jsonTable.meta and jsonTable.meta.msg or "???"))
else
Message("red", "Error : status=" .. tostring(response.status))
end
end
end,
error = function(err)
Message("red", 'httpClient:request() : Error : ' .. err)
end,
options = {
method = 'GET',
checkCertificate = false,
headers = {
["Cookie"] = Cookie,
}
}
})
-- Wait
if interval and interval > 0 then
setTimeout(function() GetDevices() end, interval*1000)
end
end -- function
--
-- Function : Create global variable
--
function CreateVG(varName, varValue, varEnum)
Message("fuchsia", "CreateVG : <b>" .. (varName or "<i>nil</i>") .. "</b>")
local isEnum = type(varEnum) == "table" and (#(varEnum or {}) > 0) and true or false
local payload = {name=varName, value=(varValue or "")}
if debug then
Message("gray", json.encode(payload))
end
local response, status = api.post("/globalVariables", payload)
if (tonumber(status) == 200 or tonumber(status) == 201) and response ~= nil and response ~= "" then
Message("", 'Global variable "'..varName..'" created')
if isEnum then
local payload = {name=varName, value=(varValue or ""), isEnum=true, enumValues=varEnum}
local response, status = api.put("/globalVariables/"..varName, payload)
if (tonumber(status) == 200 or tonumber(status) == 201) and response ~= nil and response ~= "" then
Message("", 'Global variable "'..varName..'" modified with enum values')
else
Message("red", 'Error : Can not modify enum global variable, status='..status..', payload='..json.encode(payload)..', response='..(response or ""))
end
end
else
Message("red", 'Error : Can not create global variable, status='..status..', payload='..json.encode(payload)..', response='..(response or ""))
end
end -- function
--
-- Main loop
--
-- Check if global variables exist
local VG = {
[VG_Unifi_Cookie] = {['default']='', ['enum']={}},
}
local i
for i=1, #LAN_Devices do
VG[LAN_Devices[i].vg] = {['default']='0', ['enum']={}}
end
local vg, param
for vg, param in pairs(VG) do
if debug then
Message("gray", "Check if global variable '"..vg.."' exists")
end
local variable = api.get("/globalVariables/"..vg)
-- {"created":1496865902,"modified":1497036821,"value":"XXXXX","isEnum":false,"name":"Unifi_Cookie","readOnly":false}
if not variable then
if debug then
Message("gray", 'Global variable "'..vg..'" does not exist')
end
CreateVG(vg, param['default'], param['enum'])
elseif debug then
Message("green", 'Global variable "'..vg..'" exist')
end
end
-- Get Cookie
Cookie = fibaro:getGlobalValue(VG_Unifi_Cookie)
-- Get trigger
local trigger = fibaro:getSourceTrigger()
if trigger["type"] == "autostart" then
Message(nil, os.date('%d/%m/%Y').." : Scene instance autostart")
interval = intervalle
-- Call GetDevices function recursively
setTimeout(function() GetDevices() end, 0)
elseif trigger["type"] == "other" then
Message(nil, os.date('%d/%m/%Y').." : Scene instance manual launch")
interval = 0
-- Call GetDevices function only once
if Cookie == nil or Cookie == "" then
Login(GetDevices)
else
setTimeout(function() GetDevices() end, 0)
end
else
Message(nil, os.date('%d/%m/%Y').." : Unknown trigger : "..trigger["type"])
end