Jump to content

HC3 QuickApps coding - tips and tricks


Recommended Posts

On 9/3/2020 at 6:54 PM, Rover said:

Why is the first print statement working and the second does not?

function QuickApp:onInit()

    self:debug("onInit")
    self:hello()
    self.jT = json.decode((fibaro.getGlobalVariable("HomeTable")))
    print(self.jT.TestKamer.testLicht)
end

 

function QuickApp:hello()
  print(self.jT.TestKamer.testLicht)
end

@jgab can you help me?

Link to post
Share on other sites
  • Replies 1.1k
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

This thread is most about QuickApp tricks and usually requires some deeper understanding of Lua. I'm going to make an attempt to do something more tutorial wise that could work for newcomers to Lua. I

A thread to share some coding techniques for QuickApps?  Because QAs are "long running scenes" (they don't have to be loaded and restarted for every event) - it is actually worthwhile to build up

The anatomy of QuickApps – Part 2 (Part 1)   Disclaimer1: We are now venturing into undocumented land. That means that Fibaro is free to change how things work at any time. Well, Fibaro

Posted Images

1 hour ago, Rover said:

@jgab can you help me?

Because you are calling self:hello() before you have assigned self.jT the value of your HomeTable. Thus self.jT is nil in QuickApp:hello()

Edited by jgab
  • Thanks 1
Link to post
Share on other sites

Refreshing an old discussion.

If you create your own UI elements for the QA you have a bit more control of the layout.

it's possible to squeeze in more than 5 buttons in a row (depending on how much text you want the button to have)

The pop-up works on the phone too. There is also a multi-select version of it.

The toggle control (switch - box that toggles between blue and white) works so-and-so. 

I'm still playing with the image control and will come back when I figure it out...

This is the code that I used

if dofile and not hc3_emulator then
  hc3_emulator = {
    name = "UI test",    -- Name of QA
    poll = 2000,       -- Poll HC3 for triggers every 2000ms
    --proxy = true,
    deploy = true,
    --offline = true,
  }
  dofile("fibaroapiHC3.lua")
end

if hc3_emulator then hc3_emulator.FILE("Toolbox/Toolbox_basic.lua","Toolbox") end
if hc3_emulator then hc3_emulator.FILE("Toolbox/Toolbox_ui.lua","Toolbox_ui") end

modules = {"ui"}

--hc3_emulator.debug.onAction = true

function QuickApp:onInit()
  local v = "4"
  if self:getView('lt','text') ~= v then
    self:updateViewLayout(self.id,
      {
        {label="lt",text=v},
        {{label='l1',text="Text to the left"},{button='b1',text='Button 1', onReleased='test', weight="3"}},

        {{button='b2',text='Button 2', onReleased='test', weight="3"},{label='l2',text="Text to the right"}},

        {
          {label='l11',text="Text to the left"},
          {button='b11',text='B 11', onReleased='test'},
          {button='b12',text='B 12', onReleased='test'}
        },

        {
          {button='b21',text='B 21', onReleased='test'},          
          {button='b21',text='B 21', onReleased='test'},
          {label='l21',text="Text to the right"}
        },

        {{label='l3',text="Text to the left"},{slider='s1', min=10, max=50, onChanged='tests', weight="3"}},

        {{slider='s2',onChanged='tests', weight="3"},{label='l4',text="Text to the right"}},

        {label='l5',text="Row with 'select buttons'"},
        {
          {switch='o1',onToggled="t1"},{switch='o2',onToggled="t1"},{switch='o3',onToggled="t1"},{switch='o4',onToggled="t1"},
          {switch='o5',onToggled="t1"},{switch='o6',onToggled="t1"},{switch='o7',onToggled="t1"},{switch='o8',onToggled="t1"},
          {switch='o9',onToggled="t1"},{switch='o10',onToggled="t1"},{switch='o11',onToggled="t1"},{switch='o12',onToggled="t1"}
        },

        {
          {label='l6',text='Fruits'},
          {select='m1', text="Choose one fruit:", values={"apple"}, weight="3", onToggled="t2",
            options={
              {value="1",type="options",text="apple"},
              {value="2",type="options",text="banana"},
              {value="3",type="options",text="orange"},
            }
          },
        },
        {label='l7',text=''},
      },
      true
    )
  end
  self:updateView("myopt","value","false")
end

function QuickApp:tests(e)
  self:updateView("l3","text","Value is "..e.values[1])
end

function QuickApp:t1(e) val = e.values[1] self:updateView(e.elementName,"value",tostring(not val)) end
function QuickApp:t2(e) 
  val = e.values[1] 
  self:updateView("l7","text","You choose "..(({"apple","banana","orange"})[val])) 
end

 

Edited by jgab
  • Like 3
Link to post
Share on other sites
On 9/6/2020 at 5:20 PM, jgab said:

Well, I made some tests and it seems like a two things need to fulfilled for a device to be included in an alarmzone

 

First it seems to need to have the interface "fibaroBreach".

Secondly, it seems to have to be a valid device type, like com.fibaro.motionSensor etc. Does anyone know the complete list? Ex. com.fibaro.binarySensor does not seem to work

 

I have made a new version of the HC2Proxy that allows you to add a list of interfaces to the device being created.

v1.4 HC2Proxy.fqa

You can also add "batter" and "power" and "energy".

On the HC2 if you trigger on %% property <id> battery the HC3 proxy should be updated.

Hi jgab


I tested your HC2proxy quickapp

Home Center 3 <=> Home Center 3

Control is possible

Below screen

How can I synchronize?

 

Edited by minsad79
Link to post
Share on other sites
Just now, minsad79 said:

Hi jgab
I tested your HC2proxy quickapp

Home Center 3 <=> Home Center 3

Control is possible

Below screen

How can I synchronize?

 

The current code relies on a scene running on the HC2 pushing changes back to the HC3.

For HC3<->HC3 there need to be another type of logic. It's possible to make something similar (a QA on the HC3 that pushes values to another HC3).

But wouldn't the HC3 be  able to use other HC3s as slave devices? (I only have one)

Link to post
Share on other sites
5 minutes ago, jgab said:

 

The current code relies on a scene running on the HC2 pushing changes back to the HC3.

For HC3<->HC3 there need to be another type of logic. It's possible to make something similar (a QA on the HC3 that pushes values to another HC3).

But wouldn't the HC3 be  able to use other HC3s as slave devices? (I only have one)

The gateway mode function is not available yet

I don't know when fibaro will do it

I inquired because the device of hc3 is not sync

HC3<=>Can you develop HC3 synchronization function?

Link to post
Share on other sites
1 hour ago, jgab said:

This is the code that I used

attempt to call a nil value (method 'getView')

 

unction QuickApp:onInit()
  local v = "4"
  if self:getView('lt','text') ~= v then
Link to post
Share on other sites
1 hour ago, Bodyart said:

attempt to call a nil value (method 'getView')

 

unction QuickApp:onInit()
  local v = "4"
  if self:getView('lt','text') ~= v then

Yes, it uses my QA toolbox code (and I build and deploy it to the HC3 with the hc3 emulator). The Toolbox_ui module is a new module under development. I will upload it asap.

Here is an assembled version UI_test.fqa

 

if hc3_emulator then hc3_emulator.FILE("Toolbox/Toolbox_basic.lua","Toolbox") end
if hc3_emulator then hc3_emulator.FILE("Toolbox/Toolbox_ui.lua","Toolbox_ui") end
Edited by jgab
  • Thanks 1
Link to post
Share on other sites

New version of the HC2Proxy that should work with sceneActivation devices like remote controls

HC2Proxy.fqa

HC2 scene

--[[
%% autostart
%% properties
146 value
146 power
151 sceneActivation
%% events
161 CentralSceneEvent
172 AccessControlEvent
%% globals
Test
--]]

if dofile and not _EMULATED then _EMULATED={name="EventRunner",id=99,maxtime=200} dofile("HC2.lua") end -- For HC2 emulator

if _EMULATED then
  _System.setRemote("devices",{44})
  _System.installProxy()
end

HC3_IP = "192.168.1.57"
HC3_USER = "admin"
HC3_PWD = "admin"
local format = string.format

local function buildMap(data)
  local MAP = {}
  fibaro:debug(format("Map: Checking %s HC3 devices",#data))
  for _,d in ipairs(data) do
    for _,qa in ipairs(d.properties.quickAppVariables or {}) do
      if qa.name=="HC2PROXY" then
        local id,tp = qa.value:match("(%d+):(.*)")
        MAP[tostring(id)] = {hc2ID=id,hc3ID=d.id,hc2type=tp,hc3type=d.baseType}
        fibaro:debug(format("Map: HC2_ID:%s, HC2_Type:%s, HC3_ID:%s, HC3_Type:%s",id,tp,d.id,d.baseType))
      end
    end
  end
  fibaro:setGlobal("HC3MAP",(json.encode(MAP)))
  assert(fibaro:getGlobal("HC3MAP"),"Please define HC3MAP global")
  fibaro:debug("Map built")
end

local function base64(data)
  local b='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 b:sub(c+1,c+1)
      end)..({ '', '==', '=' })[#data%3+1])
end

local baseURI = format("http://%s",HC3_IP)
local creds = 'Basic '..base64(HC3_USER..":"..HC3_PWD)

local function callHC3(uri,method,args,cont)
  local url = baseURI..uri
  fibaro:debug(url)
  local a,b = net.HTTPClient():request(url,{
      options = {
        method = method or "GET",
        headers={
          ['Authorization'] = creds,
          ["Accept"] = 'application/json',
          ["X-Fibaro-Version"] = "2",
          data = args and json.encode(args)
        }
      },
      success = function(resp) if cont then cont(resp) end end,
      error = function(resp) fibaro:debug(resp) end
    }
  )
  --fibaro:debug(format("%s, %s",tostring(a),tostring(b)))
end

function setProp(id,prop,value)
  callHC3(format("/api/callAction?deviceID=%s&name=setProperty&arg1=%s&arg2=%s",id,urlencode(prop),urlencode(tostring(value))),"GET")
end

function setVar(name,value) callHC3("/api/globalVariables/"..name,"PUT",{name=name,value=value}) end

local trigger = fibaro:getSourceTrigger()
fibaro:debug("Trigger:"..json.encode(trigger))

if trigger.type == 'autostart' or trigger.type == 'other' then
  if trigger.type=='other' and fibaro:args() then 
    local args = fibaro:args()
    fibaro:debug("Incoming test trigger:"..args[1])
    trigger = json.decode(args[1])
  else
    callHC3("/api/devices?interface=quickAppChild","GET",nil,
      function(resp)
        if resp.status == 200 then buildMap(json.decode(resp.data)) end 
      end)
    return
  end
end

local map = fibaro:getGlobal("HC3MAP")
local stat,res = pcall(function()
    local tab = json.decode(map)
    if trigger.type=='property' and tab[tostring(trigger.deviceID)] then
      local map = tab[tostring(trigger.deviceID)]
      local id = trigger.deviceID
      local prop = trigger.propertyName
      if trigger.value == nil then trigger.value = fibaro:getValue(id,prop) end
      fibaro:debug(format("Updating %s %s=%s",id, prop,trigger.value)) 
      setProp(map.hc3ID,prop,tostring(trigger.value))
      return
    elseif  trigger.type=='event' then
      local id = trigger.event.data.deviceId or trigger.event.data.id
      local map = tab[tostring(id)]
      local prop = trigger.event.type
      local value = trigger.event.data
      fibaro:debug(format("Updating %s %s=%s",id, prop,json.encode(value))) 
      setProp(map.hc3ID,prop,json.encode(value))
      return
    elseif trigger.type=='global' then
      if trigger.value==nil then trigger.value=fibaro:getGlobal(trigger.name) end
      setVar(trigger.name,trigger.value or "")
      return
    end
    error("Unknown trigger: "..json.encode(trigger))
  end)
if not stat then fibaro:debug("Error:"..res) end

 

 

Edited by jgab
  • Like 1
  • Thanks 1
Link to post
Share on other sites
3 hours ago, jgab said:

New version of the HC2Proxy that should work with sceneActivation devices like remote controls

I've installed on both sides HC2 & HC3, but instead of plenty childs (+/- 15) i have only 3. Can't figure out where to search...

Link to post
Share on other sites
3 godziny temu, jgab napisał:

New version of the HC2Proxy that should work with sceneActivation devices like remote controls

HC2Proxy.fqa 51 kB · 1 pobranie

HC2 scene

--[[
%% autostart
%% properties
146 value
146 power
151 sceneActivation
161 CentralsSceneEvent
172 AccessControlEvent
%% globals
Test
--]]

if dofile and not _EMULATED then _EMULATED={name="EventRunner",id=99,maxtime=200} dofile("HC2.lua") end -- For HC2 emulator

if _EMULATED then
  _System.setRemote("devices",{44})
  _System.installProxy()
end

HC3_IP = "192.168.1.57"
HC3_USER = "admin"
HC3_PWD = "admin"
local format = string.format

local function buildMap(data)
  local MAP = {}
  fibaro:debug(format("Map: Checking %s HC3 devices",#data))
  for _,d in ipairs(data) do
    for _,qa in ipairs(d.properties.quickAppVariables or {}) do
      if qa.name=="HC2PROXY" then
        local id,tp = qa.value:match("(%d+):(.*)")
        MAP[tostring(id)] = {hc2ID=id,hc3ID=d.id,hc2type=tp,hc3type=d.baseType}
        fibaro:debug(format("Map: HC2_ID:%s, HC2_Type:%s, HC3_ID:%s, HC3_Type:%s",id,tp,d.id,d.baseType))
      end
    end
  end
  fibaro:setGlobal("HC3MAP",(json.encode(MAP)))
  assert(fibaro:getGlobal("HC3MAP"),"Please define HC3MAP global")
  fibaro:debug("Map built")
end

local function base64(data)
  local b='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 b:sub(c+1,c+1)
      end)..({ '', '==', '=' })[#data%3+1])
end

local baseURI = format("http://%s",HC3_IP)
local creds = 'Basic '..base64(HC3_USER..":"..HC3_PWD)

local function callHC3(uri,method,args,cont)
  local url = baseURI..uri
  fibaro:debug(url)
  local a,b = net.HTTPClient():request(url,{
      options = {
        method = method or "GET",
        headers={
          ['Authorization'] = creds,
          ["Accept"] = 'application/json',
          ["X-Fibaro-Version"] = "2",
          data = args and json.encode(args)
        }
      },
      success = function(resp) if cont then cont(resp) end end,
      error = function(resp) fibaro:debug(resp) end
    }
  )
  --fibaro:debug(format("%s, %s",tostring(a),tostring(b)))
end

function setProp(id,prop,value)
  callHC3(format("/api/callAction?deviceID=%s&name=setProperty&arg1=%s&arg2=%s",id,urlencode(prop),urlencode(tostring(value))),"GET")
end

function setVar(name,value) callHC3("/api/globalVariables/"..name,"PUT",{name=name,value=value}) end

local trigger = fibaro:getSourceTrigger()
fibaro:debug("Trigger:"..json.encode(trigger))

if trigger.type == 'autostart' or trigger.type == 'other' then
  if trigger.type=='other' and fibaro:args() then 
    local args = fibaro:args()
    fibaro:debug("Incoming test trigger:"..args[1])
    trigger = json.decode(args[1])
  else
    callHC3("/api/devices?interface=quickAppChild","GET",nil,
      function(resp)
        if resp.status == 200 then buildMap(json.decode(resp.data)) end 
      end)
    return
  end
end

local map = fibaro:getGlobal("HC3MAP")
local stat,res = pcall(function()
    local tab = json.decode(map)
    if trigger.type=='property' and tab[tostring(trigger.deviceID)] then
      local map = tab[tostring(trigger.deviceID)]
      local id = trigger.deviceID
      local prop = trigger.propertyName
      if trigger.value == nil then trigger.value = fibaro:getValue(id,prop) end
      fibaro:debug(format("Updating %s %s=%s",id, prop,trigger.value)) 
      setProp(map.hc3ID,prop,tostring(trigger.value))
      return
    elseif  trigger.type=='event' then
      local id = trigger.event.data.deviceId or trigger.event.data.id
      local map = tab[tostring(id)]
      local prop = trigger.event.type
      local value = trigger.event.data
      fibaro:debug(format("Updating %s %s=%s",id, prop,json.encode(value))) 
      setProp(map.hc3ID,prop,json.encode(value))
      return
    elseif trigger.type=='global' then
      if trigger.value==nil then trigger.value=fibaro:getGlobal(trigger.name) end
      setVar(trigger.name,trigger.value or "")
      return
    end
    error("Unknown trigger: "..json.encode(trigger))
  end)
if not stat then fibaro:debug("Error:"..res) end

 

 

Is there a way to connect with HCL? Maybe after changing the firmware - https://forum.fibaro.com/topic/42908-hcl-custom-recovery/

Link to post
Share on other sites
14 hours ago, Bodyart said:

I've installed on both sides HC2 & HC3, but instead of plenty childs (+/- 15) i have only 3. Can't figure out where to search...

You need to go into the QA (main file) and edit this table

PROXIES = {
  [146] = {name='Switch', class="binarySwitch", type="com.fibaro.binarySwitch", interfaces={"fibaroBreach","power"}},
  [188] = {name='Switch2', class="multilevelSwitch", type="com.fibaro.multilevelSwitch"},
  [199] = {name='Remote1', class="sceneActivationDevice", type="com.fibaro.remoteController"},
  [200] = {name='Remote2', class="centralSceneDevice", type="com.fibaro.remoteSceneController"},
  [300] = {name='Sens1', class="binarySensor", type="com.fibaro.motionSensor", interfaces={"fibaroBreach"}},
}

-The number is the device number on the HC2

-Name is the name the childDevice will get (you can change it later)

-class is the available child device types supported. binarySwitch, binarySensor, multilevelSwitch, multilevelSensor, sceneActivationDevice,..

-type is the fibaro type the childDevice will get. It will decide the "look" of the childDevice, however, it must be supported by the previous class. A com.fibaro.doorSensor works with binarySensor etc.

 

Setup the HC2 credentials as quickVars. IP="192.168.x.y", User="[email protected]", Pwd="xyz"

On the HC2 you also need too add the trigger in the header for the devices you are proxying

 

------------------

20 hours ago, minsad79 said:

The gateway mode function is not available yet

I don't know when fibaro will do it

I inquired because the device of hc3 is not sync

HC3<=>Can you develop HC3 synchronization function?

It's not a priority at the moment....

Edited by jgab
Link to post
Share on other sites
3 hours ago, jgab said:

You need to go into the QA (main file) and edit this table

Thank you very much for the guidelines, but with version 1.4 I had all defined devices and with version 1.5 only 3 are left, while i copied the PROXIES array to the new QA and also copied the triggers to new HC2 scene....

Link to post
Share on other sites
11 godzin temu, jgab napisał:

Yes, only if you can run the scene on the HCL.

I've installed custom recovery on my HCL.

Created Proxy Scene, edited credentials.

I Have 3 sensors (siren, door sensor/ motion sensor). I Can see that they triggers scene...but i can't see it on the HC3.

 

From the HC3 i can turn on/off siren, but i can't see states changes of the other sensors...

Seems to be a problem on the HCL side? How to solve it?

Link to post
Share on other sites
Godzinę temu, michal85pl napisał:

I've installed custom recovery on my HCL.

Created Proxy Scene, edited credentials.

I Have 3 sensors (siren, door sensor/ motion sensor). I Can see that they triggers scene...but i can't see it on the HC3.

 

From the HC3 i can turn on/off siren, but i can't see states changes of the other sensors...

Seems to be a problem on the HCL side? How to solve it?

problem solved...some bug in HC3 credentials, password changed for the same one, and now works

  • Like 1
Link to post
Share on other sites

I added in HCL:

 

--[[
%% autostart
%% properties
14 battery
17 battery 

8 battery
9 battery
10 battery
* value
--]]

 

 

HC3

PROXIES = {

[14] = {name='Syrena', class="binarySwitch", type="com.fibaro.binarySwitch", interfaces={"fibaroBreach","battery"}},

  [17] = {name='Drzwi', class="binarySensor", type="com.fibaro.doorSensor", interfaces={"fibaroBreach","battery"}},

  [8] = {name='Ruch', class="binarySensor", type="com.fibaro.motionSensor", interfaces={"fibaroBreach","battery"}},

  [9] = {name='Temp', class="binarySensor", type="com.fibaro.temperatureSensor", interfaces={"battery"}},

  [10] = {name='Lux', class="binarySensor", type="com.fibaro.lightSensor", interfaces={"battery"}},

}

 

But still got 0% batt

1522058848_Adnotacja2020-09-09202149.jpg.31f74cb191f0245d52b76b8edc740296.jpg

 

what I missed?

 

Edited by michal85pl
Link to post
Share on other sites

Sorry, the interface is named "battery", but the property is "batteryLevel"

%% properties

14 batteryLevel

 

etc

Link to post
Share on other sites
4 minuty temu, jgab napisał:

Sorry, the interface is named "battery", but the property is "batteryLevel"

%% properties

14 batteryLevel

 

etc

changed but still 0%

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...