Jump to content

Welcome to Smart Home Forum by FIBARO

Dear Guest,

 

as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.

 

As a member you can:

  •     Start new topics and reply to others
  •     Follow topics and users to get email updates
  •     Get your own profile page and make new friends
  •     Send personal messages
  •     ... and learn a lot about our system!

 

Regards,

Smart Home Forum by FIBARO Team


Recommended Posts

  • Topic Author
  • 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 comment
    Share on other sites

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

    second I will try tommorow

     

    Link to comment
    Share on other sites

  • Topic Author
  • 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.

    Please login or register to see this code.

     

    Link to comment
    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.

    Please login or register to see this code.

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

     

    EDIT: 

    Nevermind, I think I found it:

    Please login or register to see this code.

     

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

     

    Edited by 3JL
    Link to comment
    Share on other sites

  • Topic Author
  • 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.

    Please login or register to see this code.

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

     

    Please login or register to see this code.

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

    3 minutes ago, jgab said:

     

    Please login or register to see this code.

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

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

    Please login or register to see this code.

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

    Edited by jgab
    Link to comment
    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 comment
    Share on other sites

  • Topic Author
  • 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?

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

    1 hour ago, jgab said:

    Shouldn't it be something like below?

    Please login or register to see this code.

     

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

    Link to comment
    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.

    Please login or register to see this code.

     

     

     

    Thanks! it works like charm

     

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

     

     

    Link to comment
    Share on other sites

  • Topic Author
  • 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.

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

  • Topic Author
  • The full blown

    Please login or register to see this link.

    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.

    Please login or register to see this code.

    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>"

    Please login or register to see this code.

    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)

    Please login or register to see this code.

    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 

    Please login or register to see this code.

    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. 

    Please login or register to see this code.

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

    Please login or register to see this code.

     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

    Please login or register to see this code.

     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)

    Please login or register to see this code.

     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.

    Please login or register to see this code.

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

    Please login or register to see this code.

     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

    Please login or register to see this code.

    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.

    Please login or register to see this code.

    '@@' 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

    Please login or register to see this code.

     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.

    Please login or register to see this code.

    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:

    Please login or register to see this code.

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

    Please login or register to see this code.

    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 <

    Please login or register to see this link.

    >

     Next up is a post on trigger rules...

     

     

     

     

    Edited by jgab
    • Like 1
    Link to comment
    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"

     

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

  • Topic Author
  • 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"

     

    Please login or register to see this code.

     

    Single line version

    Please login or register to see this code.

    ...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 comment
    Share on other sites

  • Topic Author
  • <Note. The way to debug EventRunner has changed. Now it uses the

    Please login or register to see this link.

    . 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

      Please login or register to see this link.

      . It's free and cross platform. I guess that any other would work. 
    • Please login or register to see this link.

      . The link also has a tutorial how to setup ZeroBrane.
    • Please login or register to see this link.

      , 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

    Please login or register to see this code.

    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

    Please login or register to see this code.

    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

    Please login or register to see this code.

    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

    Please login or register to see this code.

    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.

    Please login or register to see this spoiler.

     

    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 

    Please login or register to see this code.

    ...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:

    Please login or register to see this code.

    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

    Please login or register to see this code.

     

    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

    Please login or register to see this code.

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

    Please login or register to see this code.

    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 comment
    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 :)

    Please login or register to see this attachment.

    Edited by 10der
    Link to comment
    Share on other sites

  • Topic Author
  • 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 comment
    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 

    Please login or register to see this image.

     

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

     

    Link to comment
    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 comment
    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...