Skip to content

Event functions

Jan Gabrielsson edited this page Aug 7, 2018 · 32 revisions

Event functions are the basic primitives to build up scenes in the framework.

Event.event

Defining an event handler.

Event.event(<event>,<action>)

<event> is a Lua table with a 'type' key.
e.g. {type='property', deviceID=58, propertyName='value'}.
<action> is a Lua function that should be called when an event is received matching the first argument.
e.g. function(env) fibaro:debug("Ding!") end
Functions take one argument, an 'environment' with context info.
An event handler that turns on lamp with id 77 when motion sensor with id 58 is triggered would look like this

Event.event({type='property', deviceID=58, propertyName='value'},
           function(env) if fibaro:getValue(58,'value')>'0' then fibaro:call(77,'turnOn') end end)

In this case we check if the sensor was breached and then turn on the light.
The framework is helpful and complements the Fibaro event above with a 'value' field before handing it over to the event handler. It also allows for 'constraint' pattern in the matching event. E.g.

Event.event({type='property', deviceID=58, value='$>0'},
           function(env) fibaro:call(77,'turnOn') end)

This handler only matches if the value is above '0' so the handler can safely turn on the light when called without having to check the sensor value. Constraints can be '>', '<', '>=', '<=', '~='. The check can be against a numeric value or a string. For checks with equality no constraint operator is needed as fields are matched with each other.

Event.event({type='global', name='TimeOfDay', value='Night'},
           function(env) fibaro:debug('TimeOfDay is set to Night') end)

Event.post

Posting an event.

Event.post(<event>[,<time>])

Post an event immediately if <time> parameter is omitted or at a time in the future. Time formats are:

  • <number>, milliseconds epoc. Event.post({type='test'},osTime()) is the same as posting the event immediately.
  • "+/10:00", Event.post({type='test'},"+/10:00") posts event in 10 hours from now. Event.post({type='test'},"+/00:00:22") post event 22 seconds from now.
  • "t/10:00", Event.post({type='test'},"t/10:00") posts event (t)oday at 10:00.
  • "n/10:00", Event.post({type='test'},"n/10:00") posts event (n)ext time. today at 10.00AM if called before (or at) 10.00AM else 10:00AM next day
  • "t/sunset", Event.post({type='test'},"sunset") posts event at sunset (today)
  • "t/sunrise", Event.post({type='test'},"sunrise") posts event at sunrise (today)
  • "t/sunset+10", Event.post({type='test'},"sunrise+10") posts event at sunrise+10min (today)
  • "t/sunset-10", Event.post({type='test'},"sunrise-10") posts event at sunrise-10min (today)

Event.schedule

Schedule recurring user defined events.

Event.schedule(<time>,<action>[,<options>])

This function is a convenience function to create event loops.

Event.schedule("n/00:00",function(env) Log(LOG.LOG,"PING!") end)

will log "PING" at midnight every day

Event.schedule("+/01:00",function(env) Log(LOG.LOG,"PING!") end)

will log "PING" every 60min during the day. 'options' is an optional table with one or more additional arguments. {start=<true/false>, cond=, name=}
If 'start' is true the loop will execute the action at start. Otherwise "+/01:00" will run the action the next hour for the first time.
'cond' is a function that can be used as a filter for when the action should be run. E.g. if something should be done every hour if a local lua variable 'doIt' is true:

Event.schedule("+/01:00",function(env) Log(LOG.LOG,"PING!") end,{cond=function() return doIt==true end})

'name' is a string that should be used to identify this loop when debugging.


Event.cancel

Cancel a posted event.

Event.cancel(<postRef>)

cancel an Event.post given the reference. If the post is already posted, this does nothing.

local ref = Event.post({type='foo'},"n/00:00") -- post event at midnight
...
Event.cancel(ref) -- Changed my mind...

Event.postRemote

Post an event to another scene.

Event.postRemote(<SceneID>,<event>)

This post an event to another scene. If the scene is running the EventRunner framework the event will be posted there. Other scenes will get it with fibaro:args().
To implement a 'ping' function to make sure that another scene is alive could be done like this. First the watching scene that checks if scene 'scene2' is alive

local lastPong = osTime()
local scene2 = 77
Event:event({type='check'},function(env)
   if osTime()-lastPong > 2*60+15 then -- No answer 
     Log(LOG.LOG,"Scene %s not answering, restarting scene",scene2)
     fibaro:killScenes(scene2) -- Kill the scene to be sure
     fibaro:startScene(scene2) -- ..and restart it
   end
   Event.postRemote(scene2,{type='ping'}) -- Send ping to scene
   Event.post({type='check',"+/00:02")    -- check again in 2 minutes
   end)
Event.event({type='pong'},function(env) lastPong=osTime() end) -- Receive 'pong'
Event.post({type='check'}) -- start pinging

Then we have scene2 that answers 'ping' requests. A received remote event has a '._from' field with the scene that sent the event. This makes it convenient to respond to the sender

Event.event({type='ping'},function(env) Event.postRemote(env.event._from,{type='pong'}) end)

...