openhab-scripting 5.5.0 → 5.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/openhab/core/actions/audio.rb +5 -2
- data/lib/openhab/core/configuration.rb +70 -0
- data/lib/openhab/core/emulate_hash.rb +241 -0
- data/lib/openhab/core/events/abstract_event.rb +11 -0
- data/lib/openhab/core/events/timer_event.rb +48 -0
- data/lib/openhab/core/items/group_function.rb +37 -0
- data/lib/openhab/core/items/group_item.rb +10 -4
- data/lib/openhab/core/items/item.rb +31 -0
- data/lib/openhab/core/items/metadata/hash.rb +9 -179
- data/lib/openhab/core/items/metadata/namespace_hash.rb +38 -141
- data/lib/openhab/core/items/semantics/semantic_tag.rb +5 -0
- data/lib/openhab/core/items/semantics/tag_class_methods.rb +9 -0
- data/lib/openhab/core/items/semantics.rb +7 -3
- data/lib/openhab/core/rules/rule.rb +17 -4
- data/lib/openhab/core/things/links/provider.rb +1 -1
- data/lib/openhab/core/things/proxy.rb +2 -1
- data/lib/openhab/core/things/thing.rb +23 -0
- data/lib/openhab/core/types/date_time_type.rb +2 -1
- data/lib/openhab/core/types/open_closed_type.rb +2 -1
- data/lib/openhab/core/types/string_type.rb +1 -1
- data/lib/openhab/core/types/up_down_type.rb +2 -1
- data/lib/openhab/core/value_cache.rb +6 -5
- data/lib/openhab/core_ext/java/duration.rb +2 -1
- data/lib/openhab/core_ext/java/local_time.rb +8 -6
- data/lib/openhab/core_ext/java/month_day.rb +2 -1
- data/lib/openhab/core_ext/java/period.rb +1 -1
- data/lib/openhab/core_ext/ruby/numeric.rb +1 -0
- data/lib/openhab/dsl/items/builder.rb +13 -6
- data/lib/openhab/dsl/rules/automation_rule.rb +29 -5
- data/lib/openhab/dsl/rules/builder.rb +47 -22
- data/lib/openhab/dsl/rules/rule_triggers.rb +1 -1
- data/lib/openhab/dsl/rules/triggers/conditions/generic.rb +1 -1
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +43 -16
- data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +101 -96
- data/lib/openhab/dsl/things/builder.rb +8 -6
- data/lib/openhab/dsl/thread_local.rb +1 -0
- data/lib/openhab/dsl/timer_manager.rb +4 -4
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +23 -4
- data/lib/openhab/osgi.rb +1 -1
- data/lib/openhab/rspec/karaf.rb +7 -4
- data/lib/openhab/rspec/openhab/core/actions.rb +0 -3
- metadata +13 -23
@@ -28,7 +28,7 @@ module OpenHAB
|
|
28
28
|
# For a private cache, simply use an instance variable. See
|
29
29
|
# {file:docs/ruby-basics.md#variables Instance Variables}.
|
30
30
|
#
|
31
|
-
# @note Because every script or UI rule gets
|
31
|
+
# @note Because every script or UI rule gets its own JRuby engine instance,
|
32
32
|
# you cannot rely on being able to access Ruby objects between them. Only
|
33
33
|
# objects that implement a Java interface that's part of Java or openHAB
|
34
34
|
# Core (such as Hash implements {java.util.Map}, or other basic
|
@@ -107,10 +107,11 @@ module OpenHAB
|
|
107
107
|
|
108
108
|
# @see https://docs.ruby-lang.org/en/master/Hash.html#method-i-assoc Hash#assoc
|
109
109
|
def assoc(key)
|
110
|
-
[key,
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
[key,
|
111
|
+
fetch(key) do
|
112
|
+
# return nil directly, without storing a value to the cache
|
113
|
+
return nil
|
114
|
+
end]
|
114
115
|
end
|
115
116
|
|
116
117
|
# @see https://docs.ruby-lang.org/en/master/Hash.html#method-i-dig Hash#dig
|
@@ -56,12 +56,14 @@ module OpenHAB
|
|
56
56
|
return raw_parse(string, formatter) if formatter
|
57
57
|
|
58
58
|
format = /(am|pm)$/i.match?(string) ? "h[:mm[:ss][.S]][ ]a" : "H[:mm[:ss][.S]]"
|
59
|
-
java_send(:parse,
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
java_send(:parse,
|
60
|
+
[java.lang.CharSequence, java.time.format.DateTimeFormatter],
|
61
|
+
string,
|
62
|
+
java.time.format.DateTimeFormatterBuilder.new
|
63
|
+
.parse_case_insensitive
|
64
|
+
.parse_lenient
|
65
|
+
.append_pattern(format)
|
66
|
+
.to_formatter(java.util.Locale::ENGLISH))
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
@@ -21,7 +21,8 @@ module OpenHAB
|
|
21
21
|
#
|
22
22
|
def parse(string)
|
23
23
|
logger.trace("#{self.class}.parse #{string} (#{string.class})")
|
24
|
-
java_send(:parse,
|
24
|
+
java_send(:parse,
|
25
|
+
[java.lang.CharSequence, java.time.format.DateTimeFormatter],
|
25
26
|
string.to_s,
|
26
27
|
java.time.format.DateTimeFormatter.ofPattern("[--]M-d"))
|
27
28
|
end
|
@@ -230,9 +230,7 @@ module OpenHAB
|
|
230
230
|
tags.compact.map do |tag|
|
231
231
|
case tag
|
232
232
|
when String then tag
|
233
|
-
when Symbol then tag.to_s
|
234
|
-
when old_semantics then tag.java_class.simple_name
|
235
|
-
when semantics then tag.name
|
233
|
+
when Symbol, semantics, old_semantics then tag.to_s
|
236
234
|
else raise ArgumentError, "`#{tag}` must be a subclass of Semantics::Tag, a `Symbol`, or a `String`."
|
237
235
|
end
|
238
236
|
end
|
@@ -260,6 +258,8 @@ module OpenHAB
|
|
260
258
|
# @param tags [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil]
|
261
259
|
# Fluent alias for `tag`.
|
262
260
|
# @param autoupdate [true, false, nil] Autoupdate setting (see {ItemBuilder#autoupdate})
|
261
|
+
# @param thing [String, Core::Things::Thing, Core::Things::ThingUID, nil]
|
262
|
+
# A Thing to be used as the base for the channel
|
263
263
|
# @param channel [String, Core::Things::ChannelUID, nil] Channel to link the item to
|
264
264
|
# @param expire [String] An expiration specification.
|
265
265
|
# @param alexa [String, Symbol, Array<(String, Hash<String, Object>)>, nil]
|
@@ -270,7 +270,9 @@ module OpenHAB
|
|
270
270
|
# Homekit metadata (see {ItemBuilder#homekit})
|
271
271
|
# @param metadata [Hash<String, Hash>] Generic metadata (see {ItemBuilder#metadata})
|
272
272
|
# @param state [State] Initial state
|
273
|
-
def initialize(type,
|
273
|
+
def initialize(type,
|
274
|
+
name = nil,
|
275
|
+
label = nil,
|
274
276
|
provider:,
|
275
277
|
dimension: nil,
|
276
278
|
unit: nil,
|
@@ -281,6 +283,7 @@ module OpenHAB
|
|
281
283
|
tag: nil,
|
282
284
|
tags: nil,
|
283
285
|
autoupdate: nil,
|
286
|
+
thing: nil,
|
284
287
|
channel: nil,
|
285
288
|
expire: nil,
|
286
289
|
alexa: nil,
|
@@ -310,6 +313,7 @@ module OpenHAB
|
|
310
313
|
@metadata.merge!(metadata) if metadata
|
311
314
|
@autoupdate = autoupdate
|
312
315
|
@channels = []
|
316
|
+
@thing = thing
|
313
317
|
@expire = nil
|
314
318
|
if expire
|
315
319
|
expire = Array(expire)
|
@@ -420,6 +424,7 @@ module OpenHAB
|
|
420
424
|
# end
|
421
425
|
#
|
422
426
|
def channel(channel, config = {})
|
427
|
+
channel = "#{@thing}:#{channel}" if @thing && !channel.include?(":")
|
423
428
|
@channels << [channel, config]
|
424
429
|
end
|
425
430
|
|
@@ -569,7 +574,7 @@ module OpenHAB
|
|
569
574
|
RUBY
|
570
575
|
end
|
571
576
|
|
572
|
-
FUNCTION_REGEX = /^([a-z]+)(?:\((
|
577
|
+
FUNCTION_REGEX = /^([a-z]+)(?:\((.*)\))?/i.freeze
|
573
578
|
private_constant :FUNCTION_REGEX
|
574
579
|
|
575
580
|
# The combiner function for this group
|
@@ -607,11 +612,13 @@ module OpenHAB
|
|
607
612
|
def create_item
|
608
613
|
base_item = super if type
|
609
614
|
if function
|
615
|
+
require "csv"
|
616
|
+
|
610
617
|
match = function.match(FUNCTION_REGEX)
|
611
618
|
|
612
619
|
dto = org.openhab.core.items.dto.GroupFunctionDTO.new
|
613
620
|
dto.name = match[1]
|
614
|
-
dto.params = match[2
|
621
|
+
dto.params = CSV.parse_line(match[2]) if match[2]
|
615
622
|
function = org.openhab.core.items.dto.ItemDTOMapper.map_function(base_item, dto)
|
616
623
|
Core::Items::GroupItem.new(name, base_item, function)
|
617
624
|
else
|
@@ -74,6 +74,10 @@ module OpenHAB
|
|
74
74
|
|
75
75
|
# This method gets called in rspec's SuspendRules as well
|
76
76
|
def execute!(mod, inputs)
|
77
|
+
# Store the context in a thread variable. It is accessed through DSL#method_missing
|
78
|
+
# which is triggered when the context variable is referenced inside the run block.
|
79
|
+
# It is added to @thread_locals so it is also available in #process_task below.
|
80
|
+
@thread_locals[:openhab_context] = extract_context(inputs)
|
77
81
|
ThreadLocal.thread_local(**@thread_locals) do
|
78
82
|
if logger.trace?
|
79
83
|
logger.trace("Execute called with mod (#{mod&.to_string}) and inputs (#{inputs.inspect})")
|
@@ -84,10 +88,12 @@ module OpenHAB
|
|
84
88
|
@debouncer.call { process_queue(create_queue(event), mod, event) }
|
85
89
|
end
|
86
90
|
rescue Exception => e
|
87
|
-
raise if defined?(::RSpec) && ::RSpec.current_example
|
91
|
+
raise if defined?(::RSpec) && ::RSpec.current_example&.example_group&.propagate_exceptions?
|
88
92
|
|
89
93
|
@run_context.send(:logger).log_exception(e)
|
90
94
|
end
|
95
|
+
ensure
|
96
|
+
@thread_locals.delete(:openhab_context)
|
91
97
|
end
|
92
98
|
|
93
99
|
def cleanup
|
@@ -157,6 +163,24 @@ module OpenHAB
|
|
157
163
|
struct_class.new(**inputs)
|
158
164
|
end
|
159
165
|
|
166
|
+
#
|
167
|
+
# Converts inputs into context hash
|
168
|
+
# @return [Hash] Context hash.
|
169
|
+
#
|
170
|
+
def extract_context(inputs)
|
171
|
+
return unless inputs
|
172
|
+
|
173
|
+
inputs.reject { |key, _| key.include?(".") }
|
174
|
+
.to_h do |key, value|
|
175
|
+
[key.to_sym,
|
176
|
+
if value.is_a?(Item) && !value.is_a?(Core::Items::Proxy)
|
177
|
+
Core::Items::Proxy.new(value)
|
178
|
+
else
|
179
|
+
value
|
180
|
+
end]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
160
184
|
#
|
161
185
|
# Get the trigger_id for the trigger that caused the rule creation
|
162
186
|
#
|
@@ -230,7 +254,7 @@ module OpenHAB
|
|
230
254
|
ThreadLocal.thread_local(**@thread_locals) do
|
231
255
|
case task
|
232
256
|
when BuilderDSL::Run then process_run_task(event, task)
|
233
|
-
when BuilderDSL::Script then process_script_task(task)
|
257
|
+
when BuilderDSL::Script then process_script_task(event, task)
|
234
258
|
when BuilderDSL::Trigger then process_trigger_task(event, task)
|
235
259
|
when BuilderDSL::Otherwise then process_otherwise_task(event, task)
|
236
260
|
end
|
@@ -294,9 +318,9 @@ module OpenHAB
|
|
294
318
|
#
|
295
319
|
# @param [Script] task to execute
|
296
320
|
#
|
297
|
-
def process_script_task(task)
|
298
|
-
logger.trace { "Executing script '#{name}' run block" }
|
299
|
-
@run_context.instance_exec(&task.block)
|
321
|
+
def process_script_task(event, task)
|
322
|
+
logger.trace { "Executing script '#{name}' run block with event(#{event})" }
|
323
|
+
@run_context.instance_exec(event, &task.block)
|
300
324
|
end
|
301
325
|
|
302
326
|
#
|
@@ -70,7 +70,8 @@ module OpenHAB
|
|
70
70
|
builder = BuilderDSL.new(binding || block.binding)
|
71
71
|
builder.uid(id)
|
72
72
|
builder.instance_exec(builder, &block)
|
73
|
-
builder.guard = Guard.new(run_context: builder.caller,
|
73
|
+
builder.guard = Guard.new(run_context: builder.caller,
|
74
|
+
only_if: builder.only_if,
|
74
75
|
not_if: builder.not_if)
|
75
76
|
|
76
77
|
name ||= NameInference.infer_rule_name(builder)
|
@@ -1075,28 +1076,50 @@ module OpenHAB
|
|
1075
1076
|
#
|
1076
1077
|
# @overload cron(second: nil, minute: nil, hour: nil, dom: nil, month: nil, dow: nil, year: nil, attach: nil)
|
1077
1078
|
# The trigger can be created by specifying each field as keyword arguments.
|
1078
|
-
#
|
1079
|
+
#
|
1080
|
+
# When certain fields were omitted:
|
1081
|
+
# - The more specific fields will default to `0` for `hour`, `minute`, and `second`,
|
1082
|
+
# to `MON` for `dow`, and to `1` for `dom` and `month`.
|
1083
|
+
# - The less specific fields will default to `*` or `?` as appropriate.
|
1079
1084
|
#
|
1080
1085
|
# Each field is optional, but at least one must be specified.
|
1081
1086
|
#
|
1082
1087
|
# The same rules for the standard
|
1083
1088
|
# [cron expression](https://www.quartz-scheduler.org/documentation/quartz-2.2.2/tutorials/tutorial-lesson-06.html)
|
1084
1089
|
# apply for each field. For example, multiple values can be separated
|
1085
|
-
# with a comma within a string
|
1086
|
-
#
|
1087
|
-
#
|
1088
|
-
# @param [Integer, String, nil]
|
1089
|
-
# @param [Integer, String, nil]
|
1090
|
-
# @param [Integer, String, nil]
|
1091
|
-
# @param [Integer, String, nil]
|
1092
|
-
# @param [Integer, String, nil]
|
1093
|
-
# @param [Integer, String, nil]
|
1090
|
+
# with a comma within a string, and ranges can be specified with a dash or with
|
1091
|
+
# a Ruby Range.
|
1092
|
+
#
|
1093
|
+
# @param [Integer, String, Range, nil] second
|
1094
|
+
# @param [Integer, String, Range, nil] minute
|
1095
|
+
# @param [Integer, String, Range, nil] hour
|
1096
|
+
# @param [Integer, String, Symbol, Range, nil] dom
|
1097
|
+
# @param [Integer, String, Symbol, Range, nil] month
|
1098
|
+
# @param [Integer, String, Symbol, Range, nil] dow
|
1099
|
+
# @param [Integer, String, Range, nil] year
|
1094
1100
|
# @param [Object] attach object to be attached to the trigger
|
1095
|
-
#
|
1101
|
+
#
|
1102
|
+
# @example Using String values
|
1096
1103
|
# # Run every 3 minutes on Monday to Friday
|
1097
1104
|
# # equivalent to the cron expression "0 */3 * ? * MON-FRI *"
|
1098
1105
|
# rule "Using cron fields" do
|
1099
|
-
# cron
|
1106
|
+
# cron minute: "*/3", dow: "MON-FRI"
|
1107
|
+
# run { logger.info "Cron rule executed" }
|
1108
|
+
# end
|
1109
|
+
#
|
1110
|
+
# @example Defaults for unspecified fields
|
1111
|
+
# # Run at midnight on the first day of January, February, and March
|
1112
|
+
# # equivalent to the cron expression "0 0 0 1 JAN-MAR ? *"
|
1113
|
+
# rule "Using cron fields" do
|
1114
|
+
# cron month: "JAN-MAR"
|
1115
|
+
# run { logger.info "Cron rule executed" }
|
1116
|
+
# end
|
1117
|
+
#
|
1118
|
+
# @example Using Ruby Range values
|
1119
|
+
# # Run on the hour, every hour between 1pm and 5pm
|
1120
|
+
# # equivalent to the cron expression "0 0 13-17 ? * ? *"
|
1121
|
+
# rule "Using cron fields" do
|
1122
|
+
# cron hour: 13..17
|
1100
1123
|
# run { logger.info "Cron rule executed" }
|
1101
1124
|
# end
|
1102
1125
|
#
|
@@ -1112,7 +1135,6 @@ module OpenHAB
|
|
1112
1135
|
|
1113
1136
|
raise ArgumentError, "Missing cron expression or elements" unless expression
|
1114
1137
|
|
1115
|
-
add_tag("Schedule")
|
1116
1138
|
cron = Cron.new(rule_triggers: @rule_triggers)
|
1117
1139
|
cron.trigger(config: { "cronExpression" => expression }, attach: attach)
|
1118
1140
|
end
|
@@ -1211,7 +1233,6 @@ module OpenHAB
|
|
1211
1233
|
if value == :day && at.is_a?(Item)
|
1212
1234
|
raise ArgumentError, "Attachments are not supported with dynamic datetime triggers" unless attach.nil?
|
1213
1235
|
|
1214
|
-
add_tag("Schedule")
|
1215
1236
|
return trigger("timer.DateTimeTrigger", itemName: at.name, timeOnly: true)
|
1216
1237
|
end
|
1217
1238
|
|
@@ -1561,8 +1582,12 @@ module OpenHAB
|
|
1561
1582
|
# @deprecated OH3.4 - OH3 config uses eventXXX vs OH4 uses `topic`, `source`, and `types`
|
1562
1583
|
# See https://github.com/openhab/openhab-core/pull/3299
|
1563
1584
|
trigger("core.GenericEventTrigger",
|
1564
|
-
eventTopic: topic,
|
1565
|
-
|
1585
|
+
eventTopic: topic,
|
1586
|
+
eventSource: source,
|
1587
|
+
eventTypes: types, # @deprecated OH3.4
|
1588
|
+
topic: topic,
|
1589
|
+
source: source,
|
1590
|
+
types: types,
|
1566
1591
|
attach: attach)
|
1567
1592
|
end
|
1568
1593
|
|
@@ -1593,7 +1618,6 @@ module OpenHAB
|
|
1593
1618
|
#
|
1594
1619
|
def at(item)
|
1595
1620
|
item = item.name if item.is_a?(Item)
|
1596
|
-
add_tag("Schedule")
|
1597
1621
|
trigger("timer.DateTimeTrigger", itemName: item.to_s)
|
1598
1622
|
end
|
1599
1623
|
|
@@ -1834,10 +1858,11 @@ module OpenHAB
|
|
1834
1858
|
types = [binding.local_variable_get(:for)].flatten
|
1835
1859
|
|
1836
1860
|
WatchHandler::WatchTriggerHandlerFactory.instance # ensure it's registered
|
1837
|
-
trigger(WatchHandler::WATCH_TRIGGER_MODULE_ID,
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1861
|
+
trigger(WatchHandler::WATCH_TRIGGER_MODULE_ID,
|
1862
|
+
path: path.to_s,
|
1863
|
+
types: types.map(&:to_s),
|
1864
|
+
glob: glob.to_s,
|
1865
|
+
attach: attach)
|
1841
1866
|
end
|
1842
1867
|
|
1843
1868
|
# @!endgroup
|
@@ -64,7 +64,7 @@ module OpenHAB
|
|
64
64
|
org.openhab.core.automation.util.TriggerBuilder.create
|
65
65
|
.with_id(uuid)
|
66
66
|
.with_type_uid(type)
|
67
|
-
.with_configuration(
|
67
|
+
.with_configuration(Core::Configuration.new(config))
|
68
68
|
.build
|
69
69
|
end
|
70
70
|
|
@@ -29,7 +29,7 @@ module OpenHAB
|
|
29
29
|
# @param [Hash] inputs inputs from trigger
|
30
30
|
# @return [true, false] if the conditions passed (and therefore the block was run)
|
31
31
|
#
|
32
|
-
def process(mod:, inputs:)
|
32
|
+
def process(mod:, inputs:)
|
33
33
|
logger.trace("Checking #{inputs} against condition trigger #{self}")
|
34
34
|
unless check_value(Conditions.old_state_from(inputs), @from) &&
|
35
35
|
check_value(Conditions.new_state_from(inputs), @to) &&
|
@@ -12,7 +12,12 @@ module OpenHAB
|
|
12
12
|
#
|
13
13
|
class Cron < Trigger
|
14
14
|
# Trigger ID for Cron Triggers
|
15
|
-
CRON_TRIGGER_MODULE_ID = "
|
15
|
+
CRON_TRIGGER_MODULE_ID = if Gem::Version.new(OpenHAB::Core::VERSION) >= Gem::Version.new("4.0.0")
|
16
|
+
"timer.GenericCronTrigger"
|
17
|
+
else
|
18
|
+
# @deprecated OH3.4 We need to use a custom CronTrigger handler
|
19
|
+
"jsr223.jruby.CronTrigger"
|
20
|
+
end
|
16
21
|
|
17
22
|
#
|
18
23
|
# Returns a default map for cron expressions that fires every second
|
@@ -21,16 +26,15 @@ module OpenHAB
|
|
21
26
|
# @return [Hash] Map with symbols for :seconds, :minute, :hour, :dom, :month, :dow
|
22
27
|
# configured to fire every second
|
23
28
|
#
|
24
|
-
CRON_EXPRESSION_MAP =
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}.freeze
|
29
|
+
CRON_EXPRESSION_MAP = {
|
30
|
+
second: "*",
|
31
|
+
minute: "*",
|
32
|
+
hour: "*",
|
33
|
+
dom: "?",
|
34
|
+
month: "*",
|
35
|
+
dow: "?",
|
36
|
+
year: "*"
|
37
|
+
}.freeze
|
34
38
|
private_constant :CRON_EXPRESSION_MAP
|
35
39
|
|
36
40
|
# @return [Hash] Map of days of the week from symbols to to openHAB cron strings
|
@@ -47,7 +51,6 @@ module OpenHAB
|
|
47
51
|
|
48
52
|
# @return [Hash] Converts the DAY_OF_WEEK_MAP to map used by Cron Expression
|
49
53
|
DAY_OF_WEEK_EXPRESSION_MAP = DAY_OF_WEEK_MAP.transform_values { |v| CRON_EXPRESSION_MAP.merge(dow: v) }
|
50
|
-
|
51
54
|
private_constant :DAY_OF_WEEK_EXPRESSION_MAP
|
52
55
|
|
53
56
|
# @return [Hash] Create a set of cron expressions based on different time intervals
|
@@ -60,9 +63,12 @@ module OpenHAB
|
|
60
63
|
month: CRON_EXPRESSION_MAP.merge(second: "0", minute: "0", hour: "0", dom: "1"),
|
61
64
|
year: CRON_EXPRESSION_MAP.merge(second: "0", minute: "0", hour: "0", dom: "1", month: "1")
|
62
65
|
}.merge(DAY_OF_WEEK_EXPRESSION_MAP).freeze
|
63
|
-
|
64
66
|
private_constant :EXPRESSION_MAP
|
65
67
|
|
68
|
+
# @return [Hash] Translate cron field names to expression keys
|
69
|
+
FIELD_TO_EXPRESSION_KEY = Hash.new { |_, key| key }.merge({ dow: :week, dom: :day })
|
70
|
+
private_constant :FIELD_TO_EXPRESSION_KEY
|
71
|
+
|
66
72
|
#
|
67
73
|
# Create a cron map from a duration
|
68
74
|
#
|
@@ -119,10 +125,28 @@ module OpenHAB
|
|
119
125
|
"unknown keyword#{"s" if extra_fields.size > 1}: #{extra_fields.map(&:inspect).join(", ")}"
|
120
126
|
end
|
121
127
|
|
122
|
-
fields = fields.
|
128
|
+
fields = fields.to_h do |key, value|
|
129
|
+
if value.is_a?(Range)
|
130
|
+
if value.exclude_end?
|
131
|
+
raise ArgumentError,
|
132
|
+
"Range must be inclusive for '#{key}'. Try '#{value.begin}..#{value.end}' instead"
|
133
|
+
end
|
134
|
+
|
135
|
+
unless value.begin && value.end
|
136
|
+
raise ArgumentError,
|
137
|
+
"Range must have a beginning and ending for '#{key}'"
|
138
|
+
end
|
139
|
+
|
140
|
+
[key, "#{value.begin.to_s.upcase}-#{value.end.to_s.upcase}".delete(" ")]
|
141
|
+
else
|
142
|
+
[key, value.to_s.delete(" ").upcase]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
# convert fields' key dow->week, dom->day to look into EXPRESSION_MAP
|
146
|
+
fields_expression = fields.transform_keys { |key| FIELD_TO_EXPRESSION_KEY[key] }
|
123
147
|
# find the first expression map that has a field from fields.
|
124
148
|
# this ensure more-specific fields get set to 0, not *
|
125
|
-
base_key = EXPRESSION_MAP.keys.find { |field, _|
|
149
|
+
base_key = EXPRESSION_MAP.keys.find { |field, _| fields_expression.key?(field) }
|
126
150
|
base_expression = EXPRESSION_MAP[base_key]
|
127
151
|
expression_map = base_expression.merge(fields)
|
128
152
|
|
@@ -186,7 +210,10 @@ module OpenHAB
|
|
186
210
|
#
|
187
211
|
#
|
188
212
|
def trigger(config:, attach:)
|
189
|
-
|
213
|
+
# @deprecated OH3.4 needs a custom CronTriggerHandlerFactory
|
214
|
+
if Gem::Version.new(OpenHAB::Core::VERSION) < Gem::Version.new("4.0.0")
|
215
|
+
CronHandler::CronTriggerHandlerFactory.instance # ensure it's registered
|
216
|
+
end
|
190
217
|
append_trigger(type: CRON_TRIGGER_MODULE_ID, config: config, attach: attach)
|
191
218
|
end
|
192
219
|
end
|