Jump to content

Recommended Posts

Posted (edited)

I updated fibaroapiHC3.lua to v.105 with support for the new QA file format.

 

If you use the hc3_emulator.deploy=true feature to deploy the real QA you are working on to the HC3, there is some new benefits.

Default is that the code will be included in the QA file "main" if you deploy on the HC3.

 

In your code you can include other files with

hc3_emulator.FILE("myFile.lua","myLib")

If you run in ZBS this will be just a

dofile("myFile.lua")

which means that you can set breakpoints in the included file and debug as usual.

 

However, if you run with the deploy option, it will remove the "hc3_emulator.FILE("myFile.lua","myLib")" code from the 'main' and create a new file for the QA with name "myLib" and insert the code of "myFile.lua" in that file. This way you can create and deploy multi file QAs easily from the ZBS version.

(if you use the fibaroapiHC3plugin there is a ZBS menu option to deploy: Project->Deploy QuickApp)

 

Ex.

if dofile and not hc3_emulator then
  hc3_emulator = {
    name="MyQA",
    type="com.fibaro.genericDevice",
    poll=1000,
    --proxy=true,
    --offline=true,
    deploy=true,
    UI = { {button="b1", text="B1", onReleased="b1"} }
  }
  dofile("fibaroapiHC3.lua")
end

hc3_emulator.FILE("MyLib1.lua","myLib1")
hc3_emulator.FILE("myLib2","myLib2") end

function QuickApp:b1() self:debug("B1") end

function QuickApp:main()   
  self:debug("onInit")
end

We have set deploy=true so when we run this in ZBS this will deploy the QA to the HC3 and create 3 files for the QA.

'main' with the code above, but all 'hc3_emulator.FILE(...)' removed

'myLib1' with the code of MyLib1.lua

'myLib2' with the code of MyLib2.lua

 

The files will be included in the order they are included in the source.

I advise to include them in the beginning to mimic the behaviour it will have on the HC3 ('main' runs last)

 

One more trick. File that are included are stripped of the code before 

----------- Code -

That is eleven '-' followed by " Code -" and to the end of the line.

This means that in the source code example above the header stuff to include the fibaroapiHC3.lua etc is normally included in the 'main' - but it doesn't hurt because it's wrapped in "if dofile ..."

However, if we include the "code marker" we can get rid of that annoying code in the deployed QA .

Ex.

if dofile and not hc3_emulator then
  hc3_emulator = {
    name="MyQA",
    type="com.fibaro.genericDevice",
    poll=1000,
    --proxy=true,
    --offline=true,
    deploy=true,
    UI = { {button="b1", text="B1", onReleased="b1"} }
  }
  dofile("fibaroapiHC3.lua")
end

hc3_emulator.FILE("MyLib1.lua","myLib1")
hc3_emulator.FILE("myLib2","myLib2") end
----------- Code ----------------------------

function QuickApp:b1() self:debug("B1") end
function QuickApp:main()   
  self:debug("onInit")
end

which makes the QA a bit cleaner.

Edited by jgab
  • Like 1
Link to post
Share on other sites
  • Replies 113
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

This is a thread for the fibaroapiHC3.lua sdk that is under development (keeping it separate from the HC3 QuickApps coding - tips and tricks thread) I've started to run and test HC3 QuickApps off

The SDK can be useful for coding and debugging large projects with a lot of moving parts. Zerobrane studio allows for setting conditional breakpoints and live variables watches which is real time save

New version v0.120. Hopefully this version is usable in Visual Studio (Windows) thanks to debugging effort from @10der.    Besides being an emulator for the HC3, fibaroapiHC3.lua is als

Posted Images

@jgab

 

in fibaroapiHC3  you have this code:

      Log(LOG.LOG,"Updating existing device %s",struct.name)
      local d, err = api.put("/devices/"..struct.id,{
          properties={
            quickAppVariables = struct.initialProperties.quickAppVariables,
            mainFunction = struct.initialProperties.mainFunction,
            uiCallBacks = struct.initialProperties.uiCallbacks,
          }
        })

I think it should not work because of new structure of fibaro QA ("mainFunction = struct.initialProperties.mainFunction") ...

 

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

@jgab

 

in fibaroapiHC3  you have this code:

      Log(LOG.LOG,"Updating existing device %s",struct.name)
      local d, err = api.put("/devices/"..struct.id,{
          properties={
            quickAppVariables = struct.initialProperties.quickAppVariables,
            mainFunction = struct.initialProperties.mainFunction,
            uiCallBacks = struct.initialProperties.uiCallbacks,
          }
        })

I think it should not work because of new structure of fibaro QA ("mainFunction = struct.initialProperties.mainFunction") ...

 

I think that code is gone since v 0.105 (it's already v 0.110 now)

local function createQuickApp(args) looks different now.

  • Thanks 1
Link to post
Share on other sites

EventTypes report.

    QuickAppFilesChangedEvent = function() end,
    ZwaveDeviceParametersChangedEvent = function() end,
    ZwaveNodeAddedEvent = function() end,
    RefreshRequiredEvent = function() end,

Link to post
Share on other sites
1 minute ago, rangee said:

EventTypes report.

    QuickAppFilesChangedEvent = function() end,
    ZwaveDeviceParametersChangedEvent = function() end,
    ZwaveNodeAddedEvent = function() end,
    RefreshRequiredEvent = function() end,

Thanks.(and even code I could just paste in :-) )

Actually I don't know what to do with this. 

There is a routine in the emulator that looks at all incoming events and convert relevant events to sourceTriggers. If there is an event that I haven't coded for I log this warning.

So a {type='DevicePropertyUpdatedEvent, data={id=ID, property=PROP, newValue=V, oldValue=OV}

is internally re-posted as a {type='device', id=ID, property=PROP, value=V, old=OV} to mimic a sourceTrigger.

It's only Scenes that cares about sourceTriggers so for QAs that is mostly ignored.

QAs normally fetches all (raw) events with /refreshStates

 

So, in the beginning I started to logg all events that I hadn't seen before to understand if they could generate a sourceTriggers. However, I don't think that is the case anymore. There seems to be a multitude of different internal events posted these days that are of limited interest to the average QA developer.

 

So, I will probably turn off these warnings and make it an option to turn them on.

 

Btw, I have a "QA_Toolbox" framework where I have a generic /refreshStates loop that do generate more types of triggers - like when device are added/removed and modified as these events are sometimes useful. However, the emulator should stay true to the way the HC3 behaves and only generate relevant sourceTriggers.

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

I think that code is gone since v 0.105 (it's already v 0.110 now)

local function createQuickApp(args) looks different now.

I had v106 from yeasterday.

Thanks P.

Link to post
Share on other sites
Posted (edited)

New version v0.120.

Hopefully this version is usable in Visual Studio (Windows) thanks to debugging effort from @10der

 

Besides being an emulator for the HC3, fibaroapiHC3.lua is also becoming kind of a utility belt of nice to have functions.

Now there is a set of functions that can help in backing up and restoring Scenes and QAs.

They should be seen as functions to help you "roll your own" backup scripts.

hc3_emulator.backup{type="*",dir="/tmp"}

will backup all scenes and QAs to directory /tmp

The default naming convention is <ID><QA name>.fqa for QAs and <ID><Scene name>.json for Scenes.

White spaces in names are replaced with underscores.

 

However, people like to organise their backups in various ways so the backup function takes a 'namer' function that can decide name and where to place the file.

hc3_emulator.backup{
  type="*",
  dir="/tmp",
  namer = function(struct,name)
    local type = hc3_emulator.file.isType(struct) -- Returns "QA" for QAs and "Scene" for Scenes
    name = name..os.date(" %c",struct.modified or struct.updated)
    name = ""..struct.id.."_"..name:gsub("[^%w]","_")
    return type,name
  end,
}

The function is passed the resource table (struct) and name as arguments and should return <name of file> or <directory>, <name of file>. No file extension. QAs will always be saved under .fqa and Scenes under .json

Ex.

if we return "test" for a QA with dir == "/tmp" the file will be saved as "/tmp/test.fqa"

if we return "QA","test" for a QA with dir == "/tmp" the file will be saved as "/tmp/QA/test.fqa"

 

In the case above, our namer will save a QA as

/tmp/QA/<ID><name of QA><last modified date>.fqa

Ex. "/tmp/QA/1284_T100_Tue_Jul_28_21_32_09_2020.fqa"

and a Scene as

/tmp/Scene/<ID><name of QA><last modified date>.json

Ex. "/tmp/Scene/19_KeyTestupdated_Wed_Jul_29_08_24_34_2020.json"

 

That is a convenient format as it will only save modified version (rather, overwrite resources with the same modified date)

 

There are also a set of functions for uploading and replacing HC3 QAs/Scenes from backedup files.

Disclaimer. I have tested the functions and try to verify each step as not to do anything bad. However, even if so, it's easy to accidentally loose scenes and QAs using these functions in unindented ways.

hc3_emulator.file.dir(directory)        -- Returns iterator over files in directory
hc3_emulator.file.deleteQA(deviceId)    -- Removes QA from HC3
hc3_emulator.file.uploadQA(fileName)    -- Uploads QA to HC3 with new deviceId
hc3_emulator.file.replaceQA(fileName)   -- Replaces QA on HC3 with existing deviceId
hc3_emulator.file.deleteScene(sceneId)  -- Removes Scene from HC3
hc3_emulator.file.uploadScene(fileName) -- Uploads Scene to HC3 with new sceneId
hc3_emulator.file.replaceScene(sceneId) -- Replaces Scene on HC3 with existing sceneId

The 'replace' version are quite nice as it keeps the ids.

Edited by jgab
  • Like 1
  • Thanks 1
Link to post
Share on other sites
W dniu 23.07.2020 o 22:30, jgab napisał:

 

So they share the global environment and not locals, and that is expected.

Yes it seems like 'main' (that can't be removed) is run last. The rest of the files seems to be loaded in order, top to bottom.

If I have 3 files:

File 'main':  print("A1") function QuickApp:onInit() self:debug("A1") end

File 'test1': print("B1")

File 'test2': print("C1")

 

I get the log:

[23.07.2020] [22:23:32] [DEBUG] [QUICKAPP1333]: B1

[23.07.2020] [22:23:32] [DEBUG] [QUICKAPP1333]: C1

[23.07.2020] [22:23:32] [DEBUG] [QUICKAPP1333]: A1

[23.07.2020] [22:23:32] [DEBUG] [QUICKAPP1333]: B1

[23.07.2020] [22:23:32] [DEBUG] [QUICKAPP1333]: C1

[23.07.2020] [22:23:32] [DEBUG] [QUICKAPP1333]: A1

 

Which looks like they load all the files twice(!) - be aware to not have commands that execute directly in your files - like the prints in my example... 

However, it's only when we save the QA - if it restarts due to a crash it only loads the files once.

Can't reproduce that, maybe you saved it gain (after save quickapp start again that way maybe you see it 2x

obraz.png

Link to post
Share on other sites
W dniu 23.07.2020 o 20:48, rangee napisał:

I think this is preparation of QA encryption.

 

 

It is more for hint and attribute panel but encryption is on our roadmap too

2020-07-29_11h31_51.png

Link to post
Share on other sites
29 minutes ago, A.Socha said:

It is more for hint and attribute panel but encryption is on our roadmap too

 

 

Looks nice 👍

Link to post
Share on other sites

Bug(??) report... v0.121

When you set hc3_emulator.deploy=true and make QA...

If QA is already exist then  files or something updated.

It's good but when QA has viewLayout then it disappears.

To remain viewLayout, just add 1 line at 1367

Line 1367,
    for _,i in ipairs(list) do items[#items+1]=mkRow(i) end
    if #items == 0 then  return nil end -- >>ADD THIS

 

Then.. viewLayout will not disppear.

Link to post
Share on other sites
12 minutes ago, rangee said:

Bug(??) report... v0.121

When you set hc3_emulator.deploy=true and make QA...

If QA is already exist then  files or something updated.

It's good but when QA has viewLayout then it disappears.

To remain viewLayout, just add 1 line at 1367

Line 1367,
    for _,i in ipairs(list) do items[#items+1]=mkRow(i) end
    if #items == 0 then  return nil end -- >>ADD THIS

 

Then.. viewLayout will not disppear.

Do you have a hc3_emulator.UI defined ?

The idea is that whatever is in the emulator should replace what's on the HC3. 

If the emulator code says no UI then the it should be removed on the deployed HC3 version.

Otherwise isn't it a risk that you end up with UI elements in the existing QA that is not handled by the code that is deployed?

Always have the complete definition of the UI in hc3_emulator.UI, and don't update the UI on the HC3 manually - that's the only way to keep things in sync.

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

Do you have a hc3_emulator.UI defined ?

The idea is that whatever is in the emulator should replace what's on the HC3. 

If the emulator code says no UI then the it should be removed on the deployed HC3 version.

Otherwise isn't it a risk that you end up with UI elements in the existing QA that is not handled by the code that is deployed?

Always have the complete definition of the UI in hc3_emulator.UI, and don't update the UI on the HC3 manually - that's the only way to keep things in sync.

 

I share some QA with fqa files to users in my country.

Normaly, they(users who using my QA) dont need to edit LUA code but someone want to edit some lua tables like your ER Rule.

Problem is that. When edit code in fibaro editor, UI broken up. ( {{label='label1', text='-'},{button='btn1', text="-"}} )

So they need to edit code via emulator.(with ZBS)

As I do not provide UI,  user run emulator like this...

if dofile and not hc3_emulator then
  hc3_emulator = {
    name="QuickApp",
    type="com.fibaro.deviceController",
    id=device_id,
    deploy=true,
    quickVars = {}
  }
  dofile("fibaroapiHC3.lua")
end


--CODE BELOW

This is why I suggested that.

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

OK, then how about give options to update UI or not like apiHTTPS. ( e.g. replaceUI=true or false)

 

 

Always thank you  jgab :)

 

Link to post
Share on other sites
  • 2 weeks later...

hi. is there any reason you did not add fibaro.clearTimeout ?

 

I just add 1 line.

function fibaro.clearTimeout(func) return clearTimeout(func) end

Link to post
Share on other sites

No, when I did it it didn't exist and then I forgot about it when they added it. Always use clearTimeout...

I will add in next release.

  • Thanks 1
Link to post
Share on other sites

  function net.TCPSocket(opts)
    local self = { opts = opts }

 

to

 

  function net.TCPSocket(opts)
    local self = { opts = opts or {} }

Link to post
Share on other sites
1 minute ago, rangee said:

  function net.TCPSocket(opts)
    local self = { opts = opts }

 

to

 

  function net.TCPSocket(opts)
    local self = { opts = opts or {} }

Thanks, will fix.

  • Thanks 1
Link to post
Share on other sites

When you make ui row with function mkRow(elms,weight)


 

--from
    if elms[1] then
      local c = {}
      local width = format("%.2f",1/#elms)
      if width:match("%.00") then width=width:match("^(%d+)") end
      for _,e in ipairs(elms) do c[#c+1]=ELMS[e.type](e,width) end
      comp[#comp+1]={components=c,style={weight="1.2"},type='horizontal'}
      comp[#comp+1]=ELMS['space']({},"0.5")


--to
    if elms[1] then
      local c = {}
      local width = format("%.2f",1/#elms)
      if width:match("%.00") then width=width:match("^(%d+)") end
      for _,e in ipairs(elms) do c[#c+1]=ELMS[e.type](e,width) end
      if #elms > 1 then comp[#comp+1]={components=c,style={weight="1.2"},type='horizontal'}
      else comp[#comp+1]=c[1]
      end
      comp[#comp+1]=ELMS['space']({},"0.5")

 

Link to post
Share on other sites
12 minutes ago, rangee said:

When you make ui row with function mkRow(elms,weight)


 

--from
    if elms[1] then
      local c = {}
      local width = format("%.2f",1/#elms)
      if width:match("%.00") then width=width:match("^(%d+)") end
      for _,e in ipairs(elms) do c[#c+1]=ELMS[e.type](e,width) end
      comp[#comp+1]={components=c,style={weight="1.2"},type='horizontal'}
      comp[#comp+1]=ELMS['space']({},"0.5")


--to
    if elms[1] then
      local c = {}
      local width = format("%.2f",1/#elms)
      if width:match("%.00") then width=width:match("^(%d+)") end
      for _,e in ipairs(elms) do c[#c+1]=ELMS[e.type](e,width) end
      if #elms > 1 then comp[#comp+1]={components=c,style={weight="1.2"},type='horizontal'}
      else comp[#comp+1]=c[1]
      end
      comp[#comp+1]=ELMS['space']({},"0.5")

 

 

In what way will it look/behave different? Just asking because I can see that it's unnecessary to wrap a single element in a components struct but I don't notice a difference.

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

 

In what way will it look/behave different? Just asking because I can see that it's unnecessary to wrap a single element in a components struct but I don't notice a difference.

 

Um... I can't remember exactly because I edited this couple of month ago...

If don't do that, it makes problem with slider.

 

And without edit, code results different with original viewLayout...

 

If there are multi element in row,  there's no problem.

it looks like this

{ "components": [ { "components": [ { "name": "button2_1",

 

If there are one element in row,  there are some differces.

it looks like this without change

{ "components": [ { "components": [ { "name": "button1",

it looks like this with change and this is original code when you make ui at fibaro editor.

{ "components": [ { "name": "button1",
 

Edited by rangee
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...