openhab-scripting 4.1.4 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
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