openhab-scripting 2.16.2 → 2.19.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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab.rb +12 -16
  3. data/lib/openhab/core/entity_lookup.rb +173 -0
  4. data/lib/openhab/core/openhab_setup.rb +31 -0
  5. data/lib/openhab/core/osgi.rb +61 -0
  6. data/lib/openhab/dsl/actions.rb +105 -0
  7. data/lib/openhab/dsl/dsl.rb +49 -0
  8. data/lib/openhab/{core/dsl → dsl}/gems.rb +0 -1
  9. data/lib/openhab/dsl/group.rb +100 -0
  10. data/lib/openhab/dsl/items/datetime_item.rb +97 -0
  11. data/lib/openhab/dsl/items/items.rb +46 -0
  12. data/lib/openhab/dsl/items/number_item.rb +352 -0
  13. data/lib/openhab/dsl/items/rollershutter_item.rb +179 -0
  14. data/lib/openhab/dsl/items/string_item.rb +120 -0
  15. data/lib/openhab/dsl/monkey_patch/actions/actions.rb +4 -0
  16. data/lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb +32 -0
  17. data/lib/openhab/dsl/monkey_patch/events/events.rb +5 -0
  18. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +23 -0
  19. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +35 -0
  20. data/lib/openhab/dsl/monkey_patch/events/thing_status_info.rb +33 -0
  21. data/lib/openhab/dsl/monkey_patch/items/contact_item.rb +61 -0
  22. data/lib/openhab/dsl/monkey_patch/items/dimmer_item.rb +193 -0
  23. data/lib/openhab/dsl/monkey_patch/items/group_item.rb +37 -0
  24. data/lib/openhab/dsl/monkey_patch/items/items.rb +133 -0
  25. data/lib/openhab/dsl/monkey_patch/items/metadata.rb +281 -0
  26. data/lib/openhab/dsl/monkey_patch/items/persistence.rb +70 -0
  27. data/lib/openhab/dsl/monkey_patch/items/switch_item.rb +95 -0
  28. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +39 -0
  29. data/lib/openhab/dsl/monkey_patch/ruby/range.rb +47 -0
  30. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +8 -0
  31. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +41 -0
  32. data/lib/openhab/dsl/monkey_patch/ruby/time.rb +32 -0
  33. data/lib/openhab/dsl/monkey_patch/types/decimal_type.rb +70 -0
  34. data/lib/openhab/dsl/monkey_patch/types/on_off_type.rb +51 -0
  35. data/lib/openhab/dsl/monkey_patch/types/open_closed_type.rb +36 -0
  36. data/lib/openhab/dsl/monkey_patch/types/percent_type.rb +32 -0
  37. data/lib/openhab/dsl/monkey_patch/types/quantity_type.rb +69 -0
  38. data/lib/openhab/dsl/monkey_patch/types/types.rb +9 -0
  39. data/lib/openhab/dsl/monkey_patch/types/up_down_type.rb +33 -0
  40. data/lib/openhab/dsl/persistence.rb +25 -0
  41. data/lib/openhab/dsl/rules/automation_rule.rb +342 -0
  42. data/lib/openhab/dsl/rules/guard.rb +134 -0
  43. data/lib/openhab/dsl/rules/property.rb +102 -0
  44. data/lib/openhab/dsl/rules/rule.rb +116 -0
  45. data/lib/openhab/dsl/rules/rule_config.rb +151 -0
  46. data/lib/openhab/dsl/rules/triggers/changed.rb +143 -0
  47. data/lib/openhab/dsl/rules/triggers/channel.rb +53 -0
  48. data/lib/openhab/dsl/rules/triggers/command.rb +104 -0
  49. data/lib/openhab/dsl/rules/triggers/cron.rb +177 -0
  50. data/lib/openhab/dsl/rules/triggers/trigger.rb +124 -0
  51. data/lib/openhab/dsl/rules/triggers/updated.rb +98 -0
  52. data/lib/openhab/dsl/states.rb +61 -0
  53. data/lib/openhab/dsl/things.rb +91 -0
  54. data/lib/openhab/dsl/time_of_day.rb +232 -0
  55. data/lib/openhab/dsl/timers.rb +77 -0
  56. data/lib/openhab/dsl/types/datetime.rb +326 -0
  57. data/lib/openhab/dsl/types/quantity.rb +290 -0
  58. data/lib/openhab/dsl/units.rb +39 -0
  59. data/lib/openhab/log/configuration.rb +21 -0
  60. data/lib/openhab/log/logger.rb +172 -0
  61. data/lib/openhab/version.rb +1 -1
  62. metadata +60 -58
  63. data/lib/openhab/configuration.rb +0 -16
  64. data/lib/openhab/core/cron.rb +0 -27
  65. data/lib/openhab/core/debug.rb +0 -34
  66. data/lib/openhab/core/dsl.rb +0 -51
  67. data/lib/openhab/core/dsl/actions.rb +0 -107
  68. data/lib/openhab/core/dsl/entities.rb +0 -147
  69. data/lib/openhab/core/dsl/group.rb +0 -102
  70. data/lib/openhab/core/dsl/items/items.rb +0 -51
  71. data/lib/openhab/core/dsl/items/number_item.rb +0 -323
  72. data/lib/openhab/core/dsl/items/string_item.rb +0 -122
  73. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +0 -4
  74. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +0 -22
  75. data/lib/openhab/core/dsl/monkey_patch/events.rb +0 -5
  76. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +0 -13
  77. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +0 -25
  78. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +0 -26
  79. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +0 -54
  80. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +0 -182
  81. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +0 -27
  82. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +0 -132
  83. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +0 -283
  84. data/lib/openhab/core/dsl/monkey_patch/items/persistence.rb +0 -72
  85. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +0 -87
  86. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +0 -41
  87. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +0 -47
  88. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +0 -7
  89. data/lib/openhab/core/dsl/monkey_patch/ruby/string.rb +0 -43
  90. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +0 -60
  91. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +0 -41
  92. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +0 -25
  93. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +0 -23
  94. data/lib/openhab/core/dsl/monkey_patch/types/quantity_type.rb +0 -58
  95. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +0 -8
  96. data/lib/openhab/core/dsl/persistence.rb +0 -27
  97. data/lib/openhab/core/dsl/property.rb +0 -96
  98. data/lib/openhab/core/dsl/rule/automation_rule.rb +0 -345
  99. data/lib/openhab/core/dsl/rule/guard.rb +0 -136
  100. data/lib/openhab/core/dsl/rule/rule.rb +0 -117
  101. data/lib/openhab/core/dsl/rule/rule_config.rb +0 -153
  102. data/lib/openhab/core/dsl/rule/triggers/changed.rb +0 -145
  103. data/lib/openhab/core/dsl/rule/triggers/channel.rb +0 -55
  104. data/lib/openhab/core/dsl/rule/triggers/command.rb +0 -106
  105. data/lib/openhab/core/dsl/rule/triggers/cron.rb +0 -160
  106. data/lib/openhab/core/dsl/rule/triggers/trigger.rb +0 -126
  107. data/lib/openhab/core/dsl/rule/triggers/updated.rb +0 -100
  108. data/lib/openhab/core/dsl/states.rb +0 -63
  109. data/lib/openhab/core/dsl/things.rb +0 -93
  110. data/lib/openhab/core/dsl/time_of_day.rb +0 -231
  111. data/lib/openhab/core/dsl/timers.rb +0 -79
  112. data/lib/openhab/core/dsl/types/quantity.rb +0 -292
  113. data/lib/openhab/core/dsl/units.rb +0 -41
  114. data/lib/openhab/core/log.rb +0 -170
  115. data/lib/openhab/core/patch_load_path.rb +0 -7
  116. data/lib/openhab/core/startup_delay.rb +0 -23
  117. data/lib/openhab/osgi.rb +0 -59
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module MonkeyPatch
8
+ #
9
+ # Patches OpenHAB items
10
+ #
11
+ module Items
12
+ java_import Java::OrgOpenhabCoreLibraryItems::DimmerItem
13
+ java_import Java::OrgOpenhabCoreItems::GenericItem
14
+
15
+ #
16
+ # Alias class for is_a? testing
17
+ #
18
+ ::Dimmer = DimmerItem
19
+
20
+ #
21
+ # Monkey Patch DimmerItem
22
+ #
23
+ class DimmerItem
24
+ include Comparable
25
+ java_import Java::OrgOpenhabCoreLibraryTypes::DecimalType
26
+ java_import Java::OrgOpenhabCoreLibraryTypes::IncreaseDecreaseType
27
+
28
+ #
29
+ # Add the current dimmer value to the supplied object
30
+ #
31
+ # @param [Object] other object to add the dimmer value to
32
+ #
33
+ # @return [Integer] Current dimmer value plus value of supplied object
34
+ #
35
+ def +(other)
36
+ return unless state?
37
+
38
+ state.to_big_decimal.intValue + other
39
+ end
40
+
41
+ #
42
+ # Subtract the supplied object from the current value of the dimmer
43
+ #
44
+ # @param [Object] other object to subtract from the dimmer value
45
+ #
46
+ # @return [Integer] Current dimmer value minus value of supplied object
47
+ #
48
+ def -(other)
49
+ return unless state?
50
+
51
+ state.to_big_decimal.intValue - other
52
+ end
53
+
54
+ #
55
+ # Dim the dimmer
56
+ #
57
+ # @param [Integer] amount to dim by
58
+ #
59
+ # @return [Integer] level target for dimmer
60
+ #
61
+ def dim(amount = 1)
62
+ return unless state?
63
+
64
+ target = [state.to_big_decimal.intValue - amount, 0].max
65
+
66
+ if amount == 1
67
+ command(IncreaseDecreaseType::DECREASE)
68
+ else
69
+ command(target)
70
+ end
71
+
72
+ target
73
+ end
74
+
75
+ #
76
+ # Brighten the dimmer
77
+ #
78
+ # @param [Integer] amount to brighten by
79
+ #
80
+ # @return [Integer] level target for dimmer
81
+ #
82
+ def brighten(amount = 1)
83
+ return unless state?
84
+
85
+ target = state.to_big_decimal.intValue + amount
86
+
87
+ if amount == 1
88
+ command(IncreaseDecreaseType::INCREASE)
89
+ else
90
+ command(target)
91
+ end
92
+ target
93
+ end
94
+
95
+ #
96
+ # Compare DimmerItem to supplied object
97
+ #
98
+ # @param [Object] other object to compare to
99
+ #
100
+ # @return [Integer] -1,0,1 or nil depending on value supplied,
101
+ # nil comparison to supplied object is not possible.
102
+ #
103
+ def <=>(other)
104
+ logger.trace("Comparing #{self} to #{other}")
105
+ case other
106
+ when GenericItem, NumberItem then state <=> other.state
107
+ when DecimalType then state <=> other
108
+ when Numeric then state.to_big_decimal.to_d <=> other.to_d
109
+ else compare_to(other)
110
+ end
111
+ end
112
+
113
+ #
114
+ # Coerce objects into a DimmerItem
115
+ #
116
+ # @param [Object] other object to coerce to a DimmerItem if possible
117
+ #
118
+ # @return [Object] Numeric when applicable
119
+ #
120
+ def coerce(other)
121
+ logger.trace("Coercing #{self} as a request from #{other.class}")
122
+ case other
123
+ when Numeric
124
+ [other, state.to_big_decimal.to_d]
125
+ else
126
+ [other, state]
127
+ end
128
+ end
129
+
130
+ #
131
+ # Compare DimmerItem to supplied object.
132
+ # The == operator needs to be overridden because the parent java object
133
+ # has .equals which overrides the <=> operator above
134
+ #
135
+ # @param [Object] other object to compare to
136
+ #
137
+ # @return [Integer] true if the two objects contain the same value, false otherwise
138
+ #
139
+ def ==(other)
140
+ (self <=> other).zero?
141
+ end
142
+
143
+ #
144
+ # Check if dimmer has a state and state is not zero
145
+ #
146
+ # @return [Boolean] True if dimmer is not NULL or UNDEF and value is not 0
147
+ #
148
+ def truthy?
149
+ state? && state != DecimalType::ZERO
150
+ end
151
+
152
+ #
153
+ # Value of dimmer
154
+ #
155
+ # @return [Integer] Value of dimmer or nil if state is UNDEF or NULL
156
+ #
157
+ def to_i
158
+ state&.to_big_decimal&.intValue
159
+ end
160
+
161
+ alias to_int to_i
162
+
163
+ #
164
+ # Return the string representation of the dimmer item
165
+ #
166
+ # @return [String] String version of the dimmer value
167
+ #
168
+ def to_s
169
+ to_i.to_s
170
+ end
171
+
172
+ #
173
+ # Check if dimmer is on
174
+ #
175
+ # @return [Boolean] True if item is not UNDEF or NULL and has a value greater than 0
176
+ #
177
+ def on?
178
+ state&.to_big_decimal&.intValue&.positive?
179
+ end
180
+
181
+ #
182
+ # Check if dimmer is off
183
+ #
184
+ # @return [Boolean] True if item is not UNDEF or NULL and has a state of 0
185
+ #
186
+ def off?
187
+ state&.to_big_decimal&.intValue&.zero?
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module MonkeyPatch
6
+ #
7
+ # Patches OpenHAB items
8
+ #
9
+ module Items
10
+ java_import Java::OrgOpenhabCoreItems::GroupItem
11
+
12
+ #
13
+ # Monkey patch Group Item
14
+ #
15
+ class GroupItem
16
+ #
17
+ # Get all items in a group
18
+ #
19
+ # @return [Array] Array of items in the group
20
+ #
21
+ def items
22
+ to_a
23
+ end
24
+
25
+ #
26
+ # Get all items in the group as an Array
27
+ #
28
+ # @return [Array] All items in the group
29
+ #
30
+ def to_a
31
+ all_members.each_with_object([]) { |item, arr| arr << item }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'openhab/log/logger'
5
+ require 'bigdecimal'
6
+
7
+ # Monkey patch items
8
+ require 'openhab/dsl/monkey_patch/items/metadata'
9
+ require 'openhab/dsl/monkey_patch/items/persistence'
10
+ require 'openhab/dsl/monkey_patch/items/contact_item'
11
+ require 'openhab/dsl/monkey_patch/items/dimmer_item'
12
+ require 'openhab/dsl/monkey_patch/items/switch_item'
13
+ require 'openhab/dsl/monkey_patch/items/group_item'
14
+
15
+ module OpenHAB
16
+ module DSL
17
+ module MonkeyPatch
18
+ #
19
+ # Monkeypatches Items
20
+ #
21
+ module Items
22
+ #
23
+ # Extensions for Items
24
+ #
25
+ module ItemExtensions
26
+ include OpenHAB::Log
27
+ java_import Java::OrgOpenhabCoreModelScriptActions::BusEvent
28
+ java_import Java::OrgOpenhabCoreTypes::UnDefType
29
+
30
+ #
31
+ # Send a command to this item
32
+ #
33
+ # @param [Object] command to send to object
34
+ #
35
+ #
36
+ def command(command)
37
+ command = command.to_java.strip_trailing_zeros if command.is_a? BigDecimal
38
+ logger.trace "Sending Command #{command} to #{id}"
39
+ BusEvent.sendCommand(self, command.to_s)
40
+ end
41
+
42
+ alias << command
43
+
44
+ #
45
+ # Send an update to this item
46
+ #
47
+ # @param [Object] update the item
48
+ #
49
+ #
50
+ def update(update)
51
+ logger.trace "Sending Update #{update} to #{id}"
52
+ BusEvent.postUpdate(self, update.to_s)
53
+ end
54
+
55
+ #
56
+ # Check if the item state == UNDEF
57
+ #
58
+ # @return [Boolean] True if the state is UNDEF, false otherwise
59
+ #
60
+ def undef?
61
+ # Need to explicitly call the super method version because this state will never return UNDEF
62
+ method(:state).super_method.call == UnDefType::UNDEF
63
+ end
64
+
65
+ #
66
+ # Check if the item state == NULL
67
+ #
68
+ # @return [Boolean] True if the state is NULL, false otherwise
69
+ def null?
70
+ # Need to explicitly call the super method version because this state will never return NULL
71
+ method(:state).super_method.call == UnDefType::NULL
72
+ end
73
+
74
+ #
75
+ # Check if the item has a state (not UNDEF or NULL)
76
+ #
77
+ # @return [Boolean] True if state is not UNDEF or NULL
78
+ #
79
+ def state?
80
+ undef? == false && null? == false
81
+ end
82
+
83
+ #
84
+ # Get the item state
85
+ #
86
+ # @return [State] OpenHAB item state if state is not UNDEF or NULL, nil otherwise
87
+ #
88
+ def state
89
+ super if state?
90
+ end
91
+
92
+ #
93
+ # Get an ID for the item, using the item label if set, otherwise item name
94
+ #
95
+ # @return [String] label if set otherwise name
96
+ #
97
+ def id
98
+ label || name
99
+ end
100
+
101
+ #
102
+ # Get the string representation of the state of the item
103
+ #
104
+ # @return [String] State of the item as a string if not UNDEF or NULL, nil otherwise
105
+ #
106
+ def to_s
107
+ state&.to_s
108
+ end
109
+
110
+ #
111
+ # Inspect the item
112
+ #
113
+ # @return [String] details of the item
114
+ #
115
+ def inspect
116
+ toString
117
+ end
118
+ end
119
+
120
+ java_import Java::OrgOpenhabCoreItems::GenericItem
121
+
122
+ #
123
+ # Monkey patches all OpenHAB items
124
+ #
125
+ class GenericItem
126
+ prepend OpenHAB::DSL::MonkeyPatch::Items::ItemExtensions
127
+ prepend OpenHAB::DSL::MonkeyPatch::Items::Metadata
128
+ prepend OpenHAB::DSL::MonkeyPatch::Items::Persistence
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,281 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'delegate'
5
+ require 'pp'
6
+ require 'forwardable'
7
+ require 'openhab/core/osgi'
8
+ require 'openhab/log/logger'
9
+
10
+ module OpenHAB
11
+ module DSL
12
+ module MonkeyPatch
13
+ module Items
14
+ #
15
+ # Metadata extension for Items
16
+ #
17
+ module Metadata
18
+ include OpenHAB::Log
19
+
20
+ java_import Java::OrgOpenhabCoreItems::Metadata
21
+ java_import Java::OrgOpenhabCoreItems::MetadataKey
22
+
23
+ #
24
+ # Provide the interface to access namespace's value and configuration
25
+ #
26
+ class MetadataItem < SimpleDelegator
27
+ extend Forwardable
28
+
29
+ def_delegator :@metadata, :value
30
+
31
+ def initialize(metadata: nil, key: nil, value: nil, config: nil)
32
+ @metadata = metadata || Metadata.new(key || MetadataKey.new('', ''), value, config)
33
+ super(@metadata&.configuration)
34
+ end
35
+
36
+ #
37
+ # Updates the metadata configuration associated with the key
38
+ #
39
+ def []=(key, value)
40
+ configuration = {}.merge(@metadata&.configuration || {}).merge({ key => value })
41
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, configuration)
42
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
43
+ end
44
+
45
+ #
46
+ # Delete the configuration with the given key
47
+ #
48
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
49
+ #
50
+ def delete(key)
51
+ configuration = {}.merge(@metadata&.configuration || {})
52
+ configuration.delete(key)
53
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, configuration)
54
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
55
+ end
56
+
57
+ #
58
+ # Set the metadata value
59
+ #
60
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
61
+ #
62
+ def value=(value)
63
+ raise ArgumentError, 'Value must be a string' unless value.is_a? String
64
+
65
+ metadata = Metadata.new(@metadata&.uID, value, @metadata&.configuration)
66
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
67
+ end
68
+
69
+ #
70
+ # Set the entire configuration to a hash
71
+ #
72
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
73
+ #
74
+ def config=(config)
75
+ raise ArgumentError, 'Configuration must be a hash' unless config.is_a? Hash
76
+
77
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, config)
78
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
79
+ end
80
+ alias configuration= config=
81
+
82
+ #
83
+ # Convert the metadata to an array
84
+ #
85
+ # @return [Array[2]] An array of [value, configuration]
86
+ #
87
+ def to_a
88
+ [@metadata&.value, @metadata&.configuration || {}]
89
+ end
90
+ end
91
+
92
+ #
93
+ # Provide the interface to access item metadata
94
+ #
95
+ class NamespaceAccessor
96
+ include Enumerable
97
+
98
+ def initialize(item_name:)
99
+ @item_name = item_name
100
+ end
101
+
102
+ #
103
+ # Return the metadata namespace
104
+ #
105
+ # @return [OpenHAB::DSL::MonkeyPatch::Items::MetadataItem], or nil if the namespace doesn't exist
106
+ #
107
+ def [](namespace)
108
+ logger.trace("Namespaces (#{NamespaceAccessor.registry.getAll})")
109
+ logger.trace("Namespace (#{NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))})")
110
+ metadata = NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))
111
+ MetadataItem.new(metadata: metadata) if metadata
112
+ end
113
+
114
+ #
115
+ # Set the metadata namespace. If the namespace does not exist, it will be created
116
+ #
117
+ # @param value [Object] The assigned value can be a OpenHAB::DSL::MonkeyPatch::Items::MetadataItem,
118
+ # Java::Org::openhab::core::items::Metadata, Array[2] of [value, configuration],
119
+ # A String to set the value and clear the configuration,
120
+ # or a Hash to set the configuration and set the value to nil
121
+ #
122
+ # @return [OpenHAB::DSL::MonkeyPatch::Items::MetadataItem]
123
+ #
124
+ def []=(namespace, value)
125
+ meta_value, configuration = update_from_value(value)
126
+
127
+ key = MetadataKey.new(namespace, @item_name)
128
+ metadata = Metadata.new(key, meta_value, configuration)
129
+ # registry.get can be omitted, but registry.update will log a warning for nonexistent metadata
130
+ if NamespaceAccessor.registry.get(key)
131
+ NamespaceAccessor.registry.update(metadata)
132
+ else
133
+ NamespaceAccessor.registry.add(metadata)
134
+ end
135
+ end
136
+
137
+ #
138
+ # Enumerates through all the namespaces
139
+ #
140
+ def each
141
+ return unless block_given?
142
+
143
+ NamespaceAccessor.registry.getAll.each do |meta|
144
+ yield meta.uID.namespace, meta.value, meta.configuration if meta.uID.itemName == @item_name
145
+ end
146
+ end
147
+
148
+ #
149
+ # Remove all the namespaces
150
+ #
151
+ def clear
152
+ NamespaceAccessor.registry.removeItemMetadata @item_name
153
+ end
154
+
155
+ #
156
+ # Delete a specific namespace
157
+ #
158
+ # @param namespace [String] The namespace to delete
159
+ #
160
+ def delete(namespace)
161
+ NamespaceAccessor.registry.remove(MetadataKey.new(namespace, @item_name))
162
+ end
163
+
164
+ alias delete_all clear
165
+
166
+ #
167
+ # @return [Boolean] True if the given namespace exists, false otherwise
168
+ #
169
+ def key?(namespace)
170
+ !NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name)).nil?
171
+ end
172
+
173
+ alias has_key? key?
174
+ alias include? key?
175
+
176
+ #
177
+ # Merge the given hash with the current metadata. Existing namespace that matches the name
178
+ # of the new namespace will be overwritten. Others will be added.
179
+ #
180
+ def merge!(*others)
181
+ return self if others.empty?
182
+
183
+ others.each do |other|
184
+ case other
185
+ when Hash then merge_hash!(other)
186
+ when self.class then merge_metadata!(other)
187
+ else raise ArgumentError, "merge only supports Hash, or another item's metadata"
188
+ end
189
+ end
190
+ self
191
+ end
192
+
193
+ #
194
+ # @return [String] the string representation of all the namespaces with their value and config
195
+ #
196
+ def to_s
197
+ namespaces = []
198
+ each { |ns, value, config| namespaces << "\"#{ns}\"=>[\"#{value}\",#{config}]" }
199
+ "{#{namespaces.join(',')}}"
200
+ end
201
+
202
+ #
203
+ # @return [Java::org::openhab::core::items::MetadataRegistry]
204
+ #
205
+ def self.registry
206
+ @registry ||= OpenHAB::Core::OSGI.service('org.openhab.core.items.MetadataRegistry')
207
+ end
208
+
209
+ private
210
+
211
+ #
212
+ # perform an updated based on the supplied value
213
+ #
214
+ # @param [MetadataItem,Metadata,Array,Hash] value to perform update from
215
+ #
216
+ # @return [Array<Object,Hash>] Array containing the value and configuration based on the
217
+ # the supplied object
218
+ #
219
+ def update_from_value(value)
220
+ case value
221
+ when MetadataItem then [value.value, value.__getobj__]
222
+ when Metadata then [value.value, value.configuration]
223
+ when Array
224
+ raise ArgumentError, 'Array must contain 2 elements: value, config' if value.length != 2
225
+
226
+ value
227
+ when Hash then [nil, value]
228
+ else [value, nil]
229
+ end
230
+ end
231
+
232
+ #
233
+ # Merge the metadata from the supplied other metadata object
234
+ #
235
+ # @param [Hash] other metadata object to merge
236
+ # @yield [key, current_metadata, new_meta] to process merge
237
+ #
238
+ #
239
+ def merge_metadata!(other)
240
+ other.each do |key, new_value, new_config|
241
+ new_meta = new_value, new_config
242
+ if block_given?
243
+ current_meta = self[key]&.to_a
244
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
245
+ end
246
+ self[key] = new_meta
247
+ end
248
+ end
249
+
250
+ #
251
+ # Merge a hash into the metadata
252
+ #
253
+ # @param [Hash] other to merge into metadata
254
+ # @yield [key, current_metadata, new_meta] to process merge
255
+ #
256
+ #
257
+ def merge_hash!(other)
258
+ other.each do |key, new_meta|
259
+ if block_given?
260
+ current_meta = self[key]&.to_a
261
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
262
+ end
263
+ self[key] = new_meta
264
+ end
265
+ end
266
+ end
267
+
268
+ #
269
+ # Accessor to the item's metadata
270
+ #
271
+ # @return [NamespaceAccessor] an Enumerable object to access item's namespaces
272
+ #
273
+ def meta
274
+ @meta ||= NamespaceAccessor.new(item_name: name)
275
+ end
276
+ alias metadata meta
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end