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


EventLib


jgab

Recommended Posts

This is my 10th attempt to create a reusable, useful, event library for QuickApps.

My last attempt,

Please login or register to see this link.

, was ok but the model, modelled after RefreshStatesSubscriber, was not optimal for more advanced functionality.

This new model provides most of the functionality needed, with a reasonable syntax - I'm feeling pretty comfortable that this is it.

 

The functionality is provided as a QuickApp file that is included in your QuickApp project.

The code is here

Please login or register to see this link.

 

Please login or register to see this code.

The library provides a global Lua variable Event_std, but we assign it a short variable 'Event'... for 'brevity'...

 

The concept is to declare event handlers and what events that handler triggers on. 

The structure of declaring an handler for an event is

Please login or register to see this code.

The declaration opens when we do Event.<id> and closes when we do function Event:handler(...) ... end

 

We can declare another handler with another id

Please login or register to see this code.

If we try to declare two handlers with the same id the library will throw an error.

 

To get events from the HC2, like sourceTriggers, we need to enable that by calling Event:attachRefreshstate().

The problem is that we can't do that before all libraries are loaded. To solve that there is a built-in event posted whenever

the QA restart named {type='QAstart'}. 

We can then attach to the refreshStates events so we also trigger on them with our handlers.

Please login or register to see this code.

 

Some events are treated specially. {type='device' ...} is typically an event from the HC3 when a device changes property values.

We often want to trigger on a property change for more than one device.

Please login or register to see this code.

There is never an event {type='device', id={20,30}, value=true} but the declaration expands this for us automatically to

Please login or register to see this code.

Here we also see that we can declare more than one event that our handler should trigger on.

 

We could test our new handler by posting fake events for it to trigger on. Note that this will not actually turn on the device.

Please login or register to see this code.

 

The events we specify that our handler should trigger on, can have "match values" that are strings starting with "$.."

The name after that will be a variable/key in the second parameter sent to our handler

Please login or register to see this code.

Here we get vars.key and vars.attr bound to the values of the event. We could also have accessed the key values as event.value.key but this saves us some typing.

Match values are actually more powerful as they can provide constraints on what values can be matched.

If we have a dimmer, the value property is a number that is >0 if the dimmer is on. 

If we want to have a handler that triggers when a dimmer is turned on we can do

Please login or register to see this code.

 

We have some special events that helps us trigger events at recurring times

Please login or register to see this code.

The standard cron time patterns are supported.

The handler will be called at the matching times.

 

There is also a more generic recurring timer

Please login or register to see this code.

It uses the time specifier for an event every 5s

 

We can also specify that the event should be posted aligned on the time interval specified.

Please login or register to see this code.

This will make sure that the event is posted aligned on x:05, x:10, x:15, x:20, x:25, etc...

 

There is more advanced support for checking if conditions holds true for a given time

Please login or register to see this code.

Here we specify a trigger for device 88 and property value, but we don't specify what value, so it will trigger on both true and false.

First thing in the handler we call self:trueFor(<time>,<condition>) and if not true we return.

The <time> is the time we want the condition to be true and the <condition> is an expression that returns true when the condition we want to have true for <time> is true.

In this case, if the event's value property is true.

Behind the scene, the first time the condition is true a timer is started and if no further call to self:trueFor returns, the timer will trigger the handler when it expires.

If the condition is false the timer is reset waiting to start on the next true condition.

 

self:again() when called will re-trigger the handler so when another 5s, in this case, has expired, the rule will trigger again

self:again() also return the number of times it has been re-triggered.

We leverage that in this example by multiplying the value with 5, giving us the times the conditions have been true, and producing a log like

Please login or register to see this code.

Test the rule by sending it a fake event like

Please login or register to see this code.

 

There are a couple of self:* functions available inside a rule handler function

Please login or register to see this code.

 

If we don't care about the id of an event handler we can give it the id '_' and it will be assigned an incremental id of type 'event:'..n

Please login or register to see this code.

If we trigger by sending an e1 event, all 3 triggers but with their own handlers

Please login or register to see this code.

 

The are some more keys - we can assign a handler to control log level, log tags and color.

Please login or register to see this code.

 

When we post from a handler with self:post, the post is remembered if it is a delayed post.

This allows us to cancel 'outstanding' posts.

Please login or register to see this code.

This rule when triggered by a 'tc' event it will post 3 new 'tc2' events with the delay of 5,7, and 8 seconds.

 

Then we define the 'tc2' handler.

Please login or register to see this code.

 

Lets test it by triggering it...

Please login or register to see this code.

 

When 'cancelTest2' 'hc2' is triggered, it will log 'TEST2' and then call self:cancelAll('cancelTest')

That command will cancel all outstanding posts/timers of 'cancelTest' which in this case is the post after 7 and 8. (5 was the one triggering 'cancelTest2'

 

This is very useful for some common use case. 

Ex. we want a sensor to turn on a light and automatically turn off the light after x seconds when sensor turns safe..

However, if the sensor is triggered again before x seconds we want to reset the timer.

Please login or register to see this code.

When sensor 100 is breached (value==true), then we cancel all outstanding timers/posts and turn on light.

If the sensor turns safe we post an action to turn off the light after x seconds. This will be cancelled if sensor is breached again.

 

We can try the logic of our rule with some fake posts...

Please login or register to see this code.

 

There is one problem with the previous handler. If the sensor is already breached when we start/restart the QA - there will be no event that the sensor has been triggered. That event was sent before we defined the handler. We have to wait for the sensor to be safe and then triggered again before the light turns on. For a sensor it may not be a big problem but if we trigger on a global variable that only changes once a day it can be a problem.

What we can do is to post a "fake" event with the sensors current value to trigger our rule.

Please login or register to see this code.

and our rule will be triggered at startup with the sensors current value. If it's already breached the light will be turned on and off we go...

Another example

Please login or register to see this code.

When we restart our QA and the handlers are defined we want to trigger our TimeOfDay rule with the current value so the light is turned on if it's evening.

 

If we find that we do this often we can define helper functions for the task

Please login or register to see this code.

and then

Please login or register to see this code.

 

There is the current date in self.date and a between time test in self:between(start, stop)

Please login or register to see this code.

Here we check if our sensor is breached between 17:00 and sunset + 30min

 

...more to come.

Edited by jgab
  • Like 2
  • Thanks 2
Link to comment
Share on other sites

Hi @jgab started too use the eventlib insted of sourcetriggersubscriber now for diffrent things in my quickapps :D the truefor is Perfect :D 

but I cant figure out how to trigger on a spesefic time I got storred in a QuickVar (Timeon =  "20:00"  . I got the crontime working for a spesefic time each day or once and hour etc :)


so I think that is the way to go :D   just have to make my timers into cron format :)  


and a question about profiles. Is it possible to trigger on the name of profiles? instead of having to find the id of each profile and trigger on the id? 

 

I am useing an custom event that trigger on profile changes now :) and then haveing the eventlib triggering on that customevent. 

 

I found this about the cron time and I think some version of this will work :) going to test it tomorrow.

 

Found this in one post from jgab earlier for cron formate: 

Please login or register to see this link.

  :D 

 

 

 

 

 

 

 

 

Edited by Brors94
Link to comment
Share on other sites

  • Topic Author
  • 13 hours ago, Brors94 said:

    Hi @jgab started too use the eventlib insted of sourcetriggersubscriber now for diffrent things in my quickapps :D the truefor is Perfect :D 
    but I cant figure out how to trigger on a spesefic time I got storred in a QuickVar (Timeon =  "20:00"  . I got the crontime working for a spesefic time each day or once and hour etc :)

    so I think that is the way to go :D   just have to make my timers into cron format :)  
    and a question about profiles. Is it possible to trigger on the name of profiles? instead of having to find the id of each profile and trigger on the id? 

    I am useing an custom event that trigger on profile changes now :) and then haveing the eventlib triggering on that customevent. 

    I found this about the cron time and I think some version of this will work :) going to test it tomorrow.

    Found this in one post from jgab earlier for cron formate: 

    Please login or register to see this link.

      :D 

     

     

     

     

     

    Keep an eye on the github repo as the EventLib is updated (I'll try to keep it backward compatible)

    Anyway, the easiest way to do a daily timer is to use the timerhandler

    Please login or register to see this code.

    If you specify time a "+/15:00" the loop will add 15 hours before triggering the next time.

    However if we use the "n/" prefix (standing for "next") it will trigger the next time it becomes 15:00.

    If you start the QA at 16:00, it will trigger at 15:00 the next day the first time.

     

    So, if you have "20:00" stored in a global variable, You can do

    Please login or register to see this code.

     

    This works. 

    The drawback is that if you change the value of Timeon it will take until the next time it triggers on the old time before it start with the new time.

    What you can do is add another handler watching the Timeon variable and in that case restart myAction handler

     

    Please login or register to see this code.

     

     

    • Thanks 1
    Link to comment
    Share on other sites

    Hi again @jgab. I havent had mutch time to change my QA since the eventlib came :D But I am now got too try out the Timers a bit more. 

     

    I had this error every thime i tried to update the time variable: 
     

    [20.02.2024] [19:35:02] [DEBUG] [QUICKAPP1859]: 19:40[20.02.2024] [19:35:02]
    [ERROR] [QUICKAPP1859]: timer handler failed with error: ./include/JgabEvent.lua:638: Event expected

    Please login or register to see this code.

    This self:post seem too be the one causes it I think 😅

     

    But this works:

     

    Event.id='DayOn'
    Event{type='quickvar',name='DayOn'}
    function Event:handler(event)
        self:cancelAll('DayTimerAction')
        UpdateDayOn()    
    end
     
    function UpdateDayOn()
    Event:post({type='DayTimerAction'},"n/"..self:getVariable('DayOn').."") -- start loop, be careful so you have access to self here...
    end

     

    But is this a dumb way to do it? 😅

     

    this the full timer:

     
    Event.id='TimerDayTimer'
    Event{type='DayTimerAction'}
    function Event:handler(event)
        self:debug("TimerDayTimer")
        HouseProfil = "Home"
        UpdateDayTimer()
    end
     
    Event:post({type='DayTimerAction'},"n/"..self:getVariable('DayOn').."") -- start loop, be careful so you have access to self here...
     
    Event.id='DayOn'
    Event{type='quickvar',name='DayOn'}
    function Event:handler(event)
        self:cancelAll('DayTimerAction')
        UpdateDayOn()    
    end
     
    function UpdateDayOn()
    Event:post({type='DayTimerAction'},"n/"..self:getVariable('DayOn').."") -- start loop, be careful so you have access to self here...
    end
     
    function UpdateDayTimer()
            Event:post({type='DayTimerAction'},"n/"..self:getVariable('DayOn').."")
            self:setVariable("HouseProfil", "Home")  
            heatingupdate() 
    end

     

     

     

     

     

     

     

     

     

     

     

    Link to comment
    Share on other sites

  • Topic Author
  • 12 hours ago, Brors94 said:

    Hi again @jgab. I havent had mutch time to change my QA since the eventlib came :D But I am now got too try out the Timers a bit more. 

     

    I had this error every thime i tried to update the time variable: 
     

    [20.02.2024] [19:35:02] [DEBUG] [QUICKAPP1859]: 19:40[20.02.2024] [19:35:02]
    [ERROR] [QUICKAPP1859]: timer handler failed with error: ./include/JgabEvent.lua:638: Event expected

    Please login or register to see this code.

     

    Yes, because the first argument to self:post must be an event and an event is always a lua table with a 'type' key bound the event type which is a string, 'DayTimerAction' in this case.

    So,

    Please login or register to see this code.

    should work.

    Let me come back on the "dumbness" :-) 

    • Thanks 1
    Link to comment
    Share on other sites

    • 3 weeks later...

    Hi - can this library receive the "RECIEVE_EVENTS" too like ER5 (ie. respond to external events)?

     

    Use case - now that i can receive events, i want to set up the equivalent of a bunch of QAs (virtual devices of type motion sensor). I think on a different thread you mentioned that ideally one should use one ER5 instance per HC3. Say I have 10 cameras, I wouldn't create 10 ER5s.

     

    Or do I get my ER5 event handler(s) to now trigger each QA (virtual device)?

     

    (Update: meanwhile i can use the pub/sub from fibaroExtra as per 

    )

    Edited by gurpal2000
    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...