logo elektroda
logo elektroda
X
logo elektroda

Implementing Variable Time Calculations for OpenBeken's addClockEvent Function

ilengyel 1356 12
ADVERTISEMENT
  • #1 20920436
    ilengyel
    Level 11  

    I would like to create a clock event based on a calculated variable, but finding it might not be possible with the current code. I see the default tokenizer settings only allow single complete constant expansions. For example,
    addClockEvent 22:34 $ch13 1 echo daysExpanded
    is okay, but
    
    addClockEvent $ch14:$ch15 0xff 2 echo timeExpanded
    addClockEvent $ch14 0xff 3 echo timeExpanded
    

    are not okay.

    I see 2 options:

    1. Enable TOKENIZER_ALTERNATE_EXPAND_AT_START flag for the add clock event's string tokenizer. This would allow a script like
    
    setChannel 14 $hour+1
    setChannel 15 $minute+45 // does not handle minute overflow
    addClockEvent $ch14:$ch15 0xff 4 echo timeExpanded
    


    2. Allow a single integer value for the time parameter that would represent a TimerSeconds type from midnight. This would allow a script like:
    
    setChannel 10 $sunset+1800
    addClockEvent $ch10 0xff 5 echo timeExpanded
    


    Personally, my preference is the second option since the time calculations and comparisons are a lot easier when they are a single integer, but I understand there will be a few quirks in the second option:
    
    addClockEvent 7 0xff 6 echo Triggered7SecondsAfterMidnight
    addClockEvent 7:00 0xff 7 echo Triggered7am
    addClockEvent 7:00:00 0xff 8 echo AlsoTriggered7am
    addClockEvent sunset 0xff 9 echo TriggeredCorrectSunsetEveryDay
    addClockEvent $sunset 0xff 10 echo TriggeredAtTheSameTimeEveryDay
    


    I can be convinced for the first option if there is an easy way to extract hours and minutes from a TimerSeconds type. I am not seeing a way currently since evaluate expression treats everything as a float and there is no MOD operator, which I suspect is also due to only float.
  • ADVERTISEMENT
  • #2 20923004
    p.kaczmarek2
    Moderator Smart Home
    This is a good idea in general, but the approach 1 would break other scripts, because expanding all variables would also expand everything in the event body, for example:
    
    setChannel 14 $hour+1
    setChannel 15 $minute+45 // does not handle minute overflow
    addClockEvent $ch14:$ch15 0xff 4 setChannel 5 $CH10
    

    This will expand $CH10 at the addClockEvent execution time.

    For your idea 1 to work, we would need to have ability to choose what is being expanded. I can indeed see an advantage of being able to set both hours and minutes separately, but it would require some thinking how to handle it in the OBK.
    Idea 2 is simpler, but not as much as flexible as idea 1, when done correctly.
    Helpful post? Buy me a coffee.
  • #3 20924564
    ilengyel
    Level 11  
    I would contend that option 2 would be the more flexible option. Mainly because with option 1 I am not sure how to implement "setChannel 15 ($minute+45)%60" without a modulus operator. With option 2 I would just have to convert a time to seconds. I have a PR ready to go for option 2 at addClockEvent - allow TimerSeconds #1045 which I have tested to confirm that the handler's constants are not expanded like the first 3 arguments are. I.e.:
    setChannel 10 $sunset+1800
    addClockEvent $CH10 0xff 5 echo Light ON at $CH10
    listClockEvents
    // Gives the following result
    // Info:CMD:Ev 5 - 20:35:0, days 0xff, cmd echo Light ON at $CH10



    Having said that, the 2 options are not exclusive, and I would like to raise a separate PR for option 1. It just requires a bit of digging into the AddClockEvent/TokenizeString code. My current set of observations in that area are:
    Enable TOKENIZER_ALTERNATE_EXPAND_AT_START flag for the TokenizeString method would allow for $hour:$minute notation
    Tokenizer_GetArg is used for the first 3 arguments, which underneath takes the expanded arguments stored in the g_args array
    Tokenizer_GetArgFrom is used for the handler command which takes remaining unexpanded arguments from specified index stored in the g_argsFrom array
    There is a problem in the Tokenizer_TokenizeString(..) function around the line g_argsFrom[g_numArgs] = (s+(p-g_buffer)); where s is the unexpanded buffer, and p-g_buffer is the offset for the current argument in the expanded buffer. This would only work if all the constants' names have the same string length as their corresponding value string length eg $CH10 -> 12345
    Changing the TokenizeString function is a bit scary since it would affect almost all commands
  • ADVERTISEMENT
  • #5 20931598
    p.kaczmarek2
    Moderator Smart Home
    Sorry for the delay, I will try to look into it more in depth later, but in general I'd like to have module operator and braces support. I may look into it tonight, if that can help.

    ilengyel wrote:

    Changing the TokenizeString function is a bit scary since it would affect almost all commands

    If you are able to run Simulator, you can prepare some more self-tests before your changes, add them separately as a pull request so i can review them, and then we can try to improve tokenizer without breaking compatbility
    Helpful post? Buy me a coffee.
  • #6 20932902
    ilengyel
    Level 11  

    p.kaczmarek2 wrote:
    If you are able to run Simulator, you can prepare some more self-tests before your changes, add them separately as a pull request so I can review them, and then we can try to improve tokenizer without breaking compatibility


    Yep, I added some new ones in selftest_tokenizer.c and selftest_clockEvents.c. Let me know if some other conditions should be included. The actual code changes for multi expand token support were not that hard either, so I am quite confident about it now.

    p.kaczmarek2 wrote:
    In general, I'd like to have module operator and braces support.


    I think this would deserve its own thread. As far as I can tell, all numeric values are floats, and mod on floats is not obvious ... actually, some googling explained it for me: float fmodf(float a, float b).
  • #7 20933043
    p.kaczmarek2
    Moderator Smart Home
    I think I will merge your pull request tomorrow, but I will also make sure that everything else is still working. I may push some more self tests first today evening as well.
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #8 20935893
    p.kaczmarek2
    Moderator Smart Home
    I've merged your PR, but I think we need some more docs on this topic. Would you like to write a short tutorial for our tutorials section here about the usage of arguments expansion for clock operations?
    https://www.elektroda.com/rtvforum/forum517.html
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #9 20936417
    ilengyel
    Level 11  
    Yep sure I will write one up over the next few nights. Any particular format is preferred?

    In the meantime here is my ultimate porch light script that this merge enabled for me :)

    
    PowerSave 1
    startDriver ntp
    ntp_setServer 192.168.1.12
    ntp_timeZoneOfs 11
    ntp_setLatlong <latitude> <longitude>
    
    logfeature 6 0
    logfeature 7 0
    
    // Channel 10: maintain sunset time (The time when the light should turn on)
    setChannelLabel 10  "<b><span style='color:orange'\>Light ON (Civil Sunset)</span></b>"
    setChannelType 10 TimerSeconds
    
    // when using $sunset as an expression in addClockEvent, it needs to be re-calculated every day to take into account different sunset values
    alias calc_sunset backlog setChannel 10 $sunset+1800; removeClockEvent 4; addClockEvent $CH10 0xff 4 high_lights; echo Lights will turn on at $CH10
    
    // Channel 11: hidden register to store current time as TimerSeconds
    setChannelType 11 TimerSeconds
    setChannelPrivate 11 1
    setChannelVisible 11 0
    
    // Channel 12: trigger for timer_on_lights
    setChannelLabel 12 "Light Timer"
    setChannelType 12 Toggle
    setChannel 12 0
    
    alias timer_on_lights setChannel 12 1
    
    // Channel 13: 3 way toggle for light settings
    setChannelLabel 13 "Switch"
    setChannelType 13 OffDimBright
    
    alias off_lights setChannel 13 0
    alias low_lights setChannel 13 1
    alias high_lights setChannel 13 2
    
    // timer trigger: lights will be on high for 5mins, then on low for a further 25mins, then turned off
    addChangeHandler Channel12 == 1 backlog high_lights; addRepeatingEvent 300 1 low_lights; addRepeatingEvent 1500 1 off_lights
    
    addChangeHandler Channel13 == 0 backlog led_enableAll 0; setChannel 12 0; echo lights_set_off
    addChangeHandler Channel13 == 1 backlog led_temperature 500; led_dimmer 5; led_enableAll 1; echo lights_set_low
    addChangeHandler Channel13 == 2 backlog led_temperature 300; led_dimmer 30; led_enableAll 1; echo lights_set_high
    
    addClockEvent 3:30 0xff 1 calc_sunset
    addClockEvent 21:00 0xff 2 low_lights
    addClockEvent 23:00 0xff 3 off_lights
    
    waitFor NTPState 1
    waitFor MQTTState 1
    
    calc_sunset
    
    // set the current time as TimerSeconds in register for checks below
    setChannel 11 $hour*3600+$minute*60
    
    // Set initial light state to match the above clock events
    // sunset - 21:00   lights set to high (evening activities)
    // 21:00 - 23:00    lights set to low (sleepy mode: warmest temperature and very dim)
    // 23:00 - sunrise  lights on for a short period (bedtime the lights should be off, but can be forced on for a period by switching off and on)
    // sunrise - sunset lights turned off (day time the lights should be off)
    if $CH11>=$CH10&&$hour<21 then high_lights
    if $hour>=21&&$hour<23 then low_lights
    if $hour>=23||$CH11<$sunrise then timer_on_lights
    if $CH11>=$sunrise&&$CH11<$CH10 then off_lights
    


    It has a few extra features which I did not include in the automatic_day_and_night_lights_v3.bat:
    - Light timer function that can be triggered by MQTT on channel 12 or switching the light off and on after bed time
    - Off/Dim/Bright control via MQTT channel 13
  • #10 20936481
    p.kaczmarek2
    Moderator Smart Home
    Well, you can look up other topics in the tutorials section, but I don't have any specific requirements in mind. Just try to explain the feature to new users, link to our docs, link to this topic (maybe, for the reference), give some more samples... don't worry about repeating the information that is already somewhere else, I've noticed that beginners sometimes don't like to read "raw docs", they prefer step by step tutorials.

    That's a very nice script, you can add it to autoexec examples if that's not there yet.
    Helpful post? Buy me a coffee.
  • #11 20942300
    ilengyel
    Level 11  

    Finally added the tutorial in the above forum section. Let me know if any clarifications are required.
  • #12 20942539
    p.kaczmarek2
    Moderator Smart Home
    That's a nice writeup, but articles require having one image at the start of the text, can you post there something, idk, a screenshot of OBK web panel or something?
    Helpful post? Buy me a coffee.
  • #13 20942746
    ilengyel
    Level 11  

    Updated it to include the web panel of the scenario mentioned in the article.

Topic summary

The discussion revolves around implementing variable time calculations for the addClockEvent function in OpenBeken. The user proposes two options: enabling the TOKENIZER_ALTERNATE_EXPAND_AT_START flag to allow for more flexible variable expansions in clock events, or allowing a single integer value representing TimerSeconds from midnight for simpler time calculations. Responses highlight the potential complications of option 1, particularly regarding variable expansions in event bodies, while option 2 is seen as more straightforward. Several contributors express support for both options, with pull requests (PRs) being prepared for implementation. The conversation also touches on the need for additional documentation and tutorials to assist users in understanding the new features.
Summary generated by the language model.
ADVERTISEMENT