openhab-scripting 5.17.0 → 5.18.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 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