Jump to content

Recommended Posts

7 minutes ago, petrkl12 said:

I think this will change label for lblButtonID to value 4003 but I need test value not change it ...

Rule.eval("#property{deviceID=860} => label(860,'lblButtonID')=='4003' & log('Button Off 1')")
 

this rule is without reaction as you can see in log

Rule.eval("#property{deviceID=860} => || label(860,'lblButtonID')=='4003' >> log('Button Off 1')")

 

The first is doing comparison '==' not assignment '=', so it shouldn't change the label.

The second one is different from your third rule; "<event> => || <test> >> <action>"

Edited by jgab
Link to post
Share on other sites
  • Replies 2.6k
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Note. The first ~2000 posts of this thread is mainly about EventRunner3 that is for the HC2. EventRunner3 is not developed further, but bugs are fixed as they are reported. For HC3, the version i

I've been playing with the HC3 a bit  (I don't own a HC3 but a friend has allowed me to remotely login to do testing - I'm very grateful for that). ...and I have made some progress with EventRunn

Working with event runner rules it can be useful to understand a bit how they work behind the "hood". Rules are always on the form   <test> => <statments> Ex 88:breached

Posted Images

1 minute ago, petrkl12 said:

OK, first is working :)  Thanks - logic is not so easy :)

second I will try tommorow

 

The second syntax "|| >>" is a bit tricky. But it would allow you to do things like this (I don't know what codes your device returns).

Btw. "[[ ]]" is Lua syntax for strings spanning multiple lines.

Rule.eval([[#property{deviceID=860} => 
     || label(860,'lblButtonID')=='4003' >> log('Button 1')
     || label(860,'lblButtonID')=='4004' >> log('Button 2')
     || label(860,'lblButtonID')=='4005' >> log('Button 3')
     || label(860,'lblButtonID')=='4006' >> log('Button 4')
      ]])

 

Link to post
Share on other sites

Hi @jgab, another question. Sorry.

I was trying to turn on the lights at 6:45 until sunrise + 30 mins. Although I understand why the below does not work (I think), I have trouble finding a neat way of doing this.

Rule.eval("daily(06:45..sunrise+00:30) => Ht.xx.yy:on")

NB: lights should not turn on if sunrise is before 06:45

 

EDIT: 

Nevermind, I think I found it:

Rule.eval("daily(06:45) & sunrise < 07:15 => Ht.xx.yy:on")
Rule.eval("daily(sunrise+00:30) => Ht.xx.yy:off")

 

Let's wait until tomorrow morning to see whether it works ;D

 

Edited by 3JL
Link to post
Share on other sites
7 minutes ago, 3JL said:

Hi @jgab, another question. Sorry.

I was trying to turn on the lights at 6:45 until sunrise + 30 mins. Although I understand why the below does not work (I think), I have trouble finding a neat way of doing this.

Rule.eval("daily(06:45..sunrise+00:30) => Ht.xx.yy:on")

NB: lights should not turn on if sunrise is before 06:45

 

Rule.eval("@sunrise+00:30 & now >= 06:45 =>  Ht.xx.yy:on")

Need to keep '>=' and '=>' apart :-) 

3 minutes ago, jgab said:

 

Rule.eval("@sunrise+00:30 & now >= 06:45 =>  Ht.xx.yy:on")

Need to keep '>=' and '=>' apart :-) 

Typically one wants to turn on the light at sunrise or 6:45

Rule.eval("@math.max(sunset+00:30,06:45) =>  Ht.xx.yy:on")

This will turn on the light 6:45 if sunset+30min is before that or otherwise at sunset+30min

Edited by jgab
Link to post
Share on other sites

Nice! Thanks!

 

To clarify: if it is dark in the morning, lights should go on from 6:45 until the sun takes over. If not (i.e. during summer, sun rises before 6:00), the lights should remain off. The @math.max should do the trick!

Edited by 3JL
Link to post
Share on other sites
20 minutes ago, 3JL said:

Nice! Thanks!

 

To clarify: if it is dark in the morning, lights should go on from 6:45 until the sun takes over. If not (i.e. during summer, sun rises before 6:00), the lights should remain off. The @math.max should do the trick!

Shouldn't it be something like below?

Rule.eval("@06:45 & now < sunrise+00:30 => Ht.xx.yy:on") -- Turn on light every 6:45 if before sunrise+30min
Rule.eval("@sunrise+00:30 & Ht.xx.yy:isOn => Ht.xx.yy:off") -- Turn off light at sunrise+30min if lamp is on

 

Link to post
Share on other sites
1 hour ago, jgab said:

Shouldn't it be something like below?

Rule.eval("@06:45 & now < sunrise+00:30 => Ht.xx.yy:on") -- Turn on light every 6:45 if before sunrise+30min
Rule.eval("@sunrise+00:30 & Ht.xx.yy:isOn => Ht.xx.yy:off") -- Turn off light at sunrise+30min if lamp is on

 

Yes, you are right! Thank you very much! (again :) )

Link to post
Share on other sites
Quote
On 9/4/2018 at 7:38 AM, jgab said:

The second syntax "|| >>" is a bit tricky. But it would allow you to do things like this (I don't know what codes your device returns).

Btw. "[[ ]]" is Lua syntax for strings spanning multiple lines.


Rule.eval([[#property{deviceID=860} => 
     || label(860,'lblButtonID')=='4003' >> log('Button 1')
     || label(860,'lblButtonID')=='4004' >> log('Button 2')
     || label(860,'lblButtonID')=='4005' >> log('Button 3')
     || label(860,'lblButtonID')=='4006' >> log('Button 4')
      ]])

 

 

 

Thanks! it works like charm

 

 I have another question - how to get level of slider from virtual device for comparing?

 

 

Link to post
Share on other sites
34 minutes ago, petrkl12 said:

 

Thanks! it works like charm

 

 I have another question - how to get level of slider from virtual device for comparing?

 

 

Sliders are similar to labels.

--[[
%% properties
12 ui.Slider1.value
%% events
%% globals
--]]

...

function main()

     Rule.eval("label(12,'Slider1') => log('Slider value:%s',label(12,'Slider1'))")

end -- main()

 

Link to post
Share on other sites

The full blown EventRunner framework has support for more advanced event programming than the EventRunnerLite described in the first post of this tutorial. In this post the script language implemented in the EventRunner framework will be described. The script language is particularly suitable for writing compact rules handling time scheduling, device triggering of rules, and user defined event rules. 

 

This first part will describe how script rules can be used to define a flexible scheduler. A scheduler is a scene that runs actions at specific times during the day. A flexible scheduler can adjust its behaviour depending on day of week, month or state of global variables or state of other devices at that time.

 

In the EventRunner framework, the 'main()' function is used to setup rules and is called before the framework starts. 'main()' can also be used to read in a HomeTable, setup variables etc, things that needs to be done once the framework starts up.

 

To define a rule the 'Rule.eval(<string>)' function is used. A rule is a Lua string of the format "<condition> => <actions>", and is compiled to an efficient representation that is run when the <condition> is true. If the string doesn't contain a '=>' it is considered to be an expression that is just evaluated, and the result is returned. This can be useful to setup variables and other initializations.

function main()
  Rule.eval("lamp=55") -- define variable 'lamp' to be 55
  Rule.eval("lamp:on") -- turn on lamp (with deviceID 55) once when scene starts
End

A scheduler runs actions at a specific time during the day, so we use the 'daily’ or '@' rules

The generic form of a daily rule is "@<time> [<optional extra tests>] => <actions>"

function main()
  Rule.eval("lamp=55") -- define variable 'lamp' to be 55
  Rule.eval("@15:10 => lamp:on") -- turn on lamp (deviceID 55) every day at 15:10
end

The rule will be called every day at 15:10, and the left-hand expression "@15:10" will evaluate to true (because it's 15:10) and thus the right-hand side if the '=>' will be carried out. In this case the lamp with deviceID 55 will be turned on.

However, this also means that we can tuck on extra tests on the left-hand side that needs to be true for the rule to execute its actions. Any logic expression combining AND (&), OR(|), NOT(!), or comparison operators (==,>=,<=,~=) can be used.

Ex. (we don't include the 'function main()' part in the examples from now on)

Rule.eval("@15:10 & lamp:isOff => lamp:on") -- turn on lamp (deviceID 55) every day at 15:10, if the lamp is off.
Rule.eval("@15:10 & !lamp:isOn => lamp:on") -- equivalent to the previous rule.

This tests if the lamp also is off, and if so the lamp is turned on. It is important that there should be no "side-effects" on the left-hand side. No functions that turn on or off devices or set globals etc, only functions that query states.

 

Here are some examples of types of rules that can be defined 

 -- Declare a script variable 'lamp' to have value 55 (e.g. a deviceID)
 Rule.eval("lamp=55")
  -- Every day at 07:15, turn of lamp, e.g. deviceID 55
 Rule.eval("@07:15 => lamp:off")
  -- Every day at sunrise, turn off lamp
 Rule.eval("@sunrise => lamp:off")
  -- Every day at sunrise + 15min, turn off the lamp
 Rule.eval("@sunrise+00:15 => lamp:off")
  -- Every day at sunset, turn on lamp
 Rule.eval("@sunset => lamp:on")
  -- Every day at sunset-15min, if lamp is off, turn on the lamp
 Rule.eval("@sunset-00:15 & lamp:isOff => lamp:on")
  -- Every day at sunset and if it's Monday, turn off the lamp
 Rule.eval("@sunrise & wday('mon') => lamp:off")
  -- Every day at sunrise and if it is a weekday, turn off the lamp
 Rule.eval("@sunrise & wday('mon-fri') => lamp:off")
  -- Every day at sunrise on Monday,Wednesday,Friday,Saturday,Sunday, turn off the lamp 
 Rule.eval("@sunrise & wday('mon,wed,fri-sun') => lamp:off")
 -- Every day at sunrise the first day of the month, turn off the lamp 
 Rule.eval("@sunrise & day('1') => lamp:off")
 -- Every day at sunrise on the first 15 days of the month, turn off the lamp 
 Rule.eval("@sunrise & day('1-15') => lamp:off")
 -- Every day at sunrise on the last day of the month, turn off the lamp 
 Rule.eval("@sunrise & day('last') => lamp:off") -- 'last' is the number of the last day in the current month
 -- Every day at sunrise on the first day of the last week of the month, turn off the lamp 
 Rule.eval("@sunrise & day('lastw') => lamp:off") -- 'lastw' is the number of the first day in the last week of the current month
 -- Every day at sunrise on a Monday in the last week of the month, turn off the lamp 
 Rule.eval("@sunrise & day('lastw-last') & wday('mon') => lamp:off")
 -- Every day at sunrise January to Mars, turn off the lamp 
 Rule.eval("@sunrise & month('jan-mar') => lamp:off")
 -- Every day at sunrise on Mondays at even week numbers, turn off the lamp 
  Rule.eval("@sunrise & wnum%2 == 0 & wday('mon') => lamp:off")
 -- Every day at sunrise on weekdays when fibaro global 'Presence' equals 'Home', turn off the lamp 
 Rule.eval("@sunrise & $Presence=='Home' & wday('mon-fri') => lamp:off")
-- Every day at sunrise on weekdays when fibaro global 'Presence' equals 'Home' or fibaro global 'Simulate' equals 'true', turn off the lamp 
 Rule.eval("@sunrise & ($Presence=='Home' | $Simulate='true') & wday('mon-fri') => lamp:off")

The above rules run at sunrise every day and we add additional conditions that restrict it to sunrise at specific days and/or if a global variable also is set to a specific value or if a device is in a specific state.

 

All 'daily/@' rules are 'examined' at midnight and the expression after the '@' character is computed and should return a number being the seconds after midnight the rule should be run. That is why there should be no side-effects in the left-hand side of the rule as they would be carried out at midnight, which we probably don't want. When the rule is later run at the computed/specified time, the whole left-hand side is computed again as a logical expression and if it returns true the right-hand side, the action(s), is run.

 

'sunrise' and 'sunset' are constants that return seconds to sunrise and sunset respectively. Because the '@' expression is computed we can specify expressions like 'sunset+00:15' and it's computed as 15 min after sunset in seconds. Time constants like '04:15' are shorthand for '0+(60*(15+60*4))'. Seconds can also be specified '10:20:30' same as '30+(60*(20+60*10))'

We can use a value from a global variable easily, but if we want to use the time notation we need to convert it to seconds because globals always return strings. The 'time' function converts a string with a time value to seconds. 

Rule.eval("$Morning = '07:00'") -- Set global $Morning to the string "07:00". Could be set by a VD instead
Rule.eval("@time($Morning) => log('It's morning!')")

or if we want to adjust and offset to 'sunrise' with a global variable, maybe controlled from a VD

Rule.eval("@sunrise+time($SunriseOffset) => log('It's morning')")

 Remember that the times are calculated at midnight, so if the global is changed during the day it will not take effect until the next day (However, the scene can be restarted for all values to be re-calculated).

 

A typical case is to turn on a light in the morning if that time is before sunrise

Rule.eval("@06:00 & now < sunrise+00:30 => lamp:on")

 This rule is run 06:00 every morning but the constant 'now', representing the current number of seconds since midnight, must be less than sunrise + 30min for the right-hand action to be run.

 

Maybe a lamp should be turned on in the afternoon at sunset, given that sunset is within a certain time window (here in the north we can have sunset at 2PM)

 Rule.eval("@sunset-00:30 & 16:00..23:00 => lamp:on")

 The '<time1>..<time2>' operator is true if the current time is between the specified times.

 

To do something at a random interval every day, the 'rnd' function can be used. 'rnd(x,y)' returns a random number between x and y.

Rule.eval("@sunset+rnd(-00:30,00:30) => lamp:on") -- Turn on lamp at sunset +/- 30min  

 Assume we have different wake-up times depending on day of week. A short alarm clock could look like this.

Rule.eval("phone=109") -- ID of phone
Rule.eval("wakeUpTime={Mon=07:10,Tue=07:20,Wed=06:55,Thu=07:40,Fri=07:30,Sat=08:00,Sun=09:00}")
Rule.eval("@wakeUpTime[osdate('%a')] & $Presence~='Vacation' => phone:send=log('Time to wakeup')")

 This will at every midnight schedule the wakeup time associated with the weekday that we get from 'osdate' that takes same arguments as Lua's 'os.date'.

'<ID>:send=<string>' send a text string to a phone with id ID. The 'log' command prints its message to the HC2 debug window but also returns the string which we then use as input to the ':send' command. We also make sure that our global variable 'Presence' is not set to 'Vacation', as we don't want any messages then.

 

The '@' expression can also be applied to a list of times, and all will be scheduled. 

If we want to do something at every 15min between 10:00 and 14:00, it's easiest to do something like this

Rule.eval("flowerCheck = {10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00}")
Rule.eval("@flowerCheck => wday('mon-fri') & checkWater()") -- assumes we have a defined function 'checkWater()'

The advantage is that this is done every 15min between 10:00 and 14:00 every weekday and there is no time drift.

 

There is another construct that schedule actions at specific intervals, the '@@' operator.

Rule.eval("@@00:15 => log('Dong!')") -- logs 'Dong!' every 15min 24x7...

'@@' is drift free, so it will execute exactly on the interval specified, starting at what ever time it starts.

Here is a really short presence simulator

  Rule.eval("lamps={22,33,44,55,66,77,88}")
  Rule.eval("$Presence=='away' => lampStates = lamps:value") -- Save lamps current states
  Rule.eval("$Presence=='home' => lamps:value = lampStates") -- Restore lamp states
  Rule.eval("@@rnd(00:10,00:30) & $Presence=='away' & sunset..sunrise => lamps[rnd(1,length(lamps))]:toggle")

  Rule.eval("wait(00:10); $Presence='away'; wait(01:00); $Presence='home'") -- Test rule by triggering global 'Presence'

 This runs at random intervals between 10 and 30min turning on/off lamps, when the global variable 'Presence' is set to 'away' and it's between sunset and sunrise. We select a random lamp from the 'lamps' table and call the ':toggle' function to toggle the state of the lamp.

When the 'Presence' global is set we save and restore the lamp values (triggering rules will be explained in a separate post)

 

There is another way to achieve things being scheduled at specific intervals.

Rule.eval("@@00:01 & date('0 10-16/2') => log('Hupp')")

It is possible to use the date(<crontab format string>) command that is almost a crontab test  (same format and it compiles to a code that test the condition very efficient). 

date('0 10-16/2') means on the '0' minute every second hour from 10 to 16.

To make something on every hour, on the hour, the string is simply date('0 *') - * stands for any hour, the same as date('0 0-23'). Much simpler than having to list all hours with the daily '@' command.

Crontab is very flexible, date('15,45 7-19/3 * dec,jan mon-fri') means 15min and 45min past every third hour between 7 and 17 on Monday to Friday in January and December.

The '@@00:01' will run the test every minute (exactly like crontab does) and if the date() test is true it will run the action. This is very flexible.

The day(),wday(),month() functions are implemented with date(). Have a look at any crontab documentation on the net and you will get the gist of it.

 

One more note. In the examples above we have declared a local script variable ‘lamp’ that we use in the actions. It is easy to bring in HomeTable definitions to be used in the scripts.

Assume there is a hometable that looks like this:

jT = {kitchen={lamp=55,sensor=88},bedroom={lamp=57,sensor=89}}

The function ‘Util.defvars’ will declare the table as script variables.

Util.defvars(jT)
Rule.eval(“@sunset => kitchen.lamp:on; bedroom.lamp:on”)

So, script rules allow us to write compact and flexible rules for scheduling actions. It's easy to integrate with a VD and fibaro globals to adjust rules for specific contexts. The syntax for the script language and available action functions is described in more detail here <link>

 Next up is a post on trigger rules...

 

 

 

 

Edited by jgab
  • Like 1
Link to post
Share on other sites

@jgab need some expert help. My goal is to press a button on a VD after 40 minutes if Label1 is "ON"

 

Rule.load([[
    for(00:40,{label(777,'Label1')=='ON' => 
    	{777:btn=2} &
        log('Kaffebryggaren stängs nu av!'))
  ]])

 

Link to post
Share on other sites
18 minutes ago, jompa68 said:

@jgab need some expert help. My goal is to press a button on a VD after 40 minutes if Label1 is "ON"

 

Rule.load([[
    for(00:40,{label(777,'Label1')=='ON' => 
    	{777:btn=2} &
        log('Kaffebryggaren stängs nu av!'))
  ]])

 

Single line version

Rule.eval("for(00:40,label(777,'Label1')=='ON') => 777:btn=2; log('Kaffebryggaren stängs nu av!')")

...and don't forget declaring the label trigger in the scene header.

The right hand side of '=>' can be a list of independent statements separated by ';' like many programming languages use. Because there is no 'if-then-else', I often code like '<test> & <action>' or '<test> & <action1> | <action2>' that is equivalent of 'if-then' or 'if-then-else'. (there is also a 'case' statement '|| <test1> >> <action1> || <test2> >> <action2> ...')

P.S You need a reasonable new version of the EventRunner code. I pushed just the other day a version that allows triggers on 'label(id, name)' after a request from @petrkl12

Edited by jgab
Link to post
Share on other sites

<Note. The way to debug EventRunner has changed. Now it uses the HC2 emulator. Some of the general aspects and log outputs are still valid>

 

It can be really difficult to debug scenes on the HC2. 

  • There is no way to set break points so you are left to sprinkle the scene with fibaro:debug statements. 
  • The scene logic you thought through didn’t work because triggers from devices arrived in an non-anticipated order… i.e. there should be a way to replay sequences of triggers/events  to make sure that the scene logic is sound.
  • Waiting for triggers in real-time, triggers or time events that can be hours in between is really boring and unproductive when trying to find bugs in a scene – there should be some way to simulate a speed up of time for debugging purpose.

Many of us do develop our scenes off-line, on PCs/Macs/Linux machines using libraries like the “Lualibs/FibaroSceneAPI”. However, it’s still not so easy to really debug scene logic involving triggers.
The EventRunner framework is especially well suited for developing scenes off-line;

  • The programming model in EventRunner is event based, meaning we post and receive events to drive the scene logic (including device events). This means that we can replay sequences of  trigger/device events by posting fake events looking like device events, at chosen times. This allow us to see if our scene reacts in the way that we anticipated.
  • Because we run off-line we can put breakpoints in the code to understand what happens when triggers come in and follow the flow through the scene.
  • We can speed up the clock!  We can speed true a couple of days in a second and see if scene logic, like schedulers that usually act over time frames spanning days, behave as we would expect. We can do tricks like that because in the framework we control the clock…
  • ...and finally, we can run the same code off-line as we run on the HC2. When the code runs correct offline we can just cut and past it into a scene on the HC2 without changing a single line of code.

 

This has made my own productivity raise with an magnitude compared to developing on the HC2… and it has allowed me to develop much more complex scenes – like the EventRunner framework scene itself – that I would never have dared to do on the HC2…

So, to start running and debugging offline I recommend the following steps.

  • Install a Lua IDE – I would recommend ZeroBrane Studio. It's free and cross platform. I guess that any other would work. 
  • Download and install Lualibs with Fibaro/JSON APIs as described by @reimers. The link also has a tutorial how to setup ZeroBrane.
  • From the EventRunner GitHub, download 'EventRunner.lua' (or EventRunnerLite), 'EventRunnerDebug.lua', ’example_rules.lua', and ’devicemap.data’ and put them in your working directory
  • Fire up the IDE and load 'EventRunner.lua' and run it. It is setup to run test examples from the 'example_rules.lua' file (Note! The examples depends on the HomeTable definition in ’devicemap.data’). Play around with enabling other scenarios in that file.

The magic for debugging scenes are in the 'EventRunnerDebug.lua’ file. This file is conditionally included in the scene framework code

if dofile then dofile("EventRunnerDebug.lua") end

and ‘dofile’ is not available on the HC2 so the debug code is not included when you transfer the scene to the HC2. The goal have been that the one should be able to copy the whole scene from the off-line IDE to the HC2 without having to change a single line of code.
Besides including the FibaroAPI and json libraries. EventRunnerDebug.lua is responsible for implementing HC2 functions that are missing in a standard offline Lua setup.

  • There are implementations of ‘setTimeout’ and ‘clearTimeout’. The framework relies on setTimeout instead of fibaro:sleep do post events at specific times. Having our own implementation also allows for tricks like speeding up the clock.
  • net.HTTPClient, api.get, api.put,api.post behaves similar to the HC2 versions. If you setup your HC2 credentials the api.xxx calls will call your HC2.
  • FibaroAPI is included so you can do remote fibaro:xxx calls to the HC2 (also needs your HC2 credentials). However, there is a _REMOTE flag that if set to false tries to simulate the fibaro:xxx calls locally when you don’t have access to the HC2 (or you don’t want to disturb the family with blinking lights)

Top of EventRunnerDebug.lua contains some variables to control this behaviour

_SPEEDTIME         = 48*4   -- set to nil run the local clock in normal speed, set to an int <x> will speed the clock through <x> hours
_REMOTE            = false  -- If true use FibaroSceneAPI to call functions on HC2, else emulate them locally...
-- HC2 credentials and parameters
hc2_user           = "xxx" -- used for api.x/FibaroSceneAPI calls
hc2_pwd            = "xxx" 
hc2_ip             = "192.168.1.84" -- IP of HC2

There is also a global lua table with flags that can be set to 'true' to debug different parts of the framework

_debugFlags = { 
  post=true,         -- Log all posts
  invoke=true,     -- Log all handlers being invoked (triggers, rules etc)
  rule=false,        -- Log result from invoked script rule
  triggers=false,  -- Log all externally incoming triggers (devices, globals etc)
  dailys=false,     -- Log all dailys being scheduled at midnight
  timers=false,    -- Log att timers (setTimeout) being scheduled)
  fibaro=true,       -- Log all fibaro calls except get/set
  fibaroGet=false  -- Log fibaro get/set
}

_debugFlags.rule can not be change while the scene is running as it instruments the rules with debug statements.

     

If we load the example in the first post, the catching keypresses 1-2-3 from a fibaro keyfob and run it in the ZeroBrane IDE we get the output

Debugging session started in '/Users/jangabrielsson/Dropbox/LUA/EventRunner/EventRunner/'.
15:37:55:Starting EventRunnerLite demo
15:37:55:Fri Sep 14: Posting {type=event,...} for 15:37:58
15:37:55:Fri Sep 14: Posting {type=event,...} for 15:38:00
15:37:55:Fri Sep 14: Posting {type=event,...} for 15:38:02
15:37:58:key 1 pressed at 15:37:58
15:38:00:key 2 pressed at 15:38:00
15:38:02:Key 3 pressed at 15:38:02, Keys 1-2-3 pressed within 2x3sec
Program completed in 0.98 seconds (pid: 71128).

Here we see the output as expected. We see our posted fake key trigger events simulating the keyfobs CentralSceneEvents at 2seconds interval, and we see that our logic is correct.
Trying out the Presence simulation example in the first post gives this trace

Debugging session started in '/Users/jangabrielsson/Dropbox/LUA/EventRunner/EventRunner/'.
15:21:51:Starting EventRunnerLite demo
15:21:51:Fri Sep 14: Posting {type=call,...} for 15:22:01
15:21:51:Fri Sep 14: Posting {type=call,...} for 15:22:11
15:21:51:Fri Sep 14: Posting {type=call,...} for 16:21:51
15:22:01:Fri Sep 14: fibaro:call(99,'setValue', '1', '')
15:22:11:Fri Sep 14: fibaro:call(99,'setValue', '0', '')
15:22:11:Fri Sep 14: Posting {type=away,...} for 15:32:11
15:32:11:Fri Sep 14: Posting {type=presence,...} for 15:32:11
15:32:11:Starting presence simulation
15:32:11:Fri Sep 14: Posting {type=simulate,...} for 15:32:11
15:32:11:Fri Sep 14: fibaro:call(77,'turnOn')
15:32:11:Fri Sep 14: Posting {type=simulate,...} for 15:44:11
15:44:11:Fri Sep 14: fibaro:call(66,'turnOn')
15:44:11:Fri Sep 14: Posting {type=simulate,...} for 15:57:11
15:57:11:Fri Sep 14: fibaro:call(55,'turnOn')
15:57:11:Fri Sep 14: Posting {type=simulate,...} for 16:09:11
16:09:11:Fri Sep 14: fibaro:call(66,'turnOff')
16:09:11:Fri Sep 14: Posting {type=simulate,...} for 16:22:11
16:21:51:Fri Sep 14: fibaro:call(99,'setValue', '1', '')
16:21:51:Fri Sep 14: Posting {type=presence,...} for 16:21:51
16:21:51:Stopping presence simulation
Program completed in 1.04 seconds (pid: 70711).

Even if the scene takes an hour we speed through it in a second by having set the _SPEEDTIME variable to 48*4 in this case - but we still get the actual timing info in the debug statements so that we can see that it reacts at the right times.
Here the _debugFlags.post and _debugFlags.fibaro is set to true so that posts to 'main()' and fibaro calls are written to the console. Debugging in the EventRunnerLite framework is a bit limited compared to the full EventRunner framework.

Running a more complex example from the full EventRunner framework (the 'tHouse' example from 'example_rules.lua') gives this trace below. Here the example use the script language for rules and we have set the _debugFlags.invoke=true which logs when the rules are invoked/triggered. This runs over a couple of days but with _SPEEDTIME set it takes less than a second. The example also sets the clock to 08:00 at startup, that's why we see the jump from 15:48 to 08:00 in the beginning of the log. It's very practical to be able to run scenes at simulated times of the days.

Spoiler

Debugging session started in '/Users/jangabrielsson/Dropbox/LUA/EventRunner/EventRunner/'.
15:48:12:Fri Sep 14: Demo - EventRunner v1.1
15:48:12:Fri Sep 14: Loading rules
08:00:00:Fri Sep 14: Rule:1:for(00:10,kt.movement:safe&(wday('mon-fr
08:00:00:Fri Sep 14: Rule:2:for(00:10,{kt.movement,lr.movement,ha.mo
08:00:00:Fri Sep 14: Rule:3:daily(sunset-00:10) => kt.sink_led:btn=1
08:00:00:Fri Sep 14: Rule:4:daily(sunrise+00:10) => kt.sink_led:btn=
08:00:00:Fri Sep 14: Rule:5:daily(sunset-00:10) => kt.lamp_table:on;
08:00:00:Fri Sep 14: Rule:6:daily(sunset-00:10) => lr.lamp_window:on
08:00:00:Fri Sep 14: Rule:7:daily(00:00) => lr.lamp_window:off; log(
08:00:00:Fri Sep 14: Rule:8:daily(sunset-00:10) => ha.lamp_entrance:
08:00:00:Fri Sep 14: Rule:9:daily(sunset) => ha.lamp_entrance:off; l
08:00:00:Fri Sep 14: Rule:10:daily(sunset-00:10) => ba.lamp:on; log('
08:00:00:Fri Sep 14: Rule:11:daily(sunset) => ba.lamp:off; log('Turn 
08:00:00:Fri Sep 14: Rule:12:daily(sunset-00:10) => gr.lamp_window:on
08:00:00:Fri Sep 14: Rule:13:daily(23:00) => gr.lamp_window:off; log(
08:00:00:Fri Sep 14: Rule:14:daily(sunset-00:10) => {ti.bed_led,ti.la
08:00:00:Fri Sep 14: Rule:15:daily(00:00) => {ti.bed_led,ti.lamp_wind
08:00:00:Fri Sep 14: Rule:16:daily(sunset-00:10) => ma.lamp_window:on
08:00:00:Fri Sep 14: Rule:17:daily(00:00) => ma.lamp_window:off; log(
08:00:00:Fri Sep 14: Rule:18:daily(sunset) => {bd.lamp_window,bd.lamp
08:00:00:Fri Sep 14: Rule:19:daily(23:00) => {bd.lamp_window,bd.lamp_
08:00:00:Fri Sep 14: fibaro:call(kitchen.lamp_stove,'turnOn')
08:00:00:Fri Sep 14: Rule:20:for(00:10,td.movement:safe & td.door:val
08:00:00:Fri Sep 14: Rule:21:td.movement:breached => || td.door:safe 
08:00:00:Fri Sep 14: Rule:22:td.door:breached => inBathroom=false
08:00:00:Fri Sep 14: Rule:23:td.door:safe & td.movement:last<3 => inB
08:00:00:Fri Sep 14: fibaro:call(toilet_down.movement,'setValue', '0', '')
08:00:00:Fri Sep 14: fibaro:call(toilet_down.lamp_roof,'setValue', '0', '')
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":364,"value":1} for Fri Sep 14 10:00:00
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":331,"value":1} for Fri Sep 14 10:00:02
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":364,"value":0} for Fri Sep 14 10:00:04
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":331,"value":0} for Fri Sep 14 10:00:32
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":331,"value":1} for Fri Sep 14 10:00:45
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":331,"value":0} for Fri Sep 14 10:01:15
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":364,"value":1} for Fri Sep 14 10:20:00
08:00:00:Fri Sep 14: Rule:24:lr.lamp_roof_holk:scene==S2.click => lr.
08:00:00:Fri Sep 14: Rule:25:bd.lamp_roof:scene==S2.click => {bd.lamp
08:00:00:Fri Sep 14: Rule:26:ti.lamp_roof:scene==S2.click => ti.bed_l
08:00:00:Fri Sep 14: Rule:27:ti.lamp_roof:scene==S2.double => ti.lamp
08:00:00:Fri Sep 14: Rule:28:ma.lamp_roof:scene==S2.click => ma.lamp_
08:00:00:Fri Sep 14: Rule:29:gr.lamp_roof:scene==S2.click => gr.lamp_
08:00:00:Fri Sep 14: Rule:30:kt.lamp_table:scene==S2.click => || labe
08:00:00:Fri Sep 14: Rule:31:#property{deviceID=lr.lamp_window} =>  |
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":225,"value":"26","propertyName":"sceneActivation"} for Fri Sep 14 09:10:00
08:00:00:Fri Sep 14: Posting {"type":"property","deviceID":225,"value":"26","propertyName":"sceneActivation"} for Fri Sep 14 09:20:00
08:00:00:Fri Sep 14: Scene running
08:00:00:Fri Sep 14: Sunrise 06:00, Sunset 18:00
08:00:00:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
08:00:00:Fri Sep 14: Invoking:td.movement:breached => || td.door:safe >> inBathroom=true ;;td.lamp_roof:on
08:00:00:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
08:10:00:Fri Sep 14: fibaro:call(kitchen.lamp_table,'turnOff')
08:10:00:Fri Sep 14: fibaro:call(kitchen.lamp_stove,'turnOff')
08:10:00:Fri Sep 14: fibaro:call(kitchen.lamp_sink,'turnOff')
08:10:00:Fri Sep 14: fibaro:call(hall.lamp_hall,'turnOff')
08:10:00:Fri Sep 14: Turning off kitchen spots after 10 min inactivity
08:10:00:Fri Sep 14: Invoking:kt.lamp_table:scene==S2.click => || label(kt.sonos,'lblState')=='Playing' >> kt.sonos:btn=8 || true >> kt.sonos:btn=7;; log('Toggling Sonos %s',label(kt.sonos,'lblState'))
09:10:00:Fri Sep 14: Invoking:lr.lamp_roof_holk:scene==S2.click => lr.lamp_roof_sofa:toggle; log('Toggling lamp downstairs')
09:10:00:Fri Sep 14: fibaro:call(livingroom.lamp_roof_sofa,'turnOn')
09:10:00:Fri Sep 14: Toggling lamp downstairs
09:20:00:Fri Sep 14: Invoking:lr.lamp_roof_holk:scene==S2.click => lr.lamp_roof_sofa:toggle; log('Toggling lamp downstairs')
09:20:00:Fri Sep 14: fibaro:call(livingroom.lamp_roof_sofa,'turnOff')
09:20:00:Fri Sep 14: Toggling lamp downstairs
10:00:00:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:00:00:Fri Sep 14: Invoking:td.door:breached => inBathroom=false
10:00:00:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:00:02:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:00:02:Fri Sep 14: Invoking:td.movement:breached => || td.door:safe >> inBathroom=true ;;td.lamp_roof:on
10:00:02:Fri Sep 14: fibaro:call(toilet_down.lamp_roof,'turnOn')
10:00:02:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:00:04:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:00:04:Fri Sep 14: Invoking:td.door:breached => inBathroom=false
10:00:04:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:00:32:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:00:32:Fri Sep 14: Invoking:td.movement:breached => || td.door:safe >> inBathroom=true ;;td.lamp_roof:on
10:00:32:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:00:45:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:00:45:Fri Sep 14: Invoking:td.movement:breached => || td.door:safe >> inBathroom=true ;;td.lamp_roof:on
10:00:45:Fri Sep 14: fibaro:call(toilet_down.lamp_roof,'turnOn')
10:00:45:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:01:15:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:01:15:Fri Sep 14: Invoking:td.movement:breached => || td.door:safe >> inBathroom=true ;;td.lamp_roof:on
10:01:15:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:20:00:Fri Sep 14: Invoking:for(00:10,td.movement:safe & td.door:value) => not(inBathroom)&td.lamp_roof:off
10:20:00:Fri Sep 14: Invoking:td.door:breached => inBathroom=false
10:20:00:Fri Sep 14: Invoking:td.door:safe & td.movement:last<3 => inBathroom=true
10:30:00:Fri Sep 14: fibaro:call(toilet_down.lamp_roof,'turnOff')
17:50:00:Fri Sep 14: fibaro:call(kitchen.sink_led,'pressButton', '1')
17:50:00:Fri Sep 14: Turn on kitchen sink light
17:50:00:Fri Sep 14: fibaro:call(kitchen.lamp_table,'turnOn')
17:50:00:Fri Sep 14: Evening, turn on kitchen table light
17:50:00:Fri Sep 14: fibaro:call(livingroom.lamp_window,'turnOn')
17:50:00:Fri Sep 14: Turn on livingroom light
17:50:00:Fri Sep 14: fibaro:call(hall.lamp_entrance,'turnOn')
17:50:00:Fri Sep 14: Turn on lights entr.
17:50:00:Fri Sep 14: fibaro:call(back.lamp,'turnOn')
17:50:00:Fri Sep 14: Turn on lights back
17:50:00:Fri Sep 14: fibaro:call(game.lamp_window,'turnOn')
17:50:00:Fri Sep 14: Turn on gaming room light
17:50:00:Fri Sep 14: fibaro:call(tim.bed_led,'turnOn')
17:50:00:Fri Sep 14: fibaro:call(tim.lamp_window,'turnOn')
17:50:00:Fri Sep 14: Turn on lights for Tim
17:50:00:Fri Sep 14: fibaro:call(max.lamp_window,'turnOn')
17:50:00:Fri Sep 14: Turn on lights for Max
17:50:00:Fri Sep 14: Invoking:kt.lamp_table:scene==S2.click => || label(kt.sonos,'lblState')=='Playing' >> kt.sonos:btn=8 || true >> kt.sonos:btn=7;; log('Toggling Sonos %s',label(kt.sonos,'lblState'))
17:50:00:Fri Sep 14: Invoking:#property{deviceID=lr.lamp_window} =>  || lr.lamp_window:isOn >> lr.lamp_tv:btn=1; lr.lamp_globe:btn=1 || true >> lr.lamp_tv:btn=2; lr.lamp_globe:btn=2
17:50:00:Fri Sep 14: fibaro:call(livingroom.lamp_tv,'pressButton', '1')
17:50:00:Fri Sep 14: fibaro:call(livingroom.lamp_globe,'pressButton', '1')
18:00:00:Fri Sep 14: fibaro:call(hall.lamp_entrance,'turnOff')
18:00:00:Fri Sep 14: Turn off lights entr.
18:00:00:Fri Sep 14: fibaro:call(back.lamp,'turnOff')
18:00:00:Fri Sep 14: Turn off lights back
18:00:00:Fri Sep 14: fibaro:call(bedroom.lamp_window,'turnOn')
18:00:00:Fri Sep 14: fibaro:call(bedroom.lamp_table,'turnOn')
18:00:00:Fri Sep 14: fibaro:call(bedroom.bed_led,'turnOn')
18:00:00:Fri Sep 14: Turn on bedroom light
23:00:00:Fri Sep 14: fibaro:call(game.lamp_window,'turnOff')
23:00:00:Fri Sep 14: Turn off gaming room light
23:00:00:Fri Sep 14: fibaro:call(bedroom.lamp_window,'turnOff')
23:00:00:Fri Sep 14: fibaro:call(bedroom.lamp_table,'turnOff')
23:00:00:Fri Sep 14: fibaro:call(bedroom.bed_led,'turnOff')
23:00:00:Fri Sep 14: Turn off bedroom light
00:00:00:Sat Sep 15: Invoking:{"type":"_scheduler:function: 0x0002e120","_sh":true}
00:00:00:Sat Sep 15: Invoking:{"type":"_scheduler:GC","_sh":true}
00:00:00:Sat Sep 15: fibaro:call(livingroom.lamp_window,'turnOff')
00:00:00:Sat Sep 15: Turn off livingroom light
00:00:00:Sat Sep 15: fibaro:call(tim.bed_led,'turnOff')
00:00:00:Sat Sep 15: fibaro:call(tim.lamp_window,'turnOff')
00:00:00:Sat Sep 15: Turn off lights for Tim
00:00:00:Sat Sep 15: fibaro:call(max.lamp_window,'turnOff')
00:00:00:Sat Sep 15: Turn off lights for Max
00:00:00:Sat Sep 15: Invoking:#property{deviceID=lr.lamp_window} =>  || lr.lamp_window:isOn >> lr.lamp_tv:btn=1; lr.lamp_globe:btn=1 || true >> lr.lamp_tv:btn=2; lr.lamp_globe:btn=2
00:00:00:Sat Sep 15: fibaro:call(livingroom.lamp_tv,'pressButton', '2')
00:00:00:Sat Sep 15: fibaro:call(livingroom.lamp_globe,'pressButton', '2')
00:10:00:Sat Sep 15: fibaro:call(kitchen.lamp_table,'turnOff')
00:10:00:Sat Sep 15: Invoking:kt.lamp_table:scene==S2.click => || label(kt.sonos,'lblState')=='Playing' >> kt.sonos:btn=8 || true >> kt.sonos:btn=7;; log('Toggling Sonos %s',label(kt.sonos,'lblState'))
06:10:00:Sat Sep 15: fibaro:call(kitchen.sink_led,'pressButton', '2')
06:10:00:Sat Sep 15: Turn off kitchen sink light
17:50:00:Sat Sep 15: fibaro:call(kitchen.sink_led,'pressButton', '1')
17:50:00:Sat Sep 15: Turn on kitchen sink light
17:50:00:Sat Sep 15: fibaro:call(kitchen.lamp_table,'turnOn')
17:50:00:Sat Sep 15: Evening, turn on kitchen table light
17:50:00:Sat Sep 15: fibaro:call(livingroom.lamp_window,'turnOn')
17:50:00:Sat Sep 15: Turn on livingroom light
17:50:00:Sat Sep 15: fibaro:call(hall.lamp_entrance,'turnOn')
17:50:00:Sat Sep 15: Turn on lights entr.
17:50:00:Sat Sep 15: fibaro:call(back.lamp,'turnOn')
17:50:00:Sat Sep 15: Turn on lights back
17:50:00:Sat Sep 15: fibaro:call(game.lamp_window,'turnOn')
17:50:00:Sat Sep 15: Turn on gaming room light
17:50:00:Sat Sep 15: fibaro:call(tim.bed_led,'turnOn')
17:50:00:Sat Sep 15: fibaro:call(tim.lamp_window,'turnOn')
17:50:00:Sat Sep 15: Turn on lights for Tim
17:50:00:Sat Sep 15: fibaro:call(max.lamp_window,'turnOn')
17:50:00:Sat Sep 15: Turn on lights for Max
17:50:00:Sat Sep 15: Invoking:kt.lamp_table:scene==S2.click => || label(kt.sonos,'lblState')=='Playing' >> kt.sonos:btn=8 || true >> kt.sonos:btn=7;; log('Toggling Sonos %s',label(kt.sonos,'lblState'))
17:50:00:Sat Sep 15: Invoking:#property{deviceID=lr.lamp_window} =>  || lr.lamp_window:isOn >> lr.lamp_tv:btn=1; lr.lamp_globe:btn=1 || true >> lr.lamp_tv:btn=2; lr.lamp_globe:btn=2
17:50:00:Sat Sep 15: fibaro:call(livingroom.lamp_tv,'pressButton', '1')
17:50:00:Sat Sep 15: fibaro:call(livingroom.lamp_globe,'pressButton', '1')
18:00:00:Sat Sep 15: fibaro:call(hall.lamp_entrance,'turnOff')
18:00:00:Sat Sep 15: Turn off lights entr.
18:00:00:Sat Sep 15: fibaro:call(back.lamp,'turnOff')
18:00:00:Sat Sep 15: Turn off lights back
18:00:00:Sat Sep 15: fibaro:call(bedroom.lamp_window,'turnOn')
18:00:00:Sat Sep 15: fibaro:call(bedroom.lamp_table,'turnOn')
18:00:00:Sat Sep 15: fibaro:call(bedroom.bed_led,'turnOn')
18:00:00:Sat Sep 15: Turn on bedroom light
23:00:00:Sat Sep 15: fibaro:call(game.lamp_window,'turnOff')
23:00:00:Sat Sep 15: Turn off gaming room light
23:00:00:Sat Sep 15: fibaro:call(bedroom.lamp_window,'turnOff')
23:00:00:Sat Sep 15: fibaro:call(bedroom.lamp_table,'turnOff')
23:00:00:Sat Sep 15: fibaro:call(bedroom.bed_led,'turnOff')
23:00:00:Sat Sep 15: Turn off bedroom light
00:00:00:Sun Sep 16: Invoking:{"type":"_scheduler:function: 0x0002e120","_sh":true}
00:00:00:Sun Sep 16: Invoking:{"type":"_scheduler:GC","_sh":true}
00:00:00:Sun Sep 16: fibaro:call(livingroom.lamp_window,'turnOff')
00:00:00:Sun Sep 16: Turn off livingroom light
00:00:00:Sun Sep 16: fibaro:call(tim.bed_led,'turnOff')
00:00:00:Sun Sep 16: fibaro:call(tim.lamp_window,'turnOff')
00:00:00:Sun Sep 16: Turn off lights for Tim
00:00:00:Sun Sep 16: fibaro:call(max.lamp_window,'turnOff')
00:00:00:Sun Sep 16: Turn off lights for Max
00:00:00:Sun Sep 16: Invoking:#property{deviceID=lr.lamp_window} =>  || lr.lamp_window:isOn >> lr.lamp_tv:btn=1; lr.lamp_globe:btn=1 || true >> lr.lamp_tv:btn=2; lr.lamp_globe:btn=2
00:00:00:Sun Sep 16: fibaro:call(livingroom.lamp_tv,'pressButton', '2')
00:00:00:Sun Sep 16: fibaro:call(livingroom.lamp_globe,'pressButton', '2')
00:10:00:Sun Sep 16: fibaro:call(kitchen.lamp_table,'turnOff')
00:10:00:Sun Sep 16: Invoking:kt.lamp_table:scene==S2.click => || label(kt.sonos,'lblState')=='Playing' >> kt.sonos:btn=8 || true >> kt.sonos:btn=7;; log('Toggling Sonos %s',label(kt.sonos,'lblState'))
06:10:00:Sun Sep 16: fibaro:call(kitchen.sink_led,'pressButton', '2')
06:10:00:Sun Sep 16: Turn off kitchen sink light
Max time (_speedtime), 192 hours, reached, exiting
Memory start-end:-20.85
Program completed in 1.29 seconds (pid: 71397).
Debugging session completed (traced 0 instructions).

 

Sometimes scenes dies because of errors in rules, errors in the frameworks, or error in the HC2. If the error causes the main event loop in the EventRunner framework to die there will be no error messages and a symptom is that there will be many running instances of the scene. This was common a year ago when the HC2 had some issues... To safe guard against this there is a Supervisor scene in the repository that pings EventRunner scenes to keep them alive.

 

The scene when started will look through all the scenes on the HC2 and collect the ones based on the EventRunner framework.  Then it will start pinging them and if there is no response try to restart them. After 3 attempt to restart a non-response scene it will "disable" the scene and optionally send a push message to the administrators phone.

There are other "watchdog" scenes out there but EventRunner scens are special in the way that they always responds to events if they are alive. This gives a "foolproof" way to know if the scene has crashed without any error message or is just "sleeping"

 

To recognise an EventRunner based scene, there is a "magic" constant in the framework, and it has been there since v1.7 (at least). The constant is 

gEventRunnerKey="6w8562395ue734r437fg3"

...and if you have an old scene based on EventRunner you can check if it's there. It also needs to respond to PING events. There was a bug introduced there but since v1.12 I think it is correct. It should have a line that looks like:

Event.event({type=Event.PING},function(env) e=env.event;e.type=Event.PONG; Event.postRemote(e._from,e) end)

I have updated the iOSLocator scene and pushed it to GitHub too. It was only the constant missing there.

 

The scene needs to be set to "Automatic" (sceneRunConfig=="TRIGGER_AND_MANUAL") also. The supervisor will ignore scene that are "DISABLED" or only set to "MANUAL".

When a scene doesn't responds to restart attempts, the Supervisor will set its sceneRunConfig to "MANUAL" and then ignore it. Fix the scene and set it back to automatic and it will be pinged again.

 

I have used this for a while and it seems to do its tasks. Good safeguard against bugs in rules, bugs in the EventRunner framework, and bugs in the HC2...

I'm happy to receive feedback on ways to tweak the behaviour.

There are some variables in the beginning that decides how and when it polls

  local POLLINTERVAL = "+/00:03"    -- poll every 3 minute
  local PINGTIMEOUT = "+/00:00:10"  -- No answer in 10s, scene will be restarted
  local STARTUPDELAY = "+/00:00:20" -- Time for scene to startup after a restart before pinging starts again
  local MAXRESTARTS = 2             -- Number of failed restarts before disabling the scene
  local RESCANFORSCENES = "+/00:05" -- Check for new scenes every 5 minute
  local phonesToNotify = {}         -- Phone to alter when restarting scenes

 

The Supervisor scene only catches when the "engine" inside the EventRunner scene dies, the main event loop that reads and dispatches triggers to rules and Lua handlers.

When there is an error in a rule or handler it is usually caught by the framework as all invocations of rules and handlers are done within a 'pcall'. If there are an error the rule handler is disabled to not cause more trouble. The supervisor will not react on this as the framework has not crashed and is still running, executing the remaining rules and handlers and answering pings.

 

However, if a rule gives an error it can be good to be notified. The framework will log these errors, but it will also post these error as events

{type='error',
 err=<Lua error string>,
 rule=<string representation of rule/handler>,
 line=<line where rule/handler is declared - only available offline>,
 event=<json representation of event that triggered rule/handler>
}
  

and that event can then be caught by declaring an "error handler"

Event.event({type='error'},
  function(env)
    local err=env.event
    local msg=string.format("Error in '%s', receiving event '%s', Lua error '%s'",err.rule,err.event,err.err)
    fibaro:call(phone,"sendPush",msg) 
  end)

-- or

Rule.eval("#error => phone:msg=log('%s',tjson(env.event))")

so you are notified if something goes wrong.

 

Support for debugging is something that always can be improved, and debugging of script rules could be improved to further.

Edited by jgab
  • Like 1
Link to post
Share on other sites

Hi colleague! 

 

btw. my fibaro_emu.lua have in first the  line  

local is_mock = false;

(see attachment file)

 

and folder data  contain json files with id's (device)

 

so I can simple debug any events here. It's easy :)

fibaro_emu.lua

Edited by 10der
Link to post
Share on other sites

Nice, that gives you local emulation of fibaro calls (you remove the json files when re-running the scene to come back to the same state?).

The trick is, and what is important when finding bugs in a scene, is to debug *incoming* events in a realistic model. That's why an event model is so suitable - it allows you to play through sequences of events and you can debug how the code reacts. Combine that with control over the clock-speed to debug "faster than real-time", and you have some of the ingredients to simply debug scenes.

Edited by jgab
Link to post
Share on other sites
10 minutes ago, jgab said:

you remove the json files when re-running the scene to come back to the same state?

some sorf of :

I am editing files :)

for example 

bwkXFhWs2S.png

 

but. your idea made it automatically good. rnd + clock. 

 

Link to post
Share on other sites

Hi @jgab, another question :)

Is it possible to identify manual overrides? E.g. events take place, under the condition that a lamp has not changed manually recently?

J

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...