openhab-scripting 5.9.0 → 5.11.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f531c0d4e77bbee531e574b759f56e458d4eacde89520b8cf9f810dd46e61d9
4
- data.tar.gz: 7724b5709c56fb80f095c14930fd3077a2019111731865f1956f4b080a8039ab
3
+ metadata.gz: 9e7d078cc73659d0f435950d36438b67759b2e3b5c0abf80f258a36101792a0d
4
+ data.tar.gz: 2a76c20015d6320b64a2a9ea79557c7133b1101a8514fabba9241f91b455615d
5
5
  SHA512:
6
- metadata.gz: 11237012154342229a7b1a4b24a2e5e8f81833d758e81614b067c4a1187a598e5fbc45cfd300312ef0f039130a039e6df7c75f59e08e458d0bdf7761e2a85f8d
7
- data.tar.gz: 3bd394f5d950d2ab5a0016a4219d7d1ac0cb9f4fbdca541d4f41c9e59406c01a1d0df242334cc95a4cf1668f546e1f0fc7aa03cd835f71384e4a3de4cace8304
6
+ metadata.gz: bc54b1fae7be3bee15b1af2c27526cf942a13741404dd1c0e61034b82d2d472703bfb48ef921d25ed608dbe3d9c964abbded85ab1d3adfd855847229c6bf2447
7
+ data.tar.gz: c454623c911c90be03464391f885b8ccebfd2789b5e9dbbe32a6f8309fdf7e1f948e2c0730373d383bf7892271ab752bf9d8c2197ed541cff7f33a692ea296ec
@@ -10,6 +10,9 @@ module OpenHAB
10
10
  # @return [Object]
11
11
  attr_accessor :attachment
12
12
 
13
+ # @return [Hash]
14
+ attr_accessor :inputs
15
+
13
16
  # @return [String]
14
17
  alias_method :inspect, :to_s
15
18
 
@@ -16,6 +16,25 @@ module OpenHAB
16
16
  def item
17
17
  EntityLookup.lookup_item(item_name)
18
18
  end
19
+
20
+ #
21
+ # @!attribute [r] group
22
+ #
23
+ # Returns the group item whose member had triggered this event.
24
+ #
25
+ # This is the equivalent of openHAB's `triggeringGroup`, and it is only available
26
+ # on a member-of-group trigger.
27
+ #
28
+ # @return [Item,nil] The group item whose member had triggered this event.
29
+ # `nil` when the event wasn't triggered by a member-of-group trigger.
30
+ #
31
+ # @since openHAB 4.0 for file-based rules
32
+ # @since openHAB 4.1 for UI rules
33
+ #
34
+ def group
35
+ triggering_group = inputs&.[]("triggeringGroup") || $ctx&.[]("triggeringGroup")
36
+ Items::Proxy.new(triggering_group) if triggering_group
37
+ end
19
38
  end
20
39
  end
21
40
  end
@@ -133,6 +133,16 @@ module OpenHAB
133
133
  # Send the {DECREASE} command to the item
134
134
  # @return [DimmerItem] `self`
135
135
 
136
+ # @!method increase!
137
+ # Send the {INCREASE} command to the item, even when
138
+ # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
139
+ # @return [DimmerItem] `self`
140
+
141
+ # @!method decrease!
142
+ # Send the {DECREASE} command to the item, even when
143
+ # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
144
+ # @return [DimmerItem] `self`
145
+
136
146
  # raw numbers translate directly to PercentType, not a DecimalType
137
147
  # @!visibility private
138
148
  def format_type(command)
@@ -128,15 +128,19 @@ module OpenHAB
128
128
  # Send a command to this item
129
129
  #
130
130
  # When this method is chained after the {OpenHAB::DSL::Items::Ensure::Ensurable#ensure ensure}
131
- # method, or issued inside an {OpenHAB::DSL.ensure_states ensure_states} block,
131
+ # method, or issued inside an {OpenHAB::DSL.ensure_states ensure_states} block, or after
132
+ # {OpenHAB::DSL.ensure_states! ensure_states!} have been called,
132
133
  # the command will only be sent if the item is not already in the same state.
133
134
  #
135
+ # The similar method `command!`, however, will always send the command regardless of the item's state.
136
+ #
134
137
  # @param [Command] command command to send to the item
135
138
  # @return [self, nil] nil when `ensure` is in effect and the item was already in the same state,
136
139
  # otherwise the item.
137
140
  #
138
141
  # @see DSL::Items::TimedCommand#command Timed Command
139
142
  # @see OpenHAB::DSL.ensure_states ensure_states
143
+ # @see OpenHAB::DSL.ensure_states! ensure_states!
140
144
  # @see DSL::Items::Ensure::Ensurable#ensure ensure
141
145
  #
142
146
  def command(command)
@@ -145,6 +149,7 @@ module OpenHAB
145
149
  $events.send_command(self, command)
146
150
  Proxy.new(self)
147
151
  end
152
+ alias_method :command!, :command
148
153
 
149
154
  # not an alias to allow easier stubbing and overriding
150
155
  def <<(command)
@@ -170,6 +175,7 @@ module OpenHAB
170
175
  $events.post_update(self, state)
171
176
  Proxy.new(self)
172
177
  end
178
+ alias_method :update!, :update
173
179
 
174
180
  # @!visibility private
175
181
  def format_command(command)
@@ -251,6 +251,7 @@ module OpenHAB
251
251
  !(self.tags.to_a & tags).empty?
252
252
  end
253
253
 
254
+ # @!attribute thing [r]
254
255
  # Return the item's thing if this item is linked with a thing. If an item is linked to more than one thing,
255
256
  # this method only returns the first thing.
256
257
  #
@@ -260,6 +261,7 @@ module OpenHAB
260
261
  end
261
262
  alias_method :linked_thing, :thing
262
263
 
264
+ # @!attribute things [r]
263
265
  # Returns all of the item's linked things.
264
266
  #
265
267
  # @return [Array<Thing>] An array of things or an empty array
@@ -268,11 +270,80 @@ module OpenHAB
268
270
  end
269
271
  alias_method :all_linked_things, :things
270
272
 
273
+ #
274
+ # @!attribute links [r]
271
275
  # Returns all of the item's links (channels and link configurations).
272
276
  #
273
- # @return [Array<ItemChannelLink>] An array of ItemChannelLink or an empty array
277
+ # @return [ItemChannelLinks] An array of ItemChannelLink or an empty array
278
+ #
279
+ # @example Get the configuration of the first link
280
+ # LivingRoom_Light_Power.links.first.configuration
281
+ #
282
+ # @example Remove all managed links
283
+ # LivingRoom_Light_Power.links.clear
284
+ #
285
+ # @see link
286
+ # @see unlink
287
+ #
274
288
  def links
275
- Things::Links::Provider.registry.get_links(name)
289
+ ItemChannelLinks.new(self, Things::Links::Provider.registry.get_links(name))
290
+ end
291
+
292
+ #
293
+ # Links the item to a channel.
294
+ #
295
+ # @param [String, Things::Channel, Things::ChannelUID] channel The channel to link to.
296
+ # @param [Hash] config The configuration for the link.
297
+ #
298
+ # @return [Things::ItemChannelLink] The created link.
299
+ #
300
+ # @example Link an item to a channel
301
+ # LivingRoom_Light_Power.link("mqtt:topic:livingroom-light:power")
302
+ #
303
+ # @example Link to a Thing's channel
304
+ # LivingRoom_Light_Power.link(things["mqtt:topic:livingroom-light"].channels["power"])
305
+ #
306
+ # @example Specify a link configuration
307
+ # High_Temperature_Alert.link(
308
+ # "mqtt:topic:outdoor-thermometer:temperature",
309
+ # profile: "system:hysteresis",
310
+ # lower: "29 °C",
311
+ # upper: "30 °C")
312
+ #
313
+ # @see links
314
+ # @see unlink
315
+ #
316
+ def link(channel, config = {})
317
+ Core::Things::Links::Provider.create_link(self, channel, config).tap do |new_link|
318
+ provider = Core::Things::Links::Provider.current
319
+ if !(current_link = provider.get(new_link.uid))
320
+ provider.add(new_link)
321
+ elsif current_link.configuration != config
322
+ provider.update(new_link)
323
+ end
324
+ end
325
+ end
326
+
327
+ #
328
+ # Removes a link to a channel from managed link providers.
329
+ #
330
+ # @param [String, Things::Channel, Things::ChannelUID] channel The channel to remove the link to.
331
+ #
332
+ # @return [Things::ItemChannelLink, nil] The removed link, if found.
333
+ # @raise [FrozenError] if the link is not managed by a managed link provider.
334
+ #
335
+ # @see link
336
+ # @see links
337
+ #
338
+ def unlink(channel)
339
+ link_to_delete = Things::Links::Provider.create_link(self, channel, {})
340
+ provider = Things::Links::Provider.registry.provider_for(link_to_delete.uid)
341
+ unless provider.is_a?(ManagedProvider)
342
+ raise FrozenError,
343
+ "Cannot remove the link #{link_to_delete.uid} from non-managed provider #{provider.inspect}"
344
+ end
345
+
346
+ provider.remove(link_to_delete.uid)
276
347
  end
277
348
 
278
349
  # @return [String]
@@ -286,7 +357,8 @@ module OpenHAB
286
357
  "#{s}>"
287
358
  end
288
359
 
289
- # @return [org.openhab.core.common.registry.Provider, nil]
360
+ # @!attribute provider [r]
361
+ # @return [org.openhab.core.common.registry.Provider, nil] Returns the provider for this item.
290
362
  def provider
291
363
  Provider.registry.provider_for(self)
292
364
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module Items
8
+ #
9
+ # A wrapper for {Item#links} delegated to Set<{org.openhab.core.thing.link.ItemChannelLink}>.
10
+ #
11
+ # Adds methods for clearing item's links to channels.
12
+ #
13
+ class ItemChannelLinks < SimpleDelegator
14
+ #
15
+ # @param [Item] item The item that the links belong to
16
+ # @param [Set<ItemChannelLink>] links The set of links to delegate to
17
+ #
18
+ # @!visibility private
19
+ def initialize(item, links)
20
+ super(links)
21
+ @item = item
22
+ end
23
+
24
+ #
25
+ # Removes all links to channels from managed link providers.
26
+ # @return [self]
27
+ #
28
+ def clear
29
+ Things::Links::Provider.registry.all.each do |link|
30
+ next unless link.item_name == @item.name
31
+
32
+ provider = Things::Links::Provider.registry.provider_for(link.uid)
33
+ if provider.is_a?(ManagedProvider)
34
+ provider.remove(link.uid)
35
+ else
36
+ logger.warn("Cannot remove the link #{link.uid} from non-managed provider #{provider.inspect}")
37
+ end
38
+ end
39
+ self
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -39,25 +39,51 @@ module OpenHAB
39
39
  # Send the {PLAY} command to the item
40
40
  # @return [PlayerItem] `self`
41
41
 
42
+ # @!method play!
43
+ # Send the {PLAY} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
44
+ # @return [PlayerItem] `self`
45
+
42
46
  # @!method pause
43
47
  # Send the {PAUSE} command to the item
44
48
  # @return [PlayerItem] `self`
45
49
 
50
+ # @!method pause!
51
+ # Send the {PAUSE} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
52
+ # @return [PlayerItem] `self`
53
+
46
54
  # @!method rewind
47
55
  # Send the {REWIND} command to the item
48
56
  # @return [PlayerItem] `self`
49
57
 
58
+ # @!method rewind
59
+ # Send the {REWIND} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
60
+ # @return [PlayerItem] `self`
61
+
50
62
  # @!method fast_forward
51
63
  # Send the {FASTFORWARD} command to the item
52
64
  # @return [PlayerItem] `self`
53
65
 
66
+ # @!method fast_forward!
67
+ # Send the {FASTFORWARD} command to the item, even when
68
+ # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
69
+ # @return [PlayerItem] `self`
70
+
54
71
  # @!method next
55
72
  # Send the {NEXT} command to the item
56
73
  # @return [PlayerItem] `self`
57
74
 
75
+ # @!method next!
76
+ # Send the {NEXT} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
77
+ # @return [PlayerItem] `self`
78
+
58
79
  # @!method previous
59
80
  # Send the {PREVIOUS} command to the item
60
81
  # @return [PlayerItem] `self`
82
+
83
+ # @!method previous!
84
+ # Send the {PREVIOUS} command to the item, even when
85
+ # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
86
+ # @return [PlayerItem] `self`
61
87
  end
62
88
  end
63
89
  end
@@ -41,18 +41,34 @@ module OpenHAB
41
41
  # Send the {UP} command to the item
42
42
  # @return [RollershutterItem] `self`
43
43
 
44
+ # @!method up!
45
+ # Send the {UP} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
46
+ # @return [RollershutterItem] `self`
47
+
44
48
  # @!method down
45
49
  # Send the {DOWN} command to the item
46
50
  # @return [RollershutterItem] `self`
47
51
 
52
+ # @!method down!
53
+ # Send the {DOWN} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
54
+ # @return [RollershutterItem] `self`
55
+
48
56
  # @!method stop
49
57
  # Send the {STOP} command to the item
50
58
  # @return [RollershutterItem] `self`
51
59
 
60
+ # @!method stop!
61
+ # Send the {STOP} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
62
+ # @return [RollershutterItem] `self`
63
+
52
64
  # @!method move
53
65
  # Send the {MOVE} command to the item
54
66
  # @return [RollershutterItem] `self`
55
67
 
68
+ # @!method move!
69
+ # Send the {MOVE} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
70
+ # @return [RollershutterItem] `self`
71
+
56
72
  # raw numbers translate directly to PercentType, not a DecimalType
57
73
  # @!visibility private
58
74
  def format_type(command)
@@ -101,6 +101,15 @@ module Enumerable
101
101
  self if count { |i| i.command(command) }.positive?
102
102
  end
103
103
 
104
+ # Send a command to every item in the collection, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
105
+ # @return [self]
106
+ def command!(command)
107
+ # We cannot alias this to #command above, otherwise it will call
108
+ # DSL::Items::Ensure::Item#command which checks for ensure_states
109
+ each { |i| i.command!(command) }
110
+ self
111
+ end
112
+
104
113
  # Update the state of every item in the collection
105
114
  # @return [self, nil] nil when `ensure` is in effect and all the items were already in the same state,
106
115
  # otherwise self
@@ -108,6 +117,16 @@ module Enumerable
108
117
  self if count { |i| i.update(state) }.positive?
109
118
  end
110
119
 
120
+ # Update the state of every item in the collection, even when
121
+ # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
122
+ # @return [self]
123
+ def update!(state)
124
+ # We cannot alias this to #update above, otherwise it will call
125
+ # DSL::Items::Ensure::Item#update which checks for ensure_states
126
+ each { |i| i.update!(state) }
127
+ self
128
+ end
129
+
111
130
  # @!method refresh
112
131
  # Send the {REFRESH} command to every item in the collection
113
132
  # @return [self]
@@ -311,6 +311,11 @@ module OpenHAB
311
311
  synonyms = Array.wrap(synonyms).map { |s| s.to_s.strip }
312
312
 
313
313
  tags.map do |name, parent|
314
+ if (existing_tag = lookup(name))
315
+ logger.warn("Tag already exists: #{existing_tag.inspect}")
316
+ next
317
+ end
318
+
314
319
  unless parent.is_a?(SemanticTag)
315
320
  parent_tag = lookup(parent)
316
321
  raise ArgumentError, "Unknown parent: #{parent}" unless parent_tag
@@ -318,8 +323,6 @@ module OpenHAB
318
323
  parent = parent_tag
319
324
  end
320
325
 
321
- next if lookup(name)
322
-
323
326
  new_tag = org.openhab.core.semantics.SemanticTagImpl.new("#{parent.uid}_#{name}",
324
327
  label,
325
328
  description,
@@ -67,9 +67,17 @@ module OpenHAB
67
67
  # Send the {ON} command to the item
68
68
  # @return [SwitchItem] `self`
69
69
 
70
+ # @!method on!
71
+ # Send the {ON} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
72
+ # @return [SwitchItem] `self`
73
+
70
74
  # @!method off
71
75
  # Send the {OFF} command to the item
72
76
  # @return [SwitchItem] `self`
77
+
78
+ # @!method off!
79
+ # Send the {OFF} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
80
+ # @return [SwitchItem] `self`
73
81
  end
74
82
  end
75
83
  end
@@ -65,13 +65,19 @@ module OpenHAB
65
65
  ruby2_keywords def #{command}(*args, &block) # ruby2_keywords def on(*args, &block)
66
66
  command(#{value}, *args, &block) # command(ON, *args, &block)
67
67
  end # end
68
+ ruby2_keywords def #{command}!(*args, &block) # ruby2_keywords def on!(*args, &block)
69
+ command!(#{value}, *args, &block) # command!(ON, *args, &block)
70
+ end # end
68
71
  RUBY
69
72
 
70
73
  logger.trace("Defining Enumerable##{command} for #{value}")
71
74
  Enumerable.class_eval <<~RUBY, __FILE__, __LINE__ + 1
72
- def #{command} # def on
73
- each(&:#{command}) # each(&:on)
74
- end # end
75
+ def #{command} # def on
76
+ each(&:#{command}) # each(&:on)
77
+ end # end
78
+ def #{command}! # def on!
79
+ each(&:#{command}!) # each(&:on!)
80
+ end # end
75
81
  RUBY
76
82
 
77
83
  logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
@@ -42,8 +42,7 @@ module OpenHAB
42
42
  # @return [Array<Item>] An array of things or an empty array
43
43
  #
44
44
  def items
45
- registry = OSGi.service("org.openhab.core.thing.link.ItemChannelLinkRegistry")
46
- registry.get_linked_items(self).map { |i| Items::Proxy.new(i) }
45
+ Links::Provider.registry.get_linked_items(self).map { |i| Items::Proxy.new(i) }
47
46
  end
48
47
  end
49
48
  end
@@ -26,6 +26,12 @@ module OpenHAB
26
26
  DSL.items[item_name]
27
27
  end
28
28
 
29
+ # @!attribute [r] channel
30
+ # @return [Channel]
31
+ def channel
32
+ DSL.things[linked_uid.thing_uid].channels[linked_uid.id]
33
+ end
34
+
29
35
  alias_method :channel_uid, :linked_uid
30
36
  end
31
37
  end
@@ -8,44 +8,38 @@ module OpenHAB
8
8
  # and channels.
9
9
  #
10
10
  module ProfileCallback
11
- class << self
12
- #
13
- # Wraps the parent class's method to format non-Types.
14
- #
15
- # @!macro def_state_parsing_method
16
- # @!method $1($2)
17
- # @return [void]
18
- # @!visibility private
19
- def def_state_parsing_method(method, param_name)
20
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
21
- def #{method}(type) # def handle_command(type)
22
- type = link.item.format_#{(param_name == :state) ? :update : param_name}(type) # type = link.item.format_command(type)
23
- super(type) # super(type)
24
- end # end
25
- RUBY
26
- end
27
- end
28
-
29
11
  #
30
12
  # Forward the given command to the respective thing handler.
31
13
  #
32
14
  # @param [Command] command
33
15
  #
34
- def_state_parsing_method(:handle_command, :command)
16
+ def handle_command(command)
17
+ unless instance_variable_defined?(:@dummy_channel_item)
18
+ @dummy_channel_item = DSL::Items::ItemBuilder.item_factory.create_item(link.channel.accepted_item_type, "")
19
+ end
20
+ command = @dummy_channel_item.format_command(command) if @dummy_channel_item
21
+ super(command)
22
+ end
35
23
 
36
24
  #
37
25
  # Send a command to the framework.
38
26
  #
39
27
  # @param [Command] command
40
28
  #
41
- def_state_parsing_method(:send_command, :command)
29
+ def send_command(command)
30
+ command = link.item.format_command(command)
31
+ super(command)
32
+ end
42
33
 
43
34
  #
44
35
  # Send a state update to the framework.
45
36
  #
46
37
  # @param [State] state
47
38
  #
48
- def_state_parsing_method(:send_update, :state)
39
+ def send_update(state)
40
+ state = link.item.format_update(state)
41
+ super(state)
42
+ end
49
43
  end
50
44
  end
51
45
  end
@@ -156,7 +156,6 @@ module OpenHAB
156
156
  item.update(builder.state) unless builder.state.nil?
157
157
 
158
158
  # make sure to add the item to the registry before linking it
159
- provider = Core::Things::Links::Provider.current
160
159
  channel_uids = builder.channels.to_set do |(channel, config)|
161
160
  # fill in partial channel names from group's thing id
162
161
  if !channel.include?(":") &&
@@ -165,17 +164,11 @@ module OpenHAB
165
164
  channel = "#{thing}:#{channel}"
166
165
  end
167
166
 
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
167
+ item.link(channel, config).linked_uid
176
168
  end
177
169
 
178
170
  # remove links not in the new item
171
+ provider = Core::Things::Links::Provider.current
179
172
  provider.all.each do |link|
180
173
  provider.remove(link.uid) if link.item_name == item.name && !channel_uids.include?(link.linked_uid)
181
174
  end
@@ -24,7 +24,7 @@ module OpenHAB
24
24
 
25
25
  # Extensions for {::Item} to implement {Ensure}'s functionality
26
26
  #
27
- # @see OpenHAB::DSL.ensure ensure
27
+ # @see OpenHAB::DSL::Items::Ensure::Ensurable#ensure ensure
28
28
  # @see OpenHAB::DSL.ensure_states ensure_states
29
29
  module Item
30
30
  include Ensurable
@@ -149,6 +149,8 @@ module OpenHAB
149
149
  end
150
150
 
151
151
  event.attachment = attachment
152
+ # events that are not from AbstractEvent do not have inputs
153
+ event.inputs = inputs if event.respond_to?(:inputs=)
152
154
  return event
153
155
  end
154
156
 
@@ -210,7 +210,18 @@ module OpenHAB
210
210
  thing_type,
211
211
  self.class.config_description_registry
212
212
  )
213
+
214
+ predefined_channels = self.class.thing_factory_helper
215
+ .create_channels(thing_type, uid, self.class.config_description_registry)
216
+ .to_h { |channel| [channel.uid, channel] }
217
+ new_channels = channels.to_h { |channel| [channel.uid, channel] }
218
+ merged_channels = predefined_channels.merge(new_channels) do |_key, predefined_channel, new_channel|
219
+ predefined_channel.configuration.merge!(new_channel.configuration)
220
+ predefined_channel
221
+ end
222
+ @channels = merged_channels.values
213
223
  end
224
+
214
225
  builder = org.openhab.core.thing.binding.builder.ThingBuilder
215
226
  .create(thing_type_uid, uid)
216
227
  .with_label(label)
@@ -219,15 +230,7 @@ module OpenHAB
219
230
  .with_bridge(bridge_uid)
220
231
  .with_channels(channels)
221
232
 
222
- if thing_type
223
- # can't use with_channels, or it will wipe out custom channels from above
224
- self.class.thing_factory_helper.create_channels(thing_type,
225
- uid,
226
- self.class.config_description_registry).each do |channel|
227
- builder.with_channel(channel)
228
- end
229
- builder.with_properties(thing_type.properties)
230
- end
233
+ builder.with_properties(thing_type.properties) if thing_type
231
234
 
232
235
  builder.build
233
236
  end
@@ -263,8 +266,14 @@ module OpenHAB
263
266
  :default_tags,
264
267
  :properties,
265
268
  :description,
266
- :auto_update_policy,
267
- :accepted_item_type
269
+ :auto_update_policy
270
+
271
+ class << self
272
+ # @!visibility private
273
+ def channel_type_registry
274
+ @channel_type_registry ||= OSGi.service("org.openhab.core.thing.type.ChannelTypeRegistry")
275
+ end
276
+ end
268
277
 
269
278
  #
270
279
  # Constructor for ChannelBuilder
@@ -284,7 +293,7 @@ module OpenHAB
284
293
  # The default tags for this channel.
285
294
  # @param [:default, :recommend, :veto, org.openhab.core.thing.type.AutoUpdatePolicy] auto_update_policy
286
295
  # The channel's auto update policy.
287
- # @param [String] accepted_item_type The accepted item type.
296
+ # @param [String] accepted_item_type The accepted item type. If nil, infer the item type from the channel type.
288
297
  #
289
298
  def initialize(uid,
290
299
  type,
@@ -343,6 +352,12 @@ module OpenHAB
343
352
  .build
344
353
  end
345
354
 
355
+ # @!attribute [r] accepted_item_type
356
+ # @return [String] The accepted item type.
357
+ def accepted_item_type
358
+ @accepted_item_type ||= self.class.channel_type_registry.get_channel_type(type)&.item_type
359
+ end
360
+
346
361
  private
347
362
 
348
363
  def kind
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of openHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.9.0"
7
+ VERSION = "5.11.0"
8
8
  end
9
9
  end
data/lib/openhab/dsl.rb CHANGED
@@ -557,10 +557,49 @@ module OpenHAB
557
557
  # to reduce repetitions
558
558
  #
559
559
 
560
+ #
561
+ # Permanently enable conditional execution of commands and updates for the current thread.
562
+ #
563
+ # When conditional executions are enabled, commands and updates will only be sent if the
564
+ # item's current state is not the same as the command or updated state.
565
+ # This eliminates the need to chain the command and update calls through
566
+ # {DSL::Items::Ensure::Ensurable#ensure ensure}.
567
+ #
568
+ # When conditional executions are enabled either by this method or within a block of {ensure_states},
569
+ # commands and updates can still be forcefully executed using the corresponding bang methods, e.g.
570
+ # `Item1.on!`, `Item1.command!(50)`, or `Item1.update!(ON)`.
571
+ #
572
+ # @note This method is only intended for use at the top level of rule
573
+ # scripts. If it's used within library methods, or hap-hazardly within
574
+ # rules, things can get very confusing because the prior state won't be
575
+ # properly restored.
576
+ #
577
+ # @param [Boolean] active Whether to enable or disable conditional executions.
578
+ # @return [Boolean] The previous ensure_states setting.
579
+ #
580
+ # @example Make ensure_states the default for the rest of the script
581
+ # ensure_states!
582
+ #
583
+ # # From now, all commands are "ensured", i.e. only sent when the current state is different
584
+ # Item1.on
585
+ # Item2.command(ON)
586
+ #
587
+ # # While ensure_states! is active, we can still forcibly send a command
588
+ # # regardless of the item's current state
589
+ # Item2.on!
590
+ #
591
+ # @see ensure_states
592
+ #
593
+ def ensure_states!(active: true)
594
+ old = Thread.current[:openhab_ensure_states]
595
+ Thread.current[:openhab_ensure_states] = active
596
+ old
597
+ end
598
+
560
599
  #
561
600
  # Global method that takes a block and for the duration of the block
562
601
  # all commands sent will check if the item is in the command's state
563
- # before sending the command.
602
+ # before sending the command. This also applies to updates.
564
603
  #
565
604
  # @yield
566
605
  # @return [Object] The result of the block.
@@ -603,11 +642,10 @@ module OpenHAB
603
642
  # end
604
643
  #
605
644
  def ensure_states
606
- old = Thread.current[:openhab_ensure_states]
607
- Thread.current[:openhab_ensure_states] = true
645
+ old = ensure_states!
608
646
  yield
609
647
  ensure
610
- Thread.current[:openhab_ensure_states] = old
648
+ ensure_states!(active: old)
611
649
  end
612
650
 
613
651
  #
@@ -841,7 +879,7 @@ module OpenHAB
841
879
  # elements, the {Core::Items::Metadata::Hash} will be passed as an argument. Therefore it's
842
880
  # recommended that you use a Proc, not a Lambda, for permissive argument matching.
843
881
  #
844
- # @return [void]
882
+ # @return [Hash] the prior provider configuration.
845
883
  #
846
884
  # @see provider
847
885
  # @see OpenHAB::Core::Provider.current Provider.current for how the current provider is calculated
@@ -5,26 +5,36 @@ module OpenHAB
5
5
  # based on https://stackoverflow.com/questions/1197224/source-shell-script-into-environment-within-a-ruby-script#19826329
6
6
  # @!visibility private
7
7
  module Shell
8
- module_function
8
+ # @!visibility private
9
+ DEFAULT_PRINTENV_COMMAND = "printenv -0"
10
+ @printenv_command = DEFAULT_PRINTENV_COMMAND
11
+ @printenv_separator = "\0"
9
12
 
10
- # Read in the bash environment, after an optional command.
11
- # Returns Array of key/value pairs.
12
- def shell_env(cmd = nil)
13
- cmd = "#{cmd} > /dev/null; " if cmd
14
- env = `#{cmd}printenv -0`
15
- env.split("\0").map { |l| l.split("=", 2) }
16
- end
13
+ class << self
14
+ # Read in the bash environment, after an optional command.
15
+ # Returns Array of key/value pairs.
16
+ def shell_env(cmd = nil)
17
+ cmd = "#{cmd} > #{IO::NULL}; " if cmd
18
+ env = `#{cmd}#{@printenv_command} 2> #{IO::NULL}`
19
+ if !$?.success? && @printenv_command.equal?(DEFAULT_PRINTENV_COMMAND)
20
+ @printenv_command = "printenv"
21
+ @printenv_separator = "\n"
22
+ env = `#{cmd}#{@printenv_command}`
23
+ end
24
+ env.split(@printenv_separator).map { |l| l.split("=", 2) }
25
+ end
17
26
 
18
- # Source a given file, and compare environment before and after.
19
- # Returns Hash of any keys that have changed.
20
- def shell_source(file)
21
- (shell_env(". #{File.realpath(file)}") - shell_env).to_h
22
- end
27
+ # Source a given file, and compare environment before and after.
28
+ # Returns Hash of any keys that have changed.
29
+ def shell_source(file)
30
+ (shell_env(". #{File.realpath(file)}") - shell_env).to_h
31
+ end
23
32
 
24
- # Find variables changed as a result of sourcing the given file,
25
- # and update in ENV.
26
- def source_env_from(file)
27
- shell_source(file).each { |k, v| ENV[k] = v }
33
+ # Find variables changed as a result of sourcing the given file,
34
+ # and update in ENV.
35
+ def source_env_from(file)
36
+ shell_source(file).each { |k, v| ENV[k] = v }
37
+ end
28
38
  end
29
39
  end
30
40
  end
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.9.0
4
+ version: 5.11.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-10-09 00:00:00.000000000 Z
13
+ date: 2023-10-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -409,6 +409,7 @@ files:
409
409
  - lib/openhab/core/items/group_item.rb
410
410
  - lib/openhab/core/items/image_item.rb
411
411
  - lib/openhab/core/items/item.rb
412
+ - lib/openhab/core/items/item_channel_links.rb
412
413
  - lib/openhab/core/items/location_item.rb
413
414
  - lib/openhab/core/items/metadata.rb
414
415
  - lib/openhab/core/items/metadata/hash.rb