openhab-scripting 4.1.4 → 4.5.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/entity_lookup.rb +1 -57
  3. data/lib/openhab/dsl/actions.rb +2 -3
  4. data/lib/openhab/dsl/dsl.rb +8 -12
  5. data/lib/openhab/dsl/group.rb +1 -5
  6. data/lib/openhab/dsl/items/color_item.rb +60 -0
  7. data/lib/openhab/dsl/items/comparable_item.rb +49 -0
  8. data/lib/openhab/dsl/items/contact_item.rb +41 -0
  9. data/lib/openhab/dsl/items/date_time_item.rb +64 -0
  10. data/lib/openhab/dsl/items/dimmer_item.rb +59 -0
  11. data/lib/openhab/dsl/items/ensure.rb +93 -0
  12. data/lib/openhab/dsl/items/generic_item.rb +174 -0
  13. data/lib/openhab/dsl/items/group_item.rb +121 -89
  14. data/lib/openhab/dsl/items/image_item.rb +5 -41
  15. data/lib/openhab/dsl/items/item_equality.rb +36 -0
  16. data/lib/openhab/dsl/items/item_registry.rb +49 -0
  17. data/lib/openhab/dsl/items/items.rb +81 -35
  18. data/lib/openhab/dsl/items/metadata.rb +325 -0
  19. data/lib/openhab/dsl/items/number_item.rb +6 -312
  20. data/lib/openhab/dsl/items/numeric_item.rb +68 -0
  21. data/lib/openhab/dsl/items/persistence.rb +122 -0
  22. data/lib/openhab/dsl/items/player_item.rb +49 -40
  23. data/lib/openhab/dsl/items/rollershutter_item.rb +25 -77
  24. data/lib/openhab/dsl/items/string_item.rb +16 -58
  25. data/lib/openhab/dsl/items/switch_item.rb +62 -0
  26. data/lib/openhab/dsl/lazy_array.rb +8 -6
  27. data/lib/openhab/dsl/monkey_patch/events/events.rb +2 -2
  28. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +67 -24
  29. data/lib/openhab/dsl/monkey_patch/events/item_event.rb +5 -5
  30. data/lib/openhab/dsl/monkey_patch/events/item_state.rb +10 -11
  31. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +10 -11
  32. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +25 -2
  33. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +0 -3
  34. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +24 -24
  35. data/lib/openhab/dsl/rules/terse.rb +24 -0
  36. data/lib/openhab/dsl/states.rb +1 -1
  37. data/lib/openhab/dsl/time_of_day.rb +3 -5
  38. data/lib/openhab/dsl/types/comparable_type.rb +21 -0
  39. data/lib/openhab/dsl/types/date_time_type.rb +334 -0
  40. data/lib/openhab/dsl/types/decimal_type.rb +187 -0
  41. data/lib/openhab/dsl/types/hsb_type.rb +201 -0
  42. data/lib/openhab/dsl/types/increase_decrease_type.rb +23 -0
  43. data/lib/openhab/dsl/types/next_previous_type.rb +23 -0
  44. data/lib/openhab/dsl/types/numeric_type.rb +39 -0
  45. data/lib/openhab/dsl/types/on_off_type.rb +29 -0
  46. data/lib/openhab/dsl/types/open_closed_type.rb +29 -0
  47. data/lib/openhab/dsl/types/percent_type.rb +70 -0
  48. data/lib/openhab/dsl/types/play_pause_type.rb +27 -0
  49. data/lib/openhab/dsl/types/quantity_type.rb +275 -0
  50. data/lib/openhab/dsl/types/refresh_type.rb +18 -0
  51. data/lib/openhab/dsl/types/rewind_fastforward_type.rb +33 -0
  52. data/lib/openhab/dsl/types/stop_move_type.rb +23 -0
  53. data/lib/openhab/dsl/types/string_type.rb +88 -0
  54. data/lib/openhab/dsl/types/type.rb +72 -0
  55. data/lib/openhab/dsl/types/types.rb +78 -0
  56. data/lib/openhab/dsl/types/un_def_type.rb +22 -0
  57. data/lib/openhab/dsl/types/up_down_type.rb +32 -0
  58. data/lib/openhab/dsl/units.rb +11 -6
  59. data/lib/openhab/version.rb +1 -1
  60. data/lib/openhab.rb +0 -1
  61. metadata +36 -28
  62. data/lib/openhab/dsl/items/datetime_item.rb +0 -75
  63. data/lib/openhab/dsl/items/item_command.rb +0 -90
  64. data/lib/openhab/dsl/items/item_delegate.rb +0 -125
  65. data/lib/openhab/dsl/monkey_patch/items/contact_item.rb +0 -51
  66. data/lib/openhab/dsl/monkey_patch/items/dimmer_item.rb +0 -140
  67. data/lib/openhab/dsl/monkey_patch/items/items.rb +0 -142
  68. data/lib/openhab/dsl/monkey_patch/items/metadata.rb +0 -328
  69. data/lib/openhab/dsl/monkey_patch/items/persistence.rb +0 -123
  70. data/lib/openhab/dsl/monkey_patch/items/switch_item.rb +0 -71
  71. data/lib/openhab/dsl/monkey_patch/ruby/range.rb +0 -47
  72. data/lib/openhab/dsl/monkey_patch/ruby/time.rb +0 -32
  73. data/lib/openhab/dsl/monkey_patch/types/decimal_type.rb +0 -97
  74. data/lib/openhab/dsl/monkey_patch/types/increase_decrease_type.rb +0 -23
  75. data/lib/openhab/dsl/monkey_patch/types/next_previous_type.rb +0 -23
  76. data/lib/openhab/dsl/monkey_patch/types/on_off_type.rb +0 -79
  77. data/lib/openhab/dsl/monkey_patch/types/open_closed_type.rb +0 -71
  78. data/lib/openhab/dsl/monkey_patch/types/percent_type.rb +0 -77
  79. data/lib/openhab/dsl/monkey_patch/types/play_pause_type.rb +0 -23
  80. data/lib/openhab/dsl/monkey_patch/types/quantity_type.rb +0 -69
  81. data/lib/openhab/dsl/monkey_patch/types/refresh_type.rb +0 -23
  82. data/lib/openhab/dsl/monkey_patch/types/rewind_fastforward_type.rb +0 -23
  83. data/lib/openhab/dsl/monkey_patch/types/stop_move_type.rb +0 -23
  84. data/lib/openhab/dsl/monkey_patch/types/types.rb +0 -15
  85. data/lib/openhab/dsl/monkey_patch/types/up_down_type.rb +0 -72
  86. data/lib/openhab/dsl/types/datetime.rb +0 -338
  87. data/lib/openhab/dsl/types/quantity.rb +0 -300
@@ -1,52 +1,98 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'java'
4
- require 'singleton'
3
+ require 'openhab/dsl/monkey_patch/events/item_command'
5
4
 
6
- require 'openhab/core/entity_lookup'
7
- require 'openhab/dsl/lazy_array'
5
+ require_relative 'item_registry'
6
+
7
+ require_relative 'generic_item'
8
+
9
+ require_relative 'switch_item'
10
+ require_relative 'date_time_item'
11
+ require_relative 'dimmer_item'
12
+
13
+ require_relative 'color_item'
14
+ require_relative 'contact_item'
15
+ require_relative 'group_item'
16
+ require_relative 'image_item'
17
+ require_relative 'number_item'
18
+ require_relative 'player_item'
19
+ require_relative 'rollershutter_item'
20
+ require_relative 'string_item'
21
+
22
+ require_relative 'ensure'
8
23
 
9
24
  module OpenHAB
10
25
  module DSL
11
- #
12
- # Manages OpenHAB items
13
- #
26
+ # Contains all OpenHAB *Item classes, as well as associated support
27
+ # modules
14
28
  module Items
15
- #
16
- # Delegates to underlying set of all OpenHAB Items, provides convenience methods
17
- #
18
- class Items
19
- include LazyArray
20
- include Singleton
21
-
22
- # Fetches the named item from the the ItemRegistry
23
- # @param [String] name
24
- # @return Item from registry, nil if item missing or requested item is a Group Type
25
- def [](name)
26
- OpenHAB::Core::EntityLookup.lookup_item(name)
27
- rescue Java::OrgOpenhabCoreItems::ItemNotFoundException
28
- nil
29
+ class << self
30
+ private
31
+
32
+ # takes an array of Type java classes and returns
33
+ # all the Enum values, in a flat array
34
+ def values_for_enums(enums)
35
+ enums.map(&:ruby_class)
36
+ .select { |k| k < java.lang.Enum }
37
+ .flat_map(&:values)
29
38
  end
30
39
 
31
- # Returns true if the given item name exists
32
- # @param name [String] Item name to check
33
- # @return [Boolean] true if the item exists, false otherwise
34
- def include?(name)
35
- !$ir.getItems(name).empty? # rubocop: disable Style/GlobalVars
40
+ # define predicates for checking if an item is in one of the Enum states
41
+ def def_predicate_methods(klass)
42
+ values_for_enums(klass.ACCEPTED_DATA_TYPES).each do |state|
43
+ _command_predicate, state_predicate = Types::PREDICATE_ALIASES[state.to_s]
44
+ next if klass.instance_methods.include?(state_predicate)
45
+
46
+ OpenHAB::Core.logger.trace("Defining #{klass}##{state_predicate} for #{state}")
47
+ klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
48
+ def #{state_predicate} # def on?
49
+ raw_state == #{state} # raw_state == ON
50
+ end # end
51
+ RUBY
52
+ end
36
53
  end
37
- alias key? []
38
54
 
39
- # explicit conversion to array
40
- def to_a
41
- items = $ir.items.grep_v(org.openhab.core.items.GroupItem) # rubocop:disable Style/GlobalVars
42
- OpenHAB::Core::EntityLookup.decorate_items(items)
55
+ # defined methods for commanding an item to one of the Enum states
56
+ # as well as predicates for if an ItemCommandEvent is one of those commands
57
+ def def_command_methods(klass) # rubocop:disable Metrics method has single purpose
58
+ values_for_enums(klass.ACCEPTED_COMMAND_TYPES).each do |value|
59
+ command = Types::COMMAND_ALIASES[value.to_s]
60
+ next if klass.instance_methods.include?(command)
61
+
62
+ OpenHAB::Core.logger.trace("Defining #{klass}##{command} for #{value}")
63
+ klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
64
+ def #{command} # def on
65
+ command(#{value}) # command(ON)
66
+ end # end
67
+ RUBY
68
+
69
+ OpenHAB::Core.logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
70
+ GroupItem::GroupMembers.class_eval <<~RUBY, __FILE__, __LINE__ + 1
71
+ def #{command} # def on
72
+ each(&:#{command}) # each(&:on)
73
+ end # end
74
+ RUBY
75
+
76
+ OpenHAB::Core.logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
77
+ MonkeyPatch::Events::ItemCommandEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
78
+ def #{command}? # def refresh?
79
+ command == #{value} # command == REFRESH
80
+ end # end
81
+ RUBY
82
+ end
43
83
  end
44
84
  end
45
85
 
46
- # Fetches all non-group items from the item registry
47
- # @return [OpenHAB::DSL::Items::Items]
48
- def items
49
- Items.instance
86
+ # sort classes by hierarchy so we define methods on parent classes first
87
+ constants.map { |c| const_get(c) }
88
+ .grep(Module)
89
+ .select { |k| k <= GenericItem && k != GroupItem && k != StringItem }
90
+ .sort { |a, b| a < b ? 1 : -1 }
91
+ .each do |klass|
92
+ klass.field_reader :ACCEPTED_COMMAND_TYPES, :ACCEPTED_DATA_TYPES unless klass == GenericItem
93
+
94
+ def_predicate_methods(klass)
95
+ def_command_methods(klass)
50
96
  end
51
97
  end
52
98
  end
@@ -0,0 +1,325 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+ require 'pp'
5
+ require 'forwardable'
6
+ require 'openhab/core/osgi'
7
+ require 'openhab/log/logger'
8
+
9
+ module OpenHAB
10
+ module DSL
11
+ module Items
12
+ #
13
+ # Metadata extension for Items
14
+ #
15
+ module Metadata
16
+ include OpenHAB::Log
17
+
18
+ java_import Java::OrgOpenhabCoreItems::Metadata
19
+ java_import Java::OrgOpenhabCoreItems::MetadataKey
20
+
21
+ #
22
+ # Provide the interface to access namespace's value and configuration
23
+ #
24
+ class MetadataItem < SimpleDelegator
25
+ extend Forwardable
26
+
27
+ def_delegator :@metadata, :value
28
+
29
+ def initialize(metadata: nil, key: nil, value: nil, config: nil)
30
+ @metadata = metadata || Metadata.new(key || MetadataKey.new('', ''), value&.to_s, config)
31
+ super(to_ruby(@metadata&.configuration))
32
+ end
33
+
34
+ #
35
+ # Updates the metadata configuration associated with the key
36
+ #
37
+ def []=(key, value)
38
+ configuration = {}.merge(@metadata&.configuration || {}).merge({ key => value })
39
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, configuration)
40
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
41
+ end
42
+
43
+ #
44
+ # Delete the configuration with the given key
45
+ #
46
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
47
+ #
48
+ def delete(key)
49
+ configuration = {}.merge(@metadata&.configuration || {})
50
+ configuration.delete(key)
51
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, configuration)
52
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
53
+ end
54
+
55
+ #
56
+ # Set the metadata value
57
+ #
58
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
59
+ #
60
+ def value=(value)
61
+ metadata = Metadata.new(@metadata&.uID, value&.to_s, @metadata&.configuration)
62
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
63
+ end
64
+
65
+ #
66
+ # Set the entire configuration to a hash
67
+ #
68
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
69
+ #
70
+ def config=(config)
71
+ raise ArgumentError, 'Configuration must be a hash' unless config.is_a? Hash
72
+
73
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, config)
74
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
75
+ end
76
+ alias configuration= config=
77
+
78
+ #
79
+ # Convert the metadata to an array
80
+ #
81
+ # @return [Array[2]] An array of [value, configuration]
82
+ #
83
+ def to_a
84
+ [@metadata&.value, @metadata&.configuration || {}]
85
+ end
86
+
87
+ private
88
+
89
+ #
90
+ # Recursively convert the supplied Hash object into a Ruby Hash and recreate the keys and values
91
+ #
92
+ # @param [Hash] Hash to convert
93
+ #
94
+ # @return [Hash] The converted hash
95
+ #
96
+ def to_ruby_hash(hash)
97
+ return unless hash.respond_to? :each_with_object
98
+
99
+ hash.each_with_object({}) { |(key, value), ruby_hash| ruby_hash[to_ruby(key)] = to_ruby(value) }
100
+ end
101
+
102
+ #
103
+ # Recursively convert the supplied array to a Ruby array and recreate all String values
104
+ #
105
+ # @param [Object] array to convert
106
+ #
107
+ # @return [Array] The converted array
108
+ #
109
+ def to_ruby_array(array)
110
+ return unless array.respond_to? :each_with_object
111
+
112
+ array.each_with_object([]) { |value, ruby_array| ruby_array << to_ruby(value) }
113
+ end
114
+
115
+ # Convert the given object to Ruby equivalent
116
+ def to_ruby(value)
117
+ case value
118
+ when Hash, Java::JavaUtil::Map then to_ruby_hash(value)
119
+ when Array, Java::JavaUtil::List then to_ruby_array(value)
120
+ when String then String.new(value)
121
+ else value
122
+ end
123
+ end
124
+ end
125
+
126
+ #
127
+ # Provide the interface to access item metadata
128
+ #
129
+ class NamespaceAccessor
130
+ include Enumerable
131
+
132
+ def initialize(item_name:)
133
+ @item_name = item_name
134
+ end
135
+
136
+ #
137
+ # Return the metadata namespace
138
+ #
139
+ # @return [OpenHAB::DSL::Items::MetadataItem], or nil if the namespace doesn't exist
140
+ #
141
+ def [](namespace)
142
+ logger.trace("Getting metadata for item: #{@item_name}, namespace '#{namespace}'")
143
+ metadata = NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))
144
+ MetadataItem.new(metadata: metadata) if metadata
145
+ end
146
+
147
+ #
148
+ # Set the metadata namespace. If the namespace does not exist, it will be created
149
+ #
150
+ # @param value [Object] The assigned value can be a OpenHAB::DSL::Items::MetadataItem,
151
+ # Java::Org::openhab::core::items::Metadata, Array[2] of [value, configuration],
152
+ # A String to set the value and clear the configuration,
153
+ # or a Hash to set the configuration and set the value to nil
154
+ #
155
+ # @return [OpenHAB::DSL::Items::MetadataItem]
156
+ #
157
+ def []=(namespace, value)
158
+ meta_value, configuration = update_from_value(value)
159
+
160
+ key = MetadataKey.new(namespace, @item_name)
161
+ metadata = Metadata.new(key, meta_value&.to_s, configuration)
162
+ # registry.get can be omitted, but registry.update will log a warning for nonexistent metadata
163
+ if NamespaceAccessor.registry.get(key)
164
+ NamespaceAccessor.registry.update(metadata)
165
+ else
166
+ NamespaceAccessor.registry.add(metadata)
167
+ end
168
+ end
169
+
170
+ #
171
+ # Implements Hash#dig-like functionaity to metadata
172
+ #
173
+ # @param [String] key The first key
174
+ # @param [Array<String, Symbol>] keys More keys to dig deeper
175
+ #
176
+ # @return [OpenHAB::DSL::Items::MetadataItem], or nil if the namespace doesn't exist
177
+ #
178
+ def dig(key, *keys)
179
+ keys.empty? ? self[key]&.value : self[key]&.dig(*keys)
180
+ end
181
+
182
+ #
183
+ # Enumerates through all the namespaces
184
+ #
185
+ def each
186
+ return unless block_given?
187
+
188
+ NamespaceAccessor.registry.getAll.each do |meta|
189
+ yield meta.uID.namespace, meta.value, meta.configuration if meta.uID.itemName == @item_name
190
+ end
191
+ end
192
+
193
+ #
194
+ # Remove all the namespaces
195
+ #
196
+ def clear
197
+ NamespaceAccessor.registry.removeItemMetadata @item_name
198
+ end
199
+
200
+ #
201
+ # Delete a specific namespace
202
+ #
203
+ # @param namespace [String] The namespace to delete
204
+ #
205
+ def delete(namespace)
206
+ NamespaceAccessor.registry.remove(MetadataKey.new(namespace, @item_name))
207
+ end
208
+
209
+ alias delete_all clear
210
+
211
+ #
212
+ # @return [Boolean] True if the given namespace exists, false otherwise
213
+ #
214
+ def key?(namespace)
215
+ !NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name)).nil?
216
+ end
217
+
218
+ alias has_key? key?
219
+ alias include? key?
220
+
221
+ #
222
+ # Merge the given hash with the current metadata. Existing namespace that matches the name
223
+ # of the new namespace will be overwritten. Others will be added.
224
+ #
225
+ def merge!(*others)
226
+ return self if others.empty?
227
+
228
+ others.each do |other|
229
+ case other
230
+ when Hash then merge_hash!(other)
231
+ when self.class then merge_metadata!(other)
232
+ else raise ArgumentError, "merge only supports Hash, or another item's metadata"
233
+ end
234
+ end
235
+ self
236
+ end
237
+
238
+ #
239
+ # @return [String] the string representation of all the namespaces with their value and config
240
+ #
241
+ def to_s
242
+ namespaces = []
243
+ each { |ns, value, config| namespaces << "\"#{ns}\"=>[\"#{value}\",#{config}]" }
244
+ "{#{namespaces.join(',')}}"
245
+ end
246
+
247
+ #
248
+ # @return [Java::org::openhab::core::items::MetadataRegistry]
249
+ #
250
+ def self.registry
251
+ @registry ||= OpenHAB::Core::OSGI.service('org.openhab.core.items.MetadataRegistry')
252
+ end
253
+
254
+ private
255
+
256
+ #
257
+ # perform an updated based on the supplied value
258
+ #
259
+ # @param [MetadataItem,Metadata,Array,Hash] value to perform update from
260
+ #
261
+ # @return [Array<Object,Hash>] Array containing the value and configuration based on the
262
+ # the supplied object
263
+ #
264
+ def update_from_value(value)
265
+ case value
266
+ when MetadataItem then [value.value, value.__getobj__]
267
+ when Metadata then [value.value, value.configuration]
268
+ when Array
269
+ raise ArgumentError, 'Array must contain 2 elements: value, config' if value.length != 2
270
+
271
+ value
272
+ when Hash then [nil, value]
273
+ else [value, nil]
274
+ end
275
+ end
276
+
277
+ #
278
+ # Merge the metadata from the supplied other metadata object
279
+ #
280
+ # @param [Hash] other metadata object to merge
281
+ # @yield [key, current_metadata, new_meta] to process merge
282
+ #
283
+ #
284
+ def merge_metadata!(other)
285
+ other.each do |key, new_value, new_config|
286
+ new_meta = new_value, new_config
287
+ if block_given?
288
+ current_meta = self[key]&.to_a
289
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
290
+ end
291
+ self[key] = new_meta
292
+ end
293
+ end
294
+
295
+ #
296
+ # Merge a hash into the metadata
297
+ #
298
+ # @param [Hash] other to merge into metadata
299
+ # @yield [key, current_metadata, new_meta] to process merge
300
+ #
301
+ #
302
+ def merge_hash!(other)
303
+ other.each do |key, new_meta|
304
+ if block_given?
305
+ current_meta = self[key]&.to_a
306
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
307
+ end
308
+ self[key] = new_meta
309
+ end
310
+ end
311
+ end
312
+
313
+ #
314
+ # Accessor to the item's metadata
315
+ #
316
+ # @return [NamespaceAccessor] an Enumerable object to access item's namespaces
317
+ #
318
+ def meta
319
+ @meta ||= NamespaceAccessor.new(item_name: name)
320
+ end
321
+ alias metadata meta
322
+ end
323
+ end
324
+ end
325
+ end