openhab-scripting 4.19.0 → 4.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/openhab/core/openhab_setup.rb +3 -3
- data/lib/openhab/core/thread_local.rb +6 -1
- data/lib/openhab/dsl/items/date_time_item.rb +3 -0
- data/lib/openhab/dsl/items/image_item.rb +1 -1
- data/lib/openhab/dsl/items/timed_command.rb +18 -11
- data/lib/openhab/dsl/rules/automation_rule.rb +19 -15
- data/lib/openhab/dsl/rules/cron_trigger_rule.rb +42 -0
- data/lib/openhab/dsl/rules/rule.rb +54 -23
- data/lib/openhab/dsl/rules/rule_config.rb +2 -15
- data/lib/openhab/dsl/rules/triggers/cron.rb +4 -4
- data/lib/openhab/dsl/timers/reentrant_timer.rb +2 -2
- data/lib/openhab/dsl/timers/timer.rb +34 -8
- data/lib/openhab/dsl/timers.rb +7 -4
- data/lib/openhab/log/logger.rb +66 -26
- data/lib/openhab/version.rb +1 -1
- data/lib/openhab.rb +1 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '02875983081fc90123fdb23c933a77a5553255acf34904cb13bba5bfafc69f63'
|
4
|
+
data.tar.gz: c90dbef96592a4230b6a8a904493ef4db46f8a2654ac7352989111df97847638
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c8194316eee36dd5de3a10644abb991124f19a3ba4b9a079b1304bd0ee28a1ae95b0177cb6cad18f344da4ac7dceb6f3bbfde423b0c59f33f903265a4acd0cc
|
7
|
+
data.tar.gz: 3b6ba33eba28b704488d830c250a8b09ff67e7cd754179e6536b6752fb4fedf7be9c47c40358704bfdbbc27f33446116597c2ee711aea6758ef2120cb85f2c3c
|
@@ -18,14 +18,14 @@ module OpenHAB
|
|
18
18
|
#
|
19
19
|
#
|
20
20
|
def self.wait_till_openhab_ready
|
21
|
-
logger.
|
21
|
+
logger.trace('Checking readyness of OpenHAB')
|
22
22
|
# rubocop: disable Style/GlobalVars
|
23
23
|
until $scriptExtension.get('automationManager')
|
24
|
-
logger.
|
24
|
+
logger.trace("Automation manager not loaded, checking again in #{CHECK_DELAY} seconds.")
|
25
25
|
sleep CHECK_DELAY
|
26
26
|
end
|
27
27
|
# rubocop: enable Style/GlobalVars
|
28
|
-
logger.
|
28
|
+
logger.trace 'Automation manager instantiated, OpenHAB ready for rule processing.'
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'openhab/log/logger'
|
4
|
+
|
3
5
|
# OpenHAB main module
|
4
6
|
module OpenHAB
|
5
7
|
module Core
|
@@ -7,15 +9,18 @@ module OpenHAB
|
|
7
9
|
# Manages thread local varaibles for access inside of blocks
|
8
10
|
#
|
9
11
|
module ThreadLocal
|
12
|
+
include OpenHAB::Log
|
13
|
+
|
10
14
|
#
|
11
15
|
# Execute the supplied block with the supplied values set for the currently running thread
|
12
16
|
# The previous values for each key are restored after the block is executed
|
13
17
|
#
|
14
|
-
# @param [Hash] Keys and values to set for running thread
|
18
|
+
# @param [Hash] Keys and values to set for running thread, if hash is nil no values are set
|
15
19
|
#
|
16
20
|
def thread_local(**values)
|
17
21
|
old_values = values.map { |key, _value| [key, Thread.current[key]] }.to_h
|
18
22
|
values.each { |key, value| Thread.current[key] = value }
|
23
|
+
logger.trace "Executing block with thread local context: #{values} - old context: #{old_values}"
|
19
24
|
yield
|
20
25
|
ensure
|
21
26
|
old_values.each { |key, value| Thread.current[key] = value }
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'time'
|
5
|
+
require 'java'
|
5
6
|
|
6
7
|
require 'openhab/dsl/items/comparable_item'
|
7
8
|
|
@@ -9,6 +10,7 @@ module OpenHAB
|
|
9
10
|
module DSL
|
10
11
|
module Items
|
11
12
|
java_import org.openhab.core.library.items.DateTimeItem
|
13
|
+
java_import java.time.format.DateTimeFormatter
|
12
14
|
|
13
15
|
# Adds methods to core OpenHAB DateTimeItem type to make it more natural
|
14
16
|
# in Ruby
|
@@ -53,6 +55,7 @@ module OpenHAB
|
|
53
55
|
# @!visibility private
|
54
56
|
def format_type(command)
|
55
57
|
return command.iso8601 if command.respond_to?(:iso8601)
|
58
|
+
return DateTimeFormatter::ISO_OFFSET_DATE_TIME.format(command) if command.is_a? java.time.ZonedDateTime
|
56
59
|
|
57
60
|
super
|
58
61
|
end
|
@@ -33,7 +33,7 @@ module OpenHAB
|
|
33
33
|
#
|
34
34
|
#
|
35
35
|
def update_from_url(uri)
|
36
|
-
logger.
|
36
|
+
logger.trace("Downloading image from #{uri}")
|
37
37
|
response = Net::HTTP.get_response(URI(uri))
|
38
38
|
mime_type = response['content-type']
|
39
39
|
bytes = response.body
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'openhab/dsl/timers'
|
4
4
|
require 'openhab/dsl/rules/triggers/trigger'
|
5
|
+
require 'openhab/log/logger'
|
5
6
|
require 'java'
|
6
7
|
|
7
8
|
require_relative 'generic_item'
|
@@ -140,11 +141,15 @@ module OpenHAB
|
|
140
141
|
#
|
141
142
|
class TimedCommandCancelRule < Java::OrgOpenhabCoreAutomationModuleScriptRulesupportSharedSimple::SimpleRule
|
142
143
|
include OpenHAB::Log
|
144
|
+
include OpenHAB::Core::ThreadLocal
|
145
|
+
|
143
146
|
def initialize(timed_command_details, semaphore, &block)
|
144
147
|
super()
|
145
148
|
@semaphore = semaphore
|
146
149
|
@timed_command_details = timed_command_details
|
147
150
|
@block = block
|
151
|
+
# Capture rule name if known
|
152
|
+
@thread_locals = Thread.current[:RULE_NAME] ? { RULE_NAME: Thread.current[:RULE_NAME] } : {}
|
148
153
|
set_name("Cancels implicit timer for #{timed_command_details.item.id}")
|
149
154
|
set_triggers([OpenHAB::DSL::Rules::Triggers::Trigger.trigger(
|
150
155
|
type: OpenHAB::DSL::Rules::Triggers::Trigger::ITEM_STATE_UPDATE,
|
@@ -164,17 +169,19 @@ module OpenHAB
|
|
164
169
|
# There is no feasible way to break this method into smaller components
|
165
170
|
def execute(_mod = nil, inputs = nil)
|
166
171
|
@semaphore.synchronize do
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
172
|
+
thread_local(@thread_locals) do
|
173
|
+
logger.trace "Canceling implicit timer #{@timed_command_details.timer} for "\
|
174
|
+
"#{@timed_command_details.item.id} because received event #{inputs}"
|
175
|
+
@timed_command_details.timer.cancel
|
176
|
+
# rubocop: disable Style/GlobalVars
|
177
|
+
# Disabled due to OpenHAB design
|
178
|
+
$scriptExtension.get('ruleRegistry').remove(@timed_command_details.rule_uid)
|
179
|
+
# rubocop: enable Style/GlobalVars
|
180
|
+
TimedCommand.timed_commands.delete(@timed_command_details.item)
|
181
|
+
if @block
|
182
|
+
logger.trace 'Executing user supplied block on timed command cancelation'
|
183
|
+
@block&.call(@timed_command_details)
|
184
|
+
end
|
178
185
|
end
|
179
186
|
end
|
180
187
|
end
|
@@ -57,17 +57,19 @@ module OpenHAB
|
|
57
57
|
# @param [Map] inputs map provided by OpenHAB rules engine containing event and other information
|
58
58
|
#
|
59
59
|
#
|
60
|
-
def execute(mod = nil, inputs = nil)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
trigger_delay
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
def execute(mod = nil, inputs = nil) # rubocop:disable Metrics/MethodLength
|
61
|
+
thread_local(RULE_NAME: name) do
|
62
|
+
logger.trace { "Execute called with mod (#{mod&.to_string}) and inputs (#{inputs&.pretty_inspect})" }
|
63
|
+
logger.trace { "Event details #{inputs['event'].pretty_inspect}" } if inputs&.key?('event')
|
64
|
+
if trigger_delay inputs
|
65
|
+
trigger_delay = trigger_delay(inputs)
|
66
|
+
process_trigger_delay(trigger_delay, mod, inputs)
|
67
|
+
else
|
68
|
+
# If guards are satisfied execute the run type blocks
|
69
|
+
# If they are not satisfied, execute the Othewise blocks
|
70
|
+
queue = create_queue(inputs)
|
71
|
+
process_queue(queue, mod, inputs)
|
72
|
+
end
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
@@ -336,10 +338,12 @@ module OpenHAB
|
|
336
338
|
# @param [Task] task task containing otherwise block to execute
|
337
339
|
#
|
338
340
|
def process_task(event, task)
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
341
|
+
thread_local(RULE_NAME: name) do
|
342
|
+
case task
|
343
|
+
when RuleConfig::Run then process_run_task(event, task)
|
344
|
+
when RuleConfig::Trigger then process_trigger_task(event, task)
|
345
|
+
when RuleConfig::Otherwise then process_otherwise_task(event, task)
|
346
|
+
end
|
343
347
|
end
|
344
348
|
end
|
345
349
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'java'
|
4
|
+
require 'openhab/log/logger'
|
5
|
+
|
6
|
+
module OpenHAB
|
7
|
+
module DSL
|
8
|
+
#
|
9
|
+
# Creates and manages OpenHAB Rules
|
10
|
+
#
|
11
|
+
module Rules
|
12
|
+
#
|
13
|
+
# Specialized rule for cron triggers with attachments because OpenHAB does not provide trigger UID for cron rules
|
14
|
+
#
|
15
|
+
class CronTriggerRule < Java::OrgOpenhabCoreAutomationModuleScriptRulesupportSharedSimple::SimpleRule
|
16
|
+
include OpenHAB::Log
|
17
|
+
|
18
|
+
def initialize(rule_config:, rule:, trigger:)
|
19
|
+
super()
|
20
|
+
set_name("#{rule_config.name}-cron-#{trigger.id}")
|
21
|
+
set_triggers([trigger])
|
22
|
+
@rule = rule
|
23
|
+
@trigger = trigger
|
24
|
+
logger.trace("Created Cron Trigger Rule for #{@trigger}")
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Execute the rule
|
29
|
+
#
|
30
|
+
# @param [Map] mod map provided by OpenHAB rules engine
|
31
|
+
# @param [Map] inputs map provided by OpenHAB rules engine containing event and other information
|
32
|
+
#
|
33
|
+
#
|
34
|
+
def execute(mod = nil, _inputs = nil)
|
35
|
+
logger.trace "Trigger #{@trigger} fired for base rule #{@rule.inspect}"
|
36
|
+
inputs = { 'module' => @trigger.id }
|
37
|
+
@rule.execute(mod, inputs)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'openhab/
|
4
|
-
require 'openhab/
|
5
|
-
|
3
|
+
require 'openhab/core/thread_local'
|
4
|
+
require 'openhab/log/logger'
|
5
|
+
require_relative 'rule_config'
|
6
|
+
require_relative 'automation_rule'
|
7
|
+
require_relative 'cron_trigger_rule'
|
8
|
+
require_relative 'guard'
|
6
9
|
|
7
10
|
module OpenHAB
|
8
11
|
#
|
@@ -13,6 +16,9 @@ module OpenHAB
|
|
13
16
|
# Creates and manages OpenHAB Rules
|
14
17
|
#
|
15
18
|
module Rules
|
19
|
+
include OpenHAB::Core::ThreadLocal
|
20
|
+
include OpenHAB::Log
|
21
|
+
|
16
22
|
@script_rules = []
|
17
23
|
|
18
24
|
# rubocop: disable Style/GlobalVars
|
@@ -31,29 +37,22 @@ module OpenHAB
|
|
31
37
|
# @yield [] Block executed in context of a RuleConfig
|
32
38
|
#
|
33
39
|
#
|
40
|
+
# rubocop: disable Metrics/MethodLength
|
34
41
|
def rule(rule_name, &block)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
thread_local(RULE_NAME: rule_name) do
|
43
|
+
@rule_name = rule_name
|
44
|
+
config = RuleConfig.new(rule_name, block.binding)
|
45
|
+
config.instance_exec(config, &block)
|
46
|
+
config.guard = Guard::Guard.new(only_if: config.only_if, not_if: config.not_if)
|
47
|
+
logger.trace { config.inspect }
|
48
|
+
process_rule_config(config)
|
49
|
+
nil # Must return something other than the rule object. See https://github.com/boc-tothefuture/openhab-jruby/issues/438
|
50
|
+
end
|
41
51
|
rescue StandardError => e
|
52
|
+
puts "#{e.class}: #{e.message}"
|
42
53
|
re_raise_with_backtrace(e)
|
43
54
|
end
|
44
|
-
|
45
|
-
#
|
46
|
-
# Create a logger where name includes rule name if name is set
|
47
|
-
#
|
48
|
-
# @return [Log::Logger] Logger with name that appended with rule name if rule name is set
|
49
|
-
#
|
50
|
-
def logger
|
51
|
-
if @rule_name
|
52
|
-
Log.logger_for(@rule_name.chomp.gsub(/\s+/, '_'))
|
53
|
-
else
|
54
|
-
super
|
55
|
-
end
|
56
|
-
end
|
55
|
+
# rubocop: enable Metrics/MethodLength
|
57
56
|
|
58
57
|
#
|
59
58
|
# Cleanup rules in this script file
|
@@ -84,13 +83,44 @@ module OpenHAB
|
|
84
83
|
def process_rule_config(config)
|
85
84
|
return unless create_rule?(config)
|
86
85
|
|
86
|
+
cron_attach_triggers, other_triggers = partition_triggers(config)
|
87
|
+
logger.trace("Cron triggers: #{cron_attach_triggers} - Other triggers: #{other_triggers}")
|
88
|
+
config.triggers = other_triggers
|
89
|
+
|
87
90
|
rule = AutomationRule.new(config: config)
|
88
91
|
Rules.script_rules << rule
|
89
92
|
add_rule(rule)
|
93
|
+
|
94
|
+
process_cron_attach(cron_attach_triggers, config, rule)
|
95
|
+
|
90
96
|
rule.execute(nil, { 'event' => Struct.new(:attachment).new(config.start_attachment) }) if config.on_start?
|
91
97
|
rule
|
92
98
|
end
|
93
99
|
|
100
|
+
#
|
101
|
+
# Add cron triggers with attachments to rules
|
102
|
+
# @param [Array] cron_attach_triggers cron type triggers with attachments
|
103
|
+
#
|
104
|
+
def process_cron_attach(cron_attach_triggers, config, rule)
|
105
|
+
cron_attach_triggers&.map { |trigger| CronTriggerRule.new(rule_config: config, rule: rule, trigger: trigger) }
|
106
|
+
&.each { |trigger| add_rule(trigger) }
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# Partitions triggers in a config, removing cron triggers with a corresponding attachment
|
111
|
+
# so they can be used with CronTriggerRules to support attachments
|
112
|
+
# @return [Array] Two element array the first element is cron triggers with attachments,
|
113
|
+
# second element is other triggers
|
114
|
+
#
|
115
|
+
def partition_triggers(config)
|
116
|
+
config
|
117
|
+
.triggers
|
118
|
+
.partition do |trigger|
|
119
|
+
trigger.typeUID == OpenHAB::DSL::Rules::Triggers::Trigger::CRON &&
|
120
|
+
config.attachments.key?(trigger.id)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
94
124
|
#
|
95
125
|
# Should a rule be created based on rule configuration
|
96
126
|
#
|
@@ -104,7 +134,7 @@ module OpenHAB
|
|
104
134
|
elsif !execution_blocks?(config)
|
105
135
|
logger.warn "Rule '#{config.name}' has no execution blocks, not creating rule"
|
106
136
|
elsif !config.enabled
|
107
|
-
logger.
|
137
|
+
logger.trace "Rule '#{config.name}' marked as disabled, not creating rule."
|
108
138
|
else
|
109
139
|
return true
|
110
140
|
end
|
@@ -140,6 +170,7 @@ module OpenHAB
|
|
140
170
|
#
|
141
171
|
#
|
142
172
|
def add_rule(rule)
|
173
|
+
logger.trace("Adding rule: #{rule.inspect}")
|
143
174
|
Rules.automation_manager.addRule(rule)
|
144
175
|
end
|
145
176
|
end
|
@@ -33,7 +33,7 @@ module OpenHAB
|
|
33
33
|
extend OpenHAB::DSL
|
34
34
|
|
35
35
|
# @return [Array] Of triggers
|
36
|
-
|
36
|
+
attr_accessor :triggers
|
37
37
|
|
38
38
|
# @return [Array] Of trigger delays
|
39
39
|
attr_reader :trigger_delays
|
@@ -88,9 +88,9 @@ module OpenHAB
|
|
88
88
|
@trigger_delays = {}
|
89
89
|
@attachments = {}
|
90
90
|
@caller = caller_binding.eval 'self'
|
91
|
+
name(rule_name)
|
91
92
|
enabled(true)
|
92
93
|
on_start(false)
|
93
|
-
name(rule_name)
|
94
94
|
end
|
95
95
|
|
96
96
|
#
|
@@ -134,19 +134,6 @@ module OpenHAB
|
|
134
134
|
@caller.instance_eval(&block)
|
135
135
|
end
|
136
136
|
|
137
|
-
#
|
138
|
-
# Create a logger where name includes rule name if name is set
|
139
|
-
#
|
140
|
-
# @return [Log::Logger] Logger with name that appended with rule name if rule name is set
|
141
|
-
#
|
142
|
-
def logger
|
143
|
-
if name
|
144
|
-
Log.logger_for(name.chomp.gsub(/\s+/, '_'))
|
145
|
-
else
|
146
|
-
super
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
137
|
#
|
151
138
|
# Inspect the config object
|
152
139
|
#
|
@@ -68,13 +68,13 @@ module OpenHAB
|
|
68
68
|
# @param [Object] at TimeOfDay or String representing TimeOfDay in which to execute rule
|
69
69
|
#
|
70
70
|
#
|
71
|
-
def every(value, at: nil)
|
71
|
+
def every(value, at: nil, attach: nil)
|
72
72
|
cron_expression = case value
|
73
73
|
when Symbol then cron_from_symbol(value, at)
|
74
74
|
when Java::JavaTime::Duration then cron_from_duration(value, at)
|
75
75
|
else raise ArgumentExpression, 'Unknown interval'
|
76
76
|
end
|
77
|
-
cron(cron_expression)
|
77
|
+
cron(cron_expression, attach: attach)
|
78
78
|
end
|
79
79
|
|
80
80
|
#
|
@@ -82,8 +82,8 @@ module OpenHAB
|
|
82
82
|
#
|
83
83
|
# @param [String] expression OpenHAB style cron expression
|
84
84
|
#
|
85
|
-
def cron(expression)
|
86
|
-
|
85
|
+
def cron(expression, attach: nil)
|
86
|
+
append_trigger(Trigger::CRON, { 'cronExpression' => expression }, attach: attach)
|
87
87
|
end
|
88
88
|
|
89
89
|
private
|
@@ -25,12 +25,12 @@ module OpenHAB
|
|
25
25
|
# @param [Duration] duration Duration until timer should fire
|
26
26
|
# @param [Block] block Block to execute when timer fires
|
27
27
|
#
|
28
|
-
def initialize(duration:, id:, &block)
|
28
|
+
def initialize(duration:, id:, thread_locals: {}, &block)
|
29
29
|
raise 'Reentrant timers do not work in dynamically generated code' unless block.source_location
|
30
30
|
|
31
31
|
@id = id
|
32
32
|
@reentrant_id = self.class.reentrant_id(id: id, &block)
|
33
|
-
super(duration: duration, &block)
|
33
|
+
super(duration: duration, thread_locals: thread_locals, &block)
|
34
34
|
logger.trace("Created Reentrant Timer #{self} with reentrant Key #{@reentrant_id}")
|
35
35
|
end
|
36
36
|
|
@@ -4,6 +4,7 @@ require 'java'
|
|
4
4
|
require 'delegate'
|
5
5
|
require 'forwardable'
|
6
6
|
require 'openhab/log/logger'
|
7
|
+
require 'openhab/core/thread_local'
|
7
8
|
|
8
9
|
module OpenHAB
|
9
10
|
module DSL
|
@@ -22,6 +23,7 @@ module OpenHAB
|
|
22
23
|
# @since 2.0.0
|
23
24
|
class Timer < SimpleDelegator
|
24
25
|
include OpenHAB::Log
|
26
|
+
include OpenHAB::Core::ThreadLocal
|
25
27
|
extend Forwardable
|
26
28
|
|
27
29
|
def_delegator :@timer, :has_terminated, :terminated?
|
@@ -32,8 +34,10 @@ module OpenHAB
|
|
32
34
|
# @param [Duration] duration Duration until timer should fire
|
33
35
|
# @param [Block] block Block to execute when timer fires
|
34
36
|
#
|
35
|
-
|
37
|
+
# rubocop: disable Metrics/MethodLength
|
38
|
+
def initialize(duration:, thread_locals: {}, &block)
|
36
39
|
@duration = duration
|
40
|
+
@thread_locals = thread_locals
|
37
41
|
|
38
42
|
# A semaphore is used to prevent a race condition in which calling the block from the timer thread
|
39
43
|
# occurs before the @timer variable can be set resulting in @timer being nil
|
@@ -41,13 +45,14 @@ module OpenHAB
|
|
41
45
|
|
42
46
|
semaphore.synchronize do
|
43
47
|
@timer = ScriptExecution.createTimer(
|
44
|
-
ZonedDateTime.now.plus(@duration), timer_block(semaphore, &block)
|
48
|
+
ZonedDateTime.now.plus(to_duration(@duration)), timer_block(semaphore, &block)
|
45
49
|
)
|
46
50
|
@rule_timers = Thread.current[:rule_timers]
|
47
51
|
super(@timer)
|
48
52
|
Timers.timer_manager.add(self)
|
49
53
|
end
|
50
54
|
end
|
55
|
+
# rubocop: enable Metrics/MethodLength
|
51
56
|
|
52
57
|
#
|
53
58
|
# Reschedule timer
|
@@ -57,15 +62,13 @@ module OpenHAB
|
|
57
62
|
# @return [Timer] Rescheduled timer instances
|
58
63
|
#
|
59
64
|
def reschedule(duration = nil)
|
60
|
-
unless duration.nil? || duration.is_a?(Java::JavaTimeTemporal::TemporalAmount)
|
61
|
-
raise ArgumentError, 'Supplied argument must be a duration'
|
62
|
-
end
|
63
|
-
|
64
65
|
duration ||= @duration
|
66
|
+
|
65
67
|
Timers.timer_manager.add(self)
|
66
|
-
@timer.reschedule(ZonedDateTime.now.plus(duration))
|
68
|
+
@timer.reschedule(ZonedDateTime.now.plus(to_duration(duration)))
|
67
69
|
end
|
68
70
|
|
71
|
+
#
|
69
72
|
# Cancel timer
|
70
73
|
#
|
71
74
|
# @return [Boolean] True if cancel was successful, false otherwise
|
@@ -88,10 +91,33 @@ module OpenHAB
|
|
88
91
|
proc {
|
89
92
|
semaphore.synchronize do
|
90
93
|
Timers.timer_manager.delete(self)
|
91
|
-
|
94
|
+
thread_local(@thread_locals) do
|
95
|
+
yield(self)
|
96
|
+
end
|
92
97
|
end
|
93
98
|
}
|
94
99
|
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Convert argument to a duration
|
103
|
+
#
|
104
|
+
# @params [Java::JavaTimeTemporal::TemporalAmount, #to_f, #to_i, nil] duration Duration
|
105
|
+
#
|
106
|
+
# @raise if duration cannot be used for a timer
|
107
|
+
#
|
108
|
+
# @return Argument converted to seconds if it responds to #to_f or #to_i, otherwise duration unchanged
|
109
|
+
#
|
110
|
+
def to_duration(duration)
|
111
|
+
if duration.nil? || duration.is_a?(Java::JavaTimeTemporal::TemporalAmount)
|
112
|
+
duration
|
113
|
+
elsif duration.respond_to?(:to_f)
|
114
|
+
duration.to_f.seconds
|
115
|
+
elsif duration.respond_to?(:to_i)
|
116
|
+
duration.to_i.seconds
|
117
|
+
else
|
118
|
+
raise ArgumentError, "Supplied argument '#{duration}' cannot be converted to a duration"
|
119
|
+
end
|
120
|
+
end
|
95
121
|
end
|
96
122
|
end
|
97
123
|
end
|
data/lib/openhab/dsl/timers.rb
CHANGED
@@ -29,9 +29,12 @@ module OpenHAB
|
|
29
29
|
# @return [Timer] Timer object
|
30
30
|
#
|
31
31
|
def after(duration, id: nil, &block)
|
32
|
-
|
32
|
+
# Carry rule name to timer thread
|
33
|
+
thread_locals = { RULE_NAME: Thread.current[:RULE_NAME] } if Thread.current[:RULE_NAME]
|
34
|
+
thread_locals ||= {}
|
35
|
+
return Timers.reentrant_timer(duration: duration, thread_locals: thread_locals, id: id, &block) if id
|
33
36
|
|
34
|
-
Timer.new(duration: duration, &block)
|
37
|
+
Timer.new(duration: duration, thread_locals: thread_locals, &block)
|
35
38
|
end
|
36
39
|
|
37
40
|
#
|
@@ -55,7 +58,7 @@ module OpenHAB
|
|
55
58
|
# @param [Object] id to associate with timer
|
56
59
|
# @param [Block] block to execute, block is passed a Timer object
|
57
60
|
# @return [ReentrantTimer] Timer object
|
58
|
-
def self.reentrant_timer(duration:, id:, &block)
|
61
|
+
def self.reentrant_timer(duration:, id:, thread_locals: nil, &block)
|
59
62
|
timer = @timer_manager.reentrant_timer(id: id, &block)
|
60
63
|
if timer
|
61
64
|
logger.trace("Reentrant timer found - #{timer}")
|
@@ -63,7 +66,7 @@ module OpenHAB
|
|
63
66
|
else
|
64
67
|
logger.trace('No reentrant timer found, creating new timer')
|
65
68
|
end
|
66
|
-
ReentrantTimer.new(duration: duration, id: id, &block)
|
69
|
+
ReentrantTimer.new(duration: duration, id: id, thread_locals: thread_locals, &block)
|
67
70
|
end
|
68
71
|
end
|
69
72
|
end
|
data/lib/openhab/log/logger.rb
CHANGED
@@ -127,6 +127,7 @@ module OpenHAB
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
+
# Logger caches
|
130
131
|
@loggers = {}
|
131
132
|
|
132
133
|
# Return a logger with the configured log prefix plus the calling scripts name
|
@@ -137,7 +138,7 @@ module OpenHAB
|
|
137
138
|
# @return [Logger] for the current class
|
138
139
|
#
|
139
140
|
def logger
|
140
|
-
Log.logger(self
|
141
|
+
Log.logger(self)
|
141
142
|
end
|
142
143
|
|
143
144
|
class << self
|
@@ -148,29 +149,51 @@ module OpenHAB
|
|
148
149
|
#
|
149
150
|
# @return [Logger] for the supplied name
|
150
151
|
#
|
151
|
-
def logger(
|
152
|
+
def logger(object)
|
153
|
+
# Cache logger instances for each object since construction
|
154
|
+
# of logger name requires lots of operations and logger
|
155
|
+
# names for some objects are specific to the class
|
156
|
+
logger_name = logger_name(object)
|
157
|
+
@loggers[logger_name] ||= Logger.new(logger_name)
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
# Construct the logger name from the supplied object
|
163
|
+
# @param [Object] object to construct logger name from
|
164
|
+
# @return name for logger based on object
|
165
|
+
def logger_name(object)
|
166
|
+
name = Configuration.log_prefix
|
167
|
+
name += rules_file || ''
|
168
|
+
name += rule_name || ''
|
169
|
+
name += klass_name(object) || ''
|
170
|
+
name.tr_s(' ', '_').gsub('::', '.')
|
171
|
+
end
|
172
|
+
|
173
|
+
# Get the class name for the supplied object
|
174
|
+
# @param [Object] object to derive class name for
|
175
|
+
# @return [String] name of class for logging
|
176
|
+
def klass_name(object)
|
177
|
+
object.then(&:class)
|
178
|
+
.then { |klass| java_klass(klass) }
|
179
|
+
.then(&:name)
|
180
|
+
.then { |name| filter_base_classes(name) }
|
181
|
+
.then { |name| name&.prepend('.') }
|
182
|
+
end
|
183
|
+
|
184
|
+
# Get the appropriate java class for the supplied klass if the supplied
|
185
|
+
# class is a java class
|
186
|
+
# @param [Class] klass to inspect
|
187
|
+
# @return Class or Java class of supplied class
|
188
|
+
def java_klass(klass)
|
152
189
|
if klass.respond_to?(:java_class) &&
|
153
190
|
klass.java_class &&
|
154
191
|
!klass.java_class.name.start_with?('org.jruby.Ruby')
|
155
192
|
klass = klass.java_class
|
156
193
|
end
|
157
|
-
|
158
|
-
@loggers[name] ||= Log.logger_for(name)
|
159
|
-
end
|
160
|
-
|
161
|
-
#
|
162
|
-
# Configure a logger for the supplied class name
|
163
|
-
#
|
164
|
-
# @param [String] name to configure logger for
|
165
|
-
#
|
166
|
-
# @return [Logger] for the supplied classname
|
167
|
-
#
|
168
|
-
def logger_for(name)
|
169
|
-
configure_logger_for(name)
|
194
|
+
klass
|
170
195
|
end
|
171
196
|
|
172
|
-
private
|
173
|
-
|
174
197
|
#
|
175
198
|
# Configure a logger for the supplied classname
|
176
199
|
#
|
@@ -178,16 +201,33 @@ module OpenHAB
|
|
178
201
|
#
|
179
202
|
# @return [Logger] Logger for the supplied classname
|
180
203
|
#
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
end
|
188
|
-
Logger.new(log_prefix)
|
204
|
+
def rules_file
|
205
|
+
# Each rules file gets its own context
|
206
|
+
# Set it once as a class value so that threads not
|
207
|
+
# tied to a rules file pick up the rules file they
|
208
|
+
# were spawned from
|
209
|
+
@rules_file ||= log_caller&.downcase&.prepend('.')
|
189
210
|
end
|
190
211
|
|
212
|
+
# Get the name of the rule from the thread context
|
213
|
+
def rule_name
|
214
|
+
Thread.current[:RULE_NAME]&.downcase&.prepend('.')
|
215
|
+
end
|
216
|
+
|
217
|
+
# Filter out the base classes of Object and Module from the log name
|
218
|
+
def filter_base_classes(klass_name)
|
219
|
+
return nil if %w[Object Module].include?(klass_name)
|
220
|
+
|
221
|
+
klass_name
|
222
|
+
end
|
223
|
+
|
224
|
+
# "#{rule_name.downcase}.#{klass_name}"
|
225
|
+
# if klass_name == 'Object'
|
226
|
+
# "rules.#{rules_file_name.downcase}"
|
227
|
+
# else
|
228
|
+
# "rules.#{rules_file_name.downcase}.#{klass_name}"
|
229
|
+
# end
|
230
|
+
|
191
231
|
#
|
192
232
|
# Figure out the log prefix
|
193
233
|
#
|
@@ -199,7 +239,7 @@ module OpenHAB
|
|
199
239
|
.grep_v(/rubygems/)
|
200
240
|
.grep_v(%r{lib/ruby})
|
201
241
|
.first
|
202
|
-
.
|
242
|
+
.then { |caller| File.basename(caller, '.*') if caller }
|
203
243
|
end
|
204
244
|
end
|
205
245
|
|
data/lib/openhab/version.rb
CHANGED
data/lib/openhab.rb
CHANGED
@@ -20,23 +20,18 @@ module OpenHAB
|
|
20
20
|
#
|
21
21
|
#
|
22
22
|
# Number of extensions and includes requires more lines
|
23
|
-
# rubocop: disable Metrics/MethodLength
|
24
23
|
def self.extended(base)
|
25
24
|
OpenHAB::Core.wait_till_openhab_ready
|
26
25
|
base.extend Log
|
27
26
|
base.extend OpenHAB::Core::ScriptHandling
|
28
27
|
base.extend OpenHAB::Core::EntityLookup
|
29
28
|
base.extend OpenHAB::DSL
|
30
|
-
base.extend OpenHAB::DSL::Between
|
31
29
|
|
32
30
|
base.send :include, OpenHAB::Core::ScriptHandlingCallbacks
|
33
|
-
|
34
|
-
base.send :include, OpenHAB::DSL::Types
|
35
|
-
logger.info "OpenHAB JRuby Scripting Library Version #{OpenHAB::VERSION} Loaded"
|
31
|
+
logger.debug "OpenHAB JRuby Scripting Library Version #{OpenHAB::VERSION} Loaded"
|
36
32
|
|
37
33
|
OpenHAB::Core.add_rubylib_to_load_path
|
38
34
|
end
|
39
|
-
# rubocop: enable Metrics/MethodLength
|
40
35
|
end
|
41
36
|
|
42
37
|
# Extend caller with OpenHAB methods
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openhab-scripting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian O'Connell
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- lib/openhab/dsl/monkey_patch/ruby/string.rb
|
95
95
|
- lib/openhab/dsl/persistence.rb
|
96
96
|
- lib/openhab/dsl/rules/automation_rule.rb
|
97
|
+
- lib/openhab/dsl/rules/cron_trigger_rule.rb
|
97
98
|
- lib/openhab/dsl/rules/guard.rb
|
98
99
|
- lib/openhab/dsl/rules/item_event.rb
|
99
100
|
- lib/openhab/dsl/rules/property.rb
|