openhab-scripting 2.12.0 → 2.14.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab.rb +3 -0
  3. data/lib/openhab/core/dsl/actions.rb +1 -1
  4. data/lib/openhab/core/dsl/entities.rb +41 -4
  5. data/lib/openhab/core/dsl/gems.rb +1 -1
  6. data/lib/openhab/core/dsl/group.rb +3 -1
  7. data/lib/openhab/core/dsl/items/items.rb +3 -1
  8. data/lib/openhab/core/dsl/items/number_item.rb +151 -50
  9. data/lib/openhab/core/dsl/items/string_item.rb +21 -3
  10. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +42 -0
  11. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +66 -42
  12. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +2 -1
  13. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +7 -35
  14. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +2 -1
  15. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +1 -0
  16. data/lib/openhab/core/dsl/property.rb +15 -4
  17. data/lib/openhab/core/dsl/rule/automation_rule.rb +348 -0
  18. data/lib/openhab/core/dsl/rule/guard.rb +43 -6
  19. data/lib/openhab/core/dsl/rule/rule.rb +80 -354
  20. data/lib/openhab/core/dsl/rule/rule_config.rb +153 -0
  21. data/lib/openhab/core/dsl/rule/triggers/changed.rb +145 -0
  22. data/lib/openhab/core/dsl/rule/{channel.rb → triggers/channel.rb} +22 -8
  23. data/lib/openhab/core/dsl/rule/triggers/command.rb +106 -0
  24. data/lib/openhab/core/dsl/rule/{cron.rb → triggers/cron.rb} +58 -13
  25. data/lib/openhab/core/dsl/rule/triggers/trigger.rb +126 -0
  26. data/lib/openhab/core/dsl/rule/triggers/updated.rb +100 -0
  27. data/lib/openhab/core/dsl/time_of_day.rb +50 -24
  28. data/lib/openhab/core/dsl/timers.rb +3 -9
  29. data/lib/openhab/core/dsl/types/quantity.rb +106 -69
  30. data/lib/openhab/core/log.rb +3 -8
  31. data/lib/openhab/core/startup_delay.rb +1 -0
  32. data/lib/openhab/osgi.rb +7 -0
  33. data/lib/openhab/version.rb +1 -1
  34. metadata +10 -7
  35. data/lib/openhab/core/dsl/rule/item.rb +0 -208
  36. data/lib/openhab/core/dsl/rule/triggers.rb +0 -77
  37. data/lib/openhab/core/duration.rb +0 -78
@@ -4,8 +4,6 @@ require 'java'
4
4
  require 'delegate'
5
5
  require 'forwardable'
6
6
 
7
- require 'core/duration'
8
-
9
7
  module OpenHAB
10
8
  module Core
11
9
  module DSL
@@ -41,15 +39,11 @@ module OpenHAB
41
39
  # occurs before the @timer variable can be set resulting in @timer being nil
42
40
  semaphore = Mutex.new
43
41
 
44
- @block = proc do
45
- semaphore.synchronize do
46
- block.call(self)
47
- end
48
- end
42
+ timer_block = proc { semaphore.synchronize { block.call(self) } }
49
43
 
50
44
  semaphore.synchronize do
51
45
  @timer = ScriptExecution.createTimer(
52
- ZonedDateTime.now.plus(Java::JavaTime::Duration.ofMillis(@duration.to_ms)), @block
46
+ ZonedDateTime.now.plus(@duration), timer_block
53
47
  )
54
48
  super(@timer)
55
49
  end
@@ -64,7 +58,7 @@ module OpenHAB
64
58
  #
65
59
  def reschedule(duration = nil)
66
60
  duration ||= @duration
67
- @timer.reschedule(ZonedDateTime.now.plus(Java::JavaTime::Duration.ofMillis(duration.to_ms)))
61
+ @timer.reschedule(ZonedDateTime.now.plus(duration))
68
62
  end
69
63
  end
70
64
 
@@ -13,6 +13,9 @@ module OpenHAB
13
13
  #
14
14
  # Ruby implementation for OpenHAB quantities
15
15
  #
16
+ # rubocop: disable Metrics/ClassLength
17
+ # Disabled because this class has a single responsibility, there does not appear a logical
18
+ # way of breaking it up into multiple classes
16
19
  class Quantity < Numeric
17
20
  extend Forwardable
18
21
  include Logging
@@ -23,6 +26,7 @@ module OpenHAB
23
26
  java_import 'tec.uom.se.format.SimpleUnitFormat'
24
27
  java_import 'tec.uom.se.AbstractUnit'
25
28
 
29
+ # @return [Hash] Mapping of operation symbols to BigDecimal methods
26
30
  OPERATIONS = {
27
31
  '+' => 'add',
28
32
  '-' => 'subtract',
@@ -37,18 +41,15 @@ module OpenHAB
37
41
  #
38
42
  # Create a new Quantity
39
43
  #
40
- # @param [Java::org::openhab::core::library::types::QuantityType] quantity OpenHAB quantity to delegate to
44
+ # @param [object] quantity String,QuantityType or Numeric to be this quantity
41
45
  #
46
+ # Cop disabled, case statement is compact and idiomatic
42
47
  def initialize(quantity)
43
48
  @quantity = case quantity
44
- when String
45
- QuantityType.new(quantity)
46
- when QuantityType
47
- quantity
48
- when Numeric
49
- QuantityType.new(BigDecimal(quantity).to_java, AbstractUnit::ONE)
50
- else
51
- raise "Unexpected type #{quantity.class} provided to Quantity initializer"
49
+ when String then QuantityType.new(quantity)
50
+ when QuantityType then quantity
51
+ when NumberItem, Numeric then QuantityType.new(quantity.to_d.to_java, AbstractUnit::ONE)
52
+ else raise ArgumentError, "Unexpected type #{quantity.class} provided to Quantity initializer"
52
53
  end
53
54
  super()
54
55
  end
@@ -76,20 +77,8 @@ module OpenHAB
76
77
  #
77
78
  def <=>(other)
78
79
  logger.trace("Comparing #{self} to #{other}")
79
- case other
80
- when Quantity
81
- logger.trace("Comparing Quantity #{self} to Quantity #{other}")
82
- convert_unit(quantity).compare_to(convert_unit(other.quantity))
83
- when QuantityType
84
- other = convert_unit(other)
85
- quantity.compare_to(other)
86
- when String
87
- other = QuantityType.new(other)
88
- other = convert_unit(other)
89
- quantity.compare_to(other)
90
- when Numeric
91
- quantity.compare_to(QuantityType.new(other, unit)) if unit
92
- end
80
+ my_qt, other_qt = unitize(*to_qt(coerce(other).reverse))
81
+ my_qt.compare_to(other_qt)
93
82
  end
94
83
 
95
84
  #
@@ -100,14 +89,12 @@ module OpenHAB
100
89
  # @return [Array] of self and other object as Quantity types, nil if object cannot be coerced
101
90
  #
102
91
  def coerce(other)
103
- logger.trace("Coercing #{self} as a request from #{other.class}")
92
+ logger.trace("Coercing #{self} as a request from #{other.class}")
104
93
  case other
105
- when Quantity
106
- [other.quantity, quantity]
107
- when QuantityType
108
- [other, quantity]
109
- when Numeric
110
- [Quantity.new(other), self]
94
+ when Quantity then [other.quantity, quantity]
95
+ when QuantityType then [other, quantity]
96
+ when NumberItem then [other.to_qt.quantity, quantity]
97
+ when Numeric, String then [Quantity.new(other), self]
111
98
  end
112
99
  end
113
100
 
@@ -121,6 +108,7 @@ module OpenHAB
121
108
  # @return [Object] result of delegation
122
109
  #
123
110
  def method_missing(meth, *args, &block)
111
+ logger.trace("Method missing, performing dynamic lookup for: #{meth}")
124
112
  if quantity.respond_to?(meth)
125
113
  quantity.__send__(meth, *args, &block)
126
114
  elsif ::Kernel.method_defined?(meth) || ::Kernel.private_method_defined?(meth)
@@ -130,6 +118,20 @@ module OpenHAB
130
118
  end
131
119
  end
132
120
 
121
+ #
122
+ # Checks if this method responds to the missing method
123
+ #
124
+ # @param [String] method_name Name of the method to check
125
+ # @param [Boolean] _include_private boolean if private methods should be checked
126
+ #
127
+ # @return [Boolean] true if this object will respond to the supplied method, false otherwise
128
+ #
129
+ def respond_to_missing?(method_name, _include_private = false)
130
+ quantity.respond_to?(method_name) ||
131
+ ::Kernel.method_defined?(method_name) ||
132
+ ::Kernel.private_method_defined?(method_name)
133
+ end
134
+
133
135
  #
134
136
  # Negate the quantity
135
137
  #
@@ -141,22 +143,10 @@ module OpenHAB
141
143
 
142
144
  OPERATIONS.each do |operation, method|
143
145
  define_method(operation) do |other|
144
- logger.trace("Executing math operation '#{operation}' on quantity #{inspect} with other type #{other.class} and value #{other.inspect}")
145
- a, b = case other
146
- when Quantity
147
- [quantity, other.quantity]
148
- when String
149
- [quantity, QuantityType.new(other)]
150
- when NumberItem
151
- a, b = other.coerce(self)
152
- logger.trace("Number Item coerced result a(#{a.class})='#{a}' b(#{b.class})='#{b}'")
153
- [a.quantity, b.quantity]
154
- when Numeric
155
- [quantity, QuantityType.new(BigDecimal(other).to_java, AbstractUnit::ONE)]
156
- else
157
- raise TypeError,
158
- "Operation '#{operation}' cannot be performed between #{self} and #{other.class}"
159
- end
146
+ logger.trace("Executing math operation '#{operation}' on quantity #{inspect} "\
147
+ "with other type #{other.class} and value #{other.inspect}")
148
+
149
+ a, b = to_qt(coerce(other).reverse)
160
150
  logger.trace("Coerced a='#{a}' with b='#{b}'")
161
151
  a, b = unitize(a, b, operation)
162
152
  logger.trace("Unitized a='#{a}' b='#{b}'")
@@ -180,10 +170,22 @@ module OpenHAB
180
170
 
181
171
  private
182
172
 
173
+ # @return [Array] Array of strings for operations for which the operands will not be unitized
183
174
  DIMENSIONLESS_NON_UNITIZED_OPERATIONS = %w[* /].freeze
184
175
 
185
176
  # Dimensionless numbers should only be unitzed for addition and subtraction
186
177
 
178
+ #
179
+ # Convert one or more Quantity obects to the underlying quantitytypes
180
+ #
181
+ # @param [Array] quanities Array of either Quantity or QuantityType objects
182
+ #
183
+ # @return [Array] Array of QuantityType objects
184
+ #
185
+ def to_qt(*quanities)
186
+ [quanities].flatten.compact.map { |item| item.is_a?(Quantity) ? item.quantity : item }
187
+ end
188
+
187
189
  #
188
190
  # Checks if an item should be unitized
189
191
  #
@@ -193,11 +195,7 @@ module OpenHAB
193
195
  # @return [Boolean] True if the quantity should be unitzed based on the unit and operation, false otherwise
194
196
  #
195
197
  def unitize?(quantity, operation)
196
- if quantity.unit == AbstractUnit::ONE && DIMENSIONLESS_NON_UNITIZED_OPERATIONS.include?(operation)
197
- false
198
- else
199
- true
200
- end
198
+ !(quantity.unit == AbstractUnit::ONE && DIMENSIONLESS_NON_UNITIZED_OPERATIONS.include?(operation))
201
199
  end
202
200
 
203
201
  #
@@ -208,36 +206,65 @@ module OpenHAB
208
206
  # @return [Quantity] Quantity coverted to unit set by unit block
209
207
  #
210
208
  def convert_unit(quantity)
211
- if unit
212
- case quantity.unit
213
- when AbstractUnit::ONE
214
- logger.trace("Converting dimensionless #{quantity} to #{unit}")
215
- QuantityType.new(quantity.to_big_decimal, unit)
216
- when unit
217
- quantity
218
- else
219
- logger.trace("Converting dimensioned item #{inspect} to #{unit}")
220
- converted = quantity.to_unit(unit)
221
- raise "Conversion from #{quantity.unit} to #{unit} failed" if converted.nil?
222
-
223
- converted
224
- end
225
- else
209
+ return quantity unless unit?
210
+
211
+ case quantity.unit
212
+ when unit
226
213
  quantity
214
+ when AbstractUnit::ONE
215
+ convert_unit_from_dimensionless(quantity, unit)
216
+ else
217
+ convert_unit_from_dimensioned(quantity, unit)
227
218
  end
228
219
  end
229
220
 
221
+ #
222
+ # Converts a dimensioned quantity to a specific unit
223
+ #
224
+ # @param [Quantity] quantity to convert
225
+ # @param [Unit] unit to convert to
226
+ #
227
+ # @return [Java::org::openhab::core::library::types::QuantityType] converted quantity
228
+ #
229
+ def convert_unit_from_dimensioned(quantity, unit)
230
+ logger.trace("Converting dimensioned item #{inspect} to #{unit}")
231
+ quantity.to_unit(unit).tap do |converted|
232
+ raise "Conversion from #{quantity.unit} to #{unit} failed" unless converted
233
+ end
234
+ end
235
+
236
+ #
237
+ # Converts a dimensionless quantity to a unit
238
+ #
239
+ # @param [Quantity] quantity to convert
240
+ # @param [Unit] unit to convert to
241
+ #
242
+ # @return [Java::org::openhab::core::library::types::QuantityType] converted quantity
243
+ #
244
+ def convert_unit_from_dimensionless(quantity, unit)
245
+ logger.trace("Converting dimensionless #{quantity} to #{unit}")
246
+ QuantityType.new(quantity.to_big_decimal, unit)
247
+ end
248
+
230
249
  #
231
250
  # Convert quantities to appropriate units
232
251
  #
233
252
  # @param [Quantity] quantity_a Quantity on left side of operation
234
253
  # @param [Quantity] quantity_b Quantity on right side of operation
235
254
  # @param [String] operation Math operation
255
+ # @yield [quantity_a, quantity_b] yields unitized versions of supplied quantities
236
256
  #
237
- # @return [Array] of quantites in correct units for the supplied operation and set unit
257
+ # @return [Array, Object] of quantites in correct units for the supplied operation and the unit
258
+ # or the result of the block if a block is given
238
259
  #
239
- def unitize(quantity_a, quantity_b, operation)
240
- [quantity_a, quantity_b].map { |qt| unitize?(qt, operation) ? convert_unit(qt) : qt }
260
+ def unitize(quantity_a, quantity_b, operation = nil)
261
+ logger.trace("Unitizing (#{quantity_a}) and (#{quantity_b})")
262
+ quantity_a, quantity_b = [quantity_a, quantity_b].map do |qt|
263
+ unitize?(qt, operation) ? convert_unit(qt) : qt
264
+ end
265
+ return yield quantity_a, quantity_b if block_given?
266
+
267
+ [quantity_a, quantity_b]
241
268
  end
242
269
 
243
270
  #
@@ -248,8 +275,18 @@ module OpenHAB
248
275
  def unit
249
276
  Thread.current.thread_variable_get(:unit)
250
277
  end
278
+
279
+ #
280
+ # Is a unit set for this thread
281
+ #
282
+ # @return [boolean] true if a unit is set by this thread, false otherwise
283
+ #
284
+ def unit?
285
+ unit != nil
286
+ end
251
287
  end
252
288
  end
253
289
  end
254
290
  end
255
291
  end
292
+ # rubocop: enable Metrics/ClassLength
@@ -44,7 +44,8 @@ module Logging
44
44
  # Log a message to the OpenHAB Logger
45
45
  #
46
46
  # @param [Symbol] severity Severity to log message at
47
- # @param [Object] msg to log, if no msg supplied and a block is provided, the msg is taken from the result of the block
47
+ # @param [Object] msg to log, if no msg supplied and a block is provided,
48
+ # the msg is taken from the result of the block
48
49
  #
49
50
  def log(severity:, msg: nil)
50
51
  severity = severity.to_sym
@@ -55,13 +56,7 @@ module Logging
55
56
  return unless @sl4fj_logger.send("is_#{severity.to_s.downcase}_enabled")
56
57
 
57
58
  # Process block if no message provided
58
- if msg.nil?
59
- if block_given?
60
- msg = yield
61
- else
62
- return
63
- end
64
- end
59
+ msg = yield if msg.nil? && block_given?
65
60
 
66
61
  msg = message_to_string(msg: msg)
67
62
 
@@ -8,6 +8,7 @@ require 'core/log'
8
8
  module StartupDelay
9
9
  include Logging
10
10
 
11
+ # @return [Integer] Number of seconds to wait between checks for automation manager
11
12
  CHECK_DELAY = 10
12
13
  private_constant :CHECK_DELAY
13
14
 
data/lib/openhab/osgi.rb CHANGED
@@ -38,6 +38,11 @@ module OpenHAB
38
38
  end
39
39
  end
40
40
 
41
+ #
42
+ # Get the bundle context
43
+ #
44
+ # @return [java::org::osgi::framework::BundleContext] OSGI bundle context
45
+ #
41
46
  def self.bundle_context
42
47
  @bundle_context ||= bundle.getBundleContext
43
48
  end
@@ -45,7 +50,9 @@ module OpenHAB
45
50
 
46
51
  # Get the OSGI Bundle for ScriptExtension Class
47
52
  def self.bundle
53
+ # rubocop: disable Style/GlobalVars
48
54
  @bundle ||= FrameworkUtil.getBundle($scriptExtension.class)
55
+ # rubocop: enable Style/GlobalVars
49
56
  end
50
57
  private_class_method :bundle
51
58
  end
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '2.12.0'
8
+ VERSION = '2.14.2'
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.14.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian O'Connell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-02 00:00:00.000000000 Z
11
+ date: 2021-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -64,19 +64,22 @@ files:
64
64
  - lib/openhab/core/dsl/monkey_patch/types/percent_type.rb
65
65
  - lib/openhab/core/dsl/monkey_patch/types/types.rb
66
66
  - lib/openhab/core/dsl/property.rb
67
- - lib/openhab/core/dsl/rule/channel.rb
68
- - lib/openhab/core/dsl/rule/cron.rb
67
+ - lib/openhab/core/dsl/rule/automation_rule.rb
69
68
  - lib/openhab/core/dsl/rule/guard.rb
70
- - lib/openhab/core/dsl/rule/item.rb
71
69
  - lib/openhab/core/dsl/rule/rule.rb
72
- - lib/openhab/core/dsl/rule/triggers.rb
70
+ - lib/openhab/core/dsl/rule/rule_config.rb
71
+ - lib/openhab/core/dsl/rule/triggers/changed.rb
72
+ - lib/openhab/core/dsl/rule/triggers/channel.rb
73
+ - lib/openhab/core/dsl/rule/triggers/command.rb
74
+ - lib/openhab/core/dsl/rule/triggers/cron.rb
75
+ - lib/openhab/core/dsl/rule/triggers/trigger.rb
76
+ - lib/openhab/core/dsl/rule/triggers/updated.rb
73
77
  - lib/openhab/core/dsl/states.rb
74
78
  - lib/openhab/core/dsl/things.rb
75
79
  - lib/openhab/core/dsl/time_of_day.rb
76
80
  - lib/openhab/core/dsl/timers.rb
77
81
  - lib/openhab/core/dsl/types/quantity.rb
78
82
  - lib/openhab/core/dsl/units.rb
79
- - lib/openhab/core/duration.rb
80
83
  - lib/openhab/core/log.rb
81
84
  - lib/openhab/core/patch_load_path.rb
82
85
  - lib/openhab/core/startup_delay.rb
@@ -1,208 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'core/log'
4
- require 'core/dsl/group'
5
- require 'core/dsl/things'
6
- require 'core/dsl/rule/triggers'
7
- require 'openhab/core/dsl/rule/triggers'
8
-
9
- module OpenHAB
10
- module Core
11
- module DSL
12
- module Rule
13
- #
14
- # Triggers for items in rules
15
- #
16
- module Item
17
- include Logging
18
- include OpenHAB::Core::DSL::Rule
19
- include OpenHAB::Core::DSL::Groups
20
- include OpenHAB::Core::DSL::Things
21
-
22
- #
23
- # Struct capturing data necessary for a conditional trigger
24
- #
25
- TriggerDelay = Struct.new(:to, :from, :duration, :timer, :tracking_to, keyword_init: true)
26
-
27
- #
28
- # Create a TriggerDelay for for an item or group that is changed for a specific duration
29
- #
30
- # @param [Object] item to create trigger delay for
31
- # @param [OpenHAB::Core::Duration] duration to delay trigger for until condition is met
32
- # @param [Item State] to OpenHAB Item State item or group needs to change to
33
- # @param [Item State] from OpenHAB Item State item or group needs to be coming from
34
- #
35
- # @return [Array] Array of current TriggerDelay objects
36
- #
37
- def changed_wait(item, duration:, to: nil, from: nil)
38
- # Convert to testing the group if group specified rather than item
39
- item = item.group if item.is_a? Group
40
-
41
- # If GroupItems specified, use the group state trigger instead
42
- if item.is_a? GroupItems
43
- config = { 'groupName' => item.group.name }
44
- trigger = Trigger::GROUP_STATE_CHANGE
45
- else
46
- config = { 'itemName' => item.name }
47
- trigger = Trigger::ITEM_STATE_CHANGE
48
- end
49
- logger.trace("Creating Changed Wait Change Trigger for #{config}")
50
- trigger = append_trigger(trigger, config)
51
- @trigger_delays = { trigger.id => TriggerDelay.new(to: to, from: from, duration: duration) }
52
- end
53
-
54
- #
55
- # Create a trigger for when an item or group receives a command
56
- #
57
- # The commands/commands parameters are replicated for DSL fluency
58
- #
59
- # @param [Array] items Array of items to create trigger for
60
- # @param [Array] command commands to match for trigger
61
- # @param [Array] commands commands to match for trigger
62
- #
63
- #
64
- def received_command(*items, command: nil, commands: nil)
65
- items.flatten.each do |item|
66
- logger.trace("Creating received command trigger for item(#{item}) command(#{command}) commands(#{commands})")
67
-
68
- # Combine command and commands, doing union so only a single nil will be in the combined array.
69
- combined_commands = ([command] | [commands]).flatten
70
-
71
- # If either command or commands has a value and one is nil, we need to remove nil from the array.
72
- # If it is only now a single nil value, we leave the nil in place, so that we create a trigger
73
- # That isn't looking for a specific command.
74
- combined_commands = combined_commands.compact unless combined_commands.all?(&:nil?)
75
-
76
- combined_commands.each do |cmd|
77
- if item.is_a? GroupItems
78
- config = { 'groupName' => item.group.name }
79
- trigger = Trigger::GROUP_COMMAND
80
- else
81
- config = { 'itemName' => item.name }
82
- trigger = Trigger::ITEM_COMMAND
83
- end
84
- config['command'] = cmd.to_s unless cmd.nil?
85
- append_trigger(trigger, config)
86
- end
87
- end
88
- end
89
-
90
- #
91
- # Create a trigger when item, group or thing is updated
92
- #
93
- # @param [Array] items array to trigger on updated
94
- # @param [State] to to match for tigger
95
- #
96
- # @return [Trigger] Trigger for updated entity
97
- #
98
- def updated(*items, to: nil)
99
- items.flatten.each do |item|
100
- item = item.group if item.is_a? Group
101
- logger.trace("Creating updated trigger for item(#{item}) to(#{to})")
102
- [to].flatten.each do |to_state|
103
- case item
104
- when GroupItems
105
- config = { 'groupName' => item.group.name }
106
- config['state'] = to_state.to_s unless to_state.nil?
107
- trigger = Trigger::GROUP_STATE_UPDATE
108
- when Thing
109
- trigger, config = trigger_for_thing(item, Trigger::THING_UPDATE, to_state)
110
- else
111
- config = { 'itemName' => item.name }
112
- config['state'] = to_state.to_s unless to_state.nil?
113
- trigger = Trigger::ITEM_STATE_UPDATE
114
- end
115
- append_trigger(trigger, config)
116
- end
117
- end
118
- end
119
-
120
- #
121
- # Creates a trigger item, group and thing changed
122
- #
123
- # @param [Object] items array of objects to create trigger for
124
- # @param [to] to state for object to change for
125
- # @param [from] from <description>
126
- # @param [OpenHAB::Core::Duration] for Duration to delay trigger until to state is met
127
- #
128
- # @return [Trigger] OpenHAB trigger
129
- #
130
- def changed(*items, to: nil, from: nil, for: nil)
131
- items.flatten.each do |item|
132
- item = item.group if item.is_a? Group
133
- logger.trace("Creating changed trigger for entity(#{item}), to(#{to}), from(#{from})")
134
- # for is a reserved word in ruby, so use local_variable_get :for
135
- if (wait_duration = binding.local_variable_get(:for))
136
- changed_wait(item, to: to, from: from, duration: wait_duration)
137
- else
138
- # Place in array and flatten to support multiple to elements or single or nil
139
- [to].flatten.each do |to_state|
140
- case item
141
- when GroupItems
142
- config = { 'groupName' => item.group.name }
143
- config['state'] = to_state.to_s if to_state
144
- config['previousState'] = from.to_s if from
145
- trigger = Trigger::GROUP_STATE_CHANGE
146
- when Thing
147
- trigger, config = trigger_for_thing(item, Trigger::THING_CHANGE, to_state, from)
148
- else
149
- config = { 'itemName' => item.name }
150
- config['state'] = to_state.to_s if to_state
151
- config['previousState'] = from.to_s if from
152
- trigger = Trigger::ITEM_STATE_CHANGE
153
- end
154
- append_trigger(trigger, config)
155
- end
156
- end
157
- end
158
- end
159
-
160
- private
161
-
162
- #
163
- # Append a trigger to the list of triggeres
164
- #
165
- # @param [String] type of trigger to create
166
- # @param [Map] config map describing trigger configuration
167
- #
168
- # @return [Trigger] OpenHAB trigger
169
- #
170
- def append_trigger(type, config)
171
- logger.trace("Creating trigger of type #{type} for #{config}")
172
- trigger = Trigger.trigger(type: type, config: config)
173
- @triggers << trigger
174
- trigger
175
- end
176
-
177
- #
178
- # Create a trigger for a thing
179
- #
180
- # @param [Thing] thing to create trigger for
181
- # @param [Trigger] trigger to map with thing
182
- # @param [State] to for thing
183
- # @param [State] from state of thing
184
- #
185
- # @return [Array] Trigger and config for thing
186
- #
187
- def trigger_for_thing(thing, trigger, to = nil, from = nil)
188
- config = { 'thingUID' => thing.uid.to_s }
189
- config['status'] = trigger_state_from_symbol(to).to_s if to
190
- config['previousStatus'] = trigger_state_from_symbol(from).to_s if from
191
- [trigger, config]
192
- end
193
-
194
- #
195
- # converts object to upcase string if its a symbol
196
- #
197
- # @param [sym] sym potential symbol to convert
198
- #
199
- # @return [String] Upcased symbol as string
200
- #
201
- def trigger_state_from_symbol(sym)
202
- sym.to_s.upcase if (sym.is_a? Symbol) || sym
203
- end
204
- end
205
- end
206
- end
207
- end
208
- end