openhab-scripting 4.7.1 → 4.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5e39f0dd326751e6c61fcf44a85f6a9033c72fc6196f899d59305f7e77ff2cf
4
- data.tar.gz: 207a22d5633a711bdc333d1fb94befa787a6fa63a1b1050607c9f7665e1149f7
3
+ metadata.gz: 59b0441f0cce1fb707bfb5d74d051135ce37c63128359cfa98cdae2573b920d2
4
+ data.tar.gz: 0101f396a6bce5e6d52f3191973fb6db2f3cb3be93f00229b4cc5297f04488bf
5
5
  SHA512:
6
- metadata.gz: cc744a57eaad8487ffcc3bb31584bfd484ee27de0948c07a1ac47be5953e5ee2fda4a1a0713f49fda4c289ffb298908d32d69741ce83ee3c526f0bec7c5ae173
7
- data.tar.gz: 42a1fa4aa68bc0d81399f02de37761598005bed645b105f85f14af6d3419578938a3cbd33cd8a6c03b0fed46031c25730dca23074063d98ba76cc0eea43ccf24
6
+ metadata.gz: ac154dd9d98ca0305c30770286554cb0b4bc863f1af95e7e03a32090aac7cc8f13633a42d2bcd8da7bc8b585f377a4db74d8a4ef668675ac0704fed9627f9973
7
+ data.tar.gz: bc241f0713e34124057fb124658dd13b4437bbe455bbf975c616aefd6a05b49a8d224039e23175dd7c1c350a17fa782eec2c8d22748e56f24cf8e618774396a2
@@ -22,6 +22,7 @@ require_relative 'rollershutter_item'
22
22
  require_relative 'string_item'
23
23
 
24
24
  require_relative 'ensure'
25
+ require_relative 'timed_command'
25
26
 
26
27
  module OpenHAB
27
28
  module DSL
@@ -65,9 +66,9 @@ module OpenHAB
65
66
 
66
67
  logger.trace("Defining #{klass}##{command} for #{value}")
67
68
  klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
68
- def #{command} # def on
69
- command(#{value}) # command(ON)
70
- end # end
69
+ def #{command}(for: nil, on_expire: nil, &block) # def on(for: nil, on_expire: nil, &block )
70
+ command(#{value}, for: binding.local_variable_get(:for), on_expire: on_expire, &block) # command(ON, for: nil, expire: nil, &block)
71
+ end # end
71
72
  RUBY
72
73
 
73
74
  logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/dsl/timers'
4
+ require 'openhab/dsl/rules/triggers/trigger'
5
+ require 'java'
6
+
7
+ require_relative 'generic_item'
8
+
9
+ module OpenHAB
10
+ module DSL
11
+ module Items
12
+ # Module enables timed commands e.g. Switch.on for: 3.minutes
13
+ module TimedCommand
14
+ # Stores information about timed commands
15
+ TimedCommandDetails = Struct.new(:item, :command, :was, :duration, :on_expire, :timer, :expired, :cancel_rule,
16
+ :rule_uid, keyword_init: true) do
17
+ def expired?
18
+ expired
19
+ end
20
+
21
+ def canceled?
22
+ !expired?
23
+ end
24
+ end
25
+
26
+ @timed_commands = {}
27
+
28
+ class << self
29
+ attr_reader :timed_commands
30
+ end
31
+
32
+ # Extensions for {Items::GenericItem} to implement timed commands
33
+ module GenericItem
34
+ #
35
+ # Sends command to an item for specified duration, then on timer expiration sends
36
+ # the expiration command to the item
37
+ #
38
+ # @param [Types::Type] command to send to object
39
+ # @param [Duration] for duration for item to be in command state
40
+ # @param [Types::Type] on_expire Command to send when duration expires
41
+ #
42
+ #
43
+ # rubocop: disable Metrics/MethodLength
44
+ # The mutex makes this over 10 lines, but there is usable way to break thsi method up
45
+ def command(command, for: nil, on_expire: nil, &block)
46
+ duration = binding.local_variable_get(:for)
47
+ return super(command) unless duration
48
+
49
+ # Timer needs access to rule to disable, rule needs access to timer to cancel.
50
+ # Using a mutux to ensure neither fires before the other is constructed
51
+ semaphore = Mutex.new
52
+
53
+ semaphore.synchronize do
54
+ timed_command_details = TimedCommand.timed_commands[self]
55
+ if timed_command_details.nil?
56
+ create_timed_command(command: command, duration: duration,
57
+ semaphore: semaphore, on_expire: on_expire, &block)
58
+ else
59
+ logger.trace "Outstanding Timed Command #{timed_command_details} encountered - rescheduling"
60
+ timed_command_details.duration = duration # Capture updated duration
61
+ timed_command_details.timer.reschedule duration
62
+ end
63
+ end
64
+
65
+ self
66
+ end
67
+ # rubocop: enable Metrics/MethodLength
68
+ alias << command
69
+
70
+ private
71
+
72
+ # Creates a new timed command and places it in the TimedCommand hash
73
+ # rubocop: disable Metrics/AbcSize
74
+ # rubocop: disable Metrics/MethodLength
75
+ # There is no feasible way to break this method into smaller components
76
+ def create_timed_command(command:, duration:, semaphore:, on_expire:, &block)
77
+ on_expire ||= default_on_expire(command)
78
+ timed_command_details = TimedCommandDetails.new(item: self, command: command, was: state,
79
+ on_expire: on_expire, duration: duration)
80
+
81
+ # Send specified command after capturing current state
82
+ command(command)
83
+
84
+ timed_command_details.timer = timed_command_timer(timed_command_details, semaphore, &block)
85
+ timed_command_details.cancel_rule = TimedCommandCancelRule.new(timed_command_details, semaphore,
86
+ &block)
87
+ timed_command_details.rule_uid = OpenHAB::DSL::Rules.automation_manager
88
+ .addRule(timed_command_details.cancel_rule).getUID
89
+ logger.trace "Created Timed Command #{timed_command_details}"
90
+ TimedCommand.timed_commands[self] = timed_command_details
91
+ end
92
+ # rubocop: enable Metrics/AbcSize
93
+ # rubocop: enable Metrics/MethodLength
94
+
95
+ # Creates the timer to handle changing the item state when timer expires or invoking user supplied block
96
+ # @param [TimedCommandDetailes] timed_command_details details about the timed command
97
+ # @param [Mutex] semaphore Semaphore to lock on to prevent race condition between rule and timer
98
+ # @return [Timer] Timer
99
+ # rubocop: disable Metrics/MethodLength
100
+ # There is no feasible way to break this method into smaller components
101
+ def timed_command_timer(timed_command_details, semaphore, &block)
102
+ after(timed_command_details.duration, id: self) do
103
+ semaphore.synchronize do
104
+ logger.trace "Timed command expired - #{timed_command_details}"
105
+ cancel_timed_command_rule(timed_command_details)
106
+ timed_command_details.expired = true
107
+ if block
108
+ logger.trace "Invoking block #{block} after timed command for #{id} expired"
109
+ yield(timed_command_details)
110
+ else
111
+ command(timed_command_details.on_expire)
112
+ end
113
+
114
+ TimedCommand.timed_commands.delete(timed_command_details.item)
115
+ end
116
+ end
117
+ end
118
+ # rubocop: enable Metrics/MethodLength
119
+
120
+ # Cancels timed command rule
121
+ # @param [TimedCommandDetailed] timed_command details about the timed command
122
+ def cancel_timed_command_rule(timed_command_details)
123
+ logger.trace "Removing rule: #{timed_command_details.rule_uid}"
124
+ OpenHAB::DSL::Rules.registry.remove(timed_command_details.rule_uid)
125
+ end
126
+
127
+ #
128
+ # The default expire for ON/OFF is their inverse
129
+ #
130
+ def default_on_expire(command)
131
+ case format_type_pre(command)
132
+ when ON then OFF
133
+ when OFF then ON
134
+ else state
135
+ end
136
+ end
137
+
138
+ #
139
+ # Rule to cancel timed commands
140
+ #
141
+ class TimedCommandCancelRule < Java::OrgOpenhabCoreAutomationModuleScriptRulesupportSharedSimple::SimpleRule
142
+ include OpenHAB::Log
143
+ def initialize(timed_command_details, semaphore, &block)
144
+ super()
145
+ @semaphore = semaphore
146
+ @timed_command_details = timed_command_details
147
+ @block = block
148
+ set_name("Cancels implicit timer for #{timed_command_details.item.id}")
149
+ set_triggers([OpenHAB::DSL::Rules::Triggers::Trigger.trigger(
150
+ type: OpenHAB::DSL::Rules::Triggers::Trigger::ITEM_STATE_UPDATE,
151
+ config: { 'itemName' => timed_command_details.item.name }
152
+ )])
153
+ end
154
+
155
+ #
156
+ # Execute the rule
157
+ #
158
+ # @param [Map] mod map provided by OpenHAB rules engine
159
+ # @param [Map] inputs map provided by OpenHAB rules engine containing event and other information
160
+ #
161
+ #
162
+ # rubocop: disable Metrics/MethodLength
163
+ # rubocop: disable Metrics/AbcSize
164
+ # There is no feasible way to break this method into smaller components
165
+ def execute(_mod = nil, inputs = nil)
166
+ @semaphore.synchronize do
167
+ logger.trace "Canceling implicit timer #{@timed_command_details.timer} for "\
168
+ "#{@timed_command_details.item.id} because received event #{inputs}"
169
+ @timed_command_details.timer.cancel
170
+ # rubocop: disable Style/GlobalVars
171
+ # Disabled due to OpenHAB design
172
+ $scriptExtension.get('ruleRegistry').remove(@timed_command_details.rule_uid)
173
+ # rubocop: enable Style/GlobalVars
174
+ TimedCommand.timed_commands.delete(@timed_command_details.item)
175
+ if @block
176
+ logger.trace 'Executing user supplied block on timed command cancelation'
177
+ @block&.call(@timed_command_details)
178
+ end
179
+ end
180
+ end
181
+ # rubocop: enable Metrics/MethodLength
182
+ # rubocop: enable Metrics/AbcSize
183
+ end
184
+ end
185
+ end
186
+ GenericItem.prepend(TimedCommand::GenericItem)
187
+ end
188
+ end
189
+ end
@@ -68,8 +68,7 @@ module OpenHAB
68
68
  # Cleanup any resources associated with automation rule
69
69
  #
70
70
  def cleanup
71
- logger.trace "Cancelling #{@trigger_delays.length} Trigger Delays(s) for rule '#{name}'"
72
- @trigger_delays.each_value { |trigger_delay| trigger_delay.timer&.cancel }
71
+ # No cleanup is necessary right now, trigger delays are tracked and cancelled by timers library
73
72
  end
74
73
 
75
74
  private
@@ -230,9 +229,9 @@ module OpenHAB
230
229
  logger.trace("Item changed to #{state} for #{trigger_delay}, rescheduling timer.")
231
230
  trigger_delay.timer.reschedule(ZonedDateTime.now.plus(trigger_delay.duration))
232
231
  else
233
- logger.trace("Item changed to #{state} for #{trigger_delay}, cancelling timer.")
232
+ logger.trace("Item changed to #{state} for #{trigger_delay}, canceling timer.")
234
233
  trigger_delay.timer.cancel
235
- # Reprocess trigger delay after cancelling to track new state (if guards matched, etc)
234
+ # Reprocess trigger delay after canceling to track new state (if guards matched, etc)
236
235
  process_trigger_delay(trigger_delay, mod, inputs)
237
236
  end
238
237
  end
@@ -15,8 +15,13 @@ module OpenHAB
15
15
  module Rules
16
16
  @script_rules = []
17
17
 
18
+ # rubocop: disable Style/GlobalVars
19
+ @automation_manager = $scriptExtension.get('automationManager')
20
+ @registry = $scriptExtension.get('ruleRegistry')
21
+ # rubocop: enable Style/GlobalVars
22
+
18
23
  class << self
19
- attr_reader :script_rules
24
+ attr_reader :script_rules, :automation_manager, :registry
20
25
  end
21
26
 
22
27
  #
@@ -134,9 +139,7 @@ module OpenHAB
134
139
  #
135
140
  #
136
141
  def add_rule(rule)
137
- # rubocop: disable Style/GlobalVars
138
- $scriptExtension.get('automationManager').addRule(rule)
139
- # rubocop: enable Style/GlobalVars
142
+ Rules.automation_manager.addRule(rule)
140
143
  end
141
144
  end
142
145
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/log/logger'
4
+ require_relative 'reentrant_timer'
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ #
9
+ # Provides access to and ruby wrappers around OpenHAB timers
10
+ #
11
+ module Timers
12
+ #
13
+ # Manages data structures that track timers
14
+ #
15
+ class TimerManager
16
+ include OpenHAB::Log
17
+
18
+ attr_reader :timer_ids
19
+
20
+ def initialize
21
+ # Track timer IDs
22
+ @timer_ids = Hash.new { |hash, key| hash[key] = Set.new }
23
+
24
+ # Reentrant timer lookups
25
+ @reentrant_timers = {}
26
+
27
+ # Tracks active timers
28
+ @timers = Set.new
29
+ end
30
+
31
+ #
32
+ # Adds the current timer to the set of rule timers if being tracked
33
+ #
34
+ # rubocop: disable Metrics/AbcSize
35
+ # It does not make sense to break this up into seperate components
36
+ def add(timer)
37
+ logger.trace("Adding #{timer} to timers")
38
+ @timers << timer
39
+
40
+ if timer.respond_to? :id
41
+ logger.trace("Adding #{timer} with id #{timer.id.inspect} timer ids")
42
+ @timer_ids[timer.id] << timer
43
+ end
44
+
45
+ return unless timer.respond_to? :reentrant_id
46
+
47
+ logger.trace("Adding reeentrant #{timer} with reentrant id #{timer.reentrant_id} timer ids")
48
+ @reentrant_timers[timer.reentrant_id] = timer
49
+ end
50
+ # rubocop: enable Metrics/AbcSize
51
+
52
+ # Fetches the reentrant timer that matches the supplied id and block if it exists
53
+ #
54
+ # @param [Object] Object to associate with timer
55
+ # @param [Block] block to execute, block is passed a Timer object
56
+ #
57
+ # @return [RentrantTimer] Timer object if it exists, nil otherwise
58
+ #
59
+ def reentrant_timer(id:, &block)
60
+ reentrant_key = ReentrantTimer.reentrant_id(id: id, &block)
61
+ logger.trace("Checking for existing reentrant timer for #{reentrant_key}")
62
+ @reentrant_timers[reentrant_key]
63
+ end
64
+
65
+ #
66
+ # Delete the current timer to the set of rule timers if being tracked
67
+ #
68
+ def delete(timer)
69
+ logger.trace("Removing #{timer} from timers")
70
+ @timers.delete(timer)
71
+ @timer_ids[timer.id].delete(timer) if (timer.respond_to? :id) && (@timer_ids.key? timer.id)
72
+ @reentrant_timers.delete(timer.reentrant_id) if timer.respond_to? :reentrant_id
73
+ end
74
+
75
+ #
76
+ # Cancels all active timers
77
+ #
78
+ def cancel_all
79
+ logger.trace("Canceling #{@timers.length} timers")
80
+ @timers.each(&:cancel)
81
+ @timer_ids.clear
82
+ @reentrant_timers.clear
83
+ @timers.clear
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/log/logger'
4
+ require_relative 'timer'
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ #
9
+ # Provides access to and ruby wrappers around OpenHAB timers
10
+ #
11
+ module Timers
12
+ # A reentrant timer is a timer that is automatically rescheduled
13
+ # when the block it refers to is encountered again
14
+ #
15
+ # @author Brian O'Connell
16
+ # @since 2.0.0
17
+ class ReentrantTimer < Timer
18
+ include OpenHAB::Log
19
+
20
+ attr_reader :id, :reentrant_id
21
+
22
+ #
23
+ # Create a new Timer Object
24
+ #
25
+ # @param [Duration] duration Duration until timer should fire
26
+ # @param [Block] block Block to execute when timer fires
27
+ #
28
+ def initialize(duration:, id:, &block)
29
+ raise 'Reentrant timers do not work in dynamically generated code' unless block.source_location
30
+
31
+ @id = id
32
+ @reentrant_id = self.class.reentrant_id(id: id, &block)
33
+ super(duration: duration, &block)
34
+ logger.trace("Created Reentrant Timer #{self} with reentrant Key #{@reentrant_id}")
35
+ end
36
+
37
+ def self.reentrant_id(id:, &block)
38
+ [id, block.source_location].flatten
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'delegate'
5
+ require 'forwardable'
6
+ require 'openhab/log/logger'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ #
11
+ # Provides access to and ruby wrappers around OpenHAB timers
12
+ #
13
+ module Timers
14
+ include OpenHAB::Log
15
+ java_import org.openhab.core.model.script.actions.ScriptExecution
16
+ java_import java.time.ZonedDateTime
17
+
18
+ # Ruby wrapper for OpenHAB Timer
19
+ # This class implements delegator to delegate methods to the OpenHAB timer
20
+ #
21
+ # @author Brian O'Connell
22
+ # @since 2.0.0
23
+ class Timer < SimpleDelegator
24
+ include OpenHAB::Log
25
+ extend Forwardable
26
+
27
+ def_delegator :@timer, :is_active, :active?
28
+ def_delegator :@timer, :is_running, :running?
29
+ def_delegator :@timer, :has_terminated, :terminated?
30
+
31
+ #
32
+ # Create a new Timer Object
33
+ #
34
+ # @param [Duration] duration Duration until timer should fire
35
+ # @param [Block] block Block to execute when timer fires
36
+ #
37
+ def initialize(duration:, &block)
38
+ @duration = duration
39
+
40
+ # A semaphore is used to prevent a race condition in which calling the block from the timer thread
41
+ # occurs before the @timer variable can be set resulting in @timer being nil
42
+ semaphore = Mutex.new
43
+
44
+ semaphore.synchronize do
45
+ @timer = ScriptExecution.createTimer(
46
+ ZonedDateTime.now.plus(@duration), timer_block(semaphore, &block)
47
+ )
48
+ @rule_timers = Thread.current[:rule_timers]
49
+ super(@timer)
50
+ Timers.timer_manager.add(self)
51
+ end
52
+ end
53
+
54
+ #
55
+ # Reschedule timer
56
+ #
57
+ # @param [Duration] duration
58
+ #
59
+ # @return [Timer] Rescheduled timer instances
60
+ #
61
+ def reschedule(duration = nil)
62
+ duration ||= @duration
63
+ Timers.timer_manager.add(self)
64
+ @timer.reschedule(ZonedDateTime.now.plus(duration))
65
+ end
66
+
67
+ # Cancel timer
68
+ #
69
+ # @return [Boolean] True if cancel was successful, false otherwise
70
+ #
71
+ def cancel
72
+ Timers.timer_manager.delete(self)
73
+ @timer.cancel
74
+ end
75
+
76
+ private
77
+
78
+ #
79
+ # Constructs a block to execute timer within
80
+ #
81
+ # @param [Semaphore] Semaphore to obtain before executing
82
+ #
83
+ # @return [Proc] Block for timer to execute
84
+ #
85
+ def timer_block(semaphore)
86
+ proc {
87
+ semaphore.synchronize do
88
+ Timers.timer_manager.delete(self)
89
+ yield(self)
90
+ end
91
+ }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'java'
4
- require 'delegate'
5
- require 'forwardable'
6
- require 'openhab/log/logger'
3
+ require_relative 'timers/timer'
4
+ require_relative 'timers/manager'
5
+ require_relative 'timers/reentrant_timer'
7
6
 
8
7
  module OpenHAB
9
8
  module DSL
@@ -12,109 +11,58 @@ module OpenHAB
12
11
  #
13
12
  module Timers
14
13
  include OpenHAB::Log
15
- java_import org.openhab.core.model.script.actions.ScriptExecution
16
- java_import java.time.ZonedDateTime
17
14
 
18
- # Tracks active timers
19
- @timers = Set.new
20
- class << self
21
- attr_accessor :timers
22
- end
23
-
24
- # Ruby wrapper for OpenHAB Timer
25
- # This class implements delegator to delegate methods to the OpenHAB timer
26
- #
27
- # @author Brian O'Connell
28
- # @since 2.0.0
29
- class Timer < SimpleDelegator
30
- include OpenHAB::Log
31
- extend Forwardable
32
-
33
- def_delegator :@timer, :is_active, :active?
34
- def_delegator :@timer, :is_running, :running?
35
- def_delegator :@timer, :has_terminated, :terminated?
36
-
37
- #
38
- # Create a new Timer Object
39
- #
40
- # @param [Duration] duration Duration until timer should fire
41
- # @param [Block] block Block to execute when timer fires
42
- #
43
- def initialize(duration:, &block)
44
- @duration = duration
45
-
46
- # A semaphore is used to prevent a race condition in which calling the block from the timer thread
47
- # occurs before the @timer variable can be set resulting in @timer being nil
48
- semaphore = Mutex.new
49
-
50
- semaphore.synchronize do
51
- @timer = ScriptExecution.createTimer(
52
- ZonedDateTime.now.plus(@duration), timer_block(semaphore, &block)
53
- )
54
- super(@timer)
55
- Timers.timers << self
56
- end
57
- end
58
-
59
- #
60
- # Reschedule timer
61
- #
62
- # @param [Duration] duration
63
- #
64
- # @return [Timer] Rescheduled timer instances
65
- #
66
- def reschedule(duration = nil)
67
- duration ||= @duration
68
- Timers.timers << self
69
- @timer.reschedule(ZonedDateTime.now.plus(duration))
70
- end
71
-
72
- # Cancel timer
73
- #
74
- # @return [Boolean] True if cancel was successful, false otherwise
75
- #
76
- def cancel
77
- Timers.timers.delete(self)
78
- @timer.cancel
79
- end
15
+ # Manages timers
16
+ @timer_manager = TimerManager.new
80
17
 
81
- private
82
-
83
- #
84
- # Constructs a block to execute timer within
85
- #
86
- # @param [Semaphore] Semaphore to obtain before executing
87
- #
88
- # @return [Proc] Block for timer to execute
89
- #
90
- def timer_block(semaphore)
91
- proc {
92
- semaphore.synchronize do
93
- Timers.timers.delete(self)
94
- yield(self)
95
- end
96
- }
97
- end
18
+ class << self
19
+ attr_reader :timer_manager
98
20
  end
99
21
 
100
22
  #
101
23
  # Execute the supplied block after the specified duration
102
24
  #
103
25
  # @param [Duration] duration after which to execute the block
26
+ # @param [Object] id to associate with timer
104
27
  # @param [Block] block to execute, block is passed a Timer object
105
28
  #
106
29
  # @return [Timer] Timer object
107
30
  #
108
- def after(duration, &block)
31
+ def after(duration, id: nil, &block)
32
+ return Timers.reentrant_timer(duration: duration, id: id, &block) if id
33
+
109
34
  Timer.new(duration: duration, &block)
110
35
  end
111
36
 
37
+ #
38
+ # Provdes access to the hash for mapping timer ids to the set of active timers associated with that id
39
+ # @return [Hash] hash of user specified ids to sets of times
40
+ def timers
41
+ Timers.timer_manager.timer_ids
42
+ end
43
+
112
44
  #
113
45
  # Cancels all active timers
114
46
  #
115
47
  def self.cancel_all
116
- logger.trace("Cancelling #{@timers.length} timers")
117
- @timers.each(&:cancel)
48
+ @timer_manager.cancel_all
49
+ end
50
+
51
+ # Create or reschedule a reentrant time
52
+ #
53
+ # @param [Duration] duration after which to execute the block
54
+ # @param [Object] id to associate with timer
55
+ # @param [Block] block to execute, block is passed a Timer object
56
+ # @return [ReentrantTimer] Timer object
57
+ def self.reentrant_timer(duration:, id:, &block)
58
+ timer = @timer_manager.reentrant_timer(id: id, &block)
59
+ if timer
60
+ logger.trace("Reentrant timer found - #{timer}")
61
+ timer.reschedule
62
+ else
63
+ logger.trace('No reentrant timer found, creating new timer')
64
+ ReentrantTimer.new(duration: duration, id: id, &block)
65
+ end
118
66
  end
119
67
  end
120
68
  end
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '4.7.1'
8
+ VERSION = '4.8.0'
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.1
4
+ version: 4.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian O'Connell
@@ -77,6 +77,7 @@ files:
77
77
  - lib/openhab/dsl/items/rollershutter_item.rb
78
78
  - lib/openhab/dsl/items/string_item.rb
79
79
  - lib/openhab/dsl/items/switch_item.rb
80
+ - lib/openhab/dsl/items/timed_command.rb
80
81
  - lib/openhab/dsl/lazy_array.rb
81
82
  - lib/openhab/dsl/monkey_patch/actions/actions.rb
82
83
  - lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb
@@ -106,6 +107,9 @@ files:
106
107
  - lib/openhab/dsl/things.rb
107
108
  - lib/openhab/dsl/time_of_day.rb
108
109
  - lib/openhab/dsl/timers.rb
110
+ - lib/openhab/dsl/timers/manager.rb
111
+ - lib/openhab/dsl/timers/reentrant_timer.rb
112
+ - lib/openhab/dsl/timers/timer.rb
109
113
  - lib/openhab/dsl/types/comparable_type.rb
110
114
  - lib/openhab/dsl/types/date_time_type.rb
111
115
  - lib/openhab/dsl/types/decimal_type.rb