Skip to content

Event examples

Jan Gabrielsson edited this page May 24, 2018 · 9 revisions

This model based on matching and posting events. Two main functions are provided in this example code;

Event.event(pattern,function)
Event.post(event,time)

Event:event(pattern,function) declares a handler for 'incoming' events.
'pattern' is any Lua key/value table matched against incoming events. The event needs at least a 'type' key, something that all Fibaro events (source triggers) have. 'function' is the handler called if the event matches.
Ex.

Event.event({type='property', propertyName='value', deviceID=310}, 
  function(env) fibaro:debug("Hello!") end)

This prints "Hello!" when a value property event for device id 310 is recieved (given that it is declared in the scene header)
Patterns can be a bit more elaborate and may contain variables to be matched against.
Ex.

Event.event({type='event', event = {data = {deviceId=56, keyId='$key'}}},
  function(env) fibaro:debug("Key "..env.p.key.." pressed") end)

Variables start with a '$' char and matched variables are available in the env.p parameter sent to the handler. For incoming events, keys that are not part of the standard (Fibaro) event can be matched against anyway, given that the key name corresponds to a property of that device id (it's a hack but quite useful).
Ex.

Event.event({type='property', propertyName='value', deviceID=310, value='$val'}, 
  function(env) 
    if env.p.val > 0 then fibaro:debug("Hello!, the lamp is on!") end
  end)

(The key 'last' is also allowed and returns the last modification time - works for globals and devices) So this allows you to handle events, so what? Well always running in the same instance makes stuff like this work

Event.event({type='event', event = {data = {deviceId=56, keyId='$key'}}}, 
  function(env)
    if env.p.key == '1' then a = 1
    elseif env.p.key == '2' and a == 1 and env.last <= 2 then a = 2
    elseif env.p.key == '3' and a == 2 and env.last <= 2 then 
      fibaro:debug("Sequence 1-2-3 pressed with max 2sec inbetween")
    else a = -1 end
  end)

'a' is just a local Lua variable keeping its value between, in this case 3, event invocations.... 'env.last' is the time in seconds since the event was last invoked.

Recieving events is all good, but being able to post your own events makes things even more interestings, and actually turns it into a programming model...

Event.post(event,time)

'event' is a Lua key/value table (with at least the mandatory 'type' key). Time is a either an absolute time, number, seconds since 1970 e.g. 'os.time()' or a string; "10:00" representing 10.00 in seconds , e.g. 10*3600+0*60
"+/10:00" representing 10 hours from now.
"n/10:00" representing the next 10.00 o'clock. Called after 10.00, it becomes 10.00 the next day.
"Sunset" represents sunset hour. "Sunset+10" and "Sunset-10" allowed, likewise for "Sunrise"

Trying out the key press handler above we could post like this:

Event.post({type='event', event = {data = {deviceId=56, keyId='1'}}},"+/00:00:01") 
Event.post({type='event', event = {data = {deviceId=56, keyId='2'}}},"+/00:00:03") 
Event.post({type='event', event = {data = {deviceId=56, keyId='3'}}},"+/00:00:05") 

Specifying delays like this allows for scheduling events to happen in the future, the base for 'loops' and schedulers... If time is omitted the event is posted immediatly. Ex. an event that does something every hour.

Event.event({type='hourly'}, -- match 'hourly' event
  function(env) 
    fibaro:print("Ding!")             
    Event.post(env.event,"+/01:00") -- Repost event 1 hour from now.
  end)

To run the above every hour we just need to start it with

Event.post({type='hourly'})

The event matched is available in 'env.event' and is just reposted at the current time + 1 hour. So, in the same "programming model' incoming fibaro events can be mixed with own events and 'loops'. A lot of nice to have functions can be built using this model. A more general "scheduler" could be defined like this.

Event.event({type='scheduler', next='$time', event='$event'},
  function(env) 
    Event.post(env.p.event) end -- post the provided event
    Event.post(env.event, env.p.time) -- and re-schedule this event to be posted at 'time'
  end)
Event.post({type='scheduler', next="+/00:15", event={type='quarter'}})

This will post an event {type='quarter'} every 15min, that can be acted upon by some other event handler...

Event.post({type='scheduler', next="+/00:30", event={type='half_hour'}})

Will reuse the same event declaration for something that reschedules every 30min.. To be able to schedule Lua functions to be invoked, an 'action' handler can be declared.

Event.event({type='action', action='$action'}, function(env) env.p.action(env) end)

Then we can do

Event.post({type='scheduler', next="+/00:15", 
    event={type='action', action=function(env) fibaro:debug("Dong!") end}})

The scheduler wil post the 'action' event every 15min, and the 'action' handler will call the function... There are some more code in the attached example to showcase other variants of schedulers based on this.

The code is setup to be able to run offline and simulate time to see the action (see variables in the beginning of file) It is of course possible to Event:post your own Fibaro events for simulation and debugging. It is possible to use FibaroSceneAPI. I do most of my development in ZeroBraneStudio on a Mac. Still better optimisation, error handling needs to be implemented, but it runs as is... :)

A setup that is quite convenient for a scene is to have a handler that runs every
midnight and initializes upcoming events for the day, like sunsets/sunrises, stuff from calendars etc. (More examples in the included code...)

Event.({type='startup'},
  function(env)
    Event.post({type='scheduler', -- start scheduler posting 'daily_init' events
      next="n/00:10",  -- at 00:10 every night
      event={type='daily_init'}}, "n/00:10") -- and post it at 00:10 tonight
      
    Event.event({type='daily_init'}, -- Setup things happening today
      function(env)
        local sunset = fibaro:getValue(1,'sunsetHour')
        local sunrise = fibaro:getValue(1,'sunriseHour')
        Event.post({type='sunrise'},"t/"..sunrise) -- Fire event at sunrise...
        Event.post({type='sunset'},"t/"..sunset)   -- Fire event at sunset...
        -- more stuff happening today
      end)
end)
Event.post({type='startup'})