openhab-jrubyscripting 5.0.0.rc4 → 5.0.0.rc6
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/actions.rb +21 -9
- data/lib/openhab/core/dependency_tracking.rb +34 -0
- data/lib/openhab/core/entity_lookup.rb +132 -78
- data/lib/openhab/core/events/item_channel_link.rb +2 -2
- data/lib/openhab/core/events/item_command_event.rb +1 -1
- data/lib/openhab/core/events/item_event.rb +2 -2
- data/lib/openhab/core/events/item_state_changed_event.rb +1 -1
- data/lib/openhab/core/events/thing.rb +1 -1
- data/lib/openhab/core/items/accepted_data_types.rb +2 -2
- data/lib/openhab/core/items/contact_item.rb +1 -1
- data/lib/openhab/core/items/dimmer_item.rb +2 -2
- data/lib/openhab/core/items/generic_item.rb +45 -224
- data/lib/openhab/core/items/group_item.rb +5 -3
- data/lib/openhab/core/items/image_item.rb +2 -2
- data/lib/openhab/core/items/item.rb +219 -0
- data/lib/openhab/core/items/metadata/hash.rb +1 -1
- data/lib/openhab/core/items/metadata/namespace_hash.rb +1 -1
- data/lib/openhab/core/items/persistence.rb +19 -10
- data/lib/openhab/core/items/provider.rb +2 -2
- data/lib/openhab/core/items/proxy.rb +68 -7
- data/lib/openhab/core/items/registry.rb +6 -6
- data/lib/openhab/core/items/semantics/enumerable.rb +6 -6
- data/lib/openhab/core/items/semantics.rb +8 -7
- data/lib/openhab/core/items.rb +3 -2
- data/lib/openhab/core/provider.rb +14 -7
- data/lib/openhab/core/rules/registry.rb +2 -2
- data/lib/openhab/core/rules.rb +1 -1
- data/lib/openhab/core/script_handling.rb +6 -6
- data/lib/openhab/core/things/channel.rb +1 -1
- data/lib/openhab/core/things/channel_uid.rb +2 -2
- data/lib/openhab/core/things/item_channel_link.rb +2 -2
- data/lib/openhab/core/things/links/provider.rb +2 -2
- data/lib/openhab/core/things/profile_callback.rb +1 -1
- data/lib/openhab/core/things/registry.rb +1 -1
- data/lib/openhab/core/things/thing.rb +1 -1
- data/lib/openhab/core/timer.rb +21 -10
- data/lib/openhab/core/types/date_time_type.rb +4 -4
- data/lib/openhab/core/types/hsb_type.rb +2 -2
- data/lib/openhab/core/types/point_type.rb +1 -1
- data/lib/openhab/core/types/quantity_type.rb +1 -1
- data/lib/openhab/core/types.rb +1 -1
- data/lib/openhab/core/uid.rb +1 -1
- data/lib/openhab/core/value_cache.rb +188 -0
- data/lib/openhab/core.rb +57 -15
- data/lib/openhab/core_ext/between.rb +32 -0
- data/lib/openhab/core_ext/java/duration.rb +1 -0
- data/lib/openhab/core_ext/java/local_date.rb +1 -0
- data/lib/openhab/core_ext/java/local_time.rb +1 -0
- data/lib/openhab/core_ext/java/month.rb +12 -1
- data/lib/openhab/core_ext/java/month_day.rb +2 -0
- data/lib/openhab/core_ext/java/zoned_date_time.rb +4 -4
- data/lib/openhab/core_ext/ruby/date.rb +3 -1
- data/lib/openhab/core_ext/ruby/date_time.rb +1 -0
- data/lib/openhab/core_ext/ruby/symbol.rb +7 -0
- data/lib/openhab/core_ext/ruby/time.rb +1 -0
- data/lib/openhab/dsl/items/builder.rb +17 -10
- data/lib/openhab/dsl/items/ensure.rb +5 -5
- data/lib/openhab/dsl/items/timed_command.rb +5 -5
- data/lib/openhab/dsl/rules/automation_rule.rb +54 -40
- data/lib/openhab/dsl/rules/builder.rb +128 -79
- data/lib/openhab/dsl/rules/guard.rb +5 -5
- data/lib/openhab/dsl/rules/name_inference.rb +21 -2
- data/lib/openhab/dsl/rules/rule_triggers.rb +3 -3
- data/lib/openhab/dsl/rules/terse.rb +1 -0
- data/lib/openhab/dsl/rules/triggers/changed.rb +27 -24
- data/lib/openhab/dsl/rules/triggers/command.rb +6 -5
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +3 -3
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +2 -2
- data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +6 -6
- data/lib/openhab/dsl/rules/triggers/updated.rb +5 -5
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +11 -12
- data/lib/openhab/dsl/things/builder.rb +73 -14
- data/lib/openhab/dsl/version.rb +2 -2
- data/lib/openhab/dsl.rb +45 -17
- data/lib/openhab/log.rb +5 -5
- data/lib/openhab/rspec/configuration.rb +5 -5
- data/lib/openhab/rspec/example_group.rb +1 -1
- data/lib/openhab/rspec/helpers.rb +5 -5
- data/lib/openhab/rspec/hooks.rb +19 -1
- data/lib/openhab/rspec/karaf.rb +13 -21
- data/lib/openhab/rspec/mocks/persistence_service.rb +15 -0
- data/lib/openhab/rspec/mocks/thing_handler.rb +2 -2
- data/lib/openhab/rspec/suspend_rules.rb +2 -1
- data/lib/openhab/yard/base_helper.rb +46 -0
- data/lib/openhab/yard/html_helper.rb +3 -3
- data/lib/openhab/yard/markdown_directive.rb +125 -0
- data/lib/openhab/yard/markdown_helper.rb +99 -0
- metadata +15 -7
@@ -8,6 +8,20 @@ module OpenHAB
|
|
8
8
|
#
|
9
9
|
# @!visibility private
|
10
10
|
class AutomationRule < org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRule
|
11
|
+
# @!visibility private
|
12
|
+
INPUT_KEY_PATTERN = /^[a-z_]+[a-zA-Z0-9_]*$/.freeze
|
13
|
+
|
14
|
+
class << self
|
15
|
+
#
|
16
|
+
# Caches dynamically generated Struct classes so that they don't have
|
17
|
+
# to be re-generated for every event, blowing the method cache.
|
18
|
+
#
|
19
|
+
# @!visibility private
|
20
|
+
# @return [java.util.Map<Array<Symbol>, Class>]
|
21
|
+
attr_reader :event_structs
|
22
|
+
end
|
23
|
+
@event_structs = java.util.concurrent.ConcurrentHashMap.new
|
24
|
+
|
11
25
|
field_writer :uid
|
12
26
|
|
13
27
|
#
|
@@ -41,8 +55,8 @@ module OpenHAB
|
|
41
55
|
#
|
42
56
|
# Execute the rule
|
43
57
|
#
|
44
|
-
# @param [Map] mod map provided by
|
45
|
-
# @param [Map] inputs map provided by
|
58
|
+
# @param [java.util.Map] mod map provided by openHAB rules engine
|
59
|
+
# @param [java.util.Map] inputs map provided by openHAB rules engine containing event and other information
|
46
60
|
#
|
47
61
|
#
|
48
62
|
def execute(mod = nil, inputs = nil)
|
@@ -50,7 +64,8 @@ module OpenHAB
|
|
50
64
|
logger.trace { "Execute called with mod (#{mod&.to_string}) and inputs (#{inputs.inspect})" }
|
51
65
|
logger.trace { "Event details #{inputs["event"].inspect}" } if inputs&.key?("event")
|
52
66
|
trigger_conditions(inputs).process(mod: mod, inputs: inputs) do
|
53
|
-
|
67
|
+
event = extract_event(inputs)
|
68
|
+
process_queue(create_queue(event), mod, event)
|
54
69
|
end
|
55
70
|
rescue Exception => e
|
56
71
|
raise if defined?(::RSpec)
|
@@ -87,11 +102,11 @@ module OpenHAB
|
|
87
102
|
#
|
88
103
|
# Create the run queue based on guards
|
89
104
|
#
|
90
|
-
# @param [Map]
|
105
|
+
# @param [Map] event Event object
|
91
106
|
# @return [Queue] <description>
|
92
107
|
#
|
93
|
-
def create_queue(
|
94
|
-
case check_guards(event:
|
108
|
+
def create_queue(event)
|
109
|
+
case check_guards(event: event)
|
95
110
|
when true
|
96
111
|
@run_queue.dup.grep_v(BuilderDSL::Otherwise)
|
97
112
|
when false
|
@@ -108,12 +123,30 @@ module OpenHAB
|
|
108
123
|
# @return [Object] event object
|
109
124
|
#
|
110
125
|
def extract_event(inputs)
|
111
|
-
|
112
|
-
|
113
|
-
event =
|
114
|
-
event
|
126
|
+
attachment = @attachments[trigger_id(inputs)]
|
127
|
+
if inputs&.key?("event")
|
128
|
+
event = inputs["event"]
|
129
|
+
unless event
|
130
|
+
if attachment
|
131
|
+
logger.warn("Unable to attach #{attachment.inspect} to event " \
|
132
|
+
"object for rule #{uid} since the event is nil.")
|
133
|
+
end
|
134
|
+
return nil
|
135
|
+
end
|
136
|
+
|
137
|
+
event.attachment = attachment
|
138
|
+
return event
|
115
139
|
end
|
116
|
-
|
140
|
+
|
141
|
+
inputs = inputs.to_h
|
142
|
+
.select { |key, _value| key != "module" && INPUT_KEY_PATTERN.match?(key) }
|
143
|
+
.transform_keys(&:to_sym)
|
144
|
+
inputs[:attachment] = attachment
|
145
|
+
keys = inputs.keys.sort
|
146
|
+
struct_class = self.class.event_structs.compute_if_absent(keys) do
|
147
|
+
Struct.new(*keys, keyword_init: true)
|
148
|
+
end
|
149
|
+
struct_class.new(**inputs)
|
117
150
|
end
|
118
151
|
|
119
152
|
#
|
@@ -128,35 +161,18 @@ module OpenHAB
|
|
128
161
|
#
|
129
162
|
# Returns trigger conditions from inputs if it exists
|
130
163
|
#
|
131
|
-
# @param [Map] inputs map from
|
164
|
+
# @param [java.util.Map] inputs map from openHAB containing UID
|
132
165
|
#
|
133
166
|
# @return [Array] Array of trigger conditions that match rule UID
|
134
167
|
#
|
135
168
|
def trigger_conditions(inputs)
|
136
|
-
# Parse this to get the trigger UID:
|
137
|
-
# ["72698819-83cb-498a-8e61-5aab8b812623.event", "oldState", "module", \
|
138
|
-
# "72698819-83cb-498a-8e61-5aab8b812623.oldState", "event", "newState",\
|
139
|
-
# "72698819-83cb-498a-8e61-5aab8b812623.newState"]
|
140
169
|
@trigger_conditions[trigger_id(inputs)]
|
141
170
|
end
|
142
171
|
|
143
|
-
# If an attachment exists for the trigger for this event add it to the event object
|
144
|
-
# @param [Object] event Event
|
145
|
-
# @param [Hash] inputs Inputs into event
|
146
|
-
# @return [Object] Event with attachment added
|
147
|
-
#
|
148
|
-
def add_attachment(event, inputs)
|
149
|
-
attachment = @attachments[trigger_id(inputs)]
|
150
|
-
return event unless attachment
|
151
|
-
|
152
|
-
event.attachment = attachment
|
153
|
-
event
|
154
|
-
end
|
155
|
-
|
156
172
|
#
|
157
173
|
# Check if any guards prevent execution
|
158
174
|
#
|
159
|
-
# @param [
|
175
|
+
# @param [Object] event openHAB rule trigger event
|
160
176
|
#
|
161
177
|
# @return [true,false] True if guards says rule should execute, false otherwise
|
162
178
|
#
|
@@ -170,7 +186,7 @@ module OpenHAB
|
|
170
186
|
now = Time.now
|
171
187
|
return true if @between.cover? now
|
172
188
|
|
173
|
-
logger.trace("Skipped execution of rule '#{name}' because the current time #{now} "\
|
189
|
+
logger.trace("Skipped execution of rule '#{name}' because the current time #{now} " \
|
174
190
|
"is not between #{@between.begin} and #{@between.end}")
|
175
191
|
else
|
176
192
|
logger.trace("Skipped execution of rule '#{name}' because of guard #{@guard}")
|
@@ -182,15 +198,13 @@ module OpenHAB
|
|
182
198
|
# Process the run queue
|
183
199
|
#
|
184
200
|
# @param [Array] run_queue array of procs of various types to execute
|
185
|
-
# @param [Map] mod
|
186
|
-
# @param [
|
201
|
+
# @param [java.util/Map] mod openHAB map object describing rule trigger
|
202
|
+
# @param [Object] event openHAB map object describing rule trigger
|
187
203
|
#
|
188
|
-
def process_queue(run_queue, mod,
|
189
|
-
event = extract_event(inputs)
|
190
|
-
|
204
|
+
def process_queue(run_queue, mod, event)
|
191
205
|
while (task = run_queue.shift)
|
192
206
|
if task.is_a?(BuilderDSL::Delay)
|
193
|
-
process_delay_task(
|
207
|
+
process_delay_task(event, mod, run_queue, task)
|
194
208
|
else
|
195
209
|
process_task(event, task)
|
196
210
|
end
|
@@ -229,15 +243,15 @@ module OpenHAB
|
|
229
243
|
#
|
230
244
|
# Process delay task
|
231
245
|
#
|
232
|
-
# @param [Map]
|
246
|
+
# @param [Map] event Rule trigger event
|
233
247
|
# @param [Map] mod Rule modes
|
234
248
|
# @param [Queue] run_queue Queue of tasks for this rule
|
235
249
|
# @param [Delay] task to process
|
236
250
|
#
|
237
251
|
#
|
238
|
-
def process_delay_task(
|
252
|
+
def process_delay_task(event, mod, run_queue, task)
|
239
253
|
remaining_queue = run_queue.slice!(0, run_queue.length)
|
240
|
-
DSL.after(task.duration) { process_queue(remaining_queue, mod,
|
254
|
+
DSL.after(task.duration) { process_queue(remaining_queue, mod, event) }
|
241
255
|
end
|
242
256
|
|
243
257
|
#
|
@@ -14,15 +14,18 @@ end
|
|
14
14
|
module OpenHAB
|
15
15
|
module DSL
|
16
16
|
#
|
17
|
-
# Creates and manages
|
17
|
+
# Creates and manages openHAB Rules
|
18
18
|
#
|
19
19
|
module Rules
|
20
|
-
# A rules builder allows you to create
|
20
|
+
# A rules builder allows you to create openHAB rules.
|
21
21
|
#
|
22
22
|
# Note that all methods on this module are also availabe directly on {OpenHAB::DSL}.
|
23
23
|
#
|
24
24
|
class Builder
|
25
25
|
include Terse
|
26
|
+
include Core::EntityLookup
|
27
|
+
|
28
|
+
self.create_dummy_items = true
|
26
29
|
|
27
30
|
# @return [org.openhab.core.automation.RuleProvider]
|
28
31
|
attr_reader :provider
|
@@ -34,21 +37,24 @@ module OpenHAB
|
|
34
37
|
#
|
35
38
|
# Create a new rule
|
36
39
|
#
|
40
|
+
# The rule must have at least one trigger and one execution block.
|
41
|
+
# To create a "script" without any triggers, use {#script}.
|
42
|
+
#
|
37
43
|
# @param [String] name The rule name
|
38
|
-
# @yield Block executed in the context of a {Rules::
|
39
|
-
# @yieldparam [Rules::
|
44
|
+
# @yield Block executed in the context of a {Rules::BuilderDSL}
|
45
|
+
# @yieldparam [Rules::BuilderDSL] rule
|
40
46
|
# Optional parameter to access the rule configuration from within execution blocks and guards.
|
41
|
-
# @return [Rule]
|
47
|
+
# @return [Core::Rules::Rule, nil] The rule object, or nil if no rule was created.
|
42
48
|
#
|
43
|
-
# @see OpenHAB::DSL::Rules::
|
49
|
+
# @see OpenHAB::DSL::Rules::BuilderDSL Rule BuilderDSL for details on rule triggers, guards and execution blocks
|
44
50
|
# @see Rules::Terse Terse Rules
|
45
51
|
#
|
46
52
|
# @example
|
47
53
|
# require "openhab/dsl"
|
48
54
|
#
|
49
55
|
# rule "name" do
|
50
|
-
# <
|
51
|
-
# <
|
56
|
+
# <one or more triggers>
|
57
|
+
# <one or more execution blocks>
|
52
58
|
# <zero or more guards>
|
53
59
|
# end
|
54
60
|
#
|
@@ -85,7 +91,7 @@ module OpenHAB
|
|
85
91
|
# @param [String] name A descriptive name
|
86
92
|
# @param [String] id The script's ID
|
87
93
|
# @yield [] Block executed when the script is executed.
|
88
|
-
# @return [Rule]
|
94
|
+
# @return [Core::Rules::Rule]
|
89
95
|
#
|
90
96
|
def script(name = nil, id: nil, script: nil, &block)
|
91
97
|
raise ArgumentError, "Block is required" unless block
|
@@ -108,7 +114,7 @@ module OpenHAB
|
|
108
114
|
end
|
109
115
|
|
110
116
|
#
|
111
|
-
# Rule configuration for
|
117
|
+
# Rule configuration for openHAB Rules engine
|
112
118
|
#
|
113
119
|
class BuilderDSL
|
114
120
|
include Core::EntityLookup
|
@@ -117,6 +123,8 @@ module OpenHAB
|
|
117
123
|
extend Property
|
118
124
|
extend Forwardable
|
119
125
|
|
126
|
+
self.create_dummy_items = true
|
127
|
+
|
120
128
|
delegate %i[triggers trigger_conditions attachments] => :@rule_triggers
|
121
129
|
|
122
130
|
# @!visibility private
|
@@ -259,7 +267,7 @@ module OpenHAB
|
|
259
267
|
#
|
260
268
|
# @example
|
261
269
|
# rule 'Delay sleeps between execution elements' do
|
262
|
-
#
|
270
|
+
# on_load
|
263
271
|
# run { logger.info("Sleeping") }
|
264
272
|
# delay 5.seconds
|
265
273
|
# run { logger.info("Awake") }
|
@@ -267,7 +275,7 @@ module OpenHAB
|
|
267
275
|
#
|
268
276
|
# @example Like other execution blocks, multiple can exist in a single rule.
|
269
277
|
# rule 'Multiple delays can exist in a rule' do
|
270
|
-
#
|
278
|
+
# on_load
|
271
279
|
# run { logger.info("Sleeping") }
|
272
280
|
# delay 5.seconds
|
273
281
|
# run { logger.info("Sleeping Again") }
|
@@ -277,7 +285,7 @@ module OpenHAB
|
|
277
285
|
#
|
278
286
|
# @example You can use Ruby code in your rule across multiple execution blocks like a run and a delay.
|
279
287
|
# rule 'Dim a switch on system startup over 100 seconds' do
|
280
|
-
#
|
288
|
+
# on_load
|
281
289
|
# 100.times do
|
282
290
|
# run { DimmerSwitch.dim }
|
283
291
|
# delay 1.second
|
@@ -302,7 +310,7 @@ module OpenHAB
|
|
302
310
|
#
|
303
311
|
# @example
|
304
312
|
# rule 'Turn switch ON or OFF based on value of another switch' do
|
305
|
-
#
|
313
|
+
# on_load
|
306
314
|
# run { TestSwitch << ON }
|
307
315
|
# otherwise { TestSwitch << OFF }
|
308
316
|
# only_if { OtherSwitch.on? }
|
@@ -425,28 +433,28 @@ module OpenHAB
|
|
425
433
|
#
|
426
434
|
# @example String of {LocalTime}
|
427
435
|
# rule 'Log an entry if started between 3:30:04 and midnight using strings' do
|
428
|
-
#
|
436
|
+
# on_load
|
429
437
|
# run { logger.info ("Started at #{LocalTime.now}")}
|
430
438
|
# between '3:30:04'..LocalTime::MIDNIGHT
|
431
439
|
# end
|
432
440
|
#
|
433
441
|
# @example {LocalTime}
|
434
442
|
# rule 'Log an entry if started between 3:30:04 and midnight using LocalTime objects' do
|
435
|
-
#
|
443
|
+
# on_load
|
436
444
|
# run { logger.info ("Started at #{LocalTime.now}")}
|
437
445
|
# between LocalTime.of(3, 30, 4)..LocalTime::MIDNIGHT
|
438
446
|
# end
|
439
447
|
#
|
440
448
|
# @example String of {MonthDay}
|
441
449
|
# rule 'Log an entry if started between March 9th and April 10ths' do
|
442
|
-
#
|
450
|
+
# on_load
|
443
451
|
# run { logger.info ("Started at #{Time.now}")}
|
444
452
|
# between '03-09'..'04-10'
|
445
453
|
# end
|
446
454
|
#
|
447
455
|
# @example {MonthDay}
|
448
456
|
# rule 'Log an entry if started between March 9th and April 10ths' do
|
449
|
-
#
|
457
|
+
# on_load
|
450
458
|
# run { logger.info ("Started at #{Time.now}")}
|
451
459
|
# between MonthDay.of(03,09)..'04-06'
|
452
460
|
# end
|
@@ -533,8 +541,8 @@ module OpenHAB
|
|
533
541
|
@rule_triggers = RuleTriggers.new
|
534
542
|
@caller = caller_binding.eval "self"
|
535
543
|
@ruby_triggers = []
|
544
|
+
@on_load_id = nil
|
536
545
|
enabled(true)
|
537
|
-
on_start(false)
|
538
546
|
tags([])
|
539
547
|
end
|
540
548
|
|
@@ -789,19 +797,19 @@ module OpenHAB
|
|
789
797
|
# for is a reserved word in ruby, so use local_variable_get :for
|
790
798
|
duration = binding.local_variable_get(:for)
|
791
799
|
|
800
|
+
@ruby_triggers << [:changed, items, { to: to, from: from, duration: duration }]
|
801
|
+
|
792
802
|
from = [nil] if from.nil?
|
793
803
|
to = [nil] if to.nil?
|
794
|
-
|
795
|
-
@ruby_triggers << [:changed, items, { to: to, from: from, duration: duration }]
|
796
804
|
items.each do |item|
|
797
805
|
case item
|
798
806
|
when Core::Things::Thing,
|
799
807
|
Core::Things::ThingUID,
|
800
|
-
Core::Items::
|
808
|
+
Core::Items::Item,
|
801
809
|
Core::Items::GroupItem::Members
|
802
810
|
nil
|
803
811
|
else
|
804
|
-
raise ArgumentError, "items must be
|
812
|
+
raise ArgumentError, "items must be an Item, GroupItem::Members, Thing, or ThingUID"
|
805
813
|
end
|
806
814
|
|
807
815
|
logger.trace("Creating changed trigger for entity(#{item}), to(#{to.inspect}), from(#{from.inspect})")
|
@@ -818,7 +826,7 @@ module OpenHAB
|
|
818
826
|
# Create a cron trigger
|
819
827
|
#
|
820
828
|
# @overload cron(expression, attach: nil)
|
821
|
-
# @param [String, nil] expression [
|
829
|
+
# @param [String, nil] expression [openHAB style cron expression](https://www.openhab.org/docs/configuration/rules-dsl.html#time-based-triggers)
|
822
830
|
# @param [Object] attach object to be attached to the trigger
|
823
831
|
#
|
824
832
|
# @example Using a cron expression
|
@@ -962,45 +970,116 @@ module OpenHAB
|
|
962
970
|
end
|
963
971
|
|
964
972
|
#
|
965
|
-
#
|
973
|
+
# Creates a trigger that executes when the script is loaded
|
966
974
|
#
|
967
|
-
# Execute the rule
|
968
|
-
#
|
969
|
-
# especially when combined with other triggers.
|
975
|
+
# Execute the rule whenever the script is first loaded, including on openHAB start up,
|
976
|
+
# and on subsequent reloads on file modifications.
|
977
|
+
# This is useful to perform initialization routines, especially when combined with other triggers.
|
970
978
|
#
|
971
|
-
# @param [
|
972
|
-
# @param [Object] attach object to be attached to the trigger
|
979
|
+
# @param [Object] attach Object to be attached to the trigger
|
973
980
|
# @return [void]
|
974
981
|
#
|
975
982
|
# @example
|
976
|
-
# rule "startup rule" do
|
977
|
-
#
|
983
|
+
# rule "script startup rule" do
|
984
|
+
# on_load
|
978
985
|
# run do
|
979
986
|
# <calculate some item state>
|
980
987
|
# end
|
981
988
|
# end
|
982
989
|
#
|
983
990
|
# @example
|
984
|
-
# rule
|
985
|
-
#
|
991
|
+
# rule "Ensure all security lights are on" do
|
992
|
+
# on_load
|
986
993
|
# run { Security_Lights.on }
|
987
994
|
# end
|
988
995
|
#
|
989
|
-
|
990
|
-
|
991
|
-
|
996
|
+
def on_load(attach: nil)
|
997
|
+
# prevent overwriting @on_load_id
|
998
|
+
raise ArgumentError, "on_load can only be used once within a rule" if @on_load_id
|
999
|
+
|
1000
|
+
@on_load_id = SecureRandom.uuid
|
1001
|
+
attachments[@on_load_id] = attach
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
#
|
1005
|
+
# Creates a trigger that executes when openHAB reaches a certain start level
|
1006
|
+
#
|
1007
|
+
# This will only trigger once during openHAB start up. It won't trigger on script reloads.
|
1008
|
+
#
|
1009
|
+
# @param [Integer,:rules,:ruleengine,:ui,:things,:complete] at_level
|
1010
|
+
# Zero or more start levels. Note that Startlevels less than 40 are not available as triggers
|
1011
|
+
# because the rule engine needs to start up first before it can execute any rules
|
1012
|
+
#
|
1013
|
+
# | Symbol | Start Level |
|
1014
|
+
# | ------------- | ----------- |
|
1015
|
+
# | `:osgi` | 10 |
|
1016
|
+
# | `:model` | 20 |
|
1017
|
+
# | `:state` | 30 |
|
1018
|
+
# | `:rules` | 40 |
|
1019
|
+
# | `:ruleengine` | 50 |
|
1020
|
+
# | `:ui` | 70 |
|
1021
|
+
# | `:things` | 80 |
|
1022
|
+
# | `:complete` | 100 |
|
1023
|
+
# @param [Array<Integer,:rules,:ruleengine,:ui,:things,:complete>] at_levels Fluent alias for `at_level`
|
1024
|
+
# @param [Object] attach Object to be attached to the trigger
|
1025
|
+
# @return [void]
|
1026
|
+
#
|
1027
|
+
# @example
|
1028
|
+
# rule "Trigger at openHAB system start" do
|
1029
|
+
# on_start # trigger at the default startlevel 100
|
1030
|
+
# run { logger.info "openHAB start up complete." }
|
1031
|
+
# end
|
1032
|
+
#
|
1033
|
+
# @example Trigger at a specific start level
|
1034
|
+
# rule "Trigger after things are loaded" do
|
1035
|
+
# on_start at_level: :things
|
1036
|
+
# run { logger.info "Things are ready!" }
|
1037
|
+
# end
|
1038
|
+
#
|
1039
|
+
# @example Trigger at multiple levels
|
1040
|
+
# rule "Multiple start up triggers" do
|
1041
|
+
# on_start at_levels: %i[ui things complete]
|
1042
|
+
# run do |event|
|
1043
|
+
# logger.info "openHAB startlevel has reached level #{event.startlevel}"
|
1044
|
+
# end
|
1045
|
+
# end
|
1046
|
+
#
|
1047
|
+
# @see https://www.openhab.org/docs/configuration/rules-dsl.html#system-based-triggers System based triggers
|
1048
|
+
#
|
1049
|
+
def on_start(at_level: nil, at_levels: nil, attach: nil)
|
1050
|
+
levels = Array.wrap(at_level) | Array.wrap(at_levels)
|
1051
|
+
levels = [100] if levels.empty?
|
1052
|
+
|
1053
|
+
levels.map! do |level|
|
1054
|
+
next level unless level.is_a?(Symbol)
|
1055
|
+
|
1056
|
+
begin
|
1057
|
+
klass = org.openhab.core.service.StartLevelService.java_class
|
1058
|
+
klass.declared_field("STARTLEVEL_#{level.upcase}").get_int(klass)
|
1059
|
+
rescue java.lang.NoSuchFieldException
|
1060
|
+
raise ArgumentError, "Invalid symbol for at_level: :#{level}"
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
@ruby_triggers << [:on_start, levels]
|
1065
|
+
levels.each do |level|
|
1066
|
+
logger.warn "Rule engine doesn't start until start level 40" if level < 40
|
1067
|
+
config = { startlevel: level }
|
1068
|
+
logger.trace("Creating a SystemStartlevelTrigger with startlevel=#{level}")
|
1069
|
+
Triggers::Trigger.new(rule_triggers: @rule_triggers)
|
1070
|
+
.append_trigger(type: "core.SystemStartlevelTrigger", config: config, attach: attach)
|
1071
|
+
end
|
992
1072
|
end
|
993
|
-
# rubocop:enable Style/OptionalBooleanParameter
|
994
1073
|
|
995
1074
|
#
|
996
|
-
#
|
1075
|
+
# Creates a trigger for when an item or group receives a command.
|
997
1076
|
#
|
998
1077
|
# The command/commands parameters are replicated for DSL fluency.
|
999
1078
|
#
|
1000
1079
|
# The `event` passed to run blocks will be an
|
1001
1080
|
# {Core::Events::ItemCommandEvent}.
|
1002
1081
|
#
|
1003
|
-
# @param [
|
1082
|
+
# @param [Item, GroupItem::Members] items Items to create trigger for
|
1004
1083
|
# @param [Core::TypesCommand, Array<Command>, Range, Proc] command commands to match for trigger
|
1005
1084
|
# @param [Array<Command>, Range, Proc] commands Fluent alias for `command`
|
1006
1085
|
# @param [Object] attach object to be attached to the trigger
|
@@ -1072,11 +1151,11 @@ module OpenHAB
|
|
1072
1151
|
|
1073
1152
|
items.each do |item|
|
1074
1153
|
case item
|
1075
|
-
when Core::Items::
|
1154
|
+
when Core::Items::Item,
|
1076
1155
|
Core::Items::GroupItem::Members
|
1077
1156
|
nil
|
1078
1157
|
else
|
1079
|
-
raise ArgumentError, "items must be
|
1158
|
+
raise ArgumentError, "items must be an Item or GroupItem::Members"
|
1080
1159
|
end
|
1081
1160
|
commands.each do |cmd|
|
1082
1161
|
logger.trace "Creating received command trigger for items #{item.inspect} and commands #{cmd.inspect}"
|
@@ -1194,7 +1273,7 @@ module OpenHAB
|
|
1194
1273
|
# {Core::Events::ThingStatusInfoEvent} depending on if the triggering
|
1195
1274
|
# element was an item or a thing.
|
1196
1275
|
#
|
1197
|
-
# @param [
|
1276
|
+
# @param [Item, GroupItem::Members, Thing] items
|
1198
1277
|
# Objects to create trigger for.
|
1199
1278
|
# @param [State, Array<State>, Range, Proc, Symbol, String] to
|
1200
1279
|
# Only execute rule if the state matches `to` state(s). If the
|
@@ -1271,11 +1350,11 @@ module OpenHAB
|
|
1271
1350
|
case item
|
1272
1351
|
when Core::Things::Thing,
|
1273
1352
|
Core::Things::ThingUID,
|
1274
|
-
Core::Items::
|
1353
|
+
Core::Items::Item,
|
1275
1354
|
Core::Items::GroupItem::Members
|
1276
1355
|
nil
|
1277
1356
|
else
|
1278
|
-
raise ArgumentError, "items must be
|
1357
|
+
raise ArgumentError, "items must be an Item, GroupItem::Members, Thing, or ThingUID"
|
1279
1358
|
end
|
1280
1359
|
|
1281
1360
|
logger.trace("Creating updated trigger for item(#{item}) to(#{to})")
|
@@ -1317,7 +1396,7 @@ module OpenHAB
|
|
1317
1396
|
# @param [Object] attach object to be attached to the trigger
|
1318
1397
|
# @return [void]
|
1319
1398
|
#
|
1320
|
-
# @example Watch `items` directory inside of the
|
1399
|
+
# @example Watch `items` directory inside of the openHAB configuration path and log any changes.
|
1321
1400
|
# rule 'watch directory' do
|
1322
1401
|
# watch OpenHAB::Core.config_folder / 'items'
|
1323
1402
|
# run { |event| logger.info("#{event.path.basename} - #{event.type}") }
|
@@ -1358,36 +1437,6 @@ module OpenHAB
|
|
1358
1437
|
|
1359
1438
|
# @!endgroup
|
1360
1439
|
|
1361
|
-
#
|
1362
|
-
# Checks if this rule should run on start
|
1363
|
-
#
|
1364
|
-
# @return [true, false] True if rule should run on start, false otherwise.
|
1365
|
-
#
|
1366
|
-
def on_start?
|
1367
|
-
@on_start.enabled
|
1368
|
-
end
|
1369
|
-
|
1370
|
-
#
|
1371
|
-
# Get the optional start attachment
|
1372
|
-
#
|
1373
|
-
# @return [Object] optional user provided attachment to the on_start method
|
1374
|
-
#
|
1375
|
-
# @!visibility private
|
1376
|
-
def start_attachment
|
1377
|
-
@on_start.attach
|
1378
|
-
end
|
1379
|
-
|
1380
|
-
# @!visibility private
|
1381
|
-
#
|
1382
|
-
# Run the supplied block inside the object instance of the object that created the rule
|
1383
|
-
#
|
1384
|
-
# @yield [] Block executed in context of the object creating the rule
|
1385
|
-
#
|
1386
|
-
#
|
1387
|
-
def my(&block)
|
1388
|
-
@caller.instance_eval(&block)
|
1389
|
-
end
|
1390
|
-
|
1391
1440
|
#
|
1392
1441
|
# @return [String]
|
1393
1442
|
#
|
@@ -1396,7 +1445,7 @@ module OpenHAB
|
|
1396
1445
|
#<OpenHAB::DSL::Rules::Builder: #{uid}
|
1397
1446
|
triggers=#{triggers.inspect},
|
1398
1447
|
run blocks=#{run.inspect},
|
1399
|
-
|
1448
|
+
on_load=#{!@on_load_id.nil?},
|
1400
1449
|
Trigger Conditions=#{trigger_conditions.inspect},
|
1401
1450
|
Trigger UIDs=#{triggers.map(&:id).inspect},
|
1402
1451
|
Attachments=#{attachments.inspect}
|
@@ -1419,7 +1468,7 @@ module OpenHAB
|
|
1419
1468
|
added_rule.actions.first.configuration.put("type", "application/x-ruby")
|
1420
1469
|
added_rule.actions.first.configuration.put("script", script) if script
|
1421
1470
|
|
1422
|
-
rule.execute(nil, { "
|
1471
|
+
rule.execute(nil, { "module" => @on_load_id }) if @on_load_id
|
1423
1472
|
added_rule
|
1424
1473
|
end
|
1425
1474
|
|
@@ -1456,7 +1505,7 @@ module OpenHAB
|
|
1456
1505
|
# @return [true,false] True if rule has triggers, false otherwise
|
1457
1506
|
#
|
1458
1507
|
def triggers?
|
1459
|
-
|
1508
|
+
@on_load_id || !triggers.empty?
|
1460
1509
|
end
|
1461
1510
|
|
1462
1511
|
#
|
@@ -34,7 +34,7 @@ module OpenHAB
|
|
34
34
|
#
|
35
35
|
# Checks if a guard should run
|
36
36
|
#
|
37
|
-
# @param [
|
37
|
+
# @param [Object] event openHAB Trigger Event
|
38
38
|
#
|
39
39
|
# @return [true,false] True if guard is satisfied, false otherwise
|
40
40
|
#
|
@@ -51,7 +51,7 @@ module OpenHAB
|
|
51
51
|
#
|
52
52
|
# @param [Array] conditions to check
|
53
53
|
# @param [Symbol] check_type type of check to perform (:only_if or :not_if)
|
54
|
-
# @param [Event] event
|
54
|
+
# @param [Event] event openHAB event to see if it satisfies the guard
|
55
55
|
#
|
56
56
|
# @return [true,false] True if guard is satisfied, false otherwise
|
57
57
|
#
|
@@ -70,7 +70,7 @@ module OpenHAB
|
|
70
70
|
# Execute the guard check
|
71
71
|
#
|
72
72
|
# @param [Symbol] check_type :only_if or :not_if to check
|
73
|
-
# @param [
|
73
|
+
# @param [Object] event event to check if meets guard
|
74
74
|
# @param [Array<Item>] items to check if satisfy criteria
|
75
75
|
# @param [Array] procs to check if satisfy criteria
|
76
76
|
#
|
@@ -87,7 +87,7 @@ module OpenHAB
|
|
87
87
|
#
|
88
88
|
# Check not_if guard
|
89
89
|
#
|
90
|
-
# @param [
|
90
|
+
# @param [Object] event to check if meets guard
|
91
91
|
# @param [Array<Item>] items to check if satisfy criteria
|
92
92
|
# @param [Array] procs to check if satisfy criteria
|
93
93
|
#
|
@@ -100,7 +100,7 @@ module OpenHAB
|
|
100
100
|
#
|
101
101
|
# Check only_if guard
|
102
102
|
#
|
103
|
-
# @param [
|
103
|
+
# @param [Object] event to check if meets guard
|
104
104
|
# @param [Array<Item>] items to check if satisfy criteria
|
105
105
|
# @param [Array] procs to check if satisfy criteria
|
106
106
|
#
|