openhab-jrubyscripting 5.0.0.rc5 → 5.0.0.rc6

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/actions.rb +6 -6
  3. data/lib/openhab/core/dependency_tracking.rb +34 -0
  4. data/lib/openhab/core/entity_lookup.rb +132 -78
  5. data/lib/openhab/core/events/item_channel_link.rb +2 -2
  6. data/lib/openhab/core/events/item_command_event.rb +1 -1
  7. data/lib/openhab/core/events/item_event.rb +2 -2
  8. data/lib/openhab/core/events/item_state_changed_event.rb +1 -1
  9. data/lib/openhab/core/events/thing.rb +1 -1
  10. data/lib/openhab/core/items/accepted_data_types.rb +2 -2
  11. data/lib/openhab/core/items/contact_item.rb +1 -1
  12. data/lib/openhab/core/items/dimmer_item.rb +2 -2
  13. data/lib/openhab/core/items/generic_item.rb +45 -224
  14. data/lib/openhab/core/items/group_item.rb +5 -3
  15. data/lib/openhab/core/items/image_item.rb +2 -2
  16. data/lib/openhab/core/items/item.rb +219 -0
  17. data/lib/openhab/core/items/metadata/hash.rb +1 -1
  18. data/lib/openhab/core/items/persistence.rb +4 -5
  19. data/lib/openhab/core/items/provider.rb +2 -2
  20. data/lib/openhab/core/items/proxy.rb +68 -7
  21. data/lib/openhab/core/items/registry.rb +6 -6
  22. data/lib/openhab/core/items/semantics/enumerable.rb +6 -6
  23. data/lib/openhab/core/items/semantics.rb +8 -7
  24. data/lib/openhab/core/items.rb +2 -1
  25. data/lib/openhab/core/provider.rb +14 -7
  26. data/lib/openhab/core/rules/registry.rb +2 -2
  27. data/lib/openhab/core/rules.rb +1 -1
  28. data/lib/openhab/core/script_handling.rb +6 -6
  29. data/lib/openhab/core/things/channel.rb +1 -1
  30. data/lib/openhab/core/things/channel_uid.rb +2 -2
  31. data/lib/openhab/core/things/item_channel_link.rb +2 -2
  32. data/lib/openhab/core/things/links/provider.rb +2 -2
  33. data/lib/openhab/core/things/registry.rb +1 -1
  34. data/lib/openhab/core/things/thing.rb +1 -1
  35. data/lib/openhab/core/types/date_time_type.rb +4 -4
  36. data/lib/openhab/core/types/hsb_type.rb +2 -2
  37. data/lib/openhab/core/types/quantity_type.rb +1 -1
  38. data/lib/openhab/core/types.rb +1 -1
  39. data/lib/openhab/core/uid.rb +1 -1
  40. data/lib/openhab/core/value_cache.rb +188 -0
  41. data/lib/openhab/core.rb +57 -15
  42. data/lib/openhab/core_ext/ruby/symbol.rb +7 -0
  43. data/lib/openhab/dsl/items/builder.rb +17 -10
  44. data/lib/openhab/dsl/items/ensure.rb +5 -5
  45. data/lib/openhab/dsl/items/timed_command.rb +4 -4
  46. data/lib/openhab/dsl/rules/automation_rule.rb +53 -39
  47. data/lib/openhab/dsl/rules/builder.rb +128 -79
  48. data/lib/openhab/dsl/rules/guard.rb +5 -5
  49. data/lib/openhab/dsl/rules/name_inference.rb +20 -1
  50. data/lib/openhab/dsl/rules/rule_triggers.rb +3 -3
  51. data/lib/openhab/dsl/rules/terse.rb +1 -0
  52. data/lib/openhab/dsl/rules/triggers/changed.rb +26 -23
  53. data/lib/openhab/dsl/rules/triggers/command.rb +6 -5
  54. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +2 -2
  55. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +2 -2
  56. data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +6 -6
  57. data/lib/openhab/dsl/rules/triggers/updated.rb +5 -5
  58. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +11 -12
  59. data/lib/openhab/dsl/things/builder.rb +73 -14
  60. data/lib/openhab/dsl/version.rb +2 -2
  61. data/lib/openhab/dsl.rb +43 -17
  62. data/lib/openhab/log.rb +5 -5
  63. data/lib/openhab/rspec/configuration.rb +5 -5
  64. data/lib/openhab/rspec/example_group.rb +1 -1
  65. data/lib/openhab/rspec/helpers.rb +4 -4
  66. data/lib/openhab/rspec/hooks.rb +19 -1
  67. data/lib/openhab/rspec/karaf.rb +12 -19
  68. data/lib/openhab/rspec/suspend_rules.rb +2 -1
  69. data/lib/openhab/yard/base_helper.rb +46 -0
  70. data/lib/openhab/yard/markdown_directive.rb +125 -0
  71. data/lib/openhab/yard/markdown_helper.rb +99 -0
  72. metadata +10 -3
@@ -10,15 +10,9 @@ module OpenHAB
10
10
  #
11
11
  # @see https://www.openhab.org/javadoc/latest/org/openhab/core/items/genericitem
12
12
  #
13
- # @!attribute [r] name
14
- # The item's name.
15
- # @return [String]
16
- #
17
- # @!attribute [r] label
18
- # The item's descriptive label.
19
- # @return [String, nil]
20
- #
21
13
  class GenericItem
14
+ # @!parse include Item
15
+
22
16
  # rubocop:disable Naming/MethodName these mimic Java fields, which are
23
17
  # actually methods
24
18
  class << self
@@ -36,7 +30,10 @@ module OpenHAB
36
30
 
37
31
  # @!visibility private
38
32
  #
39
- # Override to support Proxy
33
+ # Override to support {Proxy}
34
+ #
35
+ # Item.=== isn't actually included (on the Ruby side) into
36
+ # {GenericItem}
40
37
  #
41
38
  def ===(other)
42
39
  other.is_a?(self)
@@ -44,11 +41,13 @@ module OpenHAB
44
41
  end
45
42
  # rubocop:enable Naming/MethodName
46
43
 
47
- # @!attribute [r] accepted_command_types
48
- # @return [Array<Class>] An array of {Command}s that can be sent as commands to this item
44
+ # @!attribute [r] name
45
+ # The item's name.
46
+ # @return [String]
49
47
 
50
- # @!attribute [r] accepted_data_types
51
- # @return [Array<Class>] An array of {State}s that can be sent as commands to this item
48
+ # @!attribute [r] label
49
+ # The item's descriptive label.
50
+ # @return [String, nil]
52
51
 
53
52
  alias_method :hash, :hash_code
54
53
 
@@ -62,6 +61,35 @@ module OpenHAB
62
61
  #
63
62
  alias_method :raw_state, :state
64
63
 
64
+ #
65
+ # Check if the item has a state (not {UNDEF} or {NULL})
66
+ #
67
+ # @return [true, false]
68
+ #
69
+ def state?
70
+ !raw_state.is_a?(Types::UnDefType)
71
+ end
72
+
73
+ #
74
+ # @!attribute [r] state
75
+ # @return [State, nil]
76
+ # openHAB item state if state is not {UNDEF} or {NULL}, nil otherwise.
77
+ # This makes it easy to use with the
78
+ # [Ruby safe navigation operator `&.`](https://ruby-doc.org/core-2.6/doc/syntax/calling_methods_rdoc.html)
79
+ # Use {#undef?} or {#null?} to check for those states.
80
+ #
81
+ def state
82
+ raw_state if state?
83
+ end
84
+
85
+ # @!method null?
86
+ # Check if the item state == {NULL}
87
+ # @return [true,false]
88
+
89
+ # @!method undef?
90
+ # Check if the item state == {UNDEF}
91
+ # @return [true,false]
92
+
65
93
  #
66
94
  # Send a command to this item
67
95
  #
@@ -91,6 +119,10 @@ module OpenHAB
91
119
 
92
120
  # @!parse alias_method :<<, :command
93
121
 
122
+ # @!method refresh
123
+ # Send the {REFRESH} command to the item
124
+ # @return [Item] `self`
125
+
94
126
  #
95
127
  # Send an update to this item
96
128
  #
@@ -105,200 +137,6 @@ module OpenHAB
105
137
  Proxy.new(self)
106
138
  end
107
139
 
108
- #
109
- # Check if the item has a state (not {UNDEF} or {NULL})
110
- #
111
- # @return [true, false]
112
- #
113
- def state?
114
- !raw_state.is_a?(Types::UnDefType)
115
- end
116
-
117
- #
118
- # @!attribute [r] state
119
- # @return [State, nil]
120
- # OpenHAB item state if state is not {UNDEF} or {NULL}, nil otherwise.
121
- # This makes it easy to use with the
122
- # [Ruby safe navigation operator `&.`](https://ruby-doc.org/core-2.6/doc/syntax/calling_methods_rdoc.html)
123
- # Use {#undef?} or {#null?} to check for those states.
124
- #
125
- def state
126
- raw_state if state?
127
- end
128
-
129
- #
130
- # The item's {#label} if one is defined, otherwise it's {#name}.
131
- #
132
- # @return [String]
133
- #
134
- def to_s
135
- label || name
136
- end
137
-
138
- #
139
- # @!attribute [r] groups
140
- #
141
- # Return all groups that this item is part of
142
- #
143
- # @return [Array<Group>] All groups that this item is part of
144
- #
145
- def groups
146
- group_names.map { |name| EntityLookup.lookup_item(name) }.compact
147
- end
148
-
149
- # rubocop:disable Layout/LineLength
150
-
151
- # @!attribute [r] metadata
152
- # @return [Metadata::NamespaceHash]
153
- #
154
- # Access to the item's metadata.
155
- #
156
- # Both the return value of this method as well as the individual
157
- # namespaces can be treated as Hashes.
158
- #
159
- # Examples assume the following items:
160
- #
161
- # ```xtend
162
- # Switch Item1 { namespace1="value" [ config1="foo", config2="bar" ] }
163
- # String StringItem1
164
- # ```
165
- #
166
- # @example Check namespace's existence
167
- # Item1.metadata["namespace"].nil?
168
- # Item1.metadata.key?("namespace")
169
- #
170
- # @example Access item's metadata value
171
- # Item1.metadata["namespace1"].value
172
- #
173
- # @example Access namespace1's configuration
174
- # Item1.metadata["namespace1"]["config1"]
175
- #
176
- # @example Safely search for the specified value - no errors are raised, only nil returned if a key in the chain doesn"t exist
177
- # Item1.metadata.dig("namespace1", "config1") # => "foo"
178
- # Item1.metadata.dig("namespace2", "config1") # => nil
179
- #
180
- # @example Set item's metadata value, preserving its config
181
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
182
- # Item1.metadata["namespace1"].value = "new value"
183
- # # Item1's metadata after: {"namespace1"=>["new value", {"config1"=>"foo", "config2"=>"bar"]}}
184
- #
185
- # @example Set item's metadata config, preserving its value
186
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
187
- # Item1.metadata["namespace1"].replace({ "scooby"=>"doo" })
188
- # # Item1's metadata after: {"namespace1"=>["value", {scooby="doo"}]}
189
- #
190
- # @example Set a namespace to a new value and config in one line
191
- # # Item1's metadata before: {"namespace1"=>"value", {"config1"=>"foo", "config2"=>"bar"}}
192
- # Item1.metadata["namespace1"] = "new value", { "scooby"=>"doo" }
193
- # # Item1's metadata after: {"namespace1"=>["new value", {scooby="doo"}]}
194
- #
195
- # @example Set item's metadata value and clear its previous config
196
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
197
- # Item1.metadata["namespace1"] = "new value"
198
- # # Item1's metadata after: {"namespace1"=>"value" }
199
- #
200
- # @example Set item's metadata config, set its value to nil, and wiping out previous config
201
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
202
- # Item1.metadata["namespace1"] = { "newconfig"=>"value" }
203
- # # Item1's metadata after: {"namespace1"=>{"config1"=>"foo", "config2"=>"bar"}}
204
- #
205
- # @example Update namespace1's specific configuration, preserving its value and other config
206
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
207
- # Item1.metadata["namespace1"]["config1"] = "doo"
208
- # # Item1's metadata will be: {"namespace1"=>["value", {"config1"=>"doo", "config2"=>"bar"}]}
209
- #
210
- # @example Add a new configuration to namespace1
211
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
212
- # Item1.metadata["namespace1"]["config3"] = "boo"
213
- # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar", config3="boo"}]}
214
- #
215
- # @example Delete a config
216
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
217
- # Item1.metadata["namespace1"].delete("config2")
218
- # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo"}]}
219
- #
220
- # @example Add a namespace and set it to a value
221
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
222
- # Item1.metadata["namespace2"] = "qx"
223
- # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace2"=>"qx"}
224
- #
225
- # @example Add a namespace and set it to a value and config
226
- # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
227
- # Item1.metadata["namespace2"] = "qx", { "config1"=>"doo" }
228
- # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace2"=>["qx", {"config1"=>"doo"}]}
229
- #
230
- # @example Enumerate Item1's namespaces
231
- # Item1.metadata.each { |namespace, metadata| logger.info("Item1's namespace: #{namespace}=#{metadata}") }
232
- #
233
- # @example Add metadata from a hash
234
- # Item1.metadata.merge!({"namespace1"=>{"foo", {"config1"=>"baz"} ], "namespace2"=>{"qux", {"config"=>"quu"} ]})
235
- #
236
- # @example Merge Item2's metadata into Item1's metadata
237
- # Item1.metadata.merge!(Item2.metadata)
238
- #
239
- # @example Delete a namespace
240
- # Item1.metadata.delete("namespace1")
241
- #
242
- # @example Delete all metadata of the item
243
- # Item1.metadata.clear
244
- #
245
- # @example Does this item have any metadata?
246
- # Item1.metadata.any?
247
- #
248
- # @example Store another item's state
249
- # StringItem1.update "TEST"
250
- # Item1.metadata["other_state"] = StringItem1.state
251
- #
252
- # @example Store event's state
253
- # rule "save event state" do
254
- # changed StringItem1
255
- # run { |event| Item1.metadata["last_event"] = event.was }
256
- # end
257
- #
258
- # @example If the namespace already exists: Update the value of a namespace but preserve its config; otherwise create a new namespace with the given value and nil config.
259
- # Item1.metadata["namespace"] = "value", Item1.metadata["namespace"]
260
- #
261
- # @example Copy another namespace
262
- # # Item1's metadata before: {"namespace2"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
263
- # Item1.metadata["namespace"] = Item1.metadata["namespace2"]
264
- # # Item1's metadata after: {"namespace2"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
265
- #
266
- def metadata
267
- @metadata ||= Metadata::NamespaceHash.new(name)
268
- end
269
- # rubocop:enable Layout/LineLength
270
-
271
- # Return the item's thing if this item is linked with a thing. If an item is linked to more than one thing,
272
- # this method only returns the first thing.
273
- #
274
- # @return [Thing] The thing associated with this item or nil
275
- def thing
276
- all_linked_things.first
277
- end
278
- alias_method :linked_thing, :thing
279
-
280
- # Returns all of the item's linked things.
281
- #
282
- # @return [Array<Thing>] An array of things or an empty array
283
- def things
284
- registry = OSGi.service("org.openhab.core.thing.link.ItemChannelLinkRegistry")
285
- channels = registry.get_bound_channels(name).to_a
286
- channels.map(&:thing_uid).uniq.map { |tuid| EntityLookup.lookup_thing(tuid) }.compact
287
- end
288
- alias_method :all_linked_things, :things
289
-
290
- # @!method null?
291
- # Check if the item state == {NULL}
292
- # @return [true,false]
293
-
294
- # @!method undef?
295
- # Check if the item state == {UNDEF}
296
- # @return [true,false]
297
-
298
- # @!method refresh
299
- # Send the {REFRESH} command to the item
300
- # @return [GenericItem] `self`
301
-
302
140
  # @!visibility private
303
141
  def format_command(command)
304
142
  command = format_type(command)
@@ -327,23 +165,6 @@ module OpenHAB
327
165
 
328
166
  type.to_s
329
167
  end
330
-
331
- # @return [String]
332
- def inspect
333
- s = "#<OpenHAB::Core::Items::#{type}Item#{type_details} #{name} #{label.inspect} state=#{raw_state.inspect}"
334
- s += " category=#{category.inspect}" if category
335
- s += " tags=#{tags.to_a.inspect}" unless tags.empty?
336
- s += " groups=#{group_names}" unless group_names.empty?
337
- meta = metadata.to_h
338
- s += " metadata=#{meta.inspect}" unless meta.empty?
339
- "#{s}>"
340
- end
341
-
342
- private
343
-
344
- # Allows sub-classes to append additional details to the type in an inspect string
345
- # @return [String]
346
- def type_details; end
347
168
  end
348
169
  end
349
170
  end
@@ -33,7 +33,7 @@ module OpenHAB
33
33
  # ```
34
34
  #
35
35
  # @!attribute [r] base_item
36
- # @return [GenericItem, nil] A typed item if the group has a particular type.
36
+ # @return [Item, nil] A typed item if the group has a particular type.
37
37
  #
38
38
  # @example Operate on items in a group using enumerable methods
39
39
  # logger.info("Total Temperatures: #{Temperatures.members.count}")
@@ -99,7 +99,9 @@ module OpenHAB
99
99
 
100
100
  # @return [String]
101
101
  def inspect
102
- "#<OpenHAB::Core::Items::GroupItems::Members #{name} #{map(&:name).inspect}>"
102
+ r = "#<OpenHAB::Core::Items::GroupItems::Members #{name}"
103
+ r += " #{map(&:name).inspect}>" unless @group.__getobj__.nil?
104
+ "#{r}>"
103
105
  end
104
106
  alias_method :to_s, :inspect
105
107
  end
@@ -120,7 +122,7 @@ module OpenHAB
120
122
  # @see Enumerable
121
123
  #
122
124
  def members
123
- Members.new(self)
125
+ Members.new(Proxy.new(self))
124
126
  end
125
127
 
126
128
  #
@@ -79,12 +79,12 @@ module OpenHAB
79
79
  private
80
80
 
81
81
  #
82
- # Encode image information in the format required by OpenHAB
82
+ # Encode image information in the format required by openHAB
83
83
  #
84
84
  # @param [String] mime_type for image
85
85
  # @param [Object] bytes image data
86
86
  #
87
- # @return [String] OpenHAB image format with image data Base64 encoded
87
+ # @return [String] openHAB image format with image data Base64 encoded
88
88
  #
89
89
  def encode_image(mime_type:, bytes:)
90
90
  "data:#{mime_type};base64,#{Base64.strict_encode64(bytes)}"
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module Items
6
+ # @interface
7
+ java_import org.openhab.core.items.Item
8
+
9
+ #
10
+ # The core features of an openHAB item.
11
+ #
12
+ module Item
13
+ class << self
14
+ # @!visibility private
15
+ #
16
+ # Override to support {Proxy}
17
+ #
18
+ def ===(other)
19
+ other.is_a?(self)
20
+ end
21
+ end
22
+
23
+ # @!attribute [r] name
24
+ # The item's name.
25
+ # @return [String]
26
+
27
+ # @!attribute [r] label
28
+ # The item's descriptive label.
29
+ # @return [String, nil]
30
+
31
+ # @!attribute [r] accepted_command_types
32
+ # @return [Array<Class>] An array of {Command}s that can be sent as commands to this item
33
+
34
+ # @!attribute [r] accepted_data_types
35
+ # @return [Array<Class>] An array of {State}s that can be sent as commands to this item
36
+
37
+ #
38
+ # The item's {#label} if one is defined, otherwise it's {#name}.
39
+ #
40
+ # @return [String]
41
+ #
42
+ def to_s
43
+ label || name
44
+ end
45
+
46
+ #
47
+ # @!attribute [r] groups
48
+ #
49
+ # Return all groups that this item is part of
50
+ #
51
+ # @return [Array<Group>] All groups that this item is part of
52
+ #
53
+ def groups
54
+ group_names.map { |name| EntityLookup.lookup_item(name) }.compact
55
+ end
56
+
57
+ # rubocop:disable Layout/LineLength
58
+
59
+ # @!attribute [r] metadata
60
+ # @return [Metadata::NamespaceHash]
61
+ #
62
+ # Access to the item's metadata.
63
+ #
64
+ # Both the return value of this method as well as the individual
65
+ # namespaces can be treated as Hashes.
66
+ #
67
+ # Examples assume the following items:
68
+ #
69
+ # ```xtend
70
+ # Switch Item1 { namespace1="value" [ config1="foo", config2="bar" ] }
71
+ # String StringItem1
72
+ # ```
73
+ #
74
+ # @example Check namespace's existence
75
+ # Item1.metadata["namespace"].nil?
76
+ # Item1.metadata.key?("namespace")
77
+ #
78
+ # @example Access item's metadata value
79
+ # Item1.metadata["namespace1"].value
80
+ #
81
+ # @example Access namespace1's configuration
82
+ # Item1.metadata["namespace1"]["config1"]
83
+ #
84
+ # @example Safely search for the specified value - no errors are raised, only nil returned if a key in the chain doesn"t exist
85
+ # Item1.metadata.dig("namespace1", "config1") # => "foo"
86
+ # Item1.metadata.dig("namespace2", "config1") # => nil
87
+ #
88
+ # @example Set item's metadata value, preserving its config
89
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
90
+ # Item1.metadata["namespace1"].value = "new value"
91
+ # # Item1's metadata after: {"namespace1"=>["new value", {"config1"=>"foo", "config2"=>"bar"]}}
92
+ #
93
+ # @example Set item's metadata config, preserving its value
94
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
95
+ # Item1.metadata["namespace1"].replace({ "scooby"=>"doo" })
96
+ # # Item1's metadata after: {"namespace1"=>["value", {scooby="doo"}]}
97
+ #
98
+ # @example Set a namespace to a new value and config in one line
99
+ # # Item1's metadata before: {"namespace1"=>"value", {"config1"=>"foo", "config2"=>"bar"}}
100
+ # Item1.metadata["namespace1"] = "new value", { "scooby"=>"doo" }
101
+ # # Item1's metadata after: {"namespace1"=>["new value", {scooby="doo"}]}
102
+ #
103
+ # @example Set item's metadata value and clear its previous config
104
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
105
+ # Item1.metadata["namespace1"] = "new value"
106
+ # # Item1's metadata after: {"namespace1"=>"value" }
107
+ #
108
+ # @example Set item's metadata config, set its value to nil, and wiping out previous config
109
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
110
+ # Item1.metadata["namespace1"] = { "newconfig"=>"value" }
111
+ # # Item1's metadata after: {"namespace1"=>{"config1"=>"foo", "config2"=>"bar"}}
112
+ #
113
+ # @example Update namespace1's specific configuration, preserving its value and other config
114
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
115
+ # Item1.metadata["namespace1"]["config1"] = "doo"
116
+ # # Item1's metadata will be: {"namespace1"=>["value", {"config1"=>"doo", "config2"=>"bar"}]}
117
+ #
118
+ # @example Add a new configuration to namespace1
119
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
120
+ # Item1.metadata["namespace1"]["config3"] = "boo"
121
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar", config3="boo"}]}
122
+ #
123
+ # @example Delete a config
124
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
125
+ # Item1.metadata["namespace1"].delete("config2")
126
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo"}]}
127
+ #
128
+ # @example Add a namespace and set it to a value
129
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
130
+ # Item1.metadata["namespace2"] = "qx"
131
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace2"=>"qx"}
132
+ #
133
+ # @example Add a namespace and set it to a value and config
134
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
135
+ # Item1.metadata["namespace2"] = "qx", { "config1"=>"doo" }
136
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace2"=>["qx", {"config1"=>"doo"}]}
137
+ #
138
+ # @example Enumerate Item1's namespaces
139
+ # Item1.metadata.each { |namespace, metadata| logger.info("Item1's namespace: #{namespace}=#{metadata}") }
140
+ #
141
+ # @example Add metadata from a hash
142
+ # Item1.metadata.merge!({"namespace1"=>{"foo", {"config1"=>"baz"} ], "namespace2"=>{"qux", {"config"=>"quu"} ]})
143
+ #
144
+ # @example Merge Item2's metadata into Item1's metadata
145
+ # Item1.metadata.merge!(Item2.metadata)
146
+ #
147
+ # @example Delete a namespace
148
+ # Item1.metadata.delete("namespace1")
149
+ #
150
+ # @example Delete all metadata of the item
151
+ # Item1.metadata.clear
152
+ #
153
+ # @example Does this item have any metadata?
154
+ # Item1.metadata.any?
155
+ #
156
+ # @example Store another item's state
157
+ # StringItem1.update "TEST"
158
+ # Item1.metadata["other_state"] = StringItem1.state
159
+ #
160
+ # @example Store event's state
161
+ # rule "save event state" do
162
+ # changed StringItem1
163
+ # run { |event| Item1.metadata["last_event"] = event.was }
164
+ # end
165
+ #
166
+ # @example If the namespace already exists: Update the value of a namespace but preserve its config; otherwise create a new namespace with the given value and nil config.
167
+ # Item1.metadata["namespace"] = "value", Item1.metadata["namespace"]
168
+ #
169
+ # @example Copy another namespace
170
+ # # Item1's metadata before: {"namespace2"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
171
+ # Item1.metadata["namespace"] = Item1.metadata["namespace2"]
172
+ # # Item1's metadata after: {"namespace2"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
173
+ #
174
+ def metadata
175
+ @metadata ||= Metadata::NamespaceHash.new(name)
176
+ end
177
+ # rubocop:enable Layout/LineLength
178
+
179
+ # Return the item's thing if this item is linked with a thing. If an item is linked to more than one thing,
180
+ # this method only returns the first thing.
181
+ #
182
+ # @return [Thing] The thing associated with this item or nil
183
+ def thing
184
+ all_linked_things.first
185
+ end
186
+ alias_method :linked_thing, :thing
187
+
188
+ # Returns all of the item's linked things.
189
+ #
190
+ # @return [Array<Thing>] An array of things or an empty array
191
+ def things
192
+ registry = OSGi.service("org.openhab.core.thing.link.ItemChannelLinkRegistry")
193
+ channels = registry.get_bound_channels(name).to_a
194
+ channels.map(&:thing_uid).uniq.map { |tuid| EntityLookup.lookup_thing(tuid) }.compact
195
+ end
196
+ alias_method :all_linked_things, :things
197
+
198
+ # @return [String]
199
+ def inspect
200
+ s = "#<OpenHAB::Core::Items::#{type}Item#{type_details} #{name} #{label.inspect} state=#{raw_state.inspect}"
201
+ s += " category=#{category.inspect}" if category
202
+ s += " tags=#{tags.to_a.inspect}" unless tags.empty?
203
+ s += " groups=#{group_names}" unless group_names.empty?
204
+ meta = metadata.to_h
205
+ s += " metadata=#{meta.inspect}" unless meta.empty?
206
+ "#{s}>"
207
+ end
208
+
209
+ private
210
+
211
+ # Allows sub-classes to append additional details to the type in an inspect string
212
+ # @return [String]
213
+ def type_details; end
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ # @!parse Item = OpenHAB::Core::Items::Item
@@ -111,7 +111,7 @@ module OpenHAB
111
111
  end
112
112
 
113
113
  # @!attribute [r] item
114
- # @return [GenericItem, nil] The item this namespace is attached to.
114
+ # @return [Item, nil] The item this namespace is attached to.
115
115
  def item
116
116
  return nil unless attached?
117
117
 
@@ -9,7 +9,7 @@ module OpenHAB
9
9
  module Items
10
10
  #
11
11
  # Items extensions to support
12
- # {https://www.openhab.org/docs/configuration/persistence.html OpenHAB's Persistence} feature.
12
+ # {https://www.openhab.org/docs/configuration/persistence.html openHAB's Persistence} feature.
13
13
  #
14
14
  # @see OpenHAB::DSL.persistence Persistence Block
15
15
  #
@@ -87,7 +87,7 @@ module OpenHAB
87
87
  # @!method last_update(service = nil)
88
88
  # Return the time the item was last updated.
89
89
  # @param [Symbol, String] service An optional persistence id instead of the default persistence service.
90
- # @return [ZonedDateTime] The timestamp of the last update
90
+ # @return [ZonedDateTime, nil] The timestamp of the last update
91
91
 
92
92
  # @!method average_since(timestamp, service = nil)
93
93
  # Return the average value of the item's state since the given time
@@ -255,7 +255,7 @@ module OpenHAB
255
255
  def previous_state(service = nil, skip_equal: false)
256
256
  service ||= persistence_service
257
257
  result = Actions::PersistenceExtensions.previous_state(self, skip_equal, service&.to_s)
258
- HistoricState.new(quantify(result.state), result)
258
+ HistoricState.new(quantify(result.state), result) if result
259
259
  end
260
260
 
261
261
  PERSISTENCE_METHODS.each do |method|
@@ -317,8 +317,7 @@ module OpenHAB
317
317
  #
318
318
  def wrap_result(result, method)
319
319
  if result.is_a?(org.openhab.core.persistence.HistoricItem)
320
- return HistoricState.new(quantify(result.state),
321
- result)
320
+ return HistoricState.new(quantify(result.state), result)
322
321
  end
323
322
  return quantify(result) if QUANTITY_METHODS.include?(method)
324
323
 
@@ -4,7 +4,7 @@ module OpenHAB
4
4
  module Core
5
5
  module Items
6
6
  #
7
- # Provides {GenericItem Items} created in Ruby to openHAB
7
+ # Provides {Item Items} created in Ruby to openHAB
8
8
  #
9
9
  class Provider < Core::Provider
10
10
  include org.openhab.core.items.ItemProvider
@@ -25,7 +25,7 @@ module OpenHAB
25
25
  #
26
26
  # @param [String] item_name
27
27
  # @param [true, false] recursive
28
- # @return [GenericItem, nil] The removed item, if found.
28
+ # @return [Item, nil] The removed item, if found.
29
29
  #
30
30
  def remove(item_name, recursive = false) # rubocop:disable Style/OptionalBooleanParameter matches Java method
31
31
  return nil unless @elements.key?(item_name)