openHAB Rules Tools [4.1.0.0;4.9.9.9]

This is a collection of blocks that allow Blockly users to leverage many of the capabilities of the openhab_rules_tools library, a JS Scripting library that provides a number of classes and utilities that add advanced capabilities to timers and provides utilities to help make managing timers easier, among other things.

This library requires openhab_rules_tools to be installed. This can be installed from openhabian-config or by running the command npm install openhab_rules_tools from the $OH_CONF/automation/js folder.

When you use a block from this library, the versions of the openhab-rules-tools library and the openhab-js libraries are checked and an exception thrown if the library is not compatible with the installed versions.

ToDo:

  • groupUtils, this one may not be feasible
  • updates to OHRT so the above work with the standard Blockly blocks (e.g. reschedule a CountdownTimer)

Blocks

Countdown Timer

This block instantiates a CountdownTimer to run at the given time. The timer is stored in the given cache under the given name, and if there is an error in the timer, the error will be reported under that name also. Every second, the passed in countdown Item is updated with the remaining amount of time left until the Timer function is run. If the Item is a Number Item, the number of seconds left until the Timer runs is posted to that Item. If it’s a String Item, the amount of time left in HH:MM:SS format is posted to the Item.

The timer created by this block can be used with the standard “cancel” and “hasTerminated” blocks in the “Timers and Delays” category (support for the rest will be added at a future date).

The above example will schedule a timer to log “Timer expired” after ten seconds. TestNumber will be updated to 10 to start and every second it will be updated with 9, 8, and so on until the timer expires.

Looping Timer


Creates a timer to run after the given time and reschedules itself to run again after the same delay as long as the passed in condition evaluates to false.

The timer created by this block can be used with the standard “cancel” and “hasTerminated” blocks in the “Timers and Delays” category (support for the rest will be added at a future date).

The above example will log “looping timer 1 X” every second five times where X counts from 0 to 4.

Deferred

This block lets you easily schedule a command or update to an Item at a future time. The same Deferred Object can be used to schedule commands/updates to multiple Items. There is no need to instantiate more than one.

Deferred commands/updates can be cancelled using the “cancel managed timer” and “cancel all managed timers” blocks (see below).

The above example is kind of contrived and doesn’t actually do anything.

The first block schedules an OFF command to TestSwitch in five seconds.
The second block schedules an update to 10 to TestNumber in ten seconds.
The third block cancels the scheduled command to TestSwitch.
The fourth block cancels all the scheduled commands and updates on “dn”.

Gatekeeper

Gatekeeper is a class that allows one to space out how quickly some code can run after the last block of code ran. For example, if you have a technology that cannot handle a blast of a bunch of commands all at once, Gatekeeper can be used to space out the commands so there is some space between them.

What makes it distinct from Rate Limit is it queues up the calls and works them off in order with the given time between them. This makes it useful for other cases, such creating a sequence of timed events like one would use to control irrigation.

Gatekeeper works with the “cancel all managed timers” block (see below).


In the above example, IrrigationZone1 will be commanded ON. After five minutes it’s commanded OFF and IrrigationZone2 is commanded to ON. After ten minutes it’s commanded to OFF and IrrigationZone3 is commanded to ON. After two minutes it’s commanded to OFF. Passing a time of 0 seconds to Gatekeeper will allow subsequent calls to run immediately.

Rate Limit

This is just like Gatekeeper except that if it’s too soon after the last call to Rate Limit, the call is completely dropped instead of being queued up and run. This can be useful to debounce a noisy sensor. Calls to this block cannot be cancelled.

In the above example you will see “RateLimit 1” and “RateLimit 3” in the logs but not “RateLimit 2” because it happens before the 2 seconds are up.

TimerMgr

TimerMgr manages one or more Timer’s entire life cycle through a simple interface. It is most useful when one has one rule that needs to manage multiple timers, one for each Item that can trigger the rule.

Property Purpose
private/shared which cache the TimerMgr is stored in
TimerMgr Name used as the key to pull the TimerMgr from the cache
“key” used as the key for the specific timer being managed
0 duration of the timer, must be a number
seconds/minutes/hours the unit of the duration
reschedule if exists when checked, if there is already a timer by the name “TimerMgr Name”, reschedule it, otherwise cancel it
run at scheduled time optional, the code to run when the timer expires
run if already exists optional, the code to run if a timer by the name “key” already exists

Timers created with this block work with the “cancel managed timer” and “cancel all managed timers” blocks (see bleow).

For example:

The above will log “Creating timer” and then create a timer named “foo” to run after five seconds. If the timer already exists it will be rescheduled for five seconds from now and “flapping” will be logged.

The next block will log “Timer foo exists false” because there is no “foo” timer scheduled. If the “bar” were changed to “true” it would log “Timer foo exists true”.

The next block waits one second. Then “Reschedule timer” is logged.

The next block behaves differently from the first because the timer already exists. You will see “flapping” in the log because the timer already exists and then the timer is rescheduled for five seconds from now. (Note: typically you’d have the one block which gets called with subsequent calls to a rule).

If we stopped there, after five seconds, it would log out “timer expired”.

If we continue you see how to cancel all timers in a timer manager and how to cancel an individual timer managed by a timer manager.

cancel managed timer

The standard cancel timer block under Timers and Delays will work for Countdown Timer but for managed timers both the manager (e.g. TimerMgr or Deferred) in addition to the “key” for the Timer itself needs to be passed. See examples above.

cancel all managed timers

This will cancel all the managed timers that are part of a TimerMgr or Deferred manager. See examples above.

timer exists

Returns true if a timer by the given “key” exists in the given TimerMgr. See example above.

to today/tomorrow/yesterday

image

Change the date portion of the passed in Date Time block to yesterday, today, or tomorrow.

The above example creates a date time four days into the past and logs it. It then logs the results of to today, to tomorrow, and to yesterday and the logs will show that the date changes accordingly.

Changelog

Version 0.5

  • Fixed problem where only static numbers can be used for the timer duration. Now a variable, the “get numericState from item” or any other block/combination of blocs that eventually evaluate to a number can be used.
  • Fixed “Utility” typos.
  • Next version that includes updates to the OHRT library will become 1.0

Version 0.4 (first published version, upgrade status to beta as it’s ready for testing)

  • a better first example created for Gatekeeper and the image that represents the library
  • implemented looping timer
  • fixed all that was broken on 0.3 (there was a lot, sorry about that)
  • made better use of utilities to make the generated code shorter and easier to read and maintain
  • added examples for all block types
  • all blocks have been tested

Version 0.3

  • cancel block for managed timers (Deferred, TimerMgr)
  • cancel all block for managed timers
  • timeUtils
  • version checking

Version 0.2

  • fixed bug in implementation of Countdown Timer
  • added Deferred, Gatekeeper, Rate Limit, and TimerMgr

Version 0.1

  • initial release with preliminary implementation of CountdownTimer

Sponsorship

If you want to send a tip my way or sponsor my work you can through Sponsor @rkoshak on GitHub or PayPal. It won’t change what I contribute to OH but it might keep me in coffee or let me buy hardware to test out new things.

Resources

uid: ohrt
tags:
  - marketplace:153371
props:
  parameters: []
  parameterGroups: []
timestamp: Feb 3, 2024, 11:54:54 AM
component: BlockLibrary
config:
  name: openHAB Rules Tools
slots:
  blocks:
    - component: BlockType
      config:
        args0:
          - check: Number
            name: DURATION
            type: input_value
          - name: UNIT
            options:
              - - seconds
                - S
              - - minutes
                - M
              - - hours
                - H
            type: field_dropdown
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - check: String
            name: TIMER_NAME
            type: input_value
          - name: COUNTDOWN_ITEM
            type: input_value
          - name: TIMER_FUNC
            type: input_statement
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: after %1 %2 with %3 %4 using countdown item %5 %6
        nextStatement: ""
        previousStatement: ""
        tooltip: Creates a countdown timer stored in the selected cache and the supplied countdown Item to count down the seconds until the timer runs.
        type: ohrt_countdown_timer
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                if(!cache.{{field:CACHE}}.exists({{input:TIMER_NAME}}) || cache.{{field:CACHE}}.get({{input:TIMER_NAME}}).hasTerminated()) {
                  cache.{{field:CACHE}}.put({{input:TIMER_NAME}},
                    {{utility:OHRT}}.CountdownTimer(
                      'PT' + {{input:DURATION}} + '{{field:UNIT}}',
                      () => {
                      {{statements:TIMER_FUNC}}
                      cache.{{field:CACHE}}.put({{input:TIMER_NAME}}, null);
                      },
                      {{input:COUNTDOWN_ITEM}},
                      {{input:TIMER_NAME}}));
                } // TODO: optionally reschedule
        toolbox:
          - component: PresetInput
            config:
              fields:
                NUM: 0
              name: DURATION
              shadow: true
              type: math_number
          - component: PresetInput
            config:
              fields:
                TEXT: MyTimer
              name: TIMER_NAME
              shadow: true
              type: text
          - component: PresetInput
            config:
              name: COUNTDOWN_ITEM
              shadow: true
              type: oh_item
    - component: BlockType
      config:
        args0:
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - cherck: String
            name: TIMER_NAME
            type: input_value
          - check: Number
            name: DURATION
            type: input_value
          - name: UNIT
            options:
              - - seconds
                - S
              - - minutes
                - M
              - - hours
                - H
            type: field_dropdown
          - type: input_dummy
          - name: TIMER_FUNC
            type: input_statement
          - check: Boolean
            name: CONDITION
            type: input_value
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: create a looping timer %1 %2 to run every %3 %4 %5 with %6 until %7
        nextStatement: ""
        previousStatement: ""
        tooltip: Creates a looping timer that will run the code periodically until the condition becomes true.
        type: ohrt_looping_timer
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:getLoopingTimer}}(cache.{{field:CACHE}}, {{input:TIMER_NAME}}).loop(() => {
                  {{statements:TIMER_FUNC}}
                  return ({{input:CONDITION}}) ? null : 'PT' + {{input:DURATION}} + '{{field:UNIT}}';
                },'PT' + {{input:DURATION}} + '{{field:UNIT}}', {{input:TIMER_NAME}});
        toolbox:
          - component: PresetInput
            config:
              fields:
                TEXT: MyTimer
              name: TIMER_NAME
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                NUM: 0
              name: DURATION
              shadow: true
              type: math_number
          - component: PresetInput
            config:
              name: CONDITION
              type: logic_boolean
    - component: BlockType
      config:
        args0:
          - check: Number
            name: DURATION
            type: input_value
          - name: UNIT
            options:
              - - seconds
                - S
              - - minutes
                - M
              - - hours
                - H
            type: field_dropdown
          - name: IS_COMMAND
            options:
              - - command
                - "true"
              - - update
                - "false"
            type: field_dropdown
          - name: ITEM
            type: input_value
          - check: String
            name: VALUE
            type: input_value
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - check: String
            name: TIMER_NAME
            type: input_value
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: after %1 %2 %3 item %4 to %5 with %6 %7
        nextStatement: ""
        previousStatement: ""
        tooltip: Creates a deferred Object which can be used to schedule a command or update to an Item.
        type: ohrt_deferred
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:getDeferred}}(cache.{{field:CACHE}}, {{input:TIMER_NAME}}).defer({{input:ITEM}}, {{input:VALUE}}, 'PT' + {{input:DURATION}} + '{{field:UNIT}}', {{field:IS_COMMAND}});
        toolbox:
          - component: PresetInput
            config:
              fields:
                NUM: 0
              name: DURATION
              shadow: true
              type: math_number
          - component: PresetInput
            config:
              fields:
                TEXT: ""
              name: VALUE
              shadow: true
              type: text
          - component: PresetInput
            config:
              name: ITEM
              shadow: true
              type: oh_item
          - component: PresetInput
            config:
              fields:
                TEXT: true
              name: VALUE
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                TEXT: Deferred Name
              name: TIMER_NAME
              shadow: true
              type: text
    - component: BlockType
      config:
        args0:
          - check: Number
            name: DURATION
            type: input_value
          - name: UNIT
            options:
              - - seconds
                - S
              - - minutes
                - M
              - - hours
                - H
            type: field_dropdown
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - check: String
            name: TIMER_NAME
            type: input_value
          - name: TIMER_FUNC
            type: input_statement
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: run this and prevent another run for %1 %2 using gatekeeper %3 %4 %5
        nextStatement: ""
        previousStatement: ""
        tooltip: Creates a gatekeeper Object if it does not already exist to prevent code from running too quickly after the last run. Gatekeeper queues subsequent calls and works them off in order with the specified delays between them.
        type: ohrt_gatekeeper
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:getGatekeeper}}(cache.{{field:CACHE}}, {{input:TIMER_NAME}}).addCommand('PT' + {{input:DURATION}} + '{{field:UNIT}}', () => {
                  {{statements:TIMER_FUNC}}
                });
        toolbox:
          - component: PresetInput
            config:
              fields:
                NUM: 0
              name: DURATION
              shadow: true
              type: math_number
          - component: PresetInput
            config:
              fields:
                TEXT: Gatekeeper Name
              name: TIMER_NAME
              shadow: true
              type: text
    - component: BlockType
      config:
        args0:
          - check: Number
            name: DURATION
            type: input_value
          - name: UNIT
            options:
              - - seconds
                - S
              - - minutes
                - M
              - - hours
                - H
            type: field_dropdown
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - check: String
            name: TIMER_NAME
            type: input_value
          - name: TIMER_FUNC
            type: input_statement
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: run this and prevent another run for %1 %2 using rate limit %3 %4 %5
        nextStatement: ""
        previousStatement: ""
        tooltip: Creates a rate limit Object if it does not already exist to prevent code from running too quickly after the last run. Rate limit drops calls that happen within the duration.
        type: ohrt_rate_limit
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:getRateLimit}}(cache.{{field:CACHE}}, {{input:TIMER_NAME}}).run(function() {
                    {{statements:TIMER_FUNC}}
                  }, 'PT' + {{input:DURATION}} + '{{field:UNIT}}');
        toolbox:
          - component: PresetInput
            config:
              fields:
                NUM: 0
              name: DURATION
              shadow: true
              type: math_number
          - component: PresetInput
            config:
              fields:
                TEXT: RateLimit Name
              name: TIMER_NAME
              shadow: true
              type: text
    - component: BlockType
      config:
        args0:
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - check: String
            name: TIMER_MGR_NAME
            type: input_value
          - check: String
            name: TIMER_KEY
            type: input_value
          - check: Number
            name: DURATION
            type: input_value
          - name: UNIT
            options:
              - - seconds
                - S
              - - minutes
                - M
              - - hours
                - H
            type: field_dropdown
          - checked: true
            name: RESCHDULE
            type: field_checkbox
          - name: TIMER_FUNC
            type: input_statement
          - name: FLAPPING_FUNC
            type: input_statement
          - type: input_dummy
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: using timer manager %1 %2 check %3 to run after %4 %5 reschdule if exists %6 %9 run at scheduled time %7 run if already exists %8
        nextStatement: ""
        previousStatement: ""
        tooltip: Manages the life cycle of multiple timers.
        type: ohrt_timerMgr
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:getTimerMgr}}(cache.{{field:CACHE}}, {{input:TIMER_MGR_NAME}}).check({{input:TIMER_KEY}}, 'PT' + {{input:DURATION}} + '{{field:UNIT}}',

                function() { {{statements:TIMER_FUNC}} },'{{field:RESCHDULE}}' == 'TRUE', 

                function() { {{statements:FLAPPING_FUNC}} }, {{input:TIMER_KEY}});
        toolbox:
          - component: PresetInput
            config:
              fields:
                TEXT: TimerMgr Name
              name: TIMER_MGR_NAME
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                TEXT: key
              name: TIMER_KEY
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                NUM: 0
              name: DURATION
              shadow: true
              type: math_number
    - component: BlockType
      config:
        args0:
          - name: TIMER_KEY
            type: input_value
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - name: TIMER_MGR_NAME
            type: input_value
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: cancel managed timer %1 from %2 %3
        nextStatement: ""
        previousStatement: ""
        tooltip: Cancels a managed timer from TimerMgr or Deferred.
        type: ohrt_cancel_managed
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                if(cache.{{field:CACHE}}.exists({{input:TIMER_MGR_NAME}})) {
                  cache.{{field:CACHE}}.get({{input:TIMER_MGR_NAME}}).cancel({{input:TIMER_KEY}});
                }
        toolbox:
          - component: PresetInput
            config:
              fields:
                TEXT: TimerMgr Name
              name: TIMER_MGR_NAME
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                TEXT: key
              name: TIMER_KEY
              shadow: true
              type: text
    - component: BlockType
      config:
        args0:
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - name: TIMER_MGR_NAME
            type: input_value
        colour: 0
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: cancel all managed timers from %1 %2
        nextStatement: ""
        previousStatement: ""
        tooltip: Cancels all managed timers from Deferred, Gatekeeper, or TimerMg.
        type: ohrt_cancel_all_managed
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                if(cache.{{field:CACHE}}.exists({{input:TIMER_MGR_NAME}})) {
                  cache.{{field:CACHE}}.get({{input:TIMER_MGR_NAME}}).cancelAll();
                }
        toolbox:
          - component: PresetInput
            config:
              fields:
                TEXT: Timer Mgr Name
              name: TIMER_MGR_NAME
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                TEXT: key
              name: TIMER_KEY
              shadow: true
              type: text
    - component: BlockType
      config:
        args0:
          - name: TIMER_KEY
            type: input_value
          - name: CACHE
            options:
              - - private
                - private
              - - shared
                - shared
            type: field_dropdown
          - name: TIMER_MGR_NAME
            type: input_value
        colour: 210
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: "%1 exists in %2 %3"
        output: Boolean
        tooltip: Returns true if a managed timer exists in indicated manager.
        type: ohrt_has_managed_timer
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                cache.{{field:CACHE}}.exists({{input:TIMER_MGR_NAME}}) && cache.{{field:CACHE}}.get({{input:TIMER_MGR_NAME}}).hasTimer({{input:TIMER_KEY}})
        toolbox:
          - component: PresetInput
            config:
              fields:
                TEXT: Timer Mgr Name
              name: TIMER_MGR_NAME
              shadow: true
              type: text
          - component: PresetInput
            config:
              fields:
                TEXT: key
              name: TIMER_KEY
              shadow: true
              type: text
    - component: BlockType
      config:
        args0:
          - name: ZDT
            type: input_value
          - name: DAY
            options:
              - - today
                - toToday
              - - tomorrow
                - toTomorrow
              - - yesterday
                - toYesterday
            type: field_dropdown
        colour: 105
        helpUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: change the date on %1 to %2
        output: oh_zdt_now
        tooltip: Changes the date of the date time block to tomorrow's date.
        type: ohrt_to_tomorrow
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:OHRT}}.timeUtils.{{field:DAY}}({{input:ZDT}})
        toolbox:
          - component: PresetInput
            config:
              name: ZDT
              shadow: true
              type: oh_zdt_now
    - component: BlockType
      config:
        args0:
          - name: VAR_NAME
            type: field_variable
            variable: item
          - name: GROUP
            type: input_value
          - name: FILTER
            type: input_statement
          - name: MAP
            type: input_statement
        colour: 270
        helperUrl: https://github.com/rkoshak/openhab-rules-tools
        inputsInline: true
        message0: create list for each %1 in %2 with filter %3 and map %4
        output: lists_create_with
        tooltip: Reduces a Group's members to a list of values (e.g. names).
        type: ohrt_members_to_mapped_list
      slots:
        code:
          - component: BlockCodeTemplate
            config:
              template: >
                {{utility:OHRT}}.membersToMappedList({{input:GROUP}}, ({{field:item}})
        toolbox:
          - component: PresetField
            config:
              name: VAR_NAME
              setEnabled: false
          - component: PresetInput
            config:
              name: GROUP
              shadow: true
              type: oh_item
  utilities:
    - component: UtilityFunction
      config:
        code: >
          var {{name}} = (() => {
            const ohrt = require('openhab_rules_tools');
            ohrt.helpers.validateLibraries('4.1.0', '2.0.3');
            return ohrt;
          })();
        name: OHRT
    - component: UtilityFunction
      config:
        code: >
          function {{name}}(cache, name, condition, create) {
            condition = (condition === undefined || condition === null) ? ((manager) => false) : condition;
            let manager = cache.get(name);
            if(manager === null || condition(manager)) {
              manager = create();
              cache.put(name, manager);
            }
            return manager;
          }
        name: getOrInstantiate
    - component: UtilityFunction
      config:
        code: >
          function {{name}}(cache, name) {
            return {{getOrInstantiate}}(cache, name, (timer) => timer.hasTerminated(), () => {{OHRT}}.LoopingTimer());
          }
        name: getLoopingTimer
    - component: UtilityFunction
      config:
        code: >
          function {{name}}(cache, name) {
            return {{getOrInstantiate}}(cache, name, null, () => {{OHRT}}.Deferred());
          }
        name: getDeferred
    - component: UtilityFunction
      config:
        code: >
          function {{name}}(cache, name) {
            return {{getOrInstantiate}}(cache, name, null, () => {{OHRT}}.Gatekeeper(name));
          }
        name: getGatekeeper
    - component: UtilityFunction
      config:
        code: >
          function {{name}}(cache, name) {
            return {{getOrInstantiate}}(cache, name, null, () => {{OHRT}}.RateLimit());
          }
        name: getRateLimit
    - component: UtilityFunction
      config:
        code: >
          function {{name}}(cache, name) {
            return {{getOrInstantiate}}(cache, name, null, () => {{OHRT}}.TimerMgr());
          }
        name: getTimerMgr
6 Likes

What an amazing and sophisticated contribution :heavy_heart_exclamation:

1 Like

amazing stuff that you started Rich,. This makes my rules a lot simpler.
and how cool that you join the blockly-club.

1 Like

It’s been on my plate for awhile. I’ve always intended to make a Blocky library to work with OHRT.

It’s going to take a bit to finish (Looping Timer is going to be "fun’) so I’m releasing it as I make progress in case intrepid users don’t want to wait. :grin:

I couldn’t manage without Gatekeeper and Timer Mgr in my own rules, with or without Blockly.

1 Like

@stefan.hoehn and @Larsen and anyone else interested. The library is now published and ready for feedback. I did some testing but I know how it’s supposed to work and likely missed some edge cases. I’ve still one more set of functions to port over (groupUtils) but I’m not certain those will be feasible to port to Blockly in the first place. I’m still gonna try though. :slight_smile:

2 Likes

I am currently at Fosdem for openHAB, so maybe i can look into it next weekend. Looks impressive.

1 Like

Testing has started. Your blocks look great. I’ll report.

1 Like

here my first feedback:
The countdown is really great. It shrinks down the rules and makes countdowns so easy and compact.
While it works great with a static number it does not work if the duration has to be evaluated from a variable or a number item.
So a block like

becomes

  Countdown = items.getItem('PlugKaffeeCountdown').numericState;
  if(!cache.private.exists('MyTimer') || cache.private.get('MyTimer').hasTerminated()) {
    cache.private.put('MyTimer',
      OHRT.CountdownTimer(
        'PTCountdownS',
        () => {....

That throws an error as the the duration is concatenated to “PTCountdownS” instead of e.g. ‘PT’ + Countdown + ‘S’

I’ll have to think about how to solve that one. Thanks for pointing it out!

FYI: Handling variables is an akward topic in blockly. The reason is that in blockly you can’t detect the type of what is contained in the variable. Therefore you always have to tell the user what the block expects when you are using a variable as an input.

By the way, did you know that the shorter way is also working since last year?

2 Likes

Totally missed this - nice to see such an advanced block library!

You have 4 instances of this typo in the code, I’m not sure if it just happens to work with it but you might want to correct it nonetheless.

Thanks for the review!

It does seem to work somehow but I definitely need to fix it. There should be an update for this and the variable issue @Larsen discovered today or tomorrow.

I’m pleased that my contribution is getting noticed. I’ve one more set of blocks to add but that is currently being blocked (pun intended :smiley:) until a change is made to the replacement logic (see [Blockly] Support blocks that create variables · Issue #2324 · openhab/openhab-webui · GitHub). I’m still struggling to figure out the way the relevant code gets called, but once I figure that out I think I can provide a PR. With that I get to where I can provide the Group membership processing utilities as blocks which can save a lot of users a lot of code I hope.

Update: Both the typos and the the issue with using variables in the duration of timers has been fixed.

I can confirm: Works perfect now! Looking forward to testing the next ones.

1 Like

How do you do this when running OH4 in a docker container?

Same way you do it for any other OH install. You already have conf mapped to a folder on your host or are using a Docker volume. Navigate to there and run npm install openhab_rules_tools. You need npm to be available on your host.

npm is not available inside the container unless you create a custom image with it installed. But it doesn’t need to be.

Thanks for clarifying. Turns out I don’t have npm installed on the host. Which makes me wonder how I got v2.0.2 of the tools installed. At least my interpretation of this error message is that I have it installed:

Script execution of rule with UID 'Toilet_presence_rule_OH4' failed: org.graalvm.polyglot.PolyglotException: Minimum library version not met: openhab_rules_tools 2.0.2 installed, 2.0.3 required

It’s not part of the add-on so you must have installed it somehow at some point. You’ll find the files under $OH_CONF/automation/js/node_modules.

Must have been on previous host. If I installed it on a different host, then migrated the container to a new host, openhab_rules_tools would be carried over but not npm, right?

In any case (for anyone running into this issue): this did the trick for me:

sudo apt install npm
sudo npm install openhab_rules_tools

Indeed, that would explain it.

OHRT doesn’t change much now that it’s been out for awhile and in use. And I try to avoid breaking changes as much as I can. So the need to upgrade OHRT is infrequent.

That’s good. But that you have to dig through the logs to find out that you need to update is not :wink: