Hjälp med Quick App

Post Reply
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Hej alla!
Har haft en HC2 i många år som (tyvärr) gav upp för ett par veckor sedan så jag hade inget annat val än att uppgradera till HC3.
Till min förtvivlan så upptäcker jag att Virtual Devices numera heter Quick App och har ett helt annat sått att kodas.... :shock:
Jag är ingen programmerare och kan i bästa fall klippa och klistra in kod som någon annan skapat.

Jag skulle behöva hjälp (från scratch) med att skapa ett antal Quick Apps som kan skicka http-kommandon till mina kameror för att aktivera rörelsesensorer.


I http form ser de ut så här:

Aktivera på en Foscam kamera
http://192.168.x.xxx/set_alarm.cgi?moti ... d=password

Deaktivera på en Foscam kamera
http://192.168.x.xxx/set_alarm.cgi?moti ... d=password

Aktivera på en Axis-kamera
http://192.168.1.xxx/axis-cgi/virtualin ... s=password

Deaktivera på en Axis-kamera
http://192.168.1.xxx/axis-cgi/virtualin ... s=password


Vore oerhört tacksam om någon kunde förbarma sig över mig och mina bristande programmeringskunskaper.
Jag kommer att vara dig/er evigt tacksam.

mvh
Lasse Hedh
jang
Medlem
Posts: 388
Joined: 05 Jan 2014, 00:44
10
Location: Stockholm

Sorry, jag verkar inte få ladda upp ngn attachment.
Skapa en QA av typ "com.fibaro.binarySwitch" och klistra in kodan nedan.
(osäker på hur du identifiera dig, password i URLen?)
QA:an kommer att ha en on och en off knapp och går även att använda från blockscener.

Code: Select all

local baseURL = "http://192.168.1.xxx/"  
local activate = "axis-cgi/virtualin ... s=password"
local deactivate = "axis-cgi/virtualin ... s=password"

local function sendCommand(cmd)
  net.HTTPClient():request(baseURL..cmd,{
      options = { method = "GET" },
      success = function(resp) quickApp:debug("Success",json.encode(resp)) end,
      error = function(err) quickApp:error(err) end
    })
end

function QuickApp:turnOn()
  self:debug("activating")
  sendCommand(activate)
  self:updateProperty("value",true)
  self:updateProperty("status",true)
end

function QuickApp:turnOff()
  self:debug("deactivating")
  sendCommand(deactivate)
  self:updateProperty("value",false)
  self:updateProperty("status",false)
end

function QuickApp:onInit()
  self:debug(self.name,self.id)
end 
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Tusen tack!
I den ena så skickades credentials i HTTP-strängen. I den andra användes
SetBasicAuthentication.
Jag ska kolla på din kod i morgon.
Har sökt med ljus och lykta efter exempel på kod för HTTP, men det är väldigt tunt, både här och på Fibaros forum.

I min tidigare VD så ut så här.

FSC = Net.FHttp("192.168.x.xxx",80)
response = FSC:GET("/set_alarm.cgi?motion_armed=1&user=USER&pwd=PASSWORD")
fibaro:log(response)

Och så här:

AXISC = Net.FHttp("192.168.1.126",80)
AXISC:setBasicAuthentication("root","pass")
response = AXISC:GET("/axis-cgi/virtualinput/activate.cgi?schemaversion=1&port=1")


Mvh
jang
Medlem
Posts: 388
Joined: 05 Jan 2014, 00:44
10
Location: Stockholm

Code: Select all

-- For axis
local user = "root"
local password = "pass"
local baseURL = "http://192.168.1.126/"  
local activate = "axis-cgi/virtualinput/activate.cgi?schemaversion=1&port=1"
local deactivate = "axis-cgi/virtualinput/deactivate.cgi?schemaversion=1&port=1"

-- For FS
--[[
local user = nil
local password = nil
local baseURL = "http://192.168.x.xxx/"  
local activate = "/set_alarm.cgi?motion_armed=1&user=USER&pwd=PASSWORD"
local deactivate = "/set_alarm.cgi?motion_armed=0&user=USER&pwd=PASSWORD"
--]]

local function base64encode(data)
  __assert_type(data,"string" )
  local bC='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  return ((data:gsub('.', function(x) 
          local r,b='',x:byte() for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
          return r;
        end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        if (#x < 6) then return '' end
        local c=0
        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
        return bC:sub(c+1,c+1)
      end)..({ '', '==', '=' })[#data%3+1])
end

local function basicAuthorization(user,password) return "Basic "..base64encode(user..":"..password) end

local function sendCommand(cmd)
  net.HTTPClient():request(baseURL..cmd,{
      options = { 
        method = "GET",
        headers = { ['Authorization'] = quickApp.creds }
      },
      success = function(resp) quickApp:debug("Success",json.encode(resp)) end,
      error = function(err) quickApp:error(err) end
    })
end

function QuickApp:turnOn()
  self:debug("activating")
  sendCommand(activate)
  self:updateProperty("value",true)
  self:updateProperty("status",true)
end

function QuickApp:turnOff()
  self:debug("deactivating")
  sendCommand(deactivate)
  self:updateProperty("value",false)
  self:updateProperty("status",false)
end

function QuickApp:onInit()
  self:debug(self.name,self.id)
  if password then 
    self.creds = basicAuthorization(user,password)
  end
end 
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Ett stort tack för ny version!
Uppskattas verkligen.
Ska sätta tänderna i det i morgon.

Lite nyfiken ”SetBasicAuthentication” fungerar det i nya QA??
Gillade den funktionen i gamla VD….

Mvh
jang
Medlem
Posts: 388
Joined: 05 Jan 2014, 00:44
10
Location: Stockholm

Nop, man måste addera headern själv. Det är den extra koden i sista version.
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

OK
Jag är med på det mesta du kodat men den delen i mitten med base64 går lite utanför mitt förstånd… Varför har du lagt till den?

Mvh
jang
Medlem
Posts: 388
Joined: 05 Jan 2014, 00:44
10
Location: Stockholm

Anropet lägger till en 'Authorization' header i http anropet. Värdet av den är en textsträng "user:password", men den får inte vara i klartext utan kodat i base64 - en sorts "fattigmanskryptering" för att inte skicka lösenord i klartext i headern. Fördelen är att man slipper lösenordet i själva URLen så man slipper ha den synlig i koden - speciellt ett problem med länkar i html sidor (webbläsaren kan då lägga till headern när den skickar requested)
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Tack igen!
Nu har jag kollat båda dina förslag till kod.
Jag vill inte kopiera rätt av utan vill förstå och sedan skapa min egen. Det är enda sättet för mig att lära mig något.
Det går framåt men jag saknar ett kraftfull debug-kommando. Ett generellt kommande som jag kan använda när jag tragglar mig framåt och där jag ser i loggen exakt vad QA-gör, rad för rad, men också vad jag får för svar från enheterna jag kommunicerar med. Finns det ett sådant?

Hittills så har jag bara fått det att fungera om jag skickar hela kommandot som en enda sträng eftersom kameran också kräver att jag lägger till port 80.

Nästa steg är att se om jag kan bygga ett kommando genom att lägga ihop variabler (som du gjort i ditt exempel). Hittills har det inte varit så lyckosamt eftersom jag inte ser vad QA skickar till kameran och inte heller vad kameran returnerar för svar.
Om man använder en browser för att skicka kommandot så får man ett svar tillbaka.
I sin enklaste form (från Foscam kameran) är det bara ett ”ok.”.
Axis sköter det med lite mer finess och skickar ett svar på flera rader.

Men än en gång, tack för att du tar dig tid.

Lev väl
Lasse Hedh
jang
Medlem
Posts: 388
Joined: 05 Jan 2014, 00:44
10
Location: Stockholm

Om du har tillgång till PC/Mac kan du använda min HC3 emulator for att koda dina QAs.
Jag utvecklar alla mina QAs dessa dagar i min emulator (inkl. koden till ditt exempel)
https://forum.fibaro.com/topic/55045-ti ... ator-tqae/

Fördelen är att man kodar i en riktig IDE med debugger (ZeroBrane studio) och kan steppa genom koden och sätta brytpunkter (ex. se vad som kommer tillbaka från ett http request)
Last edited by jang on 17 Oct 2021, 18:12, edited 1 time in total.
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Tack
Ska titta på den. Har en gammal Mac :D

Mvh
Lasse H
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Hej igen
Nu har jag ägnat stora delar av helgen till programmering utan att nå hela vägen fram.
Foscam kamerorna var inget problem då de accepterar alla credentials i URL:en.

Värre är det med styrningen av AXIS kamerorna, samma problem jag hade 2014 när jag skulle skriva den första VD:n för HC2. Då löste sig problemet med hjälp av SetBasicAuthentication som tyvärr inte fungerar i en QA.

Så här ser min senaste kod ut. Den är inte kopierad rakt av eftersom jag som sagt vill lära mig något också.
Snäll, kan du inte ta en titt på den med dina professionella programmerarögon och försöka lista ut var jag går vilse någonstans, fär fungerar gör den inte. Få bara Error 401 hela tiden.
Jag har lagt in några "print" här och där för att se vad variablerna innehåller, ett sätt för mig att förstå.
Just nu misstänker jag att headern inte är helt korrekt, men jag hittar inget sätt att se vad den innehåller.
Som du ser så är koden för turnOff ofullständig men jag har fokuserat på turnOn....

Code: Select all



-- Binary switch type should handle actions turnOn, turnOff
-- To update binary switch state, update property "value" with boolean

local function base64encode(data)
  __assert_type(data,"string" )
  local bC='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  return ((data:gsub('.', function(x) 
          local r,b='',x:byte() for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
          return r;
        end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        if (#x < 6) then return '' end
        local c=0
        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
        return bC:sub(c+1,c+1)
      end)..({ '', '==', '=' })[#data%3+1])
end

local function basicAuthorization(user,password) return "Basic "..base64encode(user..":"..password)
end





function QuickApp:turnOn()
    self:debug("binary switch turned on")
    self:updateProperty("value", true)
    http:request(httpAddress ..activateURL,{options={method="GET"},
    headers={['Authorization']=quickApp.creds},
    success=function(response)
        QuickApp:debug("Va fan",json.encode(response))
        print(response.status)
        print(response.data)
        self:updateView("label1_1", "text", "Aktiverad")
    end,
    error=function(message)
    print("ERROR:",message)
    end
    })
    print(self.creds)
    print(quickApp.creds)
    print(method)
    print(headers)
end

function QuickApp:turnOff()
    self:debug("binary switch turned off")
    self:updateProperty("value", false) 
    http:request(httpAddress ..activateURL,{options={method="GET"},
    success=function(response)
        print(response.status)
        print(response.data)
        self:updateView("label1_1", "text", "Aktiverad")
    end,
    error=function(message)
    print("ERROR:",message)
    end
    })http:request(httpAddress ..deactivateURL,{options={method="GET"},
    success=function(response)
        print(response.status)
        print(response.data)
        self:updateView("label1_1", "text", "Deaktiverad")
    end,
    error=function(message)
    print("ERROR:",message)
    end
    })   
end


function QuickApp:onInit()
    local user="root"
    local password="pass"
    self:debug("onInit")
    self:debug(self.name,self.id)
    http=net.HTTPClient({timeout=3000})
    httpAddress="http://192.168.1.202/"
    activateURL="axis-cgi/virtualinput/activate.cgi?schemaversion=1&port=1"
    deactivateURL="axis-cgi/virtualinput/deactivate.cgi?schemaversion=1&port=1"
    if password
    then
    self.creds=basicAuthorization(user,password)
    end

    print(httpAddress..activateURL)
    print(httpAddress..deactivateURL)
end




Kommer att vara dig evigt tacksam om du hittar var jag gått vilse.

Mvh
Lasse H
jang
Medlem
Posts: 388
Joined: 05 Jan 2014, 00:44
10
Location: Stockholm

Ngt i den här stilen

Code: Select all

_=loadfile and loadfile("TQAE.lua"){
  user="admin",  pwd="admin",  host="192.168.1.57",
}

-- Binary switch type should handle actions turnOn, turnOff
-- To update binary switch state, update property "value" with boolean

local function base64encode(data)
  __assert_type(data,"string" )
  local bC='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  return ((data:gsub('.', function(x) 
          local r,b='',x:byte() for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
          return r;
        end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        if (#x < 6) then return '' end
        local c=0
        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
        return bC:sub(c+1,c+1)
      end)..({ '', '==', '=' })[#data%3+1])
end

local function basicAuthorization(user,password) 
  return "Basic "..base64encode(user..":"..password)
end

function QuickApp:turnOn()
  self:debug("binary switch turned on")
  self:updateProperty("value", true)
  self.http:request(self.httpAddress ..self.activateURL,{
      options={
        method="GET",
        headers={['Authorization']=self.creds}
      },
      success=function(response)
        self:debug("Va fan",json.encode(response))
        self:debug(response.status)
        self:debug(response.data)
        self:updateView("label1_1", "text", "Aktiverad")
      end,
      error=function(message)
        self:error(message)
      end
    })
end

function QuickApp:turnOff()
  self:debug("binary switch turned off")
  self:updateProperty("value", false) 
  self.http:request(self.httpAddress ..self.deactivateURL,{
      options={
        method="GET",
        headers={['Authorization']=self.creds}
      },
      success=function(response)
        self:debug(response.status)
        self:debug(response.data)
        self:updateView("label1_1", "text", "Deaktiverad")
      end,
      error=function(message)
        self:error(message)
      end
    })   
end


function QuickApp:onInit()
  local user="root"
  local password="pass"
  self:debug("onInit")
  self:debug(self.name,self.id)
  self.http=net.HTTPClient({timeout=3000})
  self.httpAddress="http://192.168.1.202/"
  self.activateURL="axis-cgi/virtualinput/activate.cgi?schemaversion=1&port=1"
  self.deactivateURL="axis-cgi/virtualinput/deactivate.cgi?schemaversion=1&port=1"
  if password
  then
    self.creds=basicAuthorization(user,password)
  end
  self:debug(self.httpAddress..self.activateURL)
  self:debug(self.httpAddress..self.deactivateURL)
end
Det finns lite olika stilar. Antingen lägger du alla variabler i QuickApp objektet och accessar de med self.<variabelnamn> inuti alla function QuickApp:... som du kodar.
Eller så deklarera du dom 'local' i början av koden.
Du kan inte access QuickApp:debug(...). Du måste använda self:debug(...) eller quickApp:debug(...) som är en global variabel som är samma som 'self'.
Ditt största problem var att options argumentet till :request var fel så att credentials hamnade fel.
Larshedh
Medlem
Posts: 48
Joined: 15 Dec 2013, 16:24
10

Tusen tack! :)
Nu fungerar det som det ska. Tänk vad en } kan göra skillnad. :D
Börjar nu också förstå nyttan av self:debug och self.variabel.

Hoppas att någon annan på forumet också kan ha nytta av koden.

Mvh
Lasse H
Post Reply