Hi all, I created a small lua library of functions for timing on/off a group address which means the function can be called from any script, event, resident etc 1- create a library called Vibe, paste in the code below then save time_t={time_triged = {}, net= {}, app = {}, group = {}, level = {}, rrate= {}, delay_time = {}, tag = {}, index = {}, level_after_timeout = {}} function Time_func(net_f, app_f, group_f, level_f, rrate_f, delay_time_f, level_after_timeout_f) SetCBusLevel(net_f, app_f, group_f, level_f, rrate_f) time_t.time_triged[group_f] = os.time() time_t.net[group_f] = net_f time_t.app[group_f] = app_f time_t.group[group_f] = group_f time_t.level[group_f] = level_f time_t.rrate[group_f] = rrate_f time_t.delay_time[group_f] = delay_time_f time_t.tag[group_f] = GetCBusGroupTag(group, app, net) time_t.index[group_f] = group_f time_t.level_after_timeout[group_f] = level_after_timeout_f storage.set('time_t', time_t) end function Timer_Stop(group) for i = 0, 254 do yt = storage.get('time_t') if yt.group == group then yt.group = nil storage.set('time_t', yt) end end end function Timer_Chk() xt = storage.get('time_t') for ii = 0,254 do if xt.group[ii] then if os.time() - xt.time_triged[ii] >= xt.delay_time[ii] then SetCBusLevel(xt.net[ii], xt.app[ii], xt.group[ii], xt.level_after_timeout[ii], xt.rrate[ii]) xt.group[ii] = nil storage.set('time_t', xt) end end end end 2 - create resident script with delay of 0 to call the Time_Chk function require ("user.Vibe") Timer_Chk() 3- call the function from what ever script you want eg in event script require('user.Vibe') -- Time_func(net, app, group(number), level(0-255), rrate, delay_time(in sec), level after timeout(0-255) Time_func(0, 56, 22, 255, 0, 5, 0) if you want to cancel/stop timer call the Timer_Stop(group) function with group being the same group number that was included in the Time_func() as above. I will modify the group parameter to also accept ga tag name, when i have a spare 10 min... I am keen for some feedback on this one as far as i can tell it is accurate to 1sec
Thanks for posting, Pie Boy. I found a use for this by modifying your code to incorporate an 'optional' group turn-on (level to '-1' if no turn-on change desired), and also made some optimisations that you might find useful. Your previous code was limited to managing up to 255 timers, while the below is unlimited in number, and also able to manage a set of timers extending across multiple networks and applications without group number collision. I've tried to improve memory management of the LUA tables, too (still a bit of an LUA noob, so there's probably more improvements to be had). Cheers, S. Code: time_t = {time_started = {}, ramp_rate = {}, delay_time = {}, level_after_timeout = {}} function Timer_Group(net_f, app_f, group_f, level_f, rrate_f, delay_time_f, level_after_timeout_f) if (level_f > -1) then SetCBusLevel(net_f, app_f, group_f, level_f, rrate_f) end local knet, kapp, kgrp if ( type(net_f)=='string' ) then knet = GetCBusNetworkAddress(net_f) else knet = net_f end if ( type(net_f)=='string' ) then kapp = GetCBusApplicationAddress(knet, app_f) else kapp = app_f end if ( type(net_f)=='string' ) then kgrp = GetCBusGroupAddress(knet, kapp, group_f) else kgrp = grp_f end local key = tostring(knet) ..":" .. tostring(kapp) .. ":" .. tostring(kgrp) time_t.time_started[key] = os.time() time_t.ramp_rate[key] = rrate_f time_t.delay_time[key] = delay_time_f time_t.level_after_timeout[key] = level_after_timeout_f storage.set('time_t', time_t) end function Timer_Stop(net_f, app_f, group_f) time_t = storage.get('time_t') local knet, kapp, kgrp if ( type(net_f)=='string' ) then knet = GetCBusNetworkAddress(net_f) else knet = net_f end if ( type(net_f)=='string' ) then kapp = GetCBusApplicationAddress(knet, app_f) else kapp = app_f end if ( type(net_f)=='string' ) then kgrp = GetCBusGroupAddress(knet, kapp, group_f) else kgrp = grp_f end local key = tostring(knet) ..":" .. tostring(kapp) .. ":" .. tostring(kgrp) if (time_t ~= nil) then time_t.time_started[key] = nil time_t.ramp_rate[key] = nil time_t.delay_time[key] = nil time_t.level_after_timeout[key] = nil end storage.set('time_t', time_t) end function Timer_Chk() local key, time_started time_t = storage.get('time_t') if (time_t ~= nil) then for key,time_started in pairs(time_t.time_started) do if os.time() - time_t.time_started[key] >= time_t.delay_time[key] then local knet = tonumber(string.match(key, "(%d+):")) local kapp = tonumber(string.match(key, ":(%d+):")) local kgrp = tonumber(string.match(key, ":(%d+)$")) SetCBusLevel(knet, kapp, kgrp, time_t.level_after_timeout[key], time_t.ramp_rate[key]) time_t.time_started[key] = nil time_t.ramp_rate[key] = nil time_t.delay_time[key] = nil time_t.level_after_timeout[key] = nil storage.set('time_t', time_t) end end end end
Absolutely nothing at all. I used Pie Boy's code as a concept using lighting groups emulating the same thing as PulseCBusLevel, with the intent of timing things other than simple groups. Ultimately I ditched the lot in favour of using groups / PulseCBusLevel / a bunch of event-based scripts for each group, but thought the code might be useful to someone one day.
Nice Work, Ssaunders, Yeah i have on a few different sites L5504AUX auxiliary input units with various beam sensors, flow valves, pressure switches connected etc so i use these timers, for a different Ga to be activated (Than the one that triggered the timer) after the timeout period. Many Thanks.
Hey @ssaunders , Thanks for posting that enhanced Timer script. I think the forum engine might have garbled some of the syntax, could you help me to figure it the correct code? There are a few calls to store a time that was simple to spot and fix (storage.set('time_time_t') had the closing single quote missing. Unfortunately, I'm new to Lua and my fault-finding abilities end there! Line 40: (not sure how to correct this ?) Code: time_t = storage.get('time_t local knet, kapp, kgrp Line 74: (not sure how to correct this ?) Code: time_t = storage.get('time_t if (time_t ~= nil) then Would appreciate any help or guidance you can give. I am hoping to use your code snippets, as I have had trouble with the standard 'PulseCBusLevel' command, which I have found successive requests made by it seem to cancel the previous command, and set the group to 0...(as reported elsewhere on the forum)
Hi @paddyb, Found a couple of small errors with the above code (mostly setting time_t had invalid vars). Try this out: Code: time_t = {time_started = {}, ramp_rate = {}, delay_time = {}, level_after_timeout = {}} function Timer_Group(net_f, app_f, group_f, level_f, rrate_f, delay_time_f, level_after_timeout_f) if (level_f > -1) then SetCBusLevel(net_f, app_f, group_f, level_f, rrate_f) end local knet, kapp, kgrp if ( type(net_f)=='string' ) then knet = GetCBusNetworkAddress(net_f) else knet = net_f end if ( type(app_f)=='string' ) then kapp = GetCBusApplicationAddress(knet, app_f) else kapp = app_f end if ( type(group_f)=='string' ) then kgrp = GetCBusGroupAddress(knet, kapp, group_f) else kgrp = group_f end local key = tostring(knet) ..":" .. tostring(kapp) .. ":" .. tostring(kgrp) time_t.time_started[key] = os.time() time_t.ramp_rate[key] = rrate_f time_t.delay_time[key] = delay_time_f time_t.level_after_timeout[key] = level_after_timeout_f storage.set('time_t', time_t) end function Timer_Stop(net_f, app_f, group_f) time_t = storage.get('time_t') local knet, kapp, kgrp if ( type(net_f)=='string' ) then knet = GetCBusNetworkAddress(net_f) else knet = net_f end if ( type(net_f)=='string' ) then kapp = GetCBusApplicationAddress(knet, app_f) else kapp = app_f end if ( type(net_f)=='string' ) then kgrp = GetCBusGroupAddress(knet, kapp, group_f) else kgrp = group_f end local key = tostring(knet) ..":" .. tostring(kapp) .. ":" .. tostring(kgrp) if (time_t ~= nil) then time_t.time_started[key] = nil time_t.ramp_rate[key] = nil time_t.delay_time[key] = nil time_t.level_after_timeout[key] = nil end storage.set('time_t', time_t) end function Timer_Chk() local key, time_started time_t = storage.get('time_t') if (time_t ~= nil) then for key,time_started in pairs(time_t.time_started) do if os.time() - time_t.time_started[key] >= time_t.delay_time[key] then local knet = tonumber(string.match(key, "(%d+):")) local kapp = tonumber(string.match(key, ":(%d+):")) local kgrp = tonumber(string.match(key, ":(%d+)$")) SetCBusLevel(knet, kapp, kgrp, time_t.level_after_timeout[key], time_t.ramp_rate[key]) time_t.time_started[key] = nil time_t.ramp_rate[key] = nil time_t.delay_time[key] = nil time_t.level_after_timeout[key] = nil storage.set('time_t', time_t) end end end end Cheers, Tim
Hi Tim, Thanks a mill for trying to help, but it seems even the example you posted above is somehow altered by the forum engine. It seems to be parsing the code in an effort to render it safely, but unfortunately, it's rendering it in a non-functional way. It just throws errors when pasted and trying to save it in the shac editor. Even if you paste your code from your post above into a plain text editor, on line 33 for example it is missing a closing single quote on the "storage.set" command. Somethings, like this particular line, is easy to spot and fix for a novice, but other syntax errors are also introduced by the forum engine that is are not as easy for me to spot and fix, I can't tell if it's missing a closing bracket, a closing quote mark etc. ....Again, totally nothing to do with you, but if it's possible to attach a text file with the raw code, that would be great, and if not thanks for trying anyway, I appreciate your effort so far.
Morning, Not a problem - I didn't do any of the heavy lifting you can thank the others for that ^^. Just tried copy and paste into VS Code and it looks fine - I also copied into the editor and it didn't seem to complain. Try this: https://pastebin.com/CUkU9HZD Cheers, Tim
Cheers @Timbo ! The Pastebin code works perfectly, thanks. The forum seems to have issues with some closing single quotes and some closing brackets... It also removed a few 'new lines' or carriage returns, which I see now is what was throwing me... Makes much more sense now! Thanks again
I am SO sorry I missed your message @paddyb. (And thanks for helping out @Timbo.) @Ashley I came across a rather weird scenario where PulseCBusLevel would just not work for me in an LUA script. In short: Kids bedrooms have a PIR that is used to detect occupancy. The kids aren't there? Turn off the bloody light! I tried with Pulse, but it failed miserably. On getting a PIR trigger in an event script, pulse the GA to the level that it is at now, with a timeout of ten minutes to 'off'. If the PIR triggers again then the pulse occurs again. It didn't work, no matter how much I messed with it. The lights would turn on by pressing the switch, but would turn themselves off again about two seconds later! (Turning on the switch is in the field of view of the PIR.) Don't know whether it was some weird timing thing, but I dusted off this rusty old bit of script and got things to work perfectly in about two minutes, and moved on. One advantage of the script approch over pulse is that you don't have to specify an initial level of the GA, just the final timeout level, which is great for this kids-leave-lights-on scenario. I did note in the release notes for 1.10.0 that there was a database issue with pulse fixed. Sounded unrelated, but for the record I only tried the kids' light timeout on 1.6.0, have since upgraded, but not tried pulse again so no idea whether that would have helped.