Lua timers in SHAC/NAC

Discussion in 'C-Bus Automation Controllers' started by Pie Boy, Aug 15, 2018.

  1. Pie Boy

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    29
    Likes Received:
    4
    Location:
    New Zealand
    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
     
    Pie Boy, Aug 15, 2018
    #1
    1. Advertisements

  2. Pie Boy

    ssaunders

    Joined:
    Dec 17, 2008
    Messages:
    74
    Likes Received:
    0
    Location:
    Melbourne
    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 
     
    ssaunders, Feb 15, 2019
    #2
    1. Advertisements

  3. Pie Boy

    Ashley

    Joined:
    Dec 1, 2005
    Messages:
    961
    Likes Received:
    70
    Location:
    Adelaide, Australia
    What's wrong with the PulseCBusLevel command?
     
    Ashley, Feb 15, 2019
    #3
  4. Pie Boy

    ssaunders

    Joined:
    Dec 17, 2008
    Messages:
    74
    Likes Received:
    0
    Location:
    Melbourne
    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.
     
    ssaunders, Feb 15, 2019
    #4
  5. Pie Boy

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    29
    Likes Received:
    4
    Location:
    New Zealand
    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.
     
    Pie Boy, Jun 9, 2019
    #5
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.