openhab-scripting 5.17.0 → 5.18.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecc05f177e95b3a962f2b1fac6f924c5af5d6c49ed8a7e38d896c03417fe9e23
4
- data.tar.gz: 408fa59899bb838caa9a6f3fc80ef82a4051c03fc590249ab53e0a098c5f335d
3
+ metadata.gz: cfc9ae60d0f82fc677a157ac0efd58c12fc597f5ac8f3d79d7aa9c472e2c5d3a
4
+ data.tar.gz: b8bf1721d064b2f88554722518496aa6c53b89407a9fb212880972725e49901f
5
5
  SHA512:
6
- metadata.gz: ccbc0e426427d262cd1f2a5ed671979f5644b4c5b0da5ff34958254de6221283a9420e2b3c45384ac5aafc7feeffd41fa54740f76c4d99ccaa8adba207c32d52
7
- data.tar.gz: 9f9a5f3b120a838f151a1f8edf5e1400f1df0a183cef5a47b921bc661889231c1b186ce2830f8cf7349ab3f89b166de5e1ffc89675628dba21799740b9029cc6
6
+ metadata.gz: 8e50f4ce2c5832a39b3ab9c7b7a489b22697a23b20ce803a633f28ea9b44ed2661a820cdefd00bc54c71cb212a2c1a1d96c35c413937cd3ac514aec55a4c13da
7
+ data.tar.gz: a298851e7255074cb21d9fd4e495a8c8dc750425b0db3319ab17353c2e07106e0f669a40912bbe98cc6db9f252ff70ebe68b9c94fb7366c4b257200da13eefda
@@ -97,8 +97,8 @@ module Enumerable
97
97
  # Send a command to every item in the collection
98
98
  # @return [self, nil] nil when `ensure` is in effect and all the items were already in the same state,
99
99
  # otherwise self
100
- def command(command)
101
- self if count { |i| i.command(command) }.positive?
100
+ def command(command, **kwargs)
101
+ self if count { |i| i.command(command, **kwargs) }.positive?
102
102
  end
103
103
 
104
104
  # Send a command to every item in the collection, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
@@ -63,7 +63,8 @@ module OpenHAB
63
63
  #
64
64
  def remove(rule_uid)
65
65
  rule_uid = rule_uid.uid if rule_uid.is_a?(Rule)
66
- provider = Provider.registry.provider_for(rule_uid)
66
+ return nil unless (provider = Provider.registry.provider_for(rule_uid))
67
+
67
68
  unless provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
68
69
  raise "Cannot remove rule #{rule_uid} from non-managed provider #{provider.inspect}"
69
70
  end
@@ -149,6 +149,7 @@ module OpenHAB
149
149
  r += " #{visibility}" unless visible?
150
150
  r += " #{status || "<detached>"}"
151
151
  r += " (#{status_info.status_detail})" if status_info && status_info.status_detail != RuleStatusDetail::NONE
152
+ r += " description=#{description.inspect}" if description
152
153
  r += " tags=#{tags.to_a.inspect}" unless tags.empty?
153
154
  r += " configuration=#{configuration.properties.to_h}" if configuration && !configuration.properties.empty?
154
155
  "#{r}>"
@@ -26,7 +26,7 @@ module OpenHAB
26
26
  def eql?(other)
27
27
  return false unless other.instance_of?(self.class)
28
28
 
29
- to_s.compare_to(other.to_s).zero?
29
+ to_s == other.to_s
30
30
  end
31
31
 
32
32
  #
@@ -101,12 +101,22 @@ module OpenHAB
101
101
  # @note This method returns self so it can be chained, unlike the Java version.
102
102
  #
103
103
  # @param [Instant, #to_zoned_date_time, #to_instant] instant An instant for the given state.
104
- # @param [State] state The State at the given timestamp.
104
+ # @param [State, String, Numeric] state The State at the given timestamp.
105
+ # If a String is given, it will be converted to {StringType}.
106
+ # If a {Numeric} is given, it will be converted to {DecimalType}.
105
107
  # @return [self]
108
+ # @raise [ArgumentError] if state is not a {State}, String or {Numeric}
106
109
  #
107
110
  def add(instant, state)
108
111
  instant = instant.to_zoned_date_time if instant.respond_to?(:to_zoned_date_time)
109
112
  instant = instant.to_instant if instant.respond_to?(:to_instant)
113
+ state = case state
114
+ when State then state
115
+ when String then StringType.new(state)
116
+ when Numeric then DecimalType.new(state)
117
+ else
118
+ raise ArgumentError, "state must be a State, String or Numeric, but was #{state.class}"
119
+ end
110
120
  add_instant(instant, state)
111
121
  self
112
122
  end
@@ -672,7 +672,6 @@ module OpenHAB
672
672
  # @param (see ItemBuilder#initialize)
673
673
  def initialize(*args, type: nil, function: nil, thing: nil, **kwargs)
674
674
  raise ArgumentError, "invalid function #{function}" if function && !function.match?(FUNCTION_REGEX)
675
- raise ArgumentError, "state cannot be set on GroupItems" if kwargs[:state]
676
675
 
677
676
  super(type, *args, **kwargs)
678
677
  @function = function
@@ -74,6 +74,7 @@ module OpenHAB
74
74
  end
75
75
 
76
76
  Core::Items::GenericItem.prepend(self)
77
+ Core::Items::GroupItem.prepend(self)
77
78
 
78
79
  #
79
80
  # Sends command to an item for specified duration, then on timer expiration sends
@@ -40,7 +40,17 @@ module OpenHAB
40
40
  # The rule must have at least one trigger and one execution block.
41
41
  # To create a "script" without any triggers, use {OpenHAB::DSL.script script}.
42
42
  #
43
+ # When explicit `id` is not provided, the rule's ID will be inferred from the block's source location,
44
+ # and a suffix will be added to avoid clashing against existing rules.
45
+ #
46
+ # When an explicit `id` is provided and an existing rule with the same id already exists,
47
+ # the rule will not be created, and the method will return nil.
48
+ #
49
+ # To ensure that a rule is created even when the same id already exists, use {OpenHAB::DSL.rule!} or call
50
+ # {Core::Rules::Registry#remove rules.remove} to remove any existing rule prior to creating the new rule.
51
+ #
43
52
  # @param [String] name The rule name
53
+ # @param [String] id The rule's ID. This can also be defined in the block using {Rules::BuilderDSL#uid uid}.
44
54
  # @yield Block executed in the context of a {Rules::BuilderDSL}
45
55
  # @yieldparam [Rules::BuilderDSL] rule
46
56
  # Optional parameter to access the rule configuration from within execution blocks and guards.
@@ -48,20 +58,26 @@ module OpenHAB
48
58
  #
49
59
  # @see OpenHAB::DSL::Rules::BuilderDSL Rule BuilderDSL for details on rule triggers, guards and execution blocks
50
60
  # @see Rules::Terse Terse Rules
61
+ # @see DSL.rule!
51
62
  #
52
63
  # @example
53
- # require "openhab/dsl"
54
- #
55
64
  # rule "name" do
56
65
  # <one or more triggers>
57
66
  # <one or more execution blocks>
58
67
  # <zero or more guards>
59
68
  # end
60
69
  #
61
- def rule(name = nil, id: nil, script: nil, binding: nil, &block)
70
+ # @example Create a rule with an explicit id, deleting any existing rule with the same id
71
+ # rule! "name", id: "my_happy_day_reminder" do
72
+ # every :day
73
+ # run { logger.info "Happy new day!" }
74
+ # end
75
+ #
76
+ def rule(name = nil, id: nil, replace: nil, script: nil, binding: nil, &block)
62
77
  raise ArgumentError, "Block is required" unless block
63
78
 
64
- id ||= NameInference.infer_rule_id_from_block(block)
79
+ inferred_id = nil
80
+ id ||= inferred_id = NameInference.infer_rule_id_from_block(block)
65
81
  script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
66
82
 
67
83
  builder = nil
@@ -70,6 +86,18 @@ module OpenHAB
70
86
  builder = BuilderDSL.new(binding || block.binding)
71
87
  builder.uid(id)
72
88
  builder.instance_exec(builder, &block)
89
+
90
+ if replace
91
+ logger.debug { "Removing existing rule '#{builder.uid}'." } if DSL.rules.remove(builder.uid)
92
+ elsif replace.nil?
93
+ id_not_inferred = inferred_id.nil? || inferred_id != builder.uid
94
+ if id_not_inferred && (existing_rule = $rules.get(builder.uid))
95
+ logger.warn "Rule '#{builder.uid}' is not created because " \
96
+ "another rule/script/scene with the same id already exists: #{existing_rule.inspect}."
97
+ return nil
98
+ end
99
+ end
100
+
73
101
  builder.guard = Guard.new(run_context: builder.caller,
74
102
  only_if: builder.only_if,
75
103
  not_if: builder.not_if)
@@ -101,7 +129,7 @@ module OpenHAB
101
129
  # @param [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil] tags
102
130
  # Fluent alias for `tag`
103
131
  # @yield [] Block executed when the script is executed.
104
- # @return [Core::Rules::Rule]
132
+ # @return [Core::Rules::Rule, nil]
105
133
  #
106
134
  # @example A simple script
107
135
  # # return the script object into a variable
@@ -123,15 +151,26 @@ module OpenHAB
123
151
  #
124
152
  # rules.scripts["send_alert"].run(message: "The door is open!")
125
153
  #
154
+ # @see DSL.rule
126
155
  # @see Core::Rules::Rule#trigger
156
+ # @see DSL.script!
127
157
  #
128
- def script(name = nil, description: nil, id: nil, tag: nil, tags: nil, script: nil, &block)
158
+ def script(name = nil, description: nil, id: nil, tag: nil, tags: nil, replace: false, script: nil, &block)
129
159
  raise ArgumentError, "Block is required" unless block
130
160
 
131
- id ||= NameInference.infer_rule_id_from_block(block)
161
+ inferred_id = nil # rubocop:disable Lint/UselessAssignment it is used below
162
+ id ||= inferred_id = NameInference.infer_rule_id_from_block(block)
132
163
  name ||= id
133
164
  script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
134
165
 
166
+ if replace
167
+ logger.debug { "Removing existing rule '#{id}'." } if DSL.rules.remove(id)
168
+ elsif inferred_id.nil? && (existing_rule = $rules.get(id))
169
+ logger.warn "Script '#{id}' is not created because " \
170
+ "another script/scene/rule with the same id already exists: #{existing_rule.inspect}."
171
+ return nil
172
+ end
173
+
135
174
  builder = nil
136
175
  ThreadLocal.thread_local(openhab_rule_type: "script", openhab_rule_uid: id) do
137
176
  builder = BuilderDSL.new(block.binding)
@@ -159,15 +198,27 @@ module OpenHAB
159
198
  # @param [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil] tags
160
199
  # Fluent alias for `tag`
161
200
  # @yield [] Block executed when the script is executed.
162
- # @return [Core::Rules::Rule]
201
+ # @return [Core::Rules::Rule, nil]
202
+ #
203
+ # @see DSL.rule
204
+ # @see DSL.scene!
163
205
  #
164
- def scene(name = nil, description: nil, id: nil, tag: nil, tags: nil, script: nil, &block)
206
+ def scene(name = nil, description: nil, id: nil, tag: nil, tags: nil, replace: false, script: nil, &block)
165
207
  raise ArgumentError, "Block is required" unless block
166
208
 
167
- id ||= NameInference.infer_rule_id_from_block(block)
209
+ inferred_id = nil # rubocop:disable Lint/UselessAssignment
210
+ id ||= inferred_id = NameInference.infer_rule_id_from_block(block)
168
211
  name ||= id
169
212
  script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
170
213
 
214
+ if replace
215
+ logger.debug { "Removing existing rule '#{id}'." } if DSL.rules.remove(id)
216
+ elsif inferred_id.nil? && (existing_rule = $rules.get(id))
217
+ logger.warn "Scene '#{id}' is not created because " \
218
+ "another script/scene/rule with the same id already exists: #{existing_rule.inspect}."
219
+ return nil
220
+ end
221
+
171
222
  builder = nil
172
223
  ThreadLocal.thread_local(openhab_rule_type: "script", openhab_rule_uid: id) do
173
224
  builder = BuilderDSL.new(block.binding)
@@ -400,7 +451,7 @@ module OpenHAB
400
451
  # @param [String] id
401
452
  # @return [void]
402
453
  #
403
- prop :uid
454
+ prop(:uid) { |id| Thread.current[:openhab_rule_uid] = id }
404
455
 
405
456
  #
406
457
  # @!method name(value)
@@ -994,13 +1045,20 @@ module OpenHAB
994
1045
  # @param [Item, GroupItem::Members, Thing] items Objects to create trigger for.
995
1046
  # @param [State, Array<State>, #===, nil] from
996
1047
  # Only execute rule if previous state matches `from` state(s).
997
- # @param [State, Array<State>, #===, nil] to State(s) for
1048
+ # @param [State, Array<State>, #===, nil] to
998
1049
  # Only execute rule if new state matches `to` state(s).
999
- # @param [java.time.temporal.TemporalAmount] for
1000
- # Duration item must remain in the same state before executing the execution blocks.
1001
- # @param [Object] attach object to be attached to the trigger
1050
+ # @param [java.time.temporal.TemporalAmount, Proc, nil] for
1051
+ # Duration for which the item/thing must remain in the same state before executing the execution blocks.
1052
+ # When a proc is provided, it will be called when the rule is triggered to get the duration.
1053
+ # @param [Object, nil] attach object to be attached to the trigger
1002
1054
  # @return [void]
1003
1055
  #
1056
+ # @example Single item trigger
1057
+ # rule "Execute rule when a sensor changed" do
1058
+ # changed FrontMotion_Sensor
1059
+ # run { |event| logger.info("Motion detected by #{event.item.name}") }
1060
+ # end
1061
+ #
1004
1062
  # @example Multiple items can be separated with a comma:
1005
1063
  # rule "Execute rule when either sensor changed" do
1006
1064
  # changed FrontMotion_Sensor, RearMotion_Sensor
@@ -1013,23 +1071,15 @@ module OpenHAB
1013
1071
  # run { |event| logger.info("Motion detected by #{event.item.name}") }
1014
1072
  # end
1015
1073
  #
1016
- # @example `for` parameter can be a proc too:
1017
- # Alarm_Delay << 20
1018
- #
1019
- # rule "Execute rule when item is changed for specified duration" do
1020
- # changed Alarm_Mode, for: -> { Alarm_Delay.state }
1021
- # run { logger.info("Alarm Mode Updated") }
1022
- # end
1023
- #
1024
- # @example You can optionally provide `from` and `to` states to restrict the cases in which the rule executes:
1025
- # rule "Execute rule when item is changed to specific number, from specific number, for specified duration" do
1026
- # changed Alarm_Mode, from: 8, to: [14,12], for: 12.seconds
1074
+ # @example You can optionally provide `from` and/or `to` states to restrict the cases in which the rule executes:
1075
+ # rule "Execute rule when item is changed to specific number, from specific number" do
1076
+ # changed Alarm_Mode, from: 8, to: [14,12]
1027
1077
  # run { logger.info("Alarm Mode Updated") }
1028
1078
  # end
1029
1079
  #
1030
1080
  # @example Works with ranges:
1031
- # rule "Execute when item changed to a range of numbers, from a range of numbers, for specified duration" do
1032
- # changed Alarm_Mode, from: 8..10, to: 12..14, for: 12.seconds
1081
+ # rule "Execute when item changed to a range of numbers, from a range of numbers" do
1082
+ # changed Alarm_Mode, from: 8..10, to: 12..14
1033
1083
  # run { logger.info("Alarm Mode Updated") }
1034
1084
  # end
1035
1085
  #
@@ -1040,14 +1090,14 @@ module OpenHAB
1040
1090
  # end
1041
1091
  #
1042
1092
  # @example Works with procs:
1043
- # rule "Execute when item state is changed from an odd number, to an even number, for specified duration" do
1044
- # changed Alarm_Mode, from: proc { |from| from.odd? }, to: proc {|to| to.even? }, for: 12.seconds
1093
+ # rule "Execute when item state is changed from an odd number, to an even number" do
1094
+ # changed Alarm_Mode, from: proc { |from| from.odd? }, to: proc {|to| to.even? }
1045
1095
  # run { logger.info("Alarm Mode Updated") }
1046
1096
  # end
1047
1097
  #
1048
1098
  # @example Works with lambdas:
1049
- # rule "Execute when item state is changed from an odd number, to an even number, for specified duration" do
1050
- # changed Alarm_Mode, from: -> from { from.odd? }, to: -> to { to.even? }, for: 12.seconds
1099
+ # rule "Execute when item state is changed from an odd number, to an even number" do
1100
+ # changed Alarm_Mode, from: -> from { from.odd? }, to: -> to { to.even? }
1051
1101
  # run { logger.info("Alarm Mode Updated") }
1052
1102
  # end
1053
1103
  #
@@ -1057,6 +1107,22 @@ module OpenHAB
1057
1107
  # run { logger.info("Alarm armed") }
1058
1108
  # end
1059
1109
  #
1110
+ # @example Delay the trigger until the item has been in the same state for 10 seconds
1111
+ # rule "Execute rule when item is changed for specified duration" do
1112
+ # changed Closet_Door, to: CLOSED, for: 10.seconds
1113
+ # run do
1114
+ # Closet_Light.off
1115
+ # end
1116
+ # end
1117
+ #
1118
+ # @example `for` parameter can be a proc that returns a duration:
1119
+ # Alarm_Delay << 20
1120
+ #
1121
+ # rule "Execute rule when item is changed for specified duration" do
1122
+ # changed Alarm_Mode, for: -> { Alarm_Delay.state.to_i.seconds }
1123
+ # run { logger.info("Alarm Mode Updated") }
1124
+ # end
1125
+ #
1060
1126
  # @example Works with Things:
1061
1127
  # rule "Execute rule when thing is changed" do
1062
1128
  # changed things["astro:sun:home"], :from => :online, :to => :uninitialized
@@ -26,8 +26,9 @@ module OpenHAB
26
26
  class << self
27
27
  # get the block's source location, and simplify to a simple filename
28
28
  def infer_rule_id_from_block(block)
29
- file = File.basename(block.source_location.first)
30
- "#{file}:#{block.source_location.last}"
29
+ file = File.basename(block.source_location.first, ".rb")
30
+ file = "script:#{$ctx["ruleUID"]}" if $ctx&.key?("ruleUID") && file == "<script>"
31
+ "#{file}:#{block.source_location.last}".tr(".", "_")
31
32
  end
32
33
 
33
34
  # formulate a readable rule name such as "TestSwitch received command ON" if possible
@@ -47,8 +48,6 @@ module OpenHAB
47
48
  infer_rule_name_from_trigger(*config.ruby_triggers.first)
48
49
  end
49
50
 
50
- private
51
-
52
51
  # formulate a readable rule name from a single trigger if possible
53
52
  def infer_rule_name_from_trigger(trigger, items = nil, kwargs = {})
54
53
  case trigger
@@ -71,6 +70,8 @@ module OpenHAB
71
70
  end
72
71
  end
73
72
 
73
+ private
74
+
74
75
  # formulate a readable rule name from an item-type trigger
75
76
  def infer_rule_name_from_item_trigger(trigger, items, kwargs)
76
77
  kwargs.delete(:command) if kwargs[:command] == [nil]
@@ -85,10 +86,10 @@ module OpenHAB
85
86
 
86
87
  trigger_name = trigger.to_s.tr("_", " ")
87
88
  item_names = items.map do |item|
88
- if item.is_a?(GroupItem::Members)
89
- "#{item.group.name}.members"
90
- else
91
- item.name
89
+ case item
90
+ when GroupItem::Members then "#{item.group.name}.members"
91
+ when Core::Items::Item then item.name
92
+ else item.to_s
92
93
  end
93
94
  end
94
95
  name = "#{format_array(item_names)} #{trigger_name}"
@@ -13,8 +13,10 @@ module OpenHAB
13
13
  # and a setter with any number of arguments or a block.
14
14
  #
15
15
  # @param [String] name of the property
16
+ # @yield Block to call when the property is set
17
+ # @yieldparam [Object] value the value being set
16
18
  #
17
- def prop(name)
19
+ def prop(name, &assignment_block)
18
20
  # rubocop rules are disabled because this method is dynamically defined on the calling
19
21
  # object making calls to other methods in this module impossible, or if done on methods
20
22
  # in this module than instance variable belong to the module not the calling class
@@ -30,6 +32,7 @@ module OpenHAB
30
32
  elsif block
31
33
  instance_variable_set(:"@#{name}", block)
32
34
  end
35
+ assignment_block&.call(instance_variable_get(:"@#{name}"))
33
36
  end
34
37
  end
35
38
  end
@@ -41,9 +41,9 @@ module OpenHAB
41
41
  #
42
42
  # @return [org.openhab.core.automation.Trigger] openHAB trigger
43
43
  #
44
- def append_trigger(type:, config:, attach: nil, conditions: nil)
44
+ def append_trigger(type:, config:, attach: nil, conditions: nil, label: nil)
45
45
  config.transform_keys!(&:to_s)
46
- RuleTriggers.trigger(type: type, config: config).tap do |trigger|
46
+ RuleTriggers.trigger(type: type, config: config, label: label).tap do |trigger|
47
47
  logger.trace("Appending trigger (#{trigger.inspect}) attach (#{attach}) conditions(#{conditions})")
48
48
  @triggers << trigger
49
49
  @attachments[trigger.id] = attach if attach
@@ -56,15 +56,17 @@ module OpenHAB
56
56
  #
57
57
  # @param [String] type of trigger
58
58
  # @param [Map] config map
59
+ # @param [String] label for the trigger
59
60
  #
60
61
  # @return [org.openhab.core.automation.Trigger] configured by type and supplied config
61
62
  #
62
- def self.trigger(type:, config:)
63
+ def self.trigger(type:, config:, label: nil)
63
64
  logger.trace("Creating trigger of type '#{type}' config: #{config}")
64
65
  org.openhab.core.automation.util.TriggerBuilder.create
65
66
  .with_id(uuid)
66
67
  .with_type_uid(type)
67
68
  .with_configuration(Core::Configuration.new(config))
69
+ .with_label(label)
68
70
  .build
69
71
  end
70
72
 
@@ -44,22 +44,27 @@ module OpenHAB
44
44
  # @see BuilderDSL#$1
45
45
  def def_terse_rule(trigger)
46
46
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
47
- def #{trigger}(*args, id: nil, name: nil, description: nil, # def changed(*args, id: nil, name: nil, description: nil,
48
- tag: nil, tags: nil, on_load: false, **kwargs, &block) # tag: nil, tags: nil, on_load: false, **kwargs, &block)
49
- raise ArgumentError, "Block is required" unless block # raise ArgumentError, "Block is required" unless block
50
- #
51
- id ||= NameInference.infer_rule_id_from_block(block) # id ||= NameInference.infer_rule_id_from_block(block)
52
- script = block.source rescue nil # script = block.source rescue nil
53
- caller_binding = block.binding # caller_binding = block.binding
54
- rule name, id: id, script: script, binding: caller_binding do # rule name, id: id, script: script, binding: caller_binding do
55
- self.on_load if on_load # self.on_load if on_load
56
- self.description(description) if description # self.description(description) if description
57
- self.tags(*Array.wrap(tag), *Array.wrap(tags)) # self.tags(*Array.wrap(tag), *Array.wrap(tags))
58
- #{trigger}(*args, **kwargs) # changed(*args, **kwargs)
59
- run(&block) # run(&block)
60
- end # end
61
- end # end
62
- module_function #{trigger.inspect} # module_function :changed
47
+ def #{trigger}(*args, id: nil, name: nil, description: nil, # def changed(*args, id: nil, name: nil, description: nil,
48
+ tag: nil, tags: nil, on_load: false, **kwargs, &block) # tag: nil, tags: nil, on_load: false, **kwargs, &block)
49
+ raise ArgumentError, "Block is required" unless block # raise ArgumentError, "Block is required" unless block
50
+ #
51
+ replace = nil # replace = nil
52
+ unless id # unless id
53
+ replace = false # replace = false
54
+ id = NameInference.infer_rule_id_from_block(block) # id = NameInference.infer_rule_id_from_block(block)
55
+ end # end
56
+ script = block.source rescue nil # script = block.source rescue nil
57
+ caller_binding = block.binding # caller_binding = block.binding
58
+ rule name, id: id, replace: replace, script: script, # rule name, id: id, replace: replace, script: script
59
+ binding: caller_binding do # binding: caller_binding do
60
+ self.on_load if on_load # self.on_load if on_load
61
+ self.description(description) if description # self.description(description) if description
62
+ self.tags(*Array.wrap(tag), *Array.wrap(tags)) # self.tags(*Array.wrap(tag), *Array.wrap(tags))
63
+ #{trigger}(*args, **kwargs) # changed(*args, **kwargs)
64
+ run(&block) # run(&block)
65
+ end # end
66
+ end # end
67
+ module_function #{trigger.inspect} # module_function :changed
63
68
  RUBY
64
69
  end
65
70
  end
@@ -19,18 +19,26 @@ module OpenHAB
19
19
  # @param [Core::Items::Item, Core::Items::GroupItem::Members] item item to create trigger for
20
20
  # @param [Core::Types::State, Symbol, #===, nil] from state to restrict trigger to
21
21
  # @param [Core::Types::State, Symbol, #===, nil] to state to restrict trigger to
22
- # @param [Duration, nil] duration duration to delay trigger until to state is met
22
+ # @param [Duration, Proc, nil] duration duration to delay trigger until to state is met
23
23
  # @param [Object] attach object to be attached to the trigger
24
24
  #
25
25
  # @return [org.openhab.core.automation.Trigger] openHAB triggers
26
26
  #
27
27
  def trigger(item:, from:, to:, duration:, attach:)
28
28
  if duration
29
- item_name = item.respond_to?(:name) ? item.name : item.to_s
30
- logger.trace("Creating Changed Wait Change Trigger for Item(#{item_name}) Duration(#{duration}) " \
31
- "To(#{to}) From(#{from}) Attach(#{attach})")
29
+ if logger.trace?
30
+ item_name = item.respond_to?(:name) ? item.name : item.to_s
31
+ logger.trace("Creating Changed Wait Change Trigger for Item(#{item_name}) Duration(#{duration}) " \
32
+ "To(#{to}) From(#{from}) Attach(#{attach})")
33
+ end
32
34
  conditions = Conditions::Duration.new(to: to, from: from, duration: duration)
33
- changed_trigger(item: item, from: nil, to: nil, attach: attach, conditions: conditions)
35
+ label = NameInference.infer_rule_name_from_trigger(:changed,
36
+ [item],
37
+ from: from,
38
+ to: to,
39
+ duration: duration)
40
+
41
+ changed_trigger(item: item, from: nil, to: nil, attach: attach, conditions: conditions, label: label)
34
42
  else
35
43
  # swap from/to w/ nil if from/to need to be processed in Ruby
36
44
  # rubocop:disable Style/ParallelAssignment
@@ -64,7 +72,7 @@ module OpenHAB
64
72
  # @param [Object] attach object to be attached to the trigger
65
73
  # @return [org.openhab.core.automation.Trigger]
66
74
  #
67
- def changed_trigger(item:, from:, to:, attach: nil, conditions: nil)
75
+ def changed_trigger(item:, from:, to:, attach: nil, conditions: nil, label: nil)
68
76
  type, config = case item
69
77
  when GroupItem::Members
70
78
  group(group: item, from: from, to: to)
@@ -74,7 +82,7 @@ module OpenHAB
74
82
  else
75
83
  item(item: item, from: from, to: to)
76
84
  end
77
- append_trigger(type: type, config: config, attach: attach, conditions: conditions)
85
+ append_trigger(type: type, config: config, attach: attach, conditions: conditions, label: label)
78
86
  end
79
87
 
80
88
  #
@@ -301,7 +301,7 @@ module OpenHAB
301
301
  Core.automation_manager.add_trigger_type(org.openhab.core.automation.type.TriggerType.new(
302
302
  WATCH_TRIGGER_MODULE_ID,
303
303
  nil,
304
- "A path change event is detected",
304
+ "a path change event is detected",
305
305
  "Triggers when a path change event is detected",
306
306
  nil,
307
307
  org.openhab.core.automation.Visibility::VISIBLE,
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of openHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.17.0"
7
+ VERSION = "5.18.1"
8
8
  end
9
9
  end
data/lib/openhab/dsl.rb CHANGED
@@ -56,8 +56,14 @@ module OpenHAB
56
56
  # @!group Rule Creation
57
57
 
58
58
  # (see Rules::Builder#rule)
59
- def rule(name = nil, **kwargs, &block)
60
- rules.build { rule(name, **kwargs, &block) }
59
+ def rule(name = nil, id: nil, **kwargs, &block)
60
+ rules.build { rule(name, id: id, **kwargs, &block) }
61
+ end
62
+
63
+ # Creates a rule that will remove existing rules with the same id, even when the id has been inferred.
64
+ # @see rule
65
+ def rule!(name = nil, id: nil, **kwargs, &block)
66
+ rules.build { rule(name, id: id, replace: true, **kwargs, &block) }
61
67
  end
62
68
 
63
69
  # (see Rules::Builder#scene)
@@ -65,11 +71,27 @@ module OpenHAB
65
71
  rules.build { scene(name, description: description, id: id, tag: tag, tags: tags, **kwargs, &block) }
66
72
  end
67
73
 
74
+ # Creates a scene that will remove existing rules/scenes with the same id, even when the id has been inferred.
75
+ # @see scene
76
+ def scene!(name = nil, description: nil, id: nil, tag: nil, tags: nil, **kwargs, &block)
77
+ rules.build do
78
+ scene(name, description: description, id: id, tag: tag, tags: tags, replace: true, **kwargs, &block)
79
+ end
80
+ end
81
+
68
82
  # (see Rules::Builder#script)
69
83
  def script(name = nil, description: nil, id: nil, tag: nil, tags: nil, **kwargs, &block)
70
84
  rules.build { script(name, description: description, id: id, tag: tag, tags: tags, **kwargs, &block) }
71
85
  end
72
86
 
87
+ # Creates a script that will remove existing rules/scripts with the same id, even when the id has been inferred.
88
+ # @see script
89
+ def script!(name = nil, description: nil, id: nil, tag: nil, tags: nil, **kwargs, &block)
90
+ rules.build do
91
+ script(name, description: description, id: id, tag: tag, tags: tags, replace: true, **kwargs, &block)
92
+ end
93
+ end
94
+
73
95
  # @!group Rule Support
74
96
 
75
97
  # rubocop:disable Layout/LineLength
@@ -7,6 +7,15 @@ module OpenHAB
7
7
  include org.openhab.core.persistence.ModifiablePersistenceService
8
8
  include Singleton
9
9
 
10
+ OPERATOR_TO_SYMBOL = {
11
+ EQ: :==,
12
+ NEQ: :!=,
13
+ GT: :>,
14
+ LT: :<,
15
+ GTE: :>=,
16
+ LTE: :<=
17
+ }.freeze
18
+
10
19
  class HistoricItem
11
20
  include org.openhab.core.persistence.HistoricItem
12
21
 
@@ -134,9 +143,7 @@ module OpenHAB
134
143
 
135
144
  range = first_index...last_index
136
145
 
137
- operator = filter.operator.symbol
138
- operator = "==" if operator == "="
139
-
146
+ operator = OPERATOR_TO_SYMBOL[filter.operator]
140
147
  block = lambda do |i|
141
148
  next if filter.state && !item_history[i].state.send(operator, filter.state)
142
149
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.17.0
4
+ version: 5.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian O'Connell
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-01-30 00:00:00.000000000 Z
13
+ date: 2024-04-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -485,7 +485,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
485
485
  - !ruby/object:Gem::Version
486
486
  version: '0'
487
487
  requirements: []
488
- rubygems_version: 3.5.5
488
+ rubygems_version: 3.5.7
489
489
  signing_key:
490
490
  specification_version: 4
491
491
  summary: JRuby Helper Libraries for openHAB Scripting