openhab-jrubyscripting 5.0.0.rc11 → 5.0.0.rc.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/actions/exec.rb +41 -41
  3. data/lib/openhab/core/actions/transformation.rb +3 -3
  4. data/lib/openhab/core/actions.rb +1 -1
  5. data/lib/openhab/core/events/item_command_event.rb +31 -31
  6. data/lib/openhab/core/events/item_state_changed_event.rb +41 -18
  7. data/lib/openhab/core/events/item_state_event.rb +46 -18
  8. data/lib/openhab/core/items/date_time_item.rb +3 -2
  9. data/lib/openhab/core/items/generic_item.rb +119 -1
  10. data/lib/openhab/core/items/item.rb +63 -9
  11. data/lib/openhab/core/items/metadata/hash.rb +1 -1
  12. data/lib/openhab/core/items/metadata/namespace_hash.rb +10 -2
  13. data/lib/openhab/core/items/metadata/provider.rb +2 -2
  14. data/lib/openhab/core/items/persistence.rb +48 -4
  15. data/lib/openhab/core/items/provider.rb +4 -0
  16. data/lib/openhab/core/items/registry.rb +10 -1
  17. data/lib/openhab/core/items/semantics/enumerable.rb +29 -6
  18. data/lib/openhab/core/items/state_storage.rb +2 -2
  19. data/lib/openhab/core/items.rb +6 -13
  20. data/lib/openhab/core/provider.rb +2 -2
  21. data/lib/openhab/core/proxy.rb +5 -0
  22. data/lib/openhab/core/registry.rb +12 -2
  23. data/lib/openhab/core/rules/provider.rb +0 -15
  24. data/lib/openhab/core/rules.rb +1 -1
  25. data/lib/openhab/core/script_handling.rb +8 -8
  26. data/lib/openhab/core/things/links/provider.rb +38 -0
  27. data/lib/openhab/core/things/provider.rb +4 -0
  28. data/lib/openhab/core/things/registry.rb +4 -0
  29. data/lib/openhab/core/timer.rb +3 -19
  30. data/lib/openhab/core/types/date_time_type.rb +1 -1
  31. data/lib/openhab/core/types/decimal_type.rb +4 -9
  32. data/lib/openhab/core/types/hsb_type.rb +2 -2
  33. data/lib/openhab/core/types/quantity_type.rb +4 -9
  34. data/lib/openhab/core/types/string_type.rb +1 -1
  35. data/lib/openhab/core/types/type.rb +8 -28
  36. data/lib/openhab/core/types.rb +16 -3
  37. data/lib/openhab/core.rb +3 -3
  38. data/lib/openhab/core_ext/java/duration.rb +2 -0
  39. data/lib/openhab/core_ext/java/local_date.rb +15 -7
  40. data/lib/openhab/core_ext/java/local_time.rb +13 -3
  41. data/lib/openhab/core_ext/java/month.rb +1 -1
  42. data/lib/openhab/core_ext/java/month_day.rb +13 -3
  43. data/lib/openhab/core_ext/java/period.rb +1 -1
  44. data/lib/openhab/core_ext/java/temporal_amount.rb +1 -1
  45. data/lib/openhab/core_ext/java/time.rb +5 -1
  46. data/lib/openhab/core_ext/java/zoned_date_time.rb +15 -2
  47. data/lib/openhab/core_ext/ruby/date.rb +2 -2
  48. data/lib/openhab/core_ext/ruby/{class.rb → module.rb} +3 -3
  49. data/lib/openhab/core_ext/ruby/numeric.rb +6 -1
  50. data/lib/openhab/dsl/items/builder.rb +25 -12
  51. data/lib/openhab/dsl/items/ensure.rb +8 -6
  52. data/lib/openhab/dsl/rules/automation_rule.rb +2 -23
  53. data/lib/openhab/dsl/rules/builder.rb +47 -2
  54. data/lib/openhab/dsl/rules/terse.rb +15 -13
  55. data/lib/openhab/dsl/timer_manager.rb +1 -1
  56. data/lib/openhab/dsl/version.rb +1 -1
  57. data/lib/openhab/dsl.rb +38 -11
  58. data/lib/openhab/osgi.rb +1 -3
  59. data/lib/openhab/rspec/helpers.rb +3 -5
  60. data/lib/openhab/rspec/hooks.rb +1 -0
  61. data/lib/openhab/rspec/mocks/timer.rb +33 -0
  62. data/lib/openhab/rspec.rb +9 -0
  63. metadata +23 -9
@@ -110,20 +110,15 @@ module OpenHAB
110
110
  #
111
111
  # Coerce object to a {DecimalType DecimalType}
112
112
  #
113
- # @param [Numeric, Type] other object to coerce to a {DecimalType DecimalType}
114
- #
115
- # If `other` is a {Type}, `self` will instead be coerced
116
- # to that type to accomodate comparison with things such as {OnOffType}.
113
+ # @param [Numeric] other object to coerce to a {DecimalType DecimalType}
117
114
  #
118
115
  # @return [Array<(DecimalType, DecimalType)>, nil]
119
116
  #
120
117
  def coerce(other)
121
118
  logger.trace("Coercing #{self} as a request from #{other.class}")
122
- if other.is_a?(Type)
123
- [other, as(other.class)]
124
- elsif other.respond_to?(:to_d)
125
- [self.class.new(other.to_d), self]
126
- end
119
+ return unless other.respond_to?(:to_d)
120
+
121
+ [self.class.new(other.to_d), self]
127
122
  end
128
123
 
129
124
  #
@@ -142,7 +142,7 @@ module OpenHAB
142
142
  end
143
143
 
144
144
  # Convert to an HTML-style string of 6 hex characters in the default sRGB color model.
145
- # @return [String] +'#xxxxxx'+
145
+ # @return [String] `"#xxxxxx"`
146
146
  def to_hex
147
147
  Kernel.format("#%06x", rgb)
148
148
  end
@@ -174,7 +174,7 @@ module OpenHAB
174
174
 
175
175
  # @!method to_xy
176
176
  # Convert to the xyY values representing this object's color in CIE XY color model
177
- # @return [[PercentType, PercentType]]
177
+ # @return [[PercentType, PercentType, PercentType]]
178
178
  end
179
179
  end
180
180
  end
@@ -157,19 +157,14 @@ module OpenHAB
157
157
  #
158
158
  # Coerce object to a {QuantityType}
159
159
  #
160
- # @param [Numeric, Type] other object to coerce to a {QuantityType}
161
- #
162
- # if `other` is a {Type}, `self` will instead be coerced
163
- # to that type to accomodate comparison with things such as {OnOffType}
160
+ # @param [Numeric] other object to coerce to a {QuantityType}
164
161
  #
165
162
  # @return [Array<(QuantityType, QuantityType)>, nil]
166
163
  def coerce(other)
167
164
  logger.trace("Coercing #{self} as a request from #{other.class}")
168
- if other.is_a?(Type)
169
- [other, as(other.class)]
170
- elsif other.respond_to?(:to_d)
171
- [QuantityType.new(other.to_d.to_java, Units::ONE), self]
172
- end
165
+ return unless other.respond_to?(:to_d)
166
+
167
+ [QuantityType.new(other.to_d.to_java, Units::ONE), self]
173
168
  end
174
169
 
175
170
  # arithmetic operators
@@ -63,7 +63,7 @@ module OpenHAB
63
63
  #
64
64
  def coerce(other)
65
65
  logger.trace("Coercing #{self} as a request from #{other.class}")
66
- return [String.new(other.to_str), self] if other.respond_to?(:to_str)
66
+ return [other.to_str, self] if other.respond_to?(:to_str)
67
67
  end
68
68
 
69
69
  # any method that exists on String gets forwarded to to_s
@@ -25,21 +25,6 @@ module OpenHAB
25
25
  to_s
26
26
  end
27
27
 
28
- #
29
- # Type Coercion
30
- #
31
- # Coerce object to the same Type
32
- #
33
- # @param [Type] other object to coerce to the same
34
- # Type as this one
35
- #
36
- # @return [[Type, Type], nil]
37
- #
38
- def coerce(other)
39
- logger.trace("Coercing #{self} (#{self.class}) as a request from #{other.class}")
40
- return [other.as(self.class), self] if other.is_a?(Type) && other.respond_to?(:as)
41
- end
42
-
43
28
  #
44
29
  # Check equality without type conversion
45
30
  #
@@ -51,19 +36,6 @@ module OpenHAB
51
36
  equals(other)
52
37
  end
53
38
 
54
- #
55
- # Case equality
56
- #
57
- # @return [true,false] if the values are of the same Type
58
- # or item state of the same type
59
- #
60
- def ===(other)
61
- logger.trace { "Type (#{self.class}) #{self} === #{other} (#{other.class})" }
62
- return false unless instance_of?(other.class)
63
-
64
- eql?(other)
65
- end
66
-
67
39
  #
68
40
  # Check equality, including type conversion
69
41
  #
@@ -95,6 +67,14 @@ module OpenHAB
95
67
 
96
68
  super
97
69
  end
70
+
71
+ # @!visibility private
72
+ #
73
+ # some openHAB Types don't implement as; do it for them
74
+ #
75
+ def as(klass)
76
+ self if klass == self.class
77
+ end
98
78
  end
99
79
 
100
80
  #
@@ -57,11 +57,24 @@ module OpenHAB
57
57
  ([command] | states).each do |method|
58
58
  logger.trace("Defining #{klass}##{method} for #{value}")
59
59
  klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
60
- def #{method} # def on?
61
- self == #{value} # self == ON
62
- end # end
60
+ def #{method} # def on?
61
+ as(#{value.class.java_class.simple_name}).equal?(#{value}) # as(OnOffType).equal?(ON)
62
+ end # end
63
63
  RUBY
64
64
  end
65
+
66
+ method = states.last
67
+ Events::ItemState.class_eval <<~RUBY, __FILE__, __LINE__ + 1
68
+ def #{method} # def on?
69
+ item_state.as(#{value.class.java_class.simple_name}).equal?(#{value}) # item_state.as(OnOffType).equal?(ON)
70
+ end # end
71
+ RUBY
72
+
73
+ Events::ItemStateChangedEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
74
+ def was_#{method} # def was_on?
75
+ old_item_state.as(#{value.class.java_class.simple_name}).equal?(#{value}) # old_item_state.as(OnOffType).equal?(ON)
76
+ end # end
77
+ RUBY
65
78
  end
66
79
  end
67
80
  end
data/lib/openhab/core.rb CHANGED
@@ -3,12 +3,12 @@
3
3
  module OpenHAB
4
4
  # Contains classes and modules that wrap actual openHAB objects
5
5
  module Core
6
- # The openHAB Version. >= 3.3.0 is required.
6
+ # The openHAB Version. >= 3.4.0 is required.
7
7
  # @return [String]
8
8
  VERSION = org.openhab.core.OpenHAB.version.freeze
9
9
 
10
- unless Gem::Version.new(VERSION) >= Gem::Version.new("3.3.0")
11
- raise "`openhab-jrubyscripting` requires openHAB >= 3.3.0"
10
+ unless Gem::Version.new(VERSION) >= Gem::Version.new("3.4.0")
11
+ raise "`openhab-jrubyscripting` requires openHAB >= 3.4.0"
12
12
  end
13
13
 
14
14
  # @return [Integer] Number of seconds to wait between checks for automation manager
@@ -52,6 +52,8 @@ module OpenHAB
52
52
  return to_f <=> other if other.is_a?(Numeric)
53
53
 
54
54
  super
55
+ rescue TypeError
56
+ nil
55
57
  end
56
58
 
57
59
  #
@@ -7,16 +7,24 @@ module OpenHAB
7
7
  module Java
8
8
  java_import java.time.LocalDate
9
9
 
10
- # Extensions to LocalDate
10
+ # Extensions to {java.time.LocalDate}
11
11
  class LocalDate
12
12
  include Time
13
13
  include Between
14
14
  include Ephemeris
15
15
 
16
- class << self # rubocop:disable Lint/EmptyClass
17
- # @!attribute [r] now
18
- # @return [ZonedDateTime]
19
- end
16
+ # @!scope class
17
+
18
+ # @!attribute [r] now
19
+ # @return [LocalDate]
20
+
21
+ # @!method parse(text, formatter=nil)
22
+ # Converts the given text into a LocalDate.
23
+ # @param [String] text The text to parse
24
+ # @param [java.time.format.DateTimeFormatter] formatter The formatter to use
25
+ # @return [LocalDate]
26
+
27
+ # @!scope instance
20
28
 
21
29
  # @param [TemporalAmount, LocalDate, Numeric] other
22
30
  # If other is a Numeric, it's interpreted as days.
@@ -25,11 +33,11 @@ module OpenHAB
25
33
  def -(other)
26
34
  case other
27
35
  when Date
28
- Period.of_days(day_of_year - other.yday)
36
+ self - other.to_local_date
29
37
  when MonthDay
30
38
  self - other.at_year(year)
31
39
  when LocalDate
32
- Period.of_days(day_of_year - other.day_of_year)
40
+ Period.between(other, self)
33
41
  when Duration
34
42
  minus_days(other.to_days)
35
43
  when Numeric
@@ -7,6 +7,8 @@ module OpenHAB
7
7
  module Java
8
8
  java_import java.time.LocalTime
9
9
 
10
+ #
11
+ # Extensions to {java.time.LocalTime}
10
12
  #
11
13
  # @example
12
14
  # break_time = LocalTime::NOON
@@ -36,15 +38,23 @@ module OpenHAB
36
38
  include Between
37
39
  # @!parse include Time
38
40
 
39
- # @!visibility private
40
41
  class << self
42
+ # @!attribute [r] now
43
+ # @return [LocalTime]
44
+
45
+ # @!visibility private
46
+ alias_method :raw_parse, :parse
47
+
41
48
  #
42
- # Parses strings in the form "h[:mm[:ss]] [am/pm]"
49
+ # Parses strings in the form "h[:mm[:ss]] [am/pm]" when no formatter is given.
43
50
  #
44
51
  # @param [String] string
52
+ # @param [java.time.format.DateTimeFormatter] formatter The formatter to use
45
53
  # @return [LocalTime]
46
54
  #
47
- def parse(string)
55
+ def parse(string, formatter = nil)
56
+ return raw_parse(string, formatter) if formatter
57
+
48
58
  format = /(am|pm)$/i.match?(string) ? "h[:mm[:ss][.S]][ ]a" : "H[:mm[:ss][.S]]"
49
59
  java_send(:parse, [java.lang.CharSequence, java.time.format.DateTimeFormatter],
50
60
  string, java.time.format.DateTimeFormatterBuilder.new
@@ -7,7 +7,7 @@ module OpenHAB
7
7
  module Java
8
8
  Month = java.time.Month
9
9
 
10
- # Extensions to Month
10
+ # Extensions to {java.time.Month}
11
11
  class Month
12
12
  include Between
13
13
  # @!parse include Time
@@ -7,7 +7,7 @@ module OpenHAB
7
7
  module Java
8
8
  java_import java.time.MonthDay
9
9
 
10
- # Extensions to MonthDay
10
+ # Extensions to {java.time.MonthDay}
11
11
  class MonthDay
12
12
  include Between
13
13
  include Ephemeris
@@ -39,12 +39,22 @@ module OpenHAB
39
39
 
40
40
  # @return [MonthDay]
41
41
  def +(other)
42
- (LocalDate.of(1900, month, day_of_month) + other).to_month_day
42
+ case other
43
+ when java.time.temporal.TemporalAmount, Numeric
44
+ (LocalDate.of(1900, month, day_of_month) + other).to_month_day
45
+ else
46
+ (to_local_date(other.to_local_date) + other).to_month_day
47
+ end
43
48
  end
44
49
 
45
50
  # @return [MonthDay, Period]
46
51
  def -(other)
47
- d = (LocalDate.of(1900, month, day_of_month) - other)
52
+ d = case other
53
+ when java.time.temporal.TemporalAmount, Numeric
54
+ LocalDate.of(1900, month, day_of_month) - other
55
+ else
56
+ to_local_date(other.to_local_date) - other
57
+ end
48
58
  return d if d.is_a?(java.time.Period)
49
59
 
50
60
  d.to_month_day
@@ -5,7 +5,7 @@ module OpenHAB
5
5
  module Java
6
6
  java_import java.time.Period
7
7
 
8
- # Extensions to Period
8
+ # Extensions to {java.time.Period}
9
9
  class Period
10
10
  # @!parse include TemporalAmount
11
11
 
@@ -5,7 +5,7 @@ module OpenHAB
5
5
  module Java
6
6
  java_import java.time.temporal.TemporalAmount
7
7
 
8
- # Extensions to TemporalAmount
8
+ # Extensions to {java.time.temporal.TemporalAmount}
9
9
  module TemporalAmount
10
10
  # Subtract `self` to {ZonedDateTime.now}
11
11
  # @return [ZonedDateTime]
@@ -50,7 +50,11 @@ module OpenHAB
50
50
  # Convert `other` to this class, if possible
51
51
  # @return [Array, nil]
52
52
  def coerce(other)
53
- [other.send(self.class.coercion_method), self] if other.respond_to?(self.class.coercion_method)
53
+ coercion_method = self.class.coercion_method
54
+ return unless other.respond_to?(coercion_method)
55
+ return [other.send(coercion_method), self] if other.method(coercion_method).arity.zero?
56
+
57
+ [other.send(coercion_method, self), self]
54
58
  end
55
59
  end
56
60
  end
@@ -7,18 +7,31 @@ module OpenHAB
7
7
  module Java
8
8
  ZonedDateTime = java.time.ZonedDateTime
9
9
 
10
- # Extensions to ZonedDateTime
10
+ # Extensions to {java.time.ZonedDateTime}
11
11
  class ZonedDateTime
12
12
  include Time
13
13
  include Between
14
14
 
15
15
  class << self # rubocop:disable Lint/EmptyClass
16
+ # @!scope class
17
+
16
18
  # @!attribute [r] now
17
19
  # @return [ZonedDateTime]
20
+
21
+ # @!method parse(text, formatter = nil)
22
+ # Parses a string into a ZonedDateTime object.
23
+ #
24
+ # @param [String] text The text to parse.
25
+ # @param [java.time.format.DateTimeFormatter] formatter The formatter to use.
26
+ # @return [ZonedDateTime]
18
27
  end
19
28
 
29
+ # @!scope instance
30
+
20
31
  # @return [LocalTime]
21
- alias_method :to_local_time, :toLocalTime
32
+ def to_local_time(_context = nil)
33
+ toLocalTime
34
+ end
22
35
 
23
36
  # @return [Month]
24
37
  alias_method :to_month, :month
@@ -85,9 +85,9 @@ class Date
85
85
  #
86
86
  def coerce(other)
87
87
  return nil unless other.respond_to?(:to_date)
88
- return [other.to_date(self), self] if other.method(:to_date).arity == 1
88
+ return [other.to_date, self] if other.method(:to_date).arity.zero?
89
89
 
90
- [other.to_date, self]
90
+ [other.to_date(self), self]
91
91
  end
92
92
 
93
93
  remove_method :inspect
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Extensions to Class
4
- class Class
3
+ # Extensions to Module
4
+ class Module
5
5
  #
6
- # Returns the name of the class, without any containing module or package.
6
+ # Returns the name of the class or module, without any containing module or package.
7
7
  #
8
8
  # @return [String, nil]
9
9
  #
@@ -151,7 +151,12 @@ module OpenHAB
151
151
  # @return [QuantityType] `self` as a {QuantityType} of the supplied Unit
152
152
  #
153
153
  def |(unit) # rubocop:disable Naming/BinaryOperatorParameterName
154
- unit = org.openhab.core.types.util.UnitUtils.parse_unit(unit.to_str) if unit.respond_to?(:to_str)
154
+ if unit.respond_to?(:to_str)
155
+ parsed_unit = org.openhab.core.types.util.UnitUtils.parse_unit(unit.to_str)
156
+ raise ArgumentError, "Unknown unit #{unit}" unless parsed_unit
157
+
158
+ unit = parsed_unit
159
+ end
155
160
 
156
161
  return super unless unit.is_a?(javax.measure.Unit)
157
162
 
@@ -187,6 +187,30 @@ module OpenHAB
187
187
  def item_factory
188
188
  @item_factory ||= org.openhab.core.library.CoreItemFactory.new
189
189
  end
190
+
191
+ #
192
+ # Convert the given array to an array of strings.
193
+ # Convert Semantics classes to their simple name.
194
+ #
195
+ # @param [String,Symbol,Semantics::Tag] tags A list of strings, symbols, or Semantics classes
196
+ # @return [Array] An array of strings
197
+ #
198
+ # @example
199
+ # tags = normalize_tags("tag1", Semantics::LivingRoom)
200
+ #
201
+ # @!visibility private
202
+ def normalize_tags(*tags)
203
+ semantics = proc { |tag| tag.respond_to?(:java_class) && tag < Semantics::Tag }
204
+
205
+ tags.compact.map do |tag|
206
+ case tag
207
+ when String then tag
208
+ when Symbol then tag.to_s
209
+ when semantics then tag.java_class.simple_name
210
+ else raise ArgumentError, "`#{tag}` must be a subclass of Semantics::Tag, a `Symbol`, or a `String`."
211
+ end
212
+ end
213
+ end
190
214
  end
191
215
 
192
216
  # @param dimension [Symbol, nil] The unit dimension for a {NumberItem} (see {ItemBuilder#dimension})
@@ -294,18 +318,7 @@ module OpenHAB
294
318
  # @return [void]
295
319
  #
296
320
  def tag(*tags)
297
- unless tags.all? do |tag|
298
- tag.is_a?(String) ||
299
- tag.is_a?(Symbol) ||
300
- (tag.is_a?(Module) && tag < Semantics::Tag)
301
- end
302
- raise ArgumentError, "`tag` must be a subclass of Semantics::Tag, or a `String``."
303
- end
304
-
305
- tags.each do |tag|
306
- tag = tag.name.split("::").last if tag.is_a?(Module) && tag < Semantics::Tag
307
- @tags << tag.to_s
308
- end
321
+ @tags += self.class.normalize_tags(*tags)
309
322
  end
310
323
 
311
324
  #
@@ -38,23 +38,25 @@ module OpenHAB
38
38
  # def command(state)
39
39
  # return super(state) unless Thread.current[:openhab_ensure_states]
40
40
  #
41
+ # formatted_state = format_command(state)
41
42
  # logger.trace do
42
- # "#{name} ensure #{state}, format_command: #{format_command(state)}, current state: #{self.state}"
43
+ # "#{name} ensure #{state}, format_command: #{formatted_state}, current state: #{raw_state}"
43
44
  # end
44
- # return if self.state == format_command(state)
45
+ # return if raw_state == formatted_state
45
46
  #
46
- # super(state)
47
+ # super(formatted_state)
47
48
  # end
48
49
  class_eval <<~RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition
49
50
  def #{ensured_method}(state)
50
51
  return super(state) unless Thread.current[:openhab_ensure_states]
51
52
 
53
+ formatted_state = format_#{ensured_method}(state)
52
54
  logger.trace do
53
- "\#{name} ensure \#{state}, format_#{ensured_method}: \#{format_#{ensured_method}(state)}, current state: \#{self.state}"
55
+ "\#{name} ensure \#{state}, format_#{ensured_method}: \#{formatted_state}, current state: \#{raw_state}"
54
56
  end
55
- return if self.state == format_#{ensured_method}(state)
57
+ return if raw_state.as(formatted_state.class) == formatted_state
56
58
 
57
- super(state)
59
+ super(formatted_state)
58
60
  end
59
61
  RUBY
60
62
  end
@@ -35,7 +35,8 @@ module OpenHAB
35
35
  super()
36
36
  set_name(config.name)
37
37
  set_description(config.description)
38
- set_tags(to_string_set(config.tags))
38
+ tags = DSL::Items::ItemBuilder.normalize_tags(*config.tags)
39
+ set_tags(tags.to_set)
39
40
  set_triggers(config.triggers)
40
41
  self.uid = config.uid
41
42
  @run_context = config.caller
@@ -297,28 +298,6 @@ module OpenHAB
297
298
  @run_context.instance_exec(&task.block)
298
299
  end
299
300
 
300
- #
301
- # Convert the given array to a set of strings.
302
- # Convert Semantics classes to their simple name
303
- #
304
- # @example
305
- # to_string_set("tag1", Semantics::LivingRoom)
306
- #
307
- # @param tags [Array] An array of strings or Semantics classes
308
- #
309
- # @return [Set] A set of strings
310
- #
311
- def to_string_set(*tags)
312
- tags = tags.flatten.map do |tag|
313
- if tag.respond_to?(:java_class) && tag < org.openhab.core.semantics.Tag
314
- tag.java_class.simple_name
315
- else
316
- tag.to_s
317
- end
318
- end
319
- Set.new(tags)
320
- end
321
-
322
301
  #
323
302
  # Create a new hash in which all elements are converted to strings
324
303
  #
@@ -358,7 +358,7 @@ module OpenHAB
358
358
  #
359
359
  # Set the rule's tags.
360
360
  #
361
- # @param [String, Class, Array<String, Class>] tags
361
+ # @param [String, Symbol, Semantics::Tag] tags A list of tags to assign to the rule.
362
362
  # @return [void]
363
363
  #
364
364
  # @example
@@ -1101,7 +1101,10 @@ module OpenHAB
1101
1101
  # :saturday,
1102
1102
  # :sunday] value
1103
1103
  # When to execute rule.
1104
- # @param [LocalTime, String, nil] at What time of day to execute rule
1104
+ # @param [LocalTime, String, Core::Items::DateTimeItem, nil] at What time of day to execute rule
1105
+ # If `value` is `:day`, `at` can be a {Core::Items::DateTimeItem DateTimeItem}, and
1106
+ # the trigger will run every day at the (time only portion of) current state of the
1107
+ # item. If the item is {NULL} or {UNDEF}, the trigger will not run.
1105
1108
  # @param [Object] attach Object to be attached to the trigger
1106
1109
  # @return [void]
1107
1110
  #
@@ -1157,11 +1160,23 @@ module OpenHAB
1157
1160
  # run { logger.info "Happy Valentine's Day!" }
1158
1161
  # end
1159
1162
  #
1163
+ # @example
1164
+ # rule "Every day at sunset" do
1165
+ # every :day, at: Sunset_Time
1166
+ # run { logger.info "It's getting dark" }
1167
+ # end
1168
+ #
1160
1169
  def every(value, at: nil, attach: nil)
1161
1170
  return every(java.time.MonthDay.parse(value), at: at, attach: attach) if value.is_a?(String)
1162
1171
 
1163
1172
  @ruby_triggers << [:every, value, { at: at }]
1164
1173
 
1174
+ if value == :day && at.is_a?(Item)
1175
+ raise ArgumentError, "Attachments are not supported with dynamic datetime triggers" unless attach.nil?
1176
+
1177
+ return trigger("timer.DateTimeTrigger", itemName: at.name, timeOnly: true)
1178
+ end
1179
+
1165
1180
  cron_expression = case value
1166
1181
  when Symbol then Cron.from_symbol(value, at)
1167
1182
  when Duration then Cron.from_duration(value, at)
@@ -1502,6 +1517,36 @@ module OpenHAB
1502
1517
  trigger("core.GenericEventTrigger", eventTopic: topic, eventSource: source, eventTypes: types, attach: attach)
1503
1518
  end
1504
1519
 
1520
+ #
1521
+ # Creates a trigger based on the time stored in a {DateTimeItem}
1522
+ #
1523
+ # The trigger will dynamically update any time the state of the item
1524
+ # changes. If the item is {NULL} or {UNDEF}, the trigger will not run.
1525
+ #
1526
+ # @param [Item, String, Symbol] item The item (or it's name)
1527
+ # @return [void]
1528
+ #
1529
+ # @example
1530
+ # rule "say hello when the kids get home from school" do
1531
+ # at HomeFromSchool_Time
1532
+ # run do
1533
+ # KitchenEcho_TTS << "hi kids! how was school?"
1534
+ # end
1535
+ # end
1536
+ #
1537
+ # rule "set home from school time" do
1538
+ # on_load
1539
+ # every :day, at: "5:00am" do
1540
+ # run do
1541
+ # HomeFromSchool_Time.ensure.update(school_day? ? LocalTime.parse("3:30pm") : NULL)
1542
+ # end
1543
+ # end
1544
+ #
1545
+ def at(item)
1546
+ item = item.name if item.is_a?(Item)
1547
+ trigger("timer.DateTimeTrigger", itemName: item.to_s)
1548
+ end
1549
+
1505
1550
  #
1506
1551
  # Create a generic trigger given the trigger type uid and a configuration hash
1507
1552
  #