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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/actions.rb +21 -9
  3. data/lib/openhab/core/dependency_tracking.rb +34 -0
  4. data/lib/openhab/core/entity_lookup.rb +132 -78
  5. data/lib/openhab/core/events/item_channel_link.rb +2 -2
  6. data/lib/openhab/core/events/item_command_event.rb +1 -1
  7. data/lib/openhab/core/events/item_event.rb +2 -2
  8. data/lib/openhab/core/events/item_state_changed_event.rb +1 -1
  9. data/lib/openhab/core/events/thing.rb +1 -1
  10. data/lib/openhab/core/items/accepted_data_types.rb +2 -2
  11. data/lib/openhab/core/items/contact_item.rb +1 -1
  12. data/lib/openhab/core/items/dimmer_item.rb +2 -2
  13. data/lib/openhab/core/items/generic_item.rb +45 -224
  14. data/lib/openhab/core/items/group_item.rb +5 -3
  15. data/lib/openhab/core/items/image_item.rb +2 -2
  16. data/lib/openhab/core/items/item.rb +219 -0
  17. data/lib/openhab/core/items/metadata/hash.rb +1 -1
  18. data/lib/openhab/core/items/metadata/namespace_hash.rb +1 -1
  19. data/lib/openhab/core/items/persistence.rb +19 -10
  20. data/lib/openhab/core/items/provider.rb +2 -2
  21. data/lib/openhab/core/items/proxy.rb +68 -7
  22. data/lib/openhab/core/items/registry.rb +6 -6
  23. data/lib/openhab/core/items/semantics/enumerable.rb +6 -6
  24. data/lib/openhab/core/items/semantics.rb +8 -7
  25. data/lib/openhab/core/items.rb +3 -2
  26. data/lib/openhab/core/provider.rb +14 -7
  27. data/lib/openhab/core/rules/registry.rb +2 -2
  28. data/lib/openhab/core/rules.rb +1 -1
  29. data/lib/openhab/core/script_handling.rb +6 -6
  30. data/lib/openhab/core/things/channel.rb +1 -1
  31. data/lib/openhab/core/things/channel_uid.rb +2 -2
  32. data/lib/openhab/core/things/item_channel_link.rb +2 -2
  33. data/lib/openhab/core/things/links/provider.rb +2 -2
  34. data/lib/openhab/core/things/profile_callback.rb +1 -1
  35. data/lib/openhab/core/things/registry.rb +1 -1
  36. data/lib/openhab/core/things/thing.rb +1 -1
  37. data/lib/openhab/core/timer.rb +21 -10
  38. data/lib/openhab/core/types/date_time_type.rb +4 -4
  39. data/lib/openhab/core/types/hsb_type.rb +2 -2
  40. data/lib/openhab/core/types/point_type.rb +1 -1
  41. data/lib/openhab/core/types/quantity_type.rb +1 -1
  42. data/lib/openhab/core/types.rb +1 -1
  43. data/lib/openhab/core/uid.rb +1 -1
  44. data/lib/openhab/core/value_cache.rb +188 -0
  45. data/lib/openhab/core.rb +57 -15
  46. data/lib/openhab/core_ext/between.rb +32 -0
  47. data/lib/openhab/core_ext/java/duration.rb +1 -0
  48. data/lib/openhab/core_ext/java/local_date.rb +1 -0
  49. data/lib/openhab/core_ext/java/local_time.rb +1 -0
  50. data/lib/openhab/core_ext/java/month.rb +12 -1
  51. data/lib/openhab/core_ext/java/month_day.rb +2 -0
  52. data/lib/openhab/core_ext/java/zoned_date_time.rb +4 -4
  53. data/lib/openhab/core_ext/ruby/date.rb +3 -1
  54. data/lib/openhab/core_ext/ruby/date_time.rb +1 -0
  55. data/lib/openhab/core_ext/ruby/symbol.rb +7 -0
  56. data/lib/openhab/core_ext/ruby/time.rb +1 -0
  57. data/lib/openhab/dsl/items/builder.rb +17 -10
  58. data/lib/openhab/dsl/items/ensure.rb +5 -5
  59. data/lib/openhab/dsl/items/timed_command.rb +5 -5
  60. data/lib/openhab/dsl/rules/automation_rule.rb +54 -40
  61. data/lib/openhab/dsl/rules/builder.rb +128 -79
  62. data/lib/openhab/dsl/rules/guard.rb +5 -5
  63. data/lib/openhab/dsl/rules/name_inference.rb +21 -2
  64. data/lib/openhab/dsl/rules/rule_triggers.rb +3 -3
  65. data/lib/openhab/dsl/rules/terse.rb +1 -0
  66. data/lib/openhab/dsl/rules/triggers/changed.rb +27 -24
  67. data/lib/openhab/dsl/rules/triggers/command.rb +6 -5
  68. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +3 -3
  69. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +2 -2
  70. data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +6 -6
  71. data/lib/openhab/dsl/rules/triggers/updated.rb +5 -5
  72. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +11 -12
  73. data/lib/openhab/dsl/things/builder.rb +73 -14
  74. data/lib/openhab/dsl/version.rb +2 -2
  75. data/lib/openhab/dsl.rb +45 -17
  76. data/lib/openhab/log.rb +5 -5
  77. data/lib/openhab/rspec/configuration.rb +5 -5
  78. data/lib/openhab/rspec/example_group.rb +1 -1
  79. data/lib/openhab/rspec/helpers.rb +5 -5
  80. data/lib/openhab/rspec/hooks.rb +19 -1
  81. data/lib/openhab/rspec/karaf.rb +13 -21
  82. data/lib/openhab/rspec/mocks/persistence_service.rb +15 -0
  83. data/lib/openhab/rspec/mocks/thing_handler.rb +2 -2
  84. data/lib/openhab/rspec/suspend_rules.rb +2 -1
  85. data/lib/openhab/yard/base_helper.rb +46 -0
  86. data/lib/openhab/yard/html_helper.rb +3 -3
  87. data/lib/openhab/yard/markdown_directive.rb +125 -0
  88. data/lib/openhab/yard/markdown_helper.rb +99 -0
  89. 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 OpenHAB rules engine
45
- # @param [Map] inputs map provided by OpenHAB rules engine containing event and other information
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
- process_queue(create_queue(inputs), mod, inputs)
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] inputs rule inputs
105
+ # @param [Map] event Event object
91
106
  # @return [Queue] <description>
92
107
  #
93
- def create_queue(inputs)
94
- case check_guards(event: extract_event(inputs))
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
- event = inputs&.dig("event")
112
- unless event
113
- event = Struct.new(:event, :attachment, :command).new
114
- event.command = inputs&.dig("command")
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
- add_attachment(event, inputs)
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 OpenHAB containing UID
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 [Map] event OpenHAB rule trigger event
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 OpenHAB map object describing rule trigger
186
- # @param [Map] inputs OpenHAB map object describing rule trigge
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, inputs)
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(inputs, mod, run_queue, 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] inputs Rule trigger inputs
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(inputs, mod, run_queue, 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, inputs) }
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 OpenHAB Rules
17
+ # Creates and manages openHAB Rules
18
18
  #
19
19
  module Rules
20
- # A rules builder allows you to create OpenHAB rules.
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::Builder}
39
- # @yieldparam [Rules::Builder] rule
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::Builder Rule builder for details on rule triggers, guards and execution blocks
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
- # <zero or more triggers>
51
- # <zero or more execution blocks>
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 OpenHAB Rules engine
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
- # on_start
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
- # on_start
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
- # on_start
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
- # on_start
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
- # on_start
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
- # on_start
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
- # on_start
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
- # on_start
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::GenericItem,
808
+ Core::Items::Item,
801
809
  Core::Items::GroupItem::Members
802
810
  nil
803
811
  else
804
- raise ArgumentError, "items must be a GenericItem, GroupItem::Members, Thing, or ThingUID"
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 [OpenHAB style cron expression](https://www.openhab.org/docs/configuration/rules-dsl.html#time-based-triggers)
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
- # Run this rule when the script is loaded.
973
+ # Creates a trigger that executes when the script is loaded
966
974
  #
967
- # Execute the rule on OpenHAB start up and whenever the script is
968
- # reloaded. This is useful to perform initialization routines,
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 [true, false] run_on_start Run this rule on start, defaults to True
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
- # on_start
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 'Ensure all security lights are on' do
985
- # on_start
991
+ # rule "Ensure all security lights are on" do
992
+ # on_load
986
993
  # run { Security_Lights.on }
987
994
  # end
988
995
  #
989
- # rubocop:disable Style/OptionalBooleanParameter
990
- def on_start(run_on_start = true, attach: nil)
991
- @on_start = Struct.new(:enabled, :attach).new(run_on_start, attach)
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
- # Create a trigger for when an item or group receives a command
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 [GenericItem, GroupItem::Members] items Items to create trigger for
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::GenericItem,
1154
+ when Core::Items::Item,
1076
1155
  Core::Items::GroupItem::Members
1077
1156
  nil
1078
1157
  else
1079
- raise ArgumentError, "items must be a GenericItem or GroupItem::Members"
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 [GenericItem, GroupItem::Members, Thing] items
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::GenericItem,
1353
+ Core::Items::Item,
1275
1354
  Core::Items::GroupItem::Members
1276
1355
  nil
1277
1356
  else
1278
- raise ArgumentError, "items must be a GenericItem, GroupItem::Members, Thing, or ThingUID"
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 OpenHAB configuration path and log any changes.
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
- on_start=#{on_start?},
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, { "event" => Struct.new(:attachment).new(start_attachment) }) if on_start?
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
- on_start? || !triggers.empty?
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 [OpenHAB Trigger Event] event OpenHAB Trigger Event
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 OpenHAB event to see if it satisfies the guard
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 [OpenHAB Event] event event to check if meets guard
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 [OpenHAB Event] event to check if meets guard
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 [OpenHAB Event] event to check if meets guard
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
  #