openhab-scripting 5.7.1 → 5.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/openhab/core/emulate_hash.rb +6 -1
- data/lib/openhab/core/items/group_item.rb +16 -0
- data/lib/openhab/core/items/item.rb +26 -4
- data/lib/openhab/core/items/metadata/hash.rb +18 -6
- data/lib/openhab/core/items/number_item.rb +5 -0
- data/lib/openhab/core/items/registry.rb +8 -2
- data/lib/openhab/core/items/semantics.rb +45 -2
- data/lib/openhab/core/registry.rb +13 -5
- data/lib/openhab/core/sitemaps/provider.rb +4 -3
- data/lib/openhab/core/things/links/provider.rb +2 -4
- data/lib/openhab/core/things/registry.rb +8 -2
- data/lib/openhab/core/things/thing.rb +16 -1
- data/lib/openhab/core/types/point_type.rb +3 -3
- data/lib/openhab/dsl/items/builder.rb +105 -26
- data/lib/openhab/dsl/sitemaps/builder.rb +8 -3
- data/lib/openhab/dsl/things/builder.rb +27 -9
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/log.rb +4 -2
- data/lib/openhab/rspec/helpers.rb +0 -8
- data/lib/openhab/rspec/karaf.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00dfdfae614d0fc89c09ddfe86b16c4d0b41e94bc1c2e73889eb359ff09ada3c
|
4
|
+
data.tar.gz: ecafc5d2f33cf0b0015ac9e8c59449a57488e4f18316bd584e8dfe028d5ec4c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eff4e5471afb074c92cd7d3fc01d9070a80db680ed79c4814dc8b88e14eb67c8f9215a77f80c6b1a9a5eb6f4e220b6ce5e38ba01f0287779821db918f81c0fef
|
7
|
+
data.tar.gz: f187e831d86e87fe4a2e91b311f8bdd3c4e046e9107054ff74c91cdf7644d4fa303d86d8abf3c5f80e8e8cb1762f5c436b89e3e841a86ef05af351c6f0d6abbb
|
@@ -103,7 +103,12 @@ module OpenHAB
|
|
103
103
|
def merge!(*others, &block)
|
104
104
|
return self if others.empty?
|
105
105
|
|
106
|
-
replace
|
106
|
+
# don't call replace here so we don't touch other keys
|
107
|
+
others.shift.merge(*others, &block).each do |key, value|
|
108
|
+
value = yield key, self[key], value if key?(key) && block
|
109
|
+
store(key, value)
|
110
|
+
end
|
111
|
+
self
|
107
112
|
end
|
108
113
|
alias_method :update, :merge!
|
109
114
|
|
@@ -106,6 +106,9 @@ module OpenHAB
|
|
106
106
|
alias_method :to_s, :inspect
|
107
107
|
end
|
108
108
|
|
109
|
+
# @!attribute [r] function
|
110
|
+
# @return [GroupFunction] Returns the function of this GroupItem
|
111
|
+
|
109
112
|
# Override because we want to send them to the base item if possible
|
110
113
|
%i[command update].each do |method|
|
111
114
|
define_method(method) do |command|
|
@@ -152,6 +155,19 @@ module OpenHAB
|
|
152
155
|
RUBY
|
153
156
|
end
|
154
157
|
|
158
|
+
#
|
159
|
+
# Compares all attributes of the item with another item.
|
160
|
+
#
|
161
|
+
# @param other [Item] The item to compare with
|
162
|
+
# @return [true,false] true if all attributes are equal, false otherwise
|
163
|
+
#
|
164
|
+
# @!visibility private
|
165
|
+
def config_eql?(other)
|
166
|
+
return false unless super
|
167
|
+
|
168
|
+
base_item&.type == other.base_item&.type && function&.inspect == other.function&.inspect
|
169
|
+
end
|
170
|
+
|
155
171
|
private
|
156
172
|
|
157
173
|
# Add base type and function details
|
@@ -264,12 +264,17 @@ module OpenHAB
|
|
264
264
|
#
|
265
265
|
# @return [Array<Thing>] An array of things or an empty array
|
266
266
|
def things
|
267
|
-
|
268
|
-
channels = registry.get_bound_channels(name).to_a
|
269
|
-
channels.map(&:thing_uid).uniq.map { |tuid| EntityLookup.lookup_thing(tuid) }.compact
|
267
|
+
Things::Links::Provider.registry.get_bound_things(name).map { |thing| Things::Proxy.new(thing) }
|
270
268
|
end
|
271
269
|
alias_method :all_linked_things, :things
|
272
270
|
|
271
|
+
# Returns all of the item's links (channels and link configurations).
|
272
|
+
#
|
273
|
+
# @return [Array<ItemChannelLink>] An array of ItemChannelLink or an empty array
|
274
|
+
def links
|
275
|
+
Things::Links::Provider.registry.get_links(name)
|
276
|
+
end
|
277
|
+
|
273
278
|
# @return [String]
|
274
279
|
def inspect
|
275
280
|
s = "#<OpenHAB::Core::Items::#{type}Item#{type_details} #{name} #{label.inspect} state=#{raw_state.inspect}"
|
@@ -281,11 +286,28 @@ module OpenHAB
|
|
281
286
|
"#{s}>"
|
282
287
|
end
|
283
288
|
|
284
|
-
# @return [org.openhab.core.common.registry.Provider]
|
289
|
+
# @return [org.openhab.core.common.registry.Provider, nil]
|
285
290
|
def provider
|
286
291
|
Provider.registry.provider_for(self)
|
287
292
|
end
|
288
293
|
|
294
|
+
#
|
295
|
+
# Compares all attributes except metadata and channels/links of the item with another item.
|
296
|
+
#
|
297
|
+
# @param other [Item] The item to compare with
|
298
|
+
# @return [true,false] true if all attributes are equal, false otherwise
|
299
|
+
#
|
300
|
+
# @!visibility private
|
301
|
+
def config_eql?(other)
|
302
|
+
# GenericItem#equals checks whether other has the same name and class
|
303
|
+
return false unless equals(other)
|
304
|
+
|
305
|
+
%i[label category tags group_names].all? do |method|
|
306
|
+
# Don't use #send here. It is defined in GenericItem for sending commands
|
307
|
+
public_send(method) == other.public_send(method)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
289
311
|
def_type_predicate(:color)
|
290
312
|
def_type_predicate(:contact)
|
291
313
|
def_type_predicate(:date_time)
|
@@ -13,6 +13,11 @@ module OpenHAB
|
|
13
13
|
#
|
14
14
|
# All keys are converted to strings.
|
15
15
|
#
|
16
|
+
# As a special case, a #== comparison can be done against a [value, config] array.
|
17
|
+
# @example
|
18
|
+
# MyItem.metadata[:namespace] = "value", { key: "value" }
|
19
|
+
# MyItem.metadata[:namespace] == ["value", { "key" => "value" }] #=> true
|
20
|
+
#
|
16
21
|
# @!attribute [rw] value
|
17
22
|
# @return [String] The main value for the metadata namespace.
|
18
23
|
# @!attribute [r] namespace
|
@@ -88,7 +93,7 @@ module OpenHAB
|
|
88
93
|
return unless attached?
|
89
94
|
|
90
95
|
javaify
|
91
|
-
provider
|
96
|
+
provider!.update(@metadata)
|
92
97
|
end
|
93
98
|
|
94
99
|
# @!visibility private
|
@@ -96,12 +101,12 @@ module OpenHAB
|
|
96
101
|
return unless attached?
|
97
102
|
|
98
103
|
javaify
|
99
|
-
(p = provider).get(uid) ? p.update(@metadata) : p.add(@metadata)
|
104
|
+
(p = provider!).get(uid) ? p.update(@metadata) : p.add(@metadata)
|
100
105
|
end
|
101
106
|
|
102
107
|
# @!visibility private
|
103
108
|
def remove
|
104
|
-
provider
|
109
|
+
provider!.remove(uid)
|
105
110
|
end
|
106
111
|
|
107
112
|
# @!visibility private
|
@@ -149,6 +154,8 @@ module OpenHAB
|
|
149
154
|
return configuration == other.configuration
|
150
155
|
elsif value.empty? && other.respond_to?(:to_hash)
|
151
156
|
return configuration == other.to_hash
|
157
|
+
elsif other.is_a?(Array)
|
158
|
+
return other == [value, configuration]
|
152
159
|
end
|
153
160
|
false
|
154
161
|
end
|
@@ -213,12 +220,17 @@ module OpenHAB
|
|
213
220
|
[value, to_h].inspect
|
214
221
|
end
|
215
222
|
|
223
|
+
# @return [org.openhab.core.common.registry.Provider, nil]
|
224
|
+
def provider
|
225
|
+
Provider.registry.provider_for(uid)
|
226
|
+
end
|
227
|
+
|
216
228
|
#
|
217
229
|
# @raise [FrozenError] if the provider is not a
|
218
230
|
# {org.openhab.core.common.registry.ManagedProvider ManagedProvider} that can be updated.
|
219
231
|
# @return [org.openhab.core.common.registry.ManagedProvider]
|
220
232
|
#
|
221
|
-
def provider
|
233
|
+
def provider!
|
222
234
|
preferred_provider = Provider.current(
|
223
235
|
Thread.current[:openhab_providers]&.dig(:metadata_items, uid.item_name) ||
|
224
236
|
Thread.current[:openhab_providers]&.dig(:metadata_namespaces, uid.namespace),
|
@@ -226,10 +238,10 @@ module OpenHAB
|
|
226
238
|
)
|
227
239
|
|
228
240
|
if attached?
|
229
|
-
provider =
|
241
|
+
provider = self.provider
|
230
242
|
return preferred_provider unless provider
|
231
243
|
|
232
|
-
unless provider.is_a?(
|
244
|
+
unless provider.is_a?(ManagedProvider)
|
233
245
|
raise FrozenError, "Cannot modify metadata from provider #{provider.inspect} for #{uid}."
|
234
246
|
end
|
235
247
|
|
@@ -45,13 +45,19 @@ module OpenHAB
|
|
45
45
|
# Enter the Item Builder DSL.
|
46
46
|
#
|
47
47
|
# @param (see Core::Provider.current)
|
48
|
+
# @param update [true, false] Update existing items with the same name.
|
49
|
+
# When false, an error will be raised if an item with the same name already exists.
|
48
50
|
# @yield Block executed in the context of a {DSL::Items::Builder}
|
49
51
|
# @return [Object] The return value of the block.
|
52
|
+
# @raise [ArgumentError] if an item with the same name already exists and `update` is false.
|
53
|
+
# @raise [FrozenError] if `update` is true but the existing item with the same name
|
54
|
+
# wasn't created by the current provider.
|
50
55
|
#
|
51
56
|
# @see DSL::Items::Builder
|
52
57
|
#
|
53
|
-
def build(preferred_provider = nil, &block)
|
54
|
-
DSL::Items::BaseBuilderDSL.new(preferred_provider)
|
58
|
+
def build(preferred_provider = nil, update: true, &block)
|
59
|
+
DSL::Items::BaseBuilderDSL.new(preferred_provider, update: update)
|
60
|
+
.instance_eval_with_dummy_items(&block)
|
55
61
|
end
|
56
62
|
|
57
63
|
#
|
@@ -311,9 +311,14 @@ module OpenHAB
|
|
311
311
|
synonyms = Array.wrap(synonyms).map { |s| s.to_s.strip }
|
312
312
|
|
313
313
|
tags.map do |name, parent|
|
314
|
-
|
314
|
+
unless parent.is_a?(SemanticTag)
|
315
|
+
parent_tag = lookup(parent)
|
316
|
+
raise ArgumentError, "Unknown parent: #{parent}" unless parent_tag
|
317
|
+
|
318
|
+
parent = parent_tag
|
319
|
+
end
|
320
|
+
|
315
321
|
next if lookup(name)
|
316
|
-
next unless parent
|
317
322
|
|
318
323
|
new_tag = org.openhab.core.semantics.SemanticTagImpl.new("#{parent.uid}_#{name}",
|
319
324
|
label,
|
@@ -323,6 +328,44 @@ module OpenHAB
|
|
323
328
|
lookup(name)
|
324
329
|
end.compact
|
325
330
|
end
|
331
|
+
|
332
|
+
#
|
333
|
+
# Removes custom semantic tags.
|
334
|
+
#
|
335
|
+
# @param [SemanticTag, String, Symbol] tags Custom Semantic Tags to remove.
|
336
|
+
# The built in Semantic Tags cannot be removed.
|
337
|
+
# @param [true, false] recursive Remove all children of the given tags.
|
338
|
+
#
|
339
|
+
# @return [Array<SemanticTag>] An array of tags successfully removed.
|
340
|
+
# @raise [ArgumentError] if any of the tags have children
|
341
|
+
# @raise [FrozenError] if any of the tags are not custom tags
|
342
|
+
#
|
343
|
+
# @since openHAB 4.0
|
344
|
+
#
|
345
|
+
def remove(*tags, recursive: false)
|
346
|
+
tags.flat_map do |tag|
|
347
|
+
tag = lookup(tag) unless tag.is_a?(SemanticTag)
|
348
|
+
next unless tag
|
349
|
+
|
350
|
+
provider = Provider.registry.provider_for(tag)
|
351
|
+
unless provider.is_a?(ManagedProvider)
|
352
|
+
raise FrozenError, "Cannot remove item #{tag} from non-managed provider #{provider.inspect}"
|
353
|
+
end
|
354
|
+
|
355
|
+
children = []
|
356
|
+
Provider.registry.providers.grep(ManagedProvider).each do |managed_provider|
|
357
|
+
managed_provider.all.each do |existing_tag|
|
358
|
+
next unless existing_tag.parent_uid == tag.uid
|
359
|
+
raise ArgumentError, "Cannot remove #{tag} because it has children" unless recursive
|
360
|
+
|
361
|
+
children += remove(existing_tag, recursive: recursive)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
remove_const(tag.name) if provider.remove(tag.uid) && const_defined?(tag.name)
|
366
|
+
[tag] + children
|
367
|
+
end.compact
|
368
|
+
end
|
326
369
|
end
|
327
370
|
end
|
328
371
|
|
@@ -20,12 +20,20 @@ module OpenHAB
|
|
20
20
|
def provider_for(key)
|
21
21
|
elementReadLock.lock
|
22
22
|
if key.is_a?(org.openhab.core.common.registry.Identifiable)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
return unless (provider = elementToProvider[key])
|
24
|
+
|
25
|
+
# The HashMap lookup above uses java's hashCode() which has been overridden
|
26
|
+
# by GenericItem and ThingImpl to return object's uid, e.g. item's name, thing uid
|
27
|
+
# so it will return a provider even for an unmanaged object having the same uid
|
28
|
+
# as an existing managed object.
|
27
29
|
|
28
|
-
|
30
|
+
# So take an extra step to verify that the provider really holds the given instance.
|
31
|
+
# by using equal? to compare the object's identity.
|
32
|
+
# Only ManagedProviders have a #get method to look up the object by uid.
|
33
|
+
provider if !provider.is_a?(ManagedProvider) || provider.get(key.uid).equal?(key)
|
34
|
+
elsif (element = identifierToElement[key])
|
35
|
+
elementToProvider[element]
|
36
|
+
end
|
29
37
|
ensure
|
30
38
|
elementReadLock.unlock
|
31
39
|
end
|
@@ -57,6 +57,7 @@ module OpenHAB
|
|
57
57
|
#
|
58
58
|
# Enter the Sitemap Builder DSL.
|
59
59
|
#
|
60
|
+
# @param update [true, false] When true, existing sitemaps with the same name will be updated.
|
60
61
|
# @yield Block executed in the context of a {DSL::Sitemaps::Builder}
|
61
62
|
# @return [void]
|
62
63
|
#
|
@@ -82,8 +83,8 @@ module OpenHAB
|
|
82
83
|
# end
|
83
84
|
# end
|
84
85
|
#
|
85
|
-
def build(&block)
|
86
|
-
DSL::Sitemaps::Builder.new(self).instance_eval(&block)
|
86
|
+
def build(update: true, &block)
|
87
|
+
DSL::Sitemaps::Builder.new(self, update: update).instance_eval(&block)
|
87
88
|
end
|
88
89
|
# rubocop:enable Layout/LineLength
|
89
90
|
|
@@ -123,7 +124,7 @@ module OpenHAB
|
|
123
124
|
@listeners.each { |l| l.model_changed(element.name, org.openhab.core.model.core.EventType::REMOVED) }
|
124
125
|
end
|
125
126
|
|
126
|
-
def notify_listeners_about_updated_element(element)
|
127
|
+
def notify_listeners_about_updated_element(_old_element, element)
|
127
128
|
@listeners.each { |l| l.model_changed(element.name, org.openhab.core.model.core.EventType::MODIFIED) }
|
128
129
|
end
|
129
130
|
end
|
@@ -24,13 +24,11 @@ module OpenHAB
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# @!visibility private
|
27
|
-
def
|
27
|
+
def create_link(item, channel, config = {})
|
28
28
|
config = Configuration.new(config.transform_keys(&:to_s))
|
29
29
|
channel = ChannelUID.new(channel) if channel.is_a?(String)
|
30
30
|
channel = channel.uid if channel.is_a?(Channel)
|
31
|
-
|
32
|
-
|
33
|
-
current.add(link)
|
31
|
+
org.openhab.core.thing.link.ItemChannelLink.new(item.name, channel, config)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
@@ -39,11 +39,17 @@ module OpenHAB
|
|
39
39
|
#
|
40
40
|
# Enter the Thing Builder DSL.
|
41
41
|
# @param (see Core::Provider.current)
|
42
|
+
# @param update [true, false]
|
43
|
+
# When true, existing things with the same name will be redefined if they're different.
|
44
|
+
# When false, an error will be raised if a thing with the same uid already exists.
|
42
45
|
# @yield Block executed in the context of a {DSL::Things::Builder}.
|
43
46
|
# @return [Object] The result of the block.
|
47
|
+
# @raise [ArgumentError] if a thing with the same uid already exists and `update` is false.
|
48
|
+
# @raise [FrozenError] if `update` is true but the existing thing with the same uid
|
49
|
+
# wasn't created by the current provider.
|
44
50
|
#
|
45
|
-
def build(preferred_provider = nil, &block)
|
46
|
-
DSL::Things::Builder.new(preferred_provider).instance_eval(&block)
|
51
|
+
def build(preferred_provider = nil, update: true, &block)
|
52
|
+
DSL::Things::Builder.new(preferred_provider, update: update).instance_eval(&block)
|
47
53
|
end
|
48
54
|
|
49
55
|
#
|
@@ -35,7 +35,7 @@ module OpenHAB
|
|
35
35
|
# @return [org.openhab.core.thing.ThingStatus]
|
36
36
|
#
|
37
37
|
# @!attribute [r] channels
|
38
|
-
# @return [
|
38
|
+
# @return [ChannelsArray]
|
39
39
|
#
|
40
40
|
# @!attribute [r] uid
|
41
41
|
# Return the UID.
|
@@ -174,6 +174,11 @@ module OpenHAB
|
|
174
174
|
uid.to_s
|
175
175
|
end
|
176
176
|
|
177
|
+
# @return [org.openhab.core.common.registry.Provider, nil]
|
178
|
+
def provider
|
179
|
+
Provider.registry.provider_for(uid)
|
180
|
+
end
|
181
|
+
|
177
182
|
#
|
178
183
|
# Fetches the actions available for this thing.
|
179
184
|
#
|
@@ -192,6 +197,16 @@ module OpenHAB
|
|
192
197
|
$actions.get(scope || uid.binding_id, uid.to_s)
|
193
198
|
end
|
194
199
|
|
200
|
+
#
|
201
|
+
# Compares all attributes of the thing with another thing.
|
202
|
+
#
|
203
|
+
# @param other [Thing] The thing to compare with
|
204
|
+
# @return [true,false] true if all attributes are equal, false otherwise
|
205
|
+
#
|
206
|
+
def config_eql?(other)
|
207
|
+
%i[uid label channels bridge_uid location configuration].all? { |method| send(method) == other.send(method) }
|
208
|
+
end
|
209
|
+
|
195
210
|
#
|
196
211
|
# Delegate missing methods to the thing's default actions scope.
|
197
212
|
#
|
@@ -80,19 +80,19 @@ module OpenHAB
|
|
80
80
|
# @!attribute [r] latitude
|
81
81
|
# @return [QuantityType]
|
82
82
|
def latitude
|
83
|
-
QuantityType.new(raw_latitude.to_big_decimal,
|
83
|
+
QuantityType.new(raw_latitude.to_big_decimal, Units::DEGREE_ANGLE)
|
84
84
|
end
|
85
85
|
|
86
86
|
# @!attribute [r] longitude
|
87
87
|
# @return [QuantityType]
|
88
88
|
def longitude
|
89
|
-
QuantityType.new(raw_longitude.to_big_decimal,
|
89
|
+
QuantityType.new(raw_longitude.to_big_decimal, Units::DEGREE_ANGLE)
|
90
90
|
end
|
91
91
|
|
92
92
|
# @!attribute [r] altitude
|
93
93
|
# @return [QuantityType]
|
94
94
|
def altitude
|
95
|
-
QuantityType.new(raw_altitude.to_big_decimal,
|
95
|
+
QuantityType.new(raw_altitude.to_big_decimal, SIUnits::METRE)
|
96
96
|
end
|
97
97
|
|
98
98
|
#
|
@@ -118,23 +118,68 @@ module OpenHAB
|
|
118
118
|
class ProviderWrapper
|
119
119
|
attr_reader :provider
|
120
120
|
|
121
|
-
def initialize(provider)
|
121
|
+
def initialize(provider, update:)
|
122
122
|
@provider = provider
|
123
|
+
@update = update
|
123
124
|
end
|
124
125
|
|
125
126
|
# @!visibility private
|
126
127
|
def add(builder)
|
127
|
-
|
128
|
-
|
128
|
+
if DSL.items.key?(builder.name)
|
129
|
+
raise ArgumentError, "Item #{builder.name} already exists" unless @update
|
130
|
+
|
131
|
+
# Use provider.get because openHAB's ManagedProvider does not support the #[] method.
|
132
|
+
unless (old_item = provider.get(builder.name))
|
133
|
+
raise FrozenError, "Item #{builder.name} is managed by #{DSL.items[builder.name].provider}"
|
134
|
+
end
|
135
|
+
|
136
|
+
item = builder.build
|
137
|
+
if item.config_eql?(old_item)
|
138
|
+
logger.debug { "Not replacing existing item #{item.uid} because it is identical" }
|
139
|
+
item = old_item
|
140
|
+
else
|
141
|
+
logger.debug { "Replacing existing item #{item.uid} because it is not identical" }
|
142
|
+
provider.update(item)
|
143
|
+
end
|
144
|
+
item.metadata.merge!(builder.metadata)
|
145
|
+
item.metadata
|
146
|
+
.reject { |namespace, _| builder.metadata.key?(namespace) }
|
147
|
+
.each do |namespace, metadata|
|
148
|
+
item.metadata.delete(namespace) if metadata.provider == Core::Items::Metadata::Provider.current
|
149
|
+
end
|
150
|
+
else
|
151
|
+
item = builder.build
|
152
|
+
item.metadata.merge!(builder.metadata)
|
153
|
+
provider.add(item)
|
154
|
+
end
|
155
|
+
|
156
|
+
item.update(builder.state) unless builder.state.nil?
|
157
|
+
|
129
158
|
# make sure to add the item to the registry before linking it
|
130
|
-
|
159
|
+
provider = Core::Things::Links::Provider.current
|
160
|
+
channel_uids = builder.channels.to_set do |(channel, config)|
|
161
|
+
# fill in partial channel names from group's thing id
|
131
162
|
if !channel.include?(":") &&
|
132
163
|
(group = builder.groups.find { |g| g.is_a?(GroupItemBuilder) && g.thing })
|
133
164
|
thing = group.thing
|
134
165
|
channel = "#{thing}:#{channel}"
|
135
166
|
end
|
136
|
-
|
167
|
+
|
168
|
+
new_link = Core::Things::Links::Provider.create_link(item, channel, config)
|
169
|
+
if !(current_link = provider.get(new_link.uid))
|
170
|
+
provider.add(new_link)
|
171
|
+
elsif current_link.configuration != config
|
172
|
+
provider.update(new_link)
|
173
|
+
end
|
174
|
+
|
175
|
+
new_link.linked_uid
|
176
|
+
end
|
177
|
+
|
178
|
+
# remove links not in the new item
|
179
|
+
provider.all.each do |link|
|
180
|
+
provider.remove(link.uid) if link.item_name == item.name && !channel_uids.include?(link.linked_uid)
|
137
181
|
end
|
182
|
+
|
138
183
|
item
|
139
184
|
end
|
140
185
|
end
|
@@ -143,13 +188,15 @@ module OpenHAB
|
|
143
188
|
# @return [org.openhab.core.items.ItemProvider]
|
144
189
|
attr_reader :provider
|
145
190
|
|
146
|
-
def initialize(provider)
|
147
|
-
@provider = ProviderWrapper.new(Core::Items::Provider.current(provider))
|
191
|
+
def initialize(provider, update:)
|
192
|
+
@provider = ProviderWrapper.new(Core::Items::Provider.current(provider), update: update)
|
148
193
|
end
|
149
194
|
end
|
150
195
|
|
151
196
|
# The ItemBuilder DSL allows you to customize an Item
|
152
197
|
class ItemBuilder
|
198
|
+
include Core::EntityLookup
|
199
|
+
|
153
200
|
# The type of this item
|
154
201
|
# @example
|
155
202
|
# type #=> :switch
|
@@ -181,7 +228,7 @@ module OpenHAB
|
|
181
228
|
# @return [String, nil]
|
182
229
|
attr_accessor :format
|
183
230
|
# The icon to be associated with the item
|
184
|
-
# @return [Symbol, nil]
|
231
|
+
# @return [Symbol, String, nil]
|
185
232
|
attr_accessor :icon
|
186
233
|
# Groups to which this item should be added
|
187
234
|
# @return [Array<String, GroupItem>]
|
@@ -237,10 +284,11 @@ module OpenHAB
|
|
237
284
|
end
|
238
285
|
end
|
239
286
|
|
240
|
-
# @param dimension [Symbol, nil] The unit dimension for a {NumberItem} (see {ItemBuilder#dimension})
|
287
|
+
# @param dimension [Symbol, String, nil] The unit dimension for a {NumberItem} (see {ItemBuilder#dimension})
|
288
|
+
# Note the dimension must be properly capitalized.
|
241
289
|
# @param unit [Symbol, String, nil] The unit for a {NumberItem} (see {ItemBuilder#unit})
|
242
290
|
# @param format [String, nil] The formatting pattern for the item's state (see {ItemBuilder#format})
|
243
|
-
# @param icon [Symbol, nil] The icon to be associated with the item (see {ItemBuilder#icon})
|
291
|
+
# @param icon [Symbol, String, nil] The icon to be associated with the item (see {ItemBuilder#icon})
|
244
292
|
# @param group [String,
|
245
293
|
# GroupItem,
|
246
294
|
# GroupItemBuilder,
|
@@ -259,9 +307,10 @@ module OpenHAB
|
|
259
307
|
# Fluent alias for `tag`.
|
260
308
|
# @param autoupdate [true, false, nil] Autoupdate setting (see {ItemBuilder#autoupdate})
|
261
309
|
# @param thing [String, Core::Things::Thing, Core::Things::ThingUID, nil]
|
262
|
-
# A Thing to be used as the base for the channel
|
263
|
-
# @param channel [String, Core::Things::ChannelUID, nil]
|
264
|
-
#
|
310
|
+
# A Thing to be used as the base for the channel.
|
311
|
+
# @param channel [String, Symbol, Core::Things::ChannelUID, Core::Things::Channel, nil]
|
312
|
+
# Channel to link the item to (see {ItemBuilder#channel}).
|
313
|
+
# @param expire [String] An expiration specification (see {ItemBuilder#expire}).
|
265
314
|
# @param alexa [String, Symbol, Array<(String, Hash<String, Object>)>, nil]
|
266
315
|
# Alexa metadata (see {ItemBuilder#alexa})
|
267
316
|
# @param ga [String, Symbol, Array<(String, Hash<String, Object>)>, nil]
|
@@ -292,7 +341,16 @@ module OpenHAB
|
|
292
341
|
metadata: nil,
|
293
342
|
state: nil)
|
294
343
|
raise ArgumentError, "`name` cannot be nil" if name.nil?
|
295
|
-
|
344
|
+
|
345
|
+
if dimension
|
346
|
+
raise ArgumentError, "`dimension` can only be specified with NumberItem" unless type == :number
|
347
|
+
|
348
|
+
begin
|
349
|
+
org.openhab.core.types.util.UnitUtils.parse_dimension(dimension.to_s)
|
350
|
+
rescue java.lang.IllegalArgumentException
|
351
|
+
raise ArgumentError, "Invalid dimension '#{dimension}'"
|
352
|
+
end
|
353
|
+
end
|
296
354
|
|
297
355
|
name = name.name if name.respond_to?(:name)
|
298
356
|
if provider.is_a?(GroupItemBuilder)
|
@@ -413,6 +471,8 @@ module OpenHAB
|
|
413
471
|
#
|
414
472
|
# Add a channel link to this item.
|
415
473
|
#
|
474
|
+
# @param channel [String, Symbol, Core::Things::ChannelUID, Core::Things::Channel]
|
475
|
+
# Channel to link the item to. When thing is set, this can be a relative channel name.
|
416
476
|
# @param config [Hash] Additional configuration, such as profile
|
417
477
|
# @return [void]
|
418
478
|
#
|
@@ -423,16 +483,27 @@ module OpenHAB
|
|
423
483
|
# end
|
424
484
|
# end
|
425
485
|
#
|
486
|
+
# @example Relative channel name
|
487
|
+
# items.build do
|
488
|
+
# switch_item Bedroom_Light, thing: "mqtt:topic:bedroom-light", channel: :power
|
489
|
+
# end
|
490
|
+
#
|
426
491
|
def channel(channel, config = {})
|
492
|
+
channel = channel.to_s
|
427
493
|
channel = "#{@thing}:#{channel}" if @thing && !channel.include?(":")
|
428
494
|
@channels << [channel, config]
|
429
495
|
end
|
430
496
|
|
431
497
|
#
|
432
|
-
# @!method expire(command: nil, state: nil)
|
498
|
+
# @!method expire(duration, command: nil, state: nil, ignore_state_updates: nil, ignore_commands: nil)
|
433
499
|
#
|
434
500
|
# Configure item expiration
|
435
501
|
#
|
502
|
+
# @param duration [String, Duration, nil] Duration after which the command or state should be applied
|
503
|
+
# @param command [String, nil] Command to send on expiration
|
504
|
+
# @param state [String, nil] State to set on expiration
|
505
|
+
# @param ignore_state_updates [true, false] When true, state updates will not reset the expire timer
|
506
|
+
# @param ignore_commands [true, false] When true, commands will not reset the expire timer
|
436
507
|
# @return [void]
|
437
508
|
#
|
438
509
|
# @example Get the current expire setting
|
@@ -448,7 +519,12 @@ module OpenHAB
|
|
448
519
|
# expire 5.minutes, state: NULL
|
449
520
|
# @example Send a command on expiration
|
450
521
|
# expire 5.minutes, command: OFF
|
451
|
-
|
522
|
+
# @example Specify the duration and command in the same string
|
523
|
+
# expire "5h,command=OFF"
|
524
|
+
# @example Set the expire configuration
|
525
|
+
# expire 5.minutes, ignore_state_updates: true
|
526
|
+
#
|
527
|
+
def expire(*args, command: nil, state: nil, ignore_state_updates: nil, ignore_commands: nil)
|
452
528
|
unless (0..2).cover?(args.length)
|
453
529
|
raise ArgumentError,
|
454
530
|
"wrong number of arguments (given #{args.length}, expected 0..2)"
|
@@ -463,9 +539,14 @@ module OpenHAB
|
|
463
539
|
|
464
540
|
duration = duration.to_s[2..].downcase if duration.is_a?(Duration)
|
465
541
|
state = "'#{state}'" if state.respond_to?(:to_str) && type == :string
|
466
|
-
|
467
|
-
|
468
|
-
|
542
|
+
|
543
|
+
value = duration
|
544
|
+
value += ",state=#{state}" if state
|
545
|
+
value += ",command=#{command}" if command
|
546
|
+
|
547
|
+
config = { ignoreStateUpdates: ignore_state_updates, ignoreCommands: ignore_commands }
|
548
|
+
config.compact!
|
549
|
+
@expire = [value, config]
|
469
550
|
end
|
470
551
|
|
471
552
|
# @!attribute [w] unit
|
@@ -513,12 +594,10 @@ module OpenHAB
|
|
513
594
|
tags.each do |tag|
|
514
595
|
item.add_tag(tag)
|
515
596
|
end
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
item.metadata["unit"] = unit if unit
|
521
|
-
item.state = item.format_update(state) unless state.nil?
|
597
|
+
metadata["autoupdate"] = autoupdate.to_s unless autoupdate.nil?
|
598
|
+
metadata["expire"] = expire if expire
|
599
|
+
metadata["stateDescription"] = { "pattern" => format } if format
|
600
|
+
metadata["unit"] = unit if unit
|
522
601
|
item
|
523
602
|
end
|
524
603
|
|
@@ -567,7 +646,7 @@ module OpenHAB
|
|
567
646
|
|
568
647
|
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
569
648
|
def #{m}(*args, groups: nil, **kwargs) # def dimmer_item(*args, groups: nil, **kwargs)
|
570
|
-
groups
|
649
|
+
groups = Array.wrap(groups) # groups = Array.wrap(groups)
|
571
650
|
groups << self # groups << self
|
572
651
|
super # super
|
573
652
|
end # end
|
@@ -12,8 +12,9 @@ module OpenHAB
|
|
12
12
|
# Base sitemap builder DSL
|
13
13
|
class Builder
|
14
14
|
# @!visibility private
|
15
|
-
def initialize(provider)
|
15
|
+
def initialize(provider, update:)
|
16
16
|
@provider = provider
|
17
|
+
@update = update
|
17
18
|
end
|
18
19
|
|
19
20
|
# (see SitemapBuilder#initialize)
|
@@ -23,8 +24,12 @@ module OpenHAB
|
|
23
24
|
def sitemap(name, label = nil, icon: nil, &block)
|
24
25
|
sitemap = SitemapBuilder.new(name, label, icon: icon)
|
25
26
|
sitemap.instance_eval_with_dummy_items(&block) if block
|
26
|
-
|
27
|
-
sitemap
|
27
|
+
sitemap = sitemap.build
|
28
|
+
if @update && @provider.get(sitemap.uid)
|
29
|
+
@provider.update(sitemap)
|
30
|
+
else
|
31
|
+
@provider.add(sitemap)
|
32
|
+
end
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
@@ -22,7 +22,7 @@ module OpenHAB
|
|
22
22
|
# payloadNotAvailable: "offline"
|
23
23
|
# }
|
24
24
|
# things.build do
|
25
|
-
# thing("mqtt:topic:my-switch", "My Switch", bridge: "mqtt:
|
25
|
+
# thing("mqtt:topic:my-switch", "My Switch", bridge: "mqtt:broker:mosquitto", config: thing_config) do
|
26
26
|
# channel("switch1", "switch", config: {
|
27
27
|
# stateTopic: "stat/my-switch/switch1/state", commandTopic: "cmnd/my-switch/switch1/command"
|
28
28
|
# })
|
@@ -40,8 +40,9 @@ module OpenHAB
|
|
40
40
|
# @return [org.openhab.core.thing.ManagedThingProvider]
|
41
41
|
attr_reader :provider
|
42
42
|
|
43
|
-
def initialize(provider)
|
43
|
+
def initialize(provider, update: false)
|
44
44
|
@provider = Core::Things::Provider.current(provider)
|
45
|
+
@update = update
|
45
46
|
end
|
46
47
|
|
47
48
|
# Create a new Bridge
|
@@ -61,10 +62,27 @@ module OpenHAB
|
|
61
62
|
def build(klass, *args, **kwargs, &block)
|
62
63
|
builder = klass.new(*args, **kwargs)
|
63
64
|
builder.instance_eval(&block) if block
|
64
|
-
thing =
|
65
|
-
|
65
|
+
thing = builder.build
|
66
|
+
|
67
|
+
if DSL.things.key?(thing.uid)
|
68
|
+
raise ArgumentError, "Thing #{thing.uid} already exists" unless @update
|
69
|
+
|
70
|
+
unless (old_thing = provider.get(thing.uid))
|
71
|
+
raise FrozenError, "Thing #{thing.uid} is managed by #{thing.provider}"
|
72
|
+
end
|
73
|
+
|
74
|
+
if thing.config_eql?(old_thing)
|
75
|
+
logger.debug { "Not replacing existing thing #{thing.uid}" }
|
76
|
+
thing = old_thing
|
77
|
+
else
|
78
|
+
provider.update(thing)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
provider.add(thing)
|
82
|
+
end
|
66
83
|
thing.enable(enabled: builder.enabled) unless builder.enabled.nil?
|
67
|
-
|
84
|
+
|
85
|
+
Core::Things::Proxy.new(thing)
|
68
86
|
end
|
69
87
|
end
|
70
88
|
|
@@ -176,10 +194,11 @@ module OpenHAB
|
|
176
194
|
|
177
195
|
# Add an explicitly configured channel to this item
|
178
196
|
# @see ChannelBuilder#initialize
|
197
|
+
# @return [Core::Things::Channel]
|
179
198
|
def channel(*args, **kwargs, &block)
|
180
199
|
channel = ChannelBuilder.new(*args, thing: self, **kwargs)
|
181
200
|
channel.instance_eval(&block) if block
|
182
|
-
@channels <<
|
201
|
+
channel.build.tap { |c| @channels << c }
|
183
202
|
end
|
184
203
|
|
185
204
|
# @!visibility private
|
@@ -195,6 +214,7 @@ module OpenHAB
|
|
195
214
|
builder = org.openhab.core.thing.binding.builder.ThingBuilder
|
196
215
|
.create(thing_type_uid, uid)
|
197
216
|
.with_label(label)
|
217
|
+
.with_location(location)
|
198
218
|
.with_configuration(configuration)
|
199
219
|
.with_bridge(bridge_uid)
|
200
220
|
.with_channels(channels)
|
@@ -209,9 +229,7 @@ module OpenHAB
|
|
209
229
|
builder.with_properties(thing_type.properties)
|
210
230
|
end
|
211
231
|
|
212
|
-
|
213
|
-
Core::Things.manager.set_enabled(uid, enabled) unless enabled.nil?
|
214
|
-
thing
|
232
|
+
builder.build
|
215
233
|
end
|
216
234
|
|
217
235
|
private
|
data/lib/openhab/dsl/version.rb
CHANGED
data/lib/openhab/log.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
|
+
$ctx ||= nil
|
6
|
+
|
5
7
|
module OpenHAB
|
6
8
|
# rubocop:disable Layout/LineLength
|
7
9
|
|
@@ -83,8 +85,8 @@ module OpenHAB
|
|
83
85
|
when String
|
84
86
|
name = object
|
85
87
|
when :main
|
86
|
-
name = "#{Logger::PREFIX}.#{rules_file.tr_s(":", "_")
|
87
|
-
|
88
|
+
name = "#{Logger::PREFIX}.#{rules_file.tr_s(":", "_").gsub(/[^A-Za-z0-9_.-]/, "")}"
|
89
|
+
name = "#{name}.#{$ctx["ruleUID"]}" if $ctx&.key?("ruleUID")
|
88
90
|
return @loggers[name] ||= BiLogger.new(Logger.new(name))
|
89
91
|
end
|
90
92
|
|
@@ -231,14 +231,6 @@ module OpenHAB
|
|
231
231
|
|
232
232
|
rs = OSGi.service("org.openhab.core.service.ReadyService")
|
233
233
|
|
234
|
-
# Add a fake automation:scriptEngineFactories to satisfy startlevel 30
|
235
|
-
begin
|
236
|
-
sef_marker = org.openhab.core.automation.module.script.internal.ScriptEngineFactoryBundleTracker::READY_MARKER
|
237
|
-
rs.mark_ready(sef_marker)
|
238
|
-
rescue NameError
|
239
|
-
# @deprecated OH3.4 NOOP - the ScriptEngineFactoryBundleTracker doesn't exist in OH3
|
240
|
-
end
|
241
|
-
|
242
234
|
# wait for the rule engine
|
243
235
|
filter = org.openhab.core.service.ReadyMarkerFilter.new
|
244
236
|
.with_type(org.openhab.core.service.StartLevelService::STARTLEVEL_MARKER_TYPE)
|
data/lib/openhab/rspec/karaf.rb
CHANGED
@@ -327,6 +327,7 @@ module OpenHAB
|
|
327
327
|
org.openhab.core.io.monitor
|
328
328
|
org.openhab.core.io.rest
|
329
329
|
org.openhab.core.io.rest.sse
|
330
|
+
org.eclipse.jetty.http2.hpack
|
330
331
|
].freeze
|
331
332
|
private_constant :ALLOWED_BUNDLES
|
332
333
|
|
@@ -742,6 +743,8 @@ module OpenHAB
|
|
742
743
|
|
743
744
|
startlevels = File.read(config_file)
|
744
745
|
startlevels.sub!(",rules:refresh,rules:dslprovider", "")
|
746
|
+
startlevels.sub!(",automation:scriptEngineFactories", "") # since OH4
|
747
|
+
startlevels.sub!("dsl:rules,", "") # since OH41-snapshot
|
745
748
|
|
746
749
|
target_file = "#{oh_userdata}/services.cfg"
|
747
750
|
target_file_contents = File.read(target_file) if File.exist?(target_file)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openhab-scripting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian O'Connell
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-
|
13
|
+
date: 2023-10-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|