This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

detect double, single and long press from wall switch
#1
Lightbulb 
Here is the example of how to detect different types of pressing on a wall switcher that has no fixation. It was made in collaboration with Embedded Systems specialists and we very appreciate this help.
The use-case we wanted to bring to life is:
1. we have 2 groups of light in the room (e.g. on the ceiling and on the wall)
2. fast double press on the switcher changes state of first group of light and fast single press changes state of second group of light
3. long press turns off both groups
(Our client said that this is rather comfortable to use after couple weeks of testing)
Suppose we have room one with switcher, attached to address 1/1/1 with two groups of light 1/2/1 and 1/2/2, room 2 with switcher 1/1/2 and lights on 1/2/3 and 1/2/4. For every switcher we also need a memory object that has information on how many times was the switcher toggled for last specified period (we use 1 second period). For switcher 1/1/1 we create object 1/3/1 (unsigned integer) and switcher 1/1/2 has corresponded object 1/3/2. Both initialized to zero.

So, here is the code. Resident script, sleeping interval 0. This script handles all telegrams and calls function "switcher" if telegram was from specified address. Function switcher accepts address of the switcher (in format 1_1_1, not 1/1/1 - it is done because string 1_1_1 will be used to store in memory last time of changing state of 1/1/1 object), address of first and second groups of light, counter object (that is described earlier), and new state of switcher (taken from telegram).
Function counts difference between rising and falling edges on the object and detects if the press on the switcher was short or long. In case of short press counter object value increments.
Code:
1234567891011121314151617181920212223242526272829303132333435363738394041424344
if not client then  require('genohm-scada.eibdgm')    -- knx group write handler  function groupwrite(event)    local value    value = knxdatatype.decode(event.datahex, dt.bool)    --first room    if event.dst == "1/1/1" then      switcher("1_1_1", "1/2/1", "1/2/2", "1/3/1", value)    end    --second room    if event.dst == "1/1/2" then      switcher("1_1_2", "1/2/3", "1/2/4", "1/3/2", value)    end    -- add the same code for next rooms  end    client = eibdgm:new()  client:sethandler('groupwrite', groupwrite)  function switcher(event_adress, light1, light2, counter_object, value)    nowTIME = os.time()    counter = grp.getvalue(counter_object)    state = value    if (state == false) then      counter = counter + 1      lastONtime = storage.get('lastONtime' .. event_adress)      if (nowTIME - lastONtime > 1) then        log('long press ' .. event_adress)        grp.write(light1, false)        grp.write(light2, false)        grp.update(counter_object, 0)      else        grp.update(counter_object, counter)      end    else      storage.set('lastONtime'  .. event_adress, nowTIME)    end      end end client:step()

Next event script is to be attached to every counter object. It sleeps for specified interval and after waking up turns on corresponding group of light and resets the counter.


Code:
123456789101112131415161718192021
event_adress = '1/3/1' light1 = '1/2/1' light2 = '1/2/2' switcher_adress = '1/1/1' os.sleep(1) value = grp.getvalue(event_adress) if (value == 1) then  --log('single press '.. switcher_adress)  grp.write(light1, not(grp.getvalue(light1)))  grp.update(event_adress, 0) end if (value == 2) then  --log('double ' .. switcher_adress)  grp.write(light2, not(grp.getvalue(light2)))  grp.update(event_adress, 0) end if (value >= 3) then  --log('reset counter'.. switcher_adress, value)  grp.update(event_adress, 0) end

It must be said that you can detect as many toggles as you want for specified period.
The code is not excellent, but it works. I would be very glad to receive advices on optimization.
Reply
#2
Good job, though you can do it without any event-based scripts Smile

Some suggestions:
1. You don't need to use storage inside of resident script as variables are kept between each call. You can simply use a Lua table to store timer values for each group address.
2. You should use storage instead of grp.update for counters as you don't need to display this info in visualization or pass it to gateways.
Reply
#3
(10.07.2015, 13:39)admin Wrote: Good job, though you can do it without any event-based scripts Smile

Some suggestions:
1. You don't need to use storage inside of resident script as variables are kept between each call. You can simply use a Lua table to store timer values for each group address.
2. You should use storage instead of grp.update for counters as you don't need to display this info in visualization or pass it to gateways.

According to second suggestion: I need to update counter object because second script (the one that turns on the lights) runs on updating it. Is it possible to tie lua script to storage variable so I can run script when variable changes?
Reply
#4
I think the code executes the script, attached to the counter object, as many as you activate the button, so on een double press this scripts is executed two times.
Reply
#5
Yes, you are right. Still, you should check the event value in order not run the script when counter is 0, like this:


Code:
1234567891011121314151617181920212223
value = tonumber(event.datahex, 16) if value > 0 then   light1 = '1/2/1'   light2 = '1/2/2'   switcher_adress = '1/1/1'   os.sleep(1)   value = event.getvalue()   if value == 1 then     -- log('single press '.. switcher_adress)     grp.write(light1, not(grp.getvalue(light1)))   elseif value == 2 then     -- log('double ' .. switcher_adress)     grp.write(light2, not(grp.getvalue(light2)))   end   -- reset counter   if value > 0 then     grp.update(event.dst, 0)   end end
Reply
#6
Hi guys,

I have been testing our colleague's solution to be able to turn on two different lights with the same button using a single pulse or double pulse, but I can't get it to work properly (and I don't know if there is something I haven't understood well)

I have created a resident script (sleep interval 0), where the address 16/1/1 is the press that I make on the button, the addresses 1/1/10 and 1/1/120 are the lights and the address 16/1/2 is an address that I have created to perform the count
:
Code:
123456789101112131415161718192021222324252627282930313233343536373839
if not client then   require('genohm-scada.eibdgm')     -- knx group write handler   function groupwrite(event)     local value     value = knxdatatype.decode(event.datahex, dt.bool)     --first room     if event.dst == "16/1/1" then       switcher("16_1_1", "1/1/10", "1/1/120", "16/1/2", value)     end   end     client = eibdgm:new()   client:sethandler('groupwrite', groupwrite)   function switcher(event_adress, light1, light2, counter_object, value)     nowTIME = os.time()     counter = grp.getvalue(counter_object)     state = value     if (state == false) then       counter = counter + 1       log(counter)       lastONtime = storage.get('lastONtime' .. event_adress)       if (nowTIME - lastONtime > 1) then         log('long press ' .. event_adress)         grp.write(light1, false)         grp.write(light2, false)         grp.update(counter_object, 0)       else         grp.update(counter_object, counter)       end     else       storage.set('lastONtime'  .. event_adress, nowTIME)     end      end end client:step()

And also at address 16/1/2 I have created the following event script:
Code:
1234567891011121314151617181920212223
value = tonumber(event.datahex, 16) if value > 0 then   light1 = '1/1/10'   light2 = '1/1/120'   switcher_adress = '16/1/1'   os.sleep(1)   value = event.getvalue()   if value == 1 then     log('single press '.. switcher_adress)     grp.write(light1, not(grp.getvalue(light1)))   elseif value == 2 then     log('double ' .. switcher_adress)     grp.write(light2, not(grp.getvalue(light2)))   end   -- reset counter   if value > 0 then     grp.update(event.dst, 0)   end end

The problem is that I can't get it to turn on the corresponding lights by giving it a single pulse or two, but nevertheless there are times when I do a short press, it interprets that I have done a long press and turns off the lights or when I try to do a double press , it interprets that I have done one or that I have done a long press (that is, it does different things each time). I can't find what the problem is.

I hope you can help me. Thank you so much
Reply


Forum Jump: