Aller au contenu

jang

Membres confirmés
  • Compteur de contenus

    132
  • Inscription

  • Dernière visite

Réputation sur la communauté

126 Excellent

1 abonné

À propos de jang

  • Rang
    Membre passionné

Profile Information

  • Sexe :
    Homme
  • Ville :
    Home
  • Box
    Home Center 2
  • Version
    HC3

Visiteurs récents du profil

871 visualisations du profil
  1. jang

    setTimeout seule solution?

    Updated TriggerQA to v1.21 Supported triggers {type='alarm', property='armed', id=<id>, value=<value>} {type='alarm', property='breached', id=<id>, value=<value>} {type='alarm', property='homeArmed', value=<value>} {type='alarm', property='homeBreached', value=<value>} {type='alarm', property='activated', id=<id>, seconds=<seconds>} {type='weather', property=<prop>, value=<value>, old=<value>} {type='global-variable', property=<name>, value=<value>, old=<value>} {type='quickvar', id=<id>, name=<name>, value=<value>; old=<old>} {type='device', id=<id>, property=<property>, value=<value>, old=<value>} {type='device', id=<id>, property='centralSceneEvent', value={keyId=<value>, keyAttribute=<value>}} {type='device', id=<id>, property='accessControlEvent', value=<value>} {type='profile', property='activeProfile', value=<value>, old=<value>} {type='custom-event', name=<name>} {type='deviceEvent', id=<id>, value='removed'} {type='deviceEvent', id=<id>, value='changedRoom'} {type='deviceEvent', id=<id>, value='created'} {type='deviceEvent', id=<id>, value='modified'} {type='sceneEvent', id=<id>, value='started'} {type='sceneEvent', id=<id>, value='finished'} {type='sceneEvent', id=<id<, value='instance', instance=<number>} {type='sceneEvent', id=<id>, value='removed'} {type='sceneEvent', id=<id>, value='modified'} {type='sceneEvent', id=<id>, value='created'} {type='onlineEvent', value=<boolean>} {type='room', id=<id>, value='created'} {type='room', id=<id>, value='removed'} {type='room', id=<id>, value='modified'} {type='section', id=<id>, value='created'} {type='section', id=<id>, value='removede'} {type='section', id=<id>, value='modified'} {type='location',id=<userid>,property=<locationid>,value=<geofenceaction>,timestamp=<number>} {type='ClimateZone',...} {type='ClimateZoneSetpoint',...} It also supports time/cron events Time subscription: {type='cron', time=<cronString>, tag=<string>} cron string format: "<min> <hour> <day> <month> <wday> <year>" min: 0-59 hour: 0-23 day: 1-31 month: 1-12 wday: 1-7 1=sunday year: YYYY Ex. "0 * * * * *" Every hour "0/15 * * * * *" Every 15 minutes "0,20 * * * * *" At even hour and 20min past "0 * * 1-3 * *" Every hour, January to March "0 7 lastw-last * 1 *" 7:00, every sunday in the last week of the month "sunset -10 lastw-last * 1 *" 10min before sunset every sunday in the last week of the month Ex. self:subscribeTrigger({type='cron', time="0/15 * * * * *", tag="Quarter"}) will send back a source trigger ever 15min in the format {type='cron', time="0/15 * * * * *", tag="Quarter"} 'tag' can be useful to match timers to actions... This gives more or less the same or more functionality than what you get from Scene conditions.
  2. jang

    setTimeout seule solution?

    Try to install this QA TriggerQA.fqa v1.21 and then create another QA: function QuickApp:subscribeTrigger(event) local s = self:getVariable('TRIGGER_SUB') if s == nil or s == "" then s = {} end s[#s+1]=event self:setVariable('TRIGGER_SUB',s) end function QuickApp:sourceTrigger(tr) self:debug(json.encode(tr)) end function QuickApp:onInit() self:debug("onInit") self:subscribeTrigger({type='device'}) end This will call QuickApp: sourceTrigger with the trigger as soon as it happens. You can be more specific and do self:subscribeTrigger({type='device', id=88}) self:subscribeTrigger({type='device', id=99}) to only get triggers from deviceId 88 and 99 etc. Inside QuickApp: sourceTrigger you need to look at the trigger to see what trigger it is if you subscribe to different triggers. If you don't need super optimized trigger handling (then you run your own / refreshStates loop) then the TriggerQA is a simple helper that makes it easy for other QAs to receive sourceTrigger with very little overhead - similar to how scenes gets them - and it scales very well.
  3. jang

    setTimeout seule solution?

    It's not the setTimeout - it's what you do inside the setTimeouts... Here I start 1 million setTimeouts in parallell. local t = os.time() for i=1,1000000 do -- Start a million setTimeouts fibaro.setTimeout(1,function() end) end fibaro.setTimeout(30,function() print("OK2") print(os.time()-t) end) The last setTimeout with 30ms timer will not be allowed to run until all the 1 million have completed (that's how we time it). It takes 41s on the HC3 [27.05.2021] [12:07:13] [DEBUG] [SCENE24]: OK2 [27.05.2021] [12:07:13] [DEBUG] [SCENE24]: 41 That's actually quite ok. The trick with polling for state changes is not to do it with a setTimeout loop doing fibaro.getValue. It's to do http:requests to the /refreshStates api as the http request will hang if there are no events and not consume any cpu during that time. When an event is available the http request will return immediately. Granted is that you will get all kinds of events and need an efficient way to filter for events that you look for (devices changing state or globals changing value) - but that is easy to do with a table lookup. I have a ready made library 'fibaroExtra.lua' that implements an event/sourceTrigger callback function that is as efficient as it gets.
  4. jang

    Questions de débutant en Quick Apps sur HC3

    So the example becomes local function condition1(self) return true end local function condition2(self) return math.random(1,3) > 1 end local function condition3(self) return false end local function action1(self) fibaro.call(...) end local function action2(self) fibaro.call(...) end local rules = { {condition=condition1,action=action1}, {condition=condition2,action=action2}, {condition=condition3,action=action2} } function mainCode(self) for _,r in ipairs(rules) do -- Test conditions and run actions if true if r.condition(self) then r.action(self) end end end with the "passing around self' style.
  5. jang

    Questions de débutant en Quick Apps sur HC3

    Well, all QuickApp functions declared are callable from other QAs or through the web interface as has been discussed in other posts previously. Functions that are local to the QA I believe should be declared as just local functions. The problem is that you don't have access to 'self' in local functions, for calling ex. self:updateProperty() self:debug() etc. However, there is a global Lua variable that fibaro sets for us 'quickApp' that gets the value of 'self' - or the QuickApp object. The problem with 'quickApp' is that it's not set until we exit the QuickApp:onInit() function. So I use something like this. local function foo() quickApp:debug("Foo") end function QuickApp:onInit() quickApp = self foo() end The reason they set 'quickApp' after we exit :onInit() is that the object is not considered initialised until :onInit() has run. So just be careful that you don't access self variables that you initialise in :onInit() from, in this case, 'foo'. A purist would say we shouldn't use global variables like 'quickApp' but pass around the self value - however it tends to be a bit tedious if we only have one QuickApp object. However, there is an exception (or rule). If you have QuickAppChild objects too in your QA, then you in effect have several 'QuickApps' and need to pass around the right self to your local functions. local function foo(self) self:debug("Foo") end class 'Child'(QuickAppChild) function Child:onInit() foo(self) -- Child's self end function QuickApp:onInit() foo(self) -- QuickApp's self end Remember to declare 'local foo' before it's referenced in the Child:onInit() function.
  6. jang

    Gestion des appareils enfants

    The type of the QA defines a lot of the available key-values of the QA device structure. Changing the type of the QA would require some migration of values. For some types the property.value is a boolean for others a float etc. It would be messy. For children you need to update the mother QAs, as children can't migrate to another mother QA (one could experiment with changing the .parentId but my guess it could create havoc...) I have a Hue QA that I have updated the mother QA for a year now and users have been able to keep their children and more important the children deviceId's. I have my own version of the QuickAppChild class called QuickerAppChild that manages the children and reloads them with the correct class and it works well. I have also an 'UpdaterQA' that allow people to upgrade (and downgrade) my EventRunner and ChildrenOfHue's QAs.
  7. jang

    Questions de débutant en Quick Apps sur HC3

    I guess it's something like if (conditions1) then self:actions1() end ? You could make your conditions into self:condition1() too. if self:condition1() then self:action1() end The important thing is that your conditions need to return true/false. Then you could put them into an list function QuickApp:condition1() return true end function QuickApp:condition2() return math.random(1,3) > 1 end function QuickApp:condition3() return false end function QuickApp:action1() fibaro.call(...) end function QuickApp:action2() fibaro.call(...) end local rules = { {condition='condition1',action='action1'}, {condition='condition2',action='action2'}, {condition='condition3',action='action2'} } function mainCode(self) for _,r in ipairs(rules) do -- Test conditions and run actions if true if self[r.condition](self) then self[r.action](self) end end end Then you run the mainCode every 30s and rename your QA to GEA ;-) P.S I probably wouldn't declare conditions/actions as QuickApp methods.
  8. jang

    Récupérer valeur dans un API

    _ is a variable like all others... _ = 42 for _,_ in ipairs(({ 6,5,4,3 })) do print(_) end print(_G['_']) A_B, _A, _ are all valid variable names. However, as @Leisure points out it's a convention to name a temporary (local) variable that you don't need '_' as a signal to other that reads the code. Ex. code checking programs (LuaLint, Luacheck) also don't warn for "unused variables" if the variable is named '_'.
  9. jang

    Slider

    I think your analysis is justified. Fibaro is not always consistent in how they define their APIs....
  10. jang

    Questions de débutant en Quick Apps sur HC3

    https://forum.fibaro.com/topic/54915-quickapp-slider-minimum-and-maximum-range/
  11. jang

    Questions de débutant en Quick Apps sur HC3

    The general advice to declare your variables in the beginning of the code/functions is usually a very good advice. Actually, the QA is "executed" when the code is loaded. It's just that fibaro helps us by collecting a lot of nice-to-have functions in the QuickApp class and when the code is loaded is creates a QuickApp object and calls its :onInit() function as an "entry point" for our code. If fibaro had not done that we could have achieved the same thing by creating the QuickApp object ourselves at the end of our code. function QuickApp:onInit() self:debug("foo") end quickApp = QuickApp() -- create object from class quickApp:onInit() -- call our "entry point" However, we don't need an :onInit() in our QA. If there is no :onInit(), fibaro will not call it. setInterval(function() fibaro.call(88,"turnOff") end,60*60*1000) is a perfectly valid QA that will turn off device 88 every hour.
  12. jang

    Questions de débutant en Quick Apps sur HC3

    is still valid. When Lua loads your file the statements are executed top-to-bottom. Your first example: sets local test to "foo" defines function function QuickApp:onInit(). When onInit() is defined (compiled) the variable 'test' is determined to be a local variable as it has been defined previously (step 1). When the file is loaded no one has called QuickApp:onInit() yet. However after the QA is loaded, fibaro calls your QuickApp:onInit() to "start" your QA. The QA prints "foo". Your second example. defines function function QuickApp:onInit(). When onInit() is defined (compiled) the variable 'test' is determined to be a global variable as it has not been seen previously. sets local test to "foo" fibaro calls your QuickApp:onInit() functions that tries to print the global variable 'test' that has the value nil. In my previous post I talked about "forward" declaring variables. This would solve it. local test function QuickApp : onInit () self : debug ( "onInit" ) print ( test ) end test = "foo" declares local variable test defines function function QuickApp:onInit(). When onInit() is defined (compiled) the variable 'test' is determined to be a local variable as it has been defined previously (step 1). local test is set to "foo" fibaro calls your QuickApp:onInit() functions that prints the global variable 'test' that has the value "foo"
  13. jang

    Quick App - Mettre a jour un QA tout les jours a 0h00

    You can also just do local clim = 120 function QuickApp:updateClima() self:updateView("label1", "text", tostring(fibaro.getValue(clim, "power")).."W") end function QuickApp:onInit() self:debug(self.clima) setInterval(function() self:updateClima() end,10*1000) end but you probably would like to have some "smoothing" of the value...
  14. jang

    Quick App - Mettre a jour un QA tout les jours a 0h00

    It's not that straight forward.... However, you can leverage a library I have for that. Add fibaroExtra.lua to your QA https://forum.fibaro.com/topic/54538-fibaroextra/ Then in your QA main: local clim = 120 function QuickApp:updateClima() self:updateView("label1", "text", tostring(fibaro.getValue(clim, "power")).."W") end function QuickApp:onInit() self:debug(self.clima) self:updateClima() self:event({type='device', id=clima, property='power'}, function(env) self:updateClima() end ) end
  15. jang

    Questions de débutant en Quick Apps sur HC3

    Well, the local variables just shadow each other - it will work with same name - I choose different ones just for clarity. ...and clarity is good! Here you have 3 versions. Parallell - all request run and handled in parallell. Sequential - one request after another, handled in sequence. Parallell_join - The request run in parallell and the response collected in a common result that is sent to the callback when all results are ready. The advantage of sequential with the performance of parallell :-) function httpGet(self, url, callback) self.http:request(url, { success = function(response) if response.status < 400 then callback(true, url, response.data) else callback(false, url, response.status) end end, error = function(err) callback(false, url, err) end }) end local urls2call = { "https://www.apple.com", "https://www.google.com", "https://www.amazon.com", "https://www.facebook.com", } function parallell(self, urls ,handler) -- call all urls in parallell, handle asynchronous for _,url in ipairs(urls) do httpGet(self, url, handler) end end function sequential(self, urls, handler) -- call all urls in sequence local i = 1 local function callback(success, url, result) handler(success, url, result) i=i+1 if i <= #urls then httpGet(self,urls[i], callback) end end httpGet(self, urls[i], callback) end function parallell_join(self, urls, handler) -- call all urls in parallel, call join local result = {n=0,responses={}} for _,url in ipairs(urls) do httpGet(self, url, function(success, url, response) result.responses[#result.responses+1]={url=url,success=success,response=response} result.n = result.n+1 if result.n == #urls then handler(true, nil, result.responses) end end) end end function QuickApp:onInit() self.http = net.HTTPClient() -- parallell(self,urls2call, -- function(success, url, result) self:debug("Success "..tostring(success).." "..url) end -- ) -- sequential(self,urls2call, -- function(success, url, result) self:debug("Success "..tostring(success).." "..url) end -- ) parallell_join(self,urls2call, function(success, url, result) for _,r in ipairs(result) do self:debug("Success "..tostring(r.success).." "..r.url) end end ) end
×