openhab-scripting 2.14.0 → 2.16.0

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab.rb +3 -0
  3. data/lib/openhab/core/dsl.rb +4 -0
  4. data/lib/openhab/core/dsl/actions.rb +1 -1
  5. data/lib/openhab/core/dsl/entities.rb +41 -4
  6. data/lib/openhab/core/dsl/gems.rb +1 -1
  7. data/lib/openhab/core/dsl/group.rb +3 -1
  8. data/lib/openhab/core/dsl/items/items.rb +3 -1
  9. data/lib/openhab/core/dsl/items/number_item.rb +158 -52
  10. data/lib/openhab/core/dsl/items/string_item.rb +23 -3
  11. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +20 -5
  12. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +2 -0
  13. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +66 -42
  14. data/lib/openhab/core/dsl/monkey_patch/items/persistence.rb +72 -0
  15. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +2 -1
  16. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +2 -1
  17. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +2 -0
  18. data/lib/openhab/core/dsl/monkey_patch/ruby/string.rb +43 -0
  19. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +41 -5
  20. data/lib/openhab/core/dsl/monkey_patch/types/quantity_type.rb +58 -0
  21. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +1 -0
  22. data/lib/openhab/core/dsl/persistence.rb +27 -0
  23. data/lib/openhab/core/dsl/property.rb +15 -4
  24. data/lib/openhab/core/dsl/rule/automation_rule.rb +348 -0
  25. data/lib/openhab/core/dsl/rule/guard.rb +43 -6
  26. data/lib/openhab/core/dsl/rule/rule.rb +80 -367
  27. data/lib/openhab/core/dsl/rule/rule_config.rb +153 -0
  28. data/lib/openhab/core/dsl/rule/triggers/changed.rb +145 -0
  29. data/lib/openhab/core/dsl/rule/{channel.rb → triggers/channel.rb} +22 -8
  30. data/lib/openhab/core/dsl/rule/triggers/command.rb +106 -0
  31. data/lib/openhab/core/dsl/rule/{cron.rb → triggers/cron.rb} +36 -14
  32. data/lib/openhab/core/dsl/rule/triggers/trigger.rb +126 -0
  33. data/lib/openhab/core/dsl/rule/triggers/updated.rb +100 -0
  34. data/lib/openhab/core/dsl/time_of_day.rb +50 -24
  35. data/lib/openhab/core/dsl/timers.rb +2 -6
  36. data/lib/openhab/core/dsl/types/quantity.rb +106 -69
  37. data/lib/openhab/core/log.rb +3 -8
  38. data/lib/openhab/core/startup_delay.rb +1 -0
  39. data/lib/openhab/osgi.rb +7 -0
  40. data/lib/openhab/version.rb +1 -1
  41. metadata +14 -6
  42. data/lib/openhab/core/dsl/rule/item.rb +0 -203
  43. data/lib/openhab/core/dsl/rule/triggers.rb +0 -77
@@ -15,6 +15,7 @@ module OpenHAB
15
15
  extend Forwardable
16
16
  include Comparable
17
17
 
18
+ # @return [Regex] Regular expression matching blank strings
18
19
  BLANK_RE = /\A[[:space:]]*\z/.freeze
19
20
  private_constant :BLANK_RE
20
21
 
@@ -33,7 +34,8 @@ module OpenHAB
33
34
  #
34
35
  # Convert the StringItem into a String
35
36
  #
36
- # @return [String] String representation of the StringItem or nil if underlying OpenHAB StringItem does not have a state
37
+ # @return [String] String representation of the StringItem or
38
+ # nil if underlying OpenHAB StringItem does not have a state
37
39
  #
38
40
  def to_str
39
41
  @string_item.state&.to_full_string&.to_s
@@ -64,7 +66,8 @@ module OpenHAB
64
66
  #
65
67
  # @param [Object] other object to compare to
66
68
  #
67
- # @return [Integer] -1,0,1 or nil depending on value supplied, nil comparison to supplied object is not possible.
69
+ # @return [Integer] -1,0,1 or nil depending on value supplied,
70
+ # nil comparison to supplied object is not possible.
68
71
  #
69
72
  def <=>(other)
70
73
  case other
@@ -72,6 +75,8 @@ module OpenHAB
72
75
  @string_item.state <=> other.state
73
76
  when String
74
77
  @string_item.state.to_s <=> other
78
+ else
79
+ @string_item.state <=> other
75
80
  end
76
81
  end
77
82
 
@@ -87,7 +92,7 @@ module OpenHAB
87
92
  def method_missing(meth, *args, &block)
88
93
  if @string_item.respond_to?(meth)
89
94
  @string_item.__send__(meth, *args, &block)
90
- elsif @string_item.state? && @string_item.state.to_full_string.to_s.respond_to?(meth)
95
+ elsif @string_item.state&.to_full_string&.to_s.respond_to?(meth)
91
96
  @string_item.state.to_full_string.to_s.__send__(meth, *args, &block)
92
97
  elsif ::Kernel.method_defined?(meth) || ::Kernel.private_method_defined?(meth)
93
98
  ::Kernel.instance_method(meth).bind_call(self, *args, &block)
@@ -95,6 +100,21 @@ module OpenHAB
95
100
  super(meth, *args, &block)
96
101
  end
97
102
  end
103
+
104
+ #
105
+ # Checks if this method responds to the missing method
106
+ #
107
+ # @param [String] method_name Name of the method to check
108
+ # @param [Boolean] _include_private boolean if private methods should be checked
109
+ #
110
+ # @return [Boolean] true if this object will respond to the supplied method, false otherwise
111
+ #
112
+ def respond_to_missing?(method_name, _include_private = false)
113
+ @string_item.respond_to?(method_name) ||
114
+ @string_item.state&.to_full_string&.to_s.respond_to?(method_name) ||
115
+ ::Kernel.method_defined?(method_name) ||
116
+ ::Kernel.private_method_defined?(method_name)
117
+ end
98
118
  end
99
119
  end
100
120
  end
@@ -96,12 +96,27 @@ class Java::OrgOpenhabCoreLibraryItems::DimmerItem
96
96
  def <=>(other)
97
97
  logger.trace("Comparing #{self} to #{other}")
98
98
  case other
99
- when DimmerItem, NumberItem
100
- state <=> other.state
101
- when DecimalType
102
- state <=> other
99
+ when Java::OrgOpenhabCoreItems::GenericItem, NumberItem then state <=> other.state
100
+ when DecimalType then state <=> other
101
+ when Numeric then state.to_big_decimal.to_d <=> other.to_d
102
+ else compare_to(other)
103
+ end
104
+ end
105
+
106
+ #
107
+ # Coerce objects into a DimmerItem
108
+ #
109
+ # @param [Object] other object to coerce to a DimmerItem if possible
110
+ #
111
+ # @return [Object] Numeric when applicable
112
+ #
113
+ def coerce(other)
114
+ logger.trace("Coercing #{self} as a request from #{other.class}")
115
+ case other
116
+ when Numeric
117
+ [other, state.to_big_decimal.to_d]
103
118
  else
104
- to_i <=> other.to_i
119
+ [other, state]
105
120
  end
106
121
  end
107
122
 
@@ -6,6 +6,7 @@ require 'bigdecimal'
6
6
 
7
7
  # Monkey patch items
8
8
  require 'openhab/core/dsl/monkey_patch/items/metadata'
9
+ require 'openhab/core/dsl/monkey_patch/items/persistence'
9
10
  require 'openhab/core/dsl/monkey_patch/items/contact_item'
10
11
  require 'openhab/core/dsl/monkey_patch/items/dimmer_item'
11
12
  require 'openhab/core/dsl/monkey_patch/items/switch_item'
@@ -127,4 +128,5 @@ class Java::OrgOpenhabCoreItems::GenericItem
127
128
  # rubocop:enable Style/ClassAndModuleChildren
128
129
  prepend OpenHAB::Core::DSL::MonkeyPatch::Items::ItemExtensions
129
130
  prepend OpenHAB::Core::DSL::MonkeyPatch::Items::Metadata
131
+ prepend OpenHAB::Core::DSL::MonkeyPatch::Items::Persistence
130
132
  end
@@ -123,25 +123,7 @@ module OpenHAB
123
123
  # @return [OpenHAB::Core::DSL::MonkeyPatch::Items::MetadataItem]
124
124
  #
125
125
  def []=(namespace, value)
126
- case value
127
- when MetadataItem
128
- meta_value = value.value
129
- configuration = value.__getobj__
130
- when Metadata
131
- meta_value = value.value
132
- configuration = value.configuration
133
- when Array
134
- raise ArgumentError, 'Array must contain 2 elements: value, config' if value.length < 2
135
-
136
- meta_value = value[0]
137
- configuration = value[1]
138
- when Hash
139
- meta_value = nil
140
- configuration = value
141
- else
142
- meta_value = value
143
- configuration = nil
144
- end
126
+ meta_value, configuration = update_from_value(value)
145
127
 
146
128
  key = MetadataKey.new(namespace, @item_name)
147
129
  metadata = Metadata.new(key, meta_value, configuration)
@@ -185,12 +167,12 @@ module OpenHAB
185
167
  #
186
168
  # @return [Boolean] True if the given namespace exists, false otherwise
187
169
  #
188
- def has_key?(namespace)
170
+ def key?(namespace)
189
171
  !NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name)).nil?
190
172
  end
191
173
 
192
- alias key? has_key?
193
- alias include? has_key?
174
+ alias has_key? key?
175
+ alias include? key?
194
176
 
195
177
  #
196
178
  # Merge the given hash with the current metadata. Existing namespace that matches the name
@@ -201,25 +183,9 @@ module OpenHAB
201
183
 
202
184
  others.each do |other|
203
185
  case other
204
- when Hash
205
- other.each do |key, new_meta|
206
- if block_given?
207
- current_meta = self[key]&.to_a
208
- new_meta = yield key, current_meta, new_meta unless current_meta.nil?
209
- end
210
- self[key] = new_meta
211
- end
212
- when self.class
213
- other.each do |key, new_value, new_config|
214
- new_meta = new_value, new_config
215
- if block_given?
216
- current_meta = self[key]&.to_a
217
- new_meta = yield key, current_meta, new_meta unless current_meta.nil?
218
- end
219
- self[key] = new_meta
220
- end
221
- else
222
- raise ArgumentError, "merge only supports Hash, or another item's metadata"
186
+ when Hash then merge_hash!(other)
187
+ when self.class then merge_metadata!(other)
188
+ else raise ArgumentError, "merge only supports Hash, or another item's metadata"
223
189
  end
224
190
  end
225
191
  self
@@ -238,7 +204,65 @@ module OpenHAB
238
204
  # @return [Java::org::openhab::core::items::MetadataRegistry]
239
205
  #
240
206
  def self.registry
241
- @@registry ||= OpenHAB::OSGI.service('org.openhab.core.items.MetadataRegistry')
207
+ @registry ||= OpenHAB::OSGI.service('org.openhab.core.items.MetadataRegistry')
208
+ end
209
+
210
+ private
211
+
212
+ #
213
+ # perform an updated based on the supplied value
214
+ #
215
+ # @param [MetadataItem,Metadata,Array,Hash] value to perform update from
216
+ #
217
+ # @return [Array<Object,Hash>] Array containing the value and configuration based on the
218
+ # the supplied object
219
+ #
220
+ def update_from_value(value)
221
+ case value
222
+ when MetadataItem then [value.value, value.__getobj__]
223
+ when Metadata then [value.value, value.configuration]
224
+ when Array
225
+ raise ArgumentError, 'Array must contain 2 elements: value, config' if value.length != 2
226
+
227
+ value
228
+ when Hash then [nil, value]
229
+ else [value, nil]
230
+ end
231
+ end
232
+
233
+ #
234
+ # Merge the metadata from the supplied other metadata object
235
+ #
236
+ # @param [Hash] other metadata object to merge
237
+ # @yield [key, current_metadata, new_meta] to process merge
238
+ #
239
+ #
240
+ def merge_metadata!(other)
241
+ other.each do |key, new_value, new_config|
242
+ new_meta = new_value, new_config
243
+ if block_given?
244
+ current_meta = self[key]&.to_a
245
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
246
+ end
247
+ self[key] = new_meta
248
+ end
249
+ end
250
+
251
+ #
252
+ # Merge a hash into the metadata
253
+ #
254
+ # @param [Hash] other to merge into metadata
255
+ # @yield [key, current_metadata, new_meta] to process merge
256
+ #
257
+ #
258
+ def merge_hash!(other)
259
+ other.each do |key, new_meta|
260
+ if block_given?
261
+ current_meta = self[key]&.to_a
262
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
263
+ end
264
+ self[key] = new_meta
265
+ end
242
266
  end
243
267
  end
244
268
 
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module DSL
6
+ module MonkeyPatch
7
+ module Items
8
+ #
9
+ # Persistence extension for Items
10
+ #
11
+ module Persistence
12
+ %w[persist last_update].each do |method|
13
+ define_method(method) do |service = nil|
14
+ service ||= persistence_service
15
+ PersistenceExtensions.public_send(method, self, service&.to_s)
16
+ end
17
+ end
18
+
19
+ #
20
+ # Return the previous state of the item
21
+ #
22
+ # @param skip_equal [Boolean] if true, skips equal state values and
23
+ # searches the first state not equal the current state
24
+ # @param service [String] the name of the PersistenceService to use
25
+ #
26
+ # @return the previous state or nil if no previous state could be found,
27
+ # or if the default persistence service is not configured or
28
+ # does not refer to a valid service
29
+ #
30
+ def previous_state(service = nil, skip_equal: false)
31
+ service ||= persistence_service
32
+ PersistenceExtensions.previous_state(self, skip_equal, service&.to_s)
33
+ end
34
+
35
+ %w[
36
+ average_since
37
+ changed_since
38
+ delta_since
39
+ deviation_since
40
+ evolution_rate
41
+ historic_state
42
+ maximum_since
43
+ minimum_since
44
+ sum_since
45
+ updated_since
46
+ variance_since
47
+ ].each do |method|
48
+ define_method(method) do |timestamp, service = nil|
49
+ service ||= persistence_service
50
+ if timestamp.is_a? Java::JavaTimeTemporal::TemporalAmount
51
+ timestamp = Java::JavaTime::ZonedDateTime.now.minus(timestamp)
52
+ end
53
+ PersistenceExtensions.public_send(method, self, timestamp, service&.to_s)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ #
60
+ # Get the specified persistence service from the current thread local variable
61
+ #
62
+ # @return [Object] Persistence service name as String or Symbol, or nil if not set
63
+ #
64
+ def persistence_service
65
+ Thread.current.thread_variable_get(:persistence_service)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -74,7 +74,8 @@ class Java::OrgOpenhabCoreLibraryItems::SwitchItem
74
74
  #
75
75
  # @param [Object] other object to compare to
76
76
  #
77
- # @return [Boolean] True if other is a OnOffType and other equals state for this switch item, otherwise result from super
77
+ # @return [Boolean] True if other is a OnOffType and other equals state for this switch item,
78
+ # otherwise result from super
78
79
  #
79
80
  def ==(other)
80
81
  if other.is_a? OnOffType
@@ -24,7 +24,8 @@ module OpenHAB
24
24
  #
25
25
  # @param [Object] other object to compare for case equals
26
26
  #
27
- # @return [Boolean] if other is DimmerItem and state is covered by range, result from parent Range class if not DimmerItem
27
+ # @return [Boolean] if other is DimmerItem and state is covered by range,
28
+ # result from parent Range class if not DimmerItem
28
29
  #
29
30
  def ===(other)
30
31
  return super unless other.is_a? DimmerItem
@@ -3,3 +3,5 @@
3
3
  # Monkey patch ruby
4
4
  require 'openhab/core/dsl/monkey_patch/ruby/range'
5
5
  require 'openhab/core/dsl/monkey_patch/ruby/number'
6
+ require 'openhab/core/dsl/monkey_patch/ruby/string'
7
+ require 'bigdecimal/util'
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/core/dsl/types/quantity'
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module DSL
8
+ module MonkeyPatch
9
+ module Ruby
10
+ #
11
+ # Extend String class
12
+ #
13
+ module StringExtensions
14
+ include OpenHAB::Core
15
+
16
+ #
17
+ # Compares String to another object
18
+ #
19
+ # @param [Object] other object to compare to
20
+ #
21
+ # @return [Boolean] true if the two objects contain the same value, false otherwise
22
+ #
23
+ def ==(other)
24
+ case other
25
+ when OpenHAB::Core::DSL::Types::Quantity, QuantityType
26
+ other == self
27
+ else
28
+ super
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ #
39
+ # Prepend String class with comparison extensions
40
+ #
41
+ class String
42
+ prepend OpenHAB::Core::DSL::MonkeyPatch::Ruby::StringExtensions
43
+ end
@@ -10,15 +10,51 @@ class Java::OrgOpenhabCoreLibraryTypes::DecimalType
10
10
  # rubocop:enable Style/ClassAndModuleChildren
11
11
 
12
12
  #
13
- # Compare self to other using Java BigDecimal compare method
13
+ # Compare DecimalType to supplied object
14
14
  #
15
15
  # @param [Object] other object to compare to
16
16
  #
17
- # @return [Boolean] True if have the same BigDecimal representation, false otherwise
17
+ # @return [Integer] -1,0,1 or nil depending on value supplied, nil comparison to supplied object is not possible.
18
18
  #
19
- def ==(other)
20
- return equals(other) unless other.is_a? Integer
19
+ def <=>(other)
20
+ logger.trace("#{self.class} #{self} <=> #{other} (#{other.class})")
21
+ case other
22
+ when Numeric
23
+ to_big_decimal.compare_to(other.to_d)
24
+ when Java::OrgOpenhabCoreTypes::UnDefType
25
+ 1
26
+ else
27
+ other = other.state if other.respond_to? :state
28
+ compare_to(other)
29
+ end
30
+ end
31
+
32
+ #
33
+ # Coerce objects into a DecimalType
34
+ #
35
+ # @param [Object] other object to coerce to a DecimalType if possible
36
+ #
37
+ # @return [Object] Numeric when applicable
38
+ #
39
+ def coerce(other)
40
+ logger.trace("Coercing #{self} as a request from #{other.class}")
41
+ case other
42
+ when Numeric
43
+ [other.to_d, to_big_decimal]
44
+ else
45
+ [other, self]
46
+ end
47
+ end
21
48
 
22
- to_big_decimal.compare_to(Java::JavaMath::BigDecimal.new(other)).zero?
49
+ #
50
+ # Compare self to other through the spaceship operator
51
+ #
52
+ # @param [Object] other object to compare to
53
+ #
54
+ # @return [Boolean] True if equals
55
+ #
56
+ def ==(other)
57
+ logger.trace("#{self.class} #{self} == #{other} (#{other.class})")
58
+ (self <=> other).zero?
23
59
  end
24
60
  end