Aller au contenu

jang

Membres confirmés
  • Compteur de contenus

    215
  • Inscription

  • Dernière visite

  • Jours gagnés

    45

Tout ce qui a été posté par jang

  1. function intervalRunner(seconds,fun) local nxt,ref=nil,{} local function loop() if fun()==':EXIT' or ref[1]==nil then return end nxt=nxt+seconds ref[1] = setTimeout(loop,1000*(nxt-os.time())) end local t = (os.time() // seconds) * seconds nxt=t+seconds ref[1] = setTimeout(loop,1000*(nxt-os.time()-(seconds > 3600 and 3600 or 0))) return ref end function stopIntervalRunner(ref) if ref[1] then clearTimeout(ref[1]) ref[1]=nil end end local function test() print("ping") end intervalRunner(60,test) will run test every minute, on the minute. 00:05:00, 00:06:00, 00:07:00 etc. intervalRunner(30,test) will run test every 30s, on the even 30s. 00:00:30, 00:01:00, 00:01:30 etc. intervalRunner(3600,test) will run test every hour, on the hour. 03:00:00, 04:00:00, 05:00:00, etc. It's nice because it syncs to even periods and it doesn't drift. Ex. local function checkGlobals() .... end function QuickApp:onInit() intervalRunner(60,checkGlobals) end If the function returns the string ':EXIT', the loop will stop. You can also stop it with calling stopIntervalRunner(ref) with the ref that intervalRunner returns.
  2. Sorry, long text in english but I don't trust Google translate :-) A cache is a really good idea, but can be tricky also. In my emulator I cache fibaro calls as it can run faster than realtime and calling the HC3 then becomes a bottle-neck. But I only cache when running faster than realtime. It's not just a read cache as I update it when setting properties or calling actions too. The reason is that fibaro.call(x,'turnOn'); if fibaro.getValue(x,'value') then ... end wouldn't work as getValue would retrieve the cached value unless I update the property when doing the turnOn. This is not a fool-proof method as I can't guess how all actions will affect properties. If someone does fibaro.call(MY_QA,"test") if fibaro.getValue(x,"value") then ... end and MY_QA test function updates device x's value property I miss it. That's why I only use it when speeding... In my EventRunner rule engine, I don't cache values at all due to the issue above. I probably could but it requires quite a lot of code to be fool-proof, because rules can have code similar to the above. I was thinking if this is also a problem for GEA? I guess you could say that all rules in GEA run in "parallel" and should see the same state. Then it works to keep a cache for an invocation and clear it before the next. In my system the rules are run sequentially, top to bottom, and some combinations of rules depend on that. E.g. if two rules are triggered, the first rule could change a value that the second rule could use. Then I don't know if you can change a value in a single rule and expect to use that changed value later in the rules action part? What I have done instead is that I focus on keeping down the number of rules being called by triggers. If I have a rule that looks like: "IF ID1:isOn and ID2:power < 5 THEN ...END" My "rule compiler" look at the test part between IF and THEN and see that 2 device properties are involved in the test. ...and thus only 2 events can be a reason to trigger that rule {type='device', id=ID1, property='value'} {type='device', id=ID2, property='power'} With an "intricate" hash schema I associate the rule with these 2 events so if they come into the system I can quickly lookup what rule(s) to run. This allows the system's cpu usage to not be directly dependent on the number of rules as only relevant rules are triggered by incoming events and I don't have to run all of them.
  3. jang

    Quick App - Evénements

    I usually don't promote code I write, but I have a QA library file (fibaroExtra) with some of the missing fibaro functions... including a simple to use refreshStates function (you can also get them more "refined" as sourceTriggers) https://forum.fibaro.com/topic/54538-fibaroextra/ local function handler(event) print("Incoming event:",json.encode(event)) end fibaro.getRefreshStates(handler) -- install handler I'm slowly migrating my own QAs to use this code.
  4. child:setVisible(false) works for me, but I need to refresh the web GUI. I haven't tried the app.
  5. It's not a. 'property' if not api.get("/devices/"..self.id).enabled then for _,child in pairs(self.childDevices) do child:setEnabled(false) end end or (both ways): local enabled = api.get("/devices/"..self.id).enabled for _,child in pairs(self.childDevices) do child:setEnabled(enabled) end self:setEnabled(bool) is the same as api.post("/devices/"..self.id,{enabled=bool==true}) 'enabled' doesn't stop the QA from running, you have to enforce that yourself (ex. in QuickApp:onInit() ) Ex. function QuickApp:onInit() if not __fibaro_get_device(self.id).enabled then self:debug("QA ",self.name," disabled") return end : : end
  6. This is a helper QA that can send triggers to other QAs that subscribe for them. Ok, if you don't need sub seconds responses. https://forum.fibaro.com/topic/49113-hc3-quickapps-coding-tips-and-tricks/?do=findComment&amp;comment=228539
  7. jang

    HC3 Alarme

    Here is a simple QA that sends a customEvent when an alarm partition is "enabled". The customEvent is named "AlarmEnabled1" for partition 1, "AlarmEnabled2" for partition 2 etc. You need to set an exit delay so the QA have time to discover that the partition is enabled. The customEvent can be picked up in a block or Lua scene. (or in a QA with some work) AlarmNotifier.fqa Here is the code local armedPs = {} local ces = {} local function watch() local function loop() for _,p in ipairs(api.get("/alarms/v1/partitions") or {}) do local ce = "AlarmEnabled"..p.id if not (ces[ce] or api.get("/customEvents/"..ce)) then -- if you remove partition, restart QA api.post("/customEvents",{name=ce,userDescription="Alarm enabled"}) -- Create event end ces[ce]=true if p.secondsToArm and not armedPs[p.id] then api.post("/customEvents/"..ce,{}) end if p.secondsToArm then print("partition",p.id,p.secondsToArm,"seconds") end armedPs[p.id] = p.secondsToArm end quickApp:updateProperty("value",next(armedPs)~=nil) setTimeout(loop,1000) end setTimeout(loop,0) end function QuickApp:onInit() self:debug(self.name, self.id) watch() end
  8. jang

    UN petit coup de main SVP

    The Fibaro forum 'HC3 QuickApps coding - tips and tricks" have ~1200 posts starting February 2020. I wouldn't use any code before August 2020 - we have learnt a lot the last 6 months...
  9. jang

    UN petit coup de main SVP

    @ Lazer is right. I didn't notice the setInterval. Yes, the response time can vary depending if there are events available. ... and your requests "run over" each other.
  10. jang

    UN petit coup de main SVP

    Is this better? math.randomseed(os.time()) local urlTail = "&lang=en&rand="..math.random(2000,4000).."&logs=false" local lastRefresh = 0 local function pollRefresh() --self:warning("<font color=green>", "Request with lastRefresh: ", lastRefresh ,"</font>") --*****Si on ajoute ce warning tout va bien***** local stat,res = self.http:request("http://127.0.0.1:11111/api/refreshStates?last=" .. lastRefresh..urlTail, { success = function(res) local states = res.status==200 and json.decode(res.data) if states then if lastRefresh == states.last then self:warning("<font color=yellow>", "lastRefresh: ", lastRefresh , " states.last : ", states.last ,"</font>") end lastRefresh=states.last if states.events and #states.events > 0 then checkEvents(states.last) end -- Henri last pour debug only) end end, error = function(res) self:error("Error : refreshStates : " .. res) end, }) end --pollRefresh
  11. jang

    QA Dawn&Dusk

    In northern Sweden, sunrise is before 2:00 in the summer...
  12. jang

    Variables à virgule

    print(_VERSION) hour = 1 hour = hour + 1 print ("hour:".. hour) hour = hour + "1" print ("hour:".. hour) a = 1 b = 2.0 print("Type a:",type(a)) print("Type b:",type(b)) print("math.type a:",math.type(a)) print("math.type b:",math.type(b)) a = 3.0 b = 3.1 print("tointeger a:",math.tointeger(a)) print("tointeger b:",math.tointeger(b)) Lua 5.3 hour:2 hour:3.0 Type a: number Type b: number math.type a: integer math.type b: float tointeger a: 3 tointeger b: nil http://www.lua.org/manual/5.3/manual.html#pdf-math.tointeger
  13. jang

    UN petit coup de main SVP

    No, and it's tricky also for Fibaro as it is between 2 different processes (each QA is its own process) This is one way to do it https://forum.fibaro.com/topic/49113-hc3-quickapps-coding-tips-and-tricks/?do=findComment&amp;comment=207479 Client (unfortunately needs most code, but can be put in a "Library file") do local var,n = "RPC_"..plugin.mainDeviceId,0 api.post("/globalVariables",{name=var,value=""}) function rpc(id,fun,args,timeout) fibaro.setGlobalVariable(var,"") n = n + 1 fibaro.call(id,"RPC_CALL",var,n,fun,args) timeout = os.time()+(timeout or 3) while os.time() < timeout do local r = fibaro.getGlobalVariable(var) if r~="" then r = json.decode(r) if r[1] == n then if not r[2] then error(r[3],3) else return select(3,table.unpack(r)) end end end end error(string.format("RPC timeout %s:%d",fun,id),3) end end local function defineRemote(id, fun, timeout) _G[fun]=function(...) rpc(id, fun, {...}, timeout) end end function QuickApp:test() n=100 local t0 = os.clock() for i=1,n do foo(3,i) -- Remote call to QA 58 and function foo with args 3,i 100 times and calculate average time end print(string.format("Call time: %.3fms",((os.clock()-t0)*1000)/n)) end function QuickApp:onInit() self:debug("RPC") defineRemote(58,"foo") -- define remote function foo from QA 58 sel:test() end The "server" (with deviceID 58) that exports 'foo' is much simpler. In fact, all global functions in QA 58 can be called from remote. function QuickApp:RPC_CALL(var,n,fun,args) local res = {n,pcall(_G[fun],table.unpack(args))} fibaro.setGlobalVariable(var,json.encode(res)) end function foo(x,y) return x+y end -- Remote function The time it takes for a call is ~11.7ms, which is quite ok. [23.03.2021] [21:41:00] [DEBUG] [QUICKAPP57]: Call time: 11.757ms
  14. jang

    UN petit coup de main SVP

    Do we know that? I believe that in a normally loaded HC3 there are enough events to even it out (processing events/second). I.e you poll often and get few events each time or you poll less often and get many. In a light environment the request will hang waiting for new events taking no CPU.
  15. jang

    UN petit coup de main SVP

    If you use request ("http://127.0.0.1:11111/api/refreshStates?last=" ... you can poll with 0 delay. With refreshStates the trick is to efficiently map incoming refresh event to what what function/rule you want to call.
  16. jang

    UN petit coup de main SVP

    Yes, that's how I do it in EventRunner4 too. local uptime = api.get("/settings/info").serverStatus or 0 if os.time()-uptime < 30 then quickApp:post({type='se-start'}) end I have a post function that adds fake events to my refreshStates loop. Nice way to test functionality in the system too...
  17. This is how I would tackle DST local events = { {time="02:00",action=function() print("02:00 Ding!") end}, {time="15:10",action=function() print("15:10 Ding!") end}, {time="21:03",action=function() print("21:03 Ding!") end}, } local function setUpDayEvents(self) local now=os.date("*t") now=60*60*now.hour+60*now.min+now.sec for _,e in ipairs(events) do local h,m=e.time:match("(%d+):(%d+)") local t = 60*60*tonumber(h)+60*tonumber(m) if t >= now then quickApp:debug("Schedule:"..e.time) setTimeout(e.action,1000*(t-now),e.time) end end end function intervalRunner(seconds,fun) local nxt local function loop() if fun()=='RESTARTED' then return end -- We still resturn after plugin.restart... nxt=nxt+seconds local a = setTimeout(loop,1000*(nxt-os.time())) end local t = (os.time() // seconds) * seconds nxt=t+seconds setTimeout(loop,1000*(nxt-os.time()-(seconds > 3600 and 3600 or 0))) end function QuickApp:onInit() quickApp = self setUpDayEvents() intervalRunner(24*60*60,setUpDayEvents) self:setVariable("DST",os.date("*t").isdst) intervalRunner(60*60,function() if os.date("*t").isdst ~= self:getVariable("DST") then self:debug("DST changed") plugin.restart() return "RESTARTED" end end) end -- rebooting the QA at DST... In this case it could be solved in other ways (with more code) - in more complicated QAs with many timers it may be the only approach... (DST in Sweden is on Sun Mar 28 03:00:00) Program starting as '"/Applications/ZeroBraneStudio.app/Contents/ZeroBraneStudio/bin/lua.app/Contents/MacOS/lua53" -e "io.stdout:setvbuf('no')" "/var/folders/ft/sp22kj0d52l0f96grjcqwfyw0000gn/T/.kUBXRl"'. Program 'lua53' started in '/Users/erajgab/Dropbox/LUA/EventRunner/EventRunner' (pid: 65727). Debugging session started in '/Users/erajgab/Dropbox/LUA/EventRunner/EventRunner/'. [21.03.2021] [13:56:50] |SYS |: HC3 SDK v0.199 [21.03.2021] [13:56:50] |SYS |: Speeding 48 hours [21.03.2021] [13:56:50] |SYS |: Created Event server at 192.168.1.184:6872 [21.03.2021] [13:56:50] |SYS |: Created Terminal server at 192.168.1.184:6972 [27.03.2021] [10:00:00] |SYS |: Setting emulator time to Sat Mar 27 10:00:00 2021 [27.03.2021] [10:00:00] |LOG |: DST at Sun Mar 28 03:00:00 2021 [27.03.2021] [10:00:00] |SYS |: Setting speed to true [27.03.2021] [10:00:00] |-----|: ----------------------------------- Loading QuickApp 'My QA'... ----------------------------------- [27.03.2021] [10:00:00] |-----|: ---------------- QuickApp 'My QA', deviceID:999 started at Sat Mar 27 10:00:00 2021 ---------------- [27.03.2021] [10:00:00] [DEBUG] [QUICKAPP999]: Schedule:15:10 [27.03.2021] [10:00:00] [DEBUG] [QUICKAPP999]: Schedule:21:03 [27.03.2021] [10:00:00] |SDBG |: Incoming trigger:{"type":"DeviceCreatedEvent","data":{"id":999}} [27.03.2021] [15:10:00] [DEBUG] [QUICKAPP999]: 15:10 Ding! [27.03.2021] [21:03:00] [DEBUG] [QUICKAPP999]: 21:03 Ding! [28.03.2021] [00:00:00] [DEBUG] [QUICKAPP999]: Schedule:02:00 [28.03.2021] [00:00:00] [DEBUG] [QUICKAPP999]: Schedule:15:10 [28.03.2021] [00:00:00] [DEBUG] [QUICKAPP999]: Schedule:21:03 [28.03.2021] [03:00:00] [DEBUG] [QUICKAPP999]: 02:00 Ding! [28.03.2021] [03:00:00] [DEBUG] [QUICKAPP999]: DST changed [28.03.2021] [03:00:00] |SYS |: Restarting QA 999, timers=3, memory used 1298.5kB [28.03.2021] [03:00:00] |-----|: ---------------- QuickApp 'My QA', deviceID:999 started at Sun Mar 28 03:00:00 2021 ---------------- [28.03.2021] [03:00:00] [DEBUG] [QUICKAPP999]: Schedule:15:10 [28.03.2021] [03:00:00] [DEBUG] [QUICKAPP999]: Schedule:21:03 [28.03.2021] [14:00:00] |SDBG |: Incoming trigger:{"type":"DeviceModifiedEvent","data":{"id":999}} [28.03.2021] [15:10:00] [DEBUG] [QUICKAPP999]: 15:10 Ding! [28.03.2021] [21:03:00] [DEBUG] [QUICKAPP999]: 21:03 Ding! [29.03.2021] [01:00:00] [DEBUG] [QUICKAPP999]: Schedule:02:00 [29.03.2021] [01:00:00] [DEBUG] [QUICKAPP999]: Schedule:15:10 [29.03.2021] [01:00:00] [DEBUG] [QUICKAPP999]: Schedule:21:03 [29.03.2021] [02:00:00] [DEBUG] [QUICKAPP999]: 02:00 Ding! [29.03.2021] [10:00:00] |SYS |: Max time - exit Program completed in 0.84 seconds (pid: 65727). Debugging session completed (traced 0 instructions). Btw, even on the HC3 the code continues after the call to plugin.restart() until current function terminates - took me 3 hours to find the bug...:-)
  18. Home exercise: How to survive daylight time savings?...
  19. Example. local events = { {time="02:00",action=function() print("02:00 Ding!") end}, {time="15:10",action=function() print("15:10 Ding!") end}, {time="21:03",action=function() print("21:03 Ding!") end}, } local function setUpDayEvents() local now=os.date("*t") now=60*60*now.hour+60*now.min+now.sec for _,e in ipairs(events) do local h,m=e.time:match("(%d+):(%d+)") local t = 60*60*tonumber(h)+60*tonumber(m) if t >= now then setTimeout(e.action,1000*(t-now)) end end end function midnightRunner(fun) local nxt local function loop() print("Dong!") fun() nxt=nxt+24*60*60 -- Next midnight setTimeout(loop,1000*(nxt-os.time())) end local t = os.date("*t") t.hour,t.min,t.sec=0,0,0 -- Last midnight nxt=os.time(t)+24*60*60 -- Next midnight setTimeout(loop,1000*(nxt-os.time())) end function QuickApp:onInit() setUpDayEvents() -- When QA starts up midnightRunner(setUpDayEvents) -- Every midnight end Output: [20.03.2021] [08:09:02] |SYS |: HC3 SDK v0.199 [20.03.2021] [08:09:02] |SYS |: Speeding 24 hours [20.03.2021] [08:09:02] |SYS |: Created Event server at 192.168.1.184:6872 [20.03.2021] [08:09:02] |SYS |: Created Terminal server at 192.168.1.184:6972 [20.03.2021] [08:09:03] |SYS |: Setting speed to true [20.03.2021] [08:09:03] |LOG |: Polling HC3 for triggers every 2000ms [20.03.2021] [08:09:03] |-----|: ----------------------------------- Loading QuickApp 'My QA'... ----------------------------------- [20.03.2021] [08:09:03] |-----|: ---------------- QuickApp 'My QA', deviceID:999 started at Sat Mar 20 08:09:03 2021 ---------------- [20.03.2021] [08:09:03] |SDBG |: Incoming trigger:{"type":"DeviceCreatedEvent","data":{"id":999}} [20.03.2021] [15:10:00] [DEBUG] [QUICKAPP999]: 15:10 Ding! [20.03.2021] [21:03:00] [DEBUG] [QUICKAPP999]: 21:03 Ding! [21.03.2021] [00:00:00] [DEBUG] [QUICKAPP999]: Dong! [21.03.2021] [02:00:00] [DEBUG] [QUICKAPP999]: 02:00 Ding! [21.03.2021] [02:00:00] |SYS |: Max time - exit Program completed in 1.15 seconds (pid: 27233). Debugging session completed (traced 0 instructions). setTimeout can handle 24.8 days
  20. jang

    UN petit coup de main SVP

    This is not necessary anymore as we use http:request("http://127.0.0.1:11111/api/refreshStates?last=" ... that doesn't block other timers. It was necessary when we used api.get("/refreshStates...) that hanged and blocked timers if there were no events.
  21. Your QA could emit customEvents for dawn and dusk etc., Scenes can react on customEvents.
  22. jang

    question HTTP request

    Seulement le matin alors?
  23. jang

    question HTTP request

    Need to add 'http://' prefix to url
  24. jang

    UN petit coup de main SVP

    You can do the same with Python, Perl whatever. However, to pull down the code you need to do it from outside the HC3. I think that is what henri-allauch was attempting.
  25. jang

    UN petit coup de main SVP

    Yes, but you have to run the code offline on PC/Mac (HC3 don't have io.*). Ex. using this
×
×
  • Créer...