openhab-scripting 2.17.0 → 2.19.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e194635ad3998d2bfb2cb5326522012655b2197a4083ee3def1e5ec572af1bc4
4
- data.tar.gz: b8b1d13fab2d7bcbfcf8599e22bf7c51d88e27434d385dc6db22cf5127476569
3
+ metadata.gz: 92d53929fa49d74df4409422669c809e146723ef88862019ee77dbf8f671b2e0
4
+ data.tar.gz: 3d421f3dd17058b3319bf1973da3c39f4dcc74b1a04ac365b1361be0afb59ab8
5
5
  SHA512:
6
- metadata.gz: 2c924211ea0801f90fcd0b1829f932b5c4a4c7629f00a82212c2188351e6848d9deb94a6d0c20edf4202fdb77a661c64a9ad69cf779ae06e4deffc95aa6c7cca
7
- data.tar.gz: 175c047b5703f52f2e8edbcd7b8df127f19561e35cbe61a31afba9c48199606cf3fdd4b4372f292eb8dc34c4bf700c6171851fc20e976d3d2eb9cc7df693f2fe
6
+ metadata.gz: ef748b3b0b3f7e4e85a7b2523df44101ceb64c9170358e5521fb2601880aefd5fd789c71d88c2115b339323081013e53032daf7e1b7e25ffda9010493da9cbec
7
+ data.tar.gz: 7468514e99d37e180e694b07ef751c5f9badf56dbc94f43e9ed982c9a7799760c37940dfaaa5c0adaecbfb3d82505a184401bad565ab88c56c0401207c3f2176
@@ -7,6 +7,8 @@ require 'openhab/dsl/group'
7
7
  require 'openhab/log/logger'
8
8
  require 'openhab/dsl/items/number_item'
9
9
  require 'openhab/dsl/items/string_item'
10
+ require 'openhab/dsl/items/datetime_item'
11
+ require 'openhab/dsl/items/rollershutter_item'
10
12
 
11
13
  # Automation lookup and injection of OpenHab entities
12
14
  java_import org.openhab.core.items.GroupItem
@@ -84,6 +86,9 @@ module OpenHAB
84
86
  #
85
87
  # @return [Object] the ruby wrapper for the item
86
88
  #
89
+ # rubocop: disable Metrics/MethodLength
90
+ # rubocop: disable Metrics/AbcSize
91
+ # Disabled line length and branch size - case dispatch pattern
87
92
  private_class_method def self.decorate_item(item)
88
93
  case item
89
94
  when GroupItem
@@ -92,10 +97,16 @@ module OpenHAB
92
97
  OpenHAB::DSL::Items::NumberItem.new(item)
93
98
  when Java::Org.openhab.core.library.items::StringItem
94
99
  OpenHAB::DSL::Items::StringItem.new(item)
100
+ when Java::Org.openhab.core.library.items::DateTimeItem
101
+ OpenHAB::DSL::Items::DateTimeItem.new(item)
102
+ when Java::Org.openhab.core.library.items::RollershutterItem
103
+ OpenHAB::DSL::Items::RollershutterItem.new(item)
95
104
  else
96
105
  item
97
106
  end
98
107
  end
108
+ # rubocop: enable Metrics/AbcSize
109
+ # rubocop: enable Metrics/MethodLength
99
110
 
100
111
  #
101
112
  # Looks up a Thing in the OpenHAB registry replacing '_' with ':'
@@ -13,11 +13,13 @@ require 'openhab/dsl/timers'
13
13
  require 'openhab/dsl/group'
14
14
  require 'openhab/dsl/things'
15
15
  require 'openhab/dsl/items/items'
16
+ require 'openhab/dsl/items/datetime_item'
16
17
  require 'openhab/dsl/items/number_item'
17
18
  require 'openhab/dsl/time_of_day'
18
19
  require 'openhab/dsl/gems'
19
20
  require 'openhab/dsl/persistence'
20
21
  require 'openhab/dsl/units'
22
+ require 'openhab/dsl/types/datetime'
21
23
  require 'openhab/dsl/types/quantity'
22
24
  require 'openhab/dsl/states'
23
25
 
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'java'
5
+ require 'time'
6
+ require 'openhab/dsl/types/datetime'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ module Items
11
+ #
12
+ # Delegation to OpenHAB DateTime Item
13
+ #
14
+ # @author Anders Alfredsson
15
+ #
16
+ class DateTimeItem
17
+ extend Forwardable
18
+ include Comparable
19
+
20
+ def_delegator :@datetime_item, :to_s
21
+
22
+ #
23
+ # Create a new DateTimeItem
24
+ #
25
+ # @param [Java::org::openhab::core::libarary::items::DateTimeItem] datetime_item Openhab DateTimeItem to
26
+ # delegate to
27
+ #
28
+ def initialize(datetime_item)
29
+ @datetime_item = datetime_item
30
+ end
31
+
32
+ #
33
+ # Return an instance of DateTime that wraps the DateTimeItem's state
34
+ #
35
+ # @return [OpenHAB::DSL::Types::DateTime] Wrapper for the Item's state, or nil if it has no state
36
+ #
37
+ def to_dt
38
+ OpenHAB::DSL::Types::DateTime.new(@datetime_item.state) if state?
39
+ end
40
+
41
+ #
42
+ # Compare the Item's state to another Item or object that can be compared
43
+ #
44
+ # @param [Object] other Other objet to compare against
45
+ #
46
+ # @return [Integer] -1, 0 or 1 depending on the result of the comparison
47
+ #
48
+ def <=>(other)
49
+ return unless state?
50
+
51
+ logger.trace("Comparing self (#{self.class}) to #{other} (#{other.class})")
52
+ other = other.to_dt if other.is_a? DateTimeItem
53
+ to_dt <=> other
54
+ end
55
+
56
+ #
57
+ # Get the time zone of the Item
58
+ #
59
+ # @return [String] The timezone in `[+-]hh:mm(:ss)` format or nil if the Item has no state
60
+ #
61
+ def zone
62
+ to_dt.zone if state?
63
+ end
64
+
65
+ #
66
+ # Check if missing method can be delegated to other contained objects
67
+ #
68
+ # @param [String, Symbol] meth The method name to check for
69
+ #
70
+ # @return [Boolean] true if DateTimeItem or DateTime responds to the method, false otherwise
71
+ #
72
+ def respond_to_missing?(meth, *)
73
+ @datetime_item.respond_to?(meth) || to_dt.respond_to?(meth)
74
+ end
75
+
76
+ #
77
+ # Forward missing methods to the OpenHAB Item, or a DateTime object wrapping its state
78
+ #
79
+ # @param [String] meth method name
80
+ # @param [Array] args arguments for method
81
+ # @param [Proc] block <description>
82
+ #
83
+ # @return [Object] Value from delegated method in OpenHAB NumberItem
84
+ #
85
+ def method_missing(meth, *args, &block)
86
+ if @datetime_item.respond_to?(meth)
87
+ @datetime_item.__send__(meth, *args, &block)
88
+ elsif state?
89
+ to_dt.send(meth, *args, &block)
90
+ else
91
+ raise NoMethodError, "undefined method `#{meth}' for #{self.class}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'java'
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ module Items
9
+ #
10
+ # Delegator to OpenHAB Rollershutter Item
11
+ #
12
+ class RollershutterItem < Numeric
13
+ extend Forwardable
14
+ include Comparable
15
+
16
+ def_delegator :@rollershutter_item, :to_s
17
+
18
+ java_import Java::OrgOpenhabCoreLibraryTypes::PercentType
19
+ java_import Java::OrgOpenhabCoreLibraryTypes::UpDownType
20
+ java_import Java::OrgOpenhabCoreLibraryTypes::StopMoveType
21
+
22
+ #
23
+ # Creates a new RollershutterItem
24
+ #
25
+ # @param [Java::OrgOpenhabCoreLibraryItems::RollershutterItem] rollershutter_item
26
+ # The OpenHAB RollershutterItem to delegate to
27
+ #
28
+ def initialize(rollershutter_item)
29
+ logger.trace("Wrapping #{rollershutter_item}")
30
+ @rollershutter_item = rollershutter_item
31
+
32
+ super()
33
+ end
34
+
35
+ #
36
+ # Check if the rollershutter is up
37
+ #
38
+ # @return [Boolean] true if the rollershutter is up, false otherwise
39
+ #
40
+ def up?
41
+ state.as(UpDownType) == UpDownType::UP
42
+ end
43
+
44
+ #
45
+ # Check if the rollershutter is down
46
+ #
47
+ # @return [Boolean] true if the rollershutter is down, false otherwise
48
+ #
49
+ def down?
50
+ state.as(UpDownType) == UpDownType::DOWN
51
+ end
52
+
53
+ #
54
+ # Returns the rollershutter's position
55
+ #
56
+ # @return [Java::OrgOpenhabCoreLibraryTypes::PercentType] the position of the rollershutter
57
+ #
58
+ def position
59
+ state.as(PercentType)
60
+ end
61
+
62
+ #
63
+ # Compare the rollershutter's position against another object
64
+ #
65
+ # @param [Object] other object to compare against
66
+ #
67
+ # @return [Integer] -1, 0 or 1 depending on the result of the comparison
68
+ #
69
+ def <=>(other)
70
+ case other
71
+ when PercentType, Java::OrgOpenhabCoreLibraryTypes::DecimalType then position.compare_to(other)
72
+ when Numeric then position.int_value <=> other
73
+ when RollershutterItem then position.compare_to(other.position)
74
+ when UpDownType then state.as(UpDownType) == other
75
+ end
76
+ end
77
+
78
+ #
79
+ # Coerce self into other to enable calculations
80
+ #
81
+ # @param [Numeric] other Other numeric to coerce into
82
+ #
83
+ # @return [Array<Numeric>] an array of other and self coerced into other's type
84
+ #
85
+ def coerce(other)
86
+ raise ArgumentError, "Cannot coerce to #{other.class}" unless other.is_a? Numeric
87
+
88
+ case other
89
+ when Integer then [other, position.int_value]
90
+ when Float then [other, position.float_value]
91
+ end
92
+ end
93
+
94
+ #
95
+ # Case equality
96
+ #
97
+ # @param [Java::OrgOpenhabCoreLibraryTypes::UpDownType, Numeric] other Other object to compare against
98
+ #
99
+ # @return [Boolean] true if self can be defined as other, false otherwise
100
+ #
101
+ def ===(other)
102
+ super unless other.is_a? UpDownType
103
+
104
+ state.as(UpDownType).equals(other)
105
+ end
106
+
107
+ #
108
+ # Sends an UP command to the Item
109
+ #
110
+ def up
111
+ command UpDownType::UP
112
+ end
113
+
114
+ #
115
+ # Sends a DOWN command to the Item
116
+ #
117
+ def down
118
+ command UpDownType::DOWN
119
+ end
120
+
121
+ #
122
+ # Sends a STOP command to the Item
123
+ #
124
+ def stop
125
+ command StopMoveType::STOP
126
+ end
127
+
128
+ #
129
+ # Sends a MOVE command to the Item
130
+ #
131
+ def move
132
+ command StopMoveType::MOVE
133
+ end
134
+
135
+ #
136
+ # Define math operations
137
+ #
138
+ %i[+ - * / %].each do |operator|
139
+ define_method(operator) do |other|
140
+ right, left = coerce(other)
141
+ left.send(operator, right)
142
+ end
143
+ end
144
+
145
+ #
146
+ # Checks if this method responds to the missing method
147
+ #
148
+ # @param [String] meth Name of the method to check
149
+ # @param [Boolean] _include_private boolean if private methods should be checked
150
+ #
151
+ # @return [Boolean] true if this object will respond to the supplied method, false otherwise
152
+ #
153
+ def respond_to_missing?(meth, _include_private = false)
154
+ @rollershutter_item.respond_to?(meth) || position.respond_to?(meth)
155
+ end
156
+
157
+ #
158
+ # Forward missing methods to Openhab RollershutterItem or the PercentType representing it's state
159
+ # if they are defined
160
+ #
161
+ # @param [String] meth method name
162
+ # @param [Array] args arguments for method
163
+ # @param [Proc] block <description>
164
+ #
165
+ # @return [Object] Value from delegated method in OpenHAB NumberItem
166
+ #
167
+ def method_missing(meth, *args, &block)
168
+ if @rollershutter_item.respond_to?(meth)
169
+ @rollershutter_item.__send__(meth, *args, &block)
170
+ elsif position.respond_to?(meth)
171
+ position.__send__(meth, *args, &block)
172
+ else
173
+ raise NoMethodError, "No method `#{meth}' defined for #{self.class}"
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -4,4 +4,5 @@
4
4
  require 'openhab/dsl/monkey_patch/ruby/range'
5
5
  require 'openhab/dsl/monkey_patch/ruby/number'
6
6
  require 'openhab/dsl/monkey_patch/ruby/string'
7
+ require 'openhab/dsl/monkey_patch/ruby/time'
7
8
  require 'bigdecimal/util'
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module MonkeyPatch
6
+ module Ruby
7
+ #
8
+ # Extend Time to make to_s return string parseable by OpenHAB
9
+ #
10
+ module TimeExtensions
11
+ include OpenHAB::Core
12
+
13
+ #
14
+ # Convert to ISO 8601 format
15
+ #
16
+ # @return [Java::JavaTime::Duration] Duration with number of units from self
17
+ #
18
+ def to_s
19
+ strftime '%FT%T.%N%:z'
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ #
28
+ # Extend Time class with to_s method
29
+ #
30
+ class Time
31
+ prepend OpenHAB::DSL::MonkeyPatch::Ruby::TimeExtensions
32
+ end
@@ -6,3 +6,4 @@ require 'openhab/dsl/monkey_patch/types/on_off_type'
6
6
  require 'openhab/dsl/monkey_patch/types/decimal_type'
7
7
  require 'openhab/dsl/monkey_patch/types/percent_type'
8
8
  require 'openhab/dsl/monkey_patch/types/quantity_type'
9
+ require 'openhab/dsl/monkey_patch/types/up_down_type'
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ module OpenHAB
5
+ module DSL
6
+ module MonkeyPatch
7
+ #
8
+ # Patches OpenHAB types
9
+ #
10
+ module Types
11
+ java_import Java::OrgOpenhabCoreLibraryTypes::UpDownType
12
+
13
+ #
14
+ # MonkeyPatching UpDownType
15
+ #
16
+ class UpDownType
17
+ #
18
+ # Check if the supplied object is case equals to self
19
+ #
20
+ # @param [Object] other object to compare
21
+ #
22
+ # @return [Boolean] True if the other object is a RollershutterItem and has the same state
23
+ #
24
+ def ===(other)
25
+ super unless other.is_a? OpenHAB::DSL::Items::RollershutterItem
26
+
27
+ equals(other.state.as(UpDownType))
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -70,7 +70,7 @@ module OpenHAB
70
70
  def create_queue(inputs)
71
71
  case check_guards(event: inputs&.dig('event'))
72
72
  when true
73
- @run_queue.dup
73
+ @run_queue.dup.grep_v(RuleConfig::Otherwise)
74
74
  when false
75
75
  @run_queue.dup.grep(RuleConfig::Otherwise)
76
76
  end
@@ -145,16 +145,14 @@ module OpenHAB
145
145
  #
146
146
  #
147
147
  def process_trigger_delay(trigger_delay, mod, inputs)
148
- if check_trigger_guards(trigger_delay, inputs)
148
+ if trigger_delay.timer_active?
149
+ process_active_timer(inputs, mod, trigger_delay)
150
+ elsif check_trigger_guards(trigger_delay, inputs)
149
151
  logger.trace("Trigger Guards Matched for #{trigger_delay}, delaying rule execution")
150
152
  # Add timer and attach timer to delay object, and also state being tracked to so timer can be cancelled if
151
153
  # state changes
152
154
  # Also another timer should not be created if changed to same value again but instead rescheduled
153
- if trigger_delay.timer_active?
154
- process_active_timer(inputs, mod, trigger_delay)
155
- else
156
- create_trigger_delay_timer(inputs, mod, trigger_delay)
157
- end
155
+ create_trigger_delay_timer(inputs, mod, trigger_delay)
158
156
  else
159
157
  logger.trace("Trigger Guards did not match for #{trigger_delay}, ignoring trigger.")
160
158
  end
@@ -173,7 +171,8 @@ module OpenHAB
173
171
  trigger_delay.timer = after(trigger_delay.duration) do
174
172
  logger.trace("Delay Complete for #{trigger_delay}, executing rule")
175
173
  trigger_delay.timer = nil
176
- process_queue(@run_queue.dup, mod, inputs)
174
+ queue = create_queue(inputs)
175
+ process_queue(queue, mod, inputs)
177
176
  end
178
177
  trigger_delay.tracking_to = inputs['newState']
179
178
  end
@@ -2,8 +2,9 @@
2
2
 
3
3
  require 'java'
4
4
  require 'openhab/log/logger'
5
+ require 'openhab/dsl/items/datetime_item'
6
+ require 'openhab/dsl/types/datetime'
5
7
  require 'time'
6
- require 'date'
7
8
 
8
9
  module OpenHAB
9
10
  module DSL
@@ -172,8 +173,9 @@ module OpenHAB
172
173
  case object
173
174
  when TimeOfDay then adjust_second_of_day(object.local_time.to_second_of_day)
174
175
  when String then adjust_second_of_day(TimeOfDay.parse(object).local_time.to_second_of_day)
175
- when Time then adjust_second_of_day(TimeOfDay.new(h: object.hour, m: object.min,
176
- s: object.sec).local_time.to_second_of_day)
176
+ when Time, OpenHAB::DSL::Types::DateTime, OpenHAB::DSL::Items::DateTimeItem
177
+ adjust_second_of_day(TimeOfDay.new(h: object.hour, m: object.min, s: object.sec)
178
+ .local_time.to_second_of_day)
177
179
  when TimeOfDayRangeElement then object.sod
178
180
  else raise ArgumentError, 'Supplied argument cannot be converted into Time Of Day Object'
179
181
  end
@@ -216,6 +218,8 @@ module OpenHAB
216
218
  private_class_method def to_time_of_day(object)
217
219
  case object
218
220
  when String then TimeOfDay.parse(object)
221
+ when Time, OpenHAB::DSL::Types::DateTime, OpenHAB::DSL::Items::DateTimeItem
222
+ TimeOfDay.new(h: object.hour, m: object.min, s: object.sec)
219
223
  else object
220
224
  end
221
225
  end
@@ -0,0 +1,326 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'forwardable'
5
+ require 'time'
6
+
7
+ module OpenHAB
8
+ module DSL
9
+ module Types
10
+ #
11
+ # Ruby implementation for OpenHAB DateTimeType
12
+ #
13
+ # @author Anders Alfredsson
14
+ #
15
+ # rubocop: disable Metrics/ClassLength
16
+ # Disabled because this class has a single responsibility, there does not appear a logical
17
+ # way of breaking it up into multiple classes
18
+ class DateTime
19
+ extend Forwardable
20
+ include Comparable
21
+ include OpenHAB::Log
22
+
23
+ def_delegator :datetime, :to_s
24
+ def_delegator :zoned_date_time, :month_value, :month
25
+ def_delegator :zoned_date_time, :minute, :min
26
+ def_delegator :zoned_date_time, :second, :sec
27
+ def_delegator :zoned_date_time, :nano, :nsec
28
+ def_delegator :zoned_date_time, :to_epoch_second, :to_i
29
+ alias inspect to_s
30
+
31
+ java_import Java::OrgOpenhabCoreLibraryTypes::DateTimeType
32
+ java_import java.time.ZonedDateTime
33
+ java_import java.time.Instant
34
+ java_import java.time.ZoneId
35
+ java_import java.time.ZoneOffset
36
+ java_import java.time.Duration
37
+
38
+ #
39
+ # Regex expression to identify strings defining a time in hours, minutes and optionally seconds
40
+ #
41
+ TIME_ONLY_REGEX = /\A\d\d:\d\d(:\d\d)?\Z/.freeze
42
+
43
+ #
44
+ # Regex expression to identify strings defining a time in hours, minutes and optionally seconds
45
+ #
46
+ DATE_ONLY_REGEX = /\A\d{4}-\d\d-\d\d\Z/.freeze
47
+
48
+ attr_reader :datetime
49
+
50
+ #
51
+ # Create a new DateTime instance wrapping an OpenHAB DateTimeType
52
+ #
53
+ # @param [Java::org::openhab::core::library::types::DateTimeType] datetime The DateTimeType instance to
54
+ # delegate to, or an object that can be converted to a DateTimeType
55
+ #
56
+ def initialize(datetime)
57
+ @datetime = case datetime
58
+ when DateTimeType
59
+ datetime
60
+ when ZonedDateTime
61
+ DateTimeType.new(datetime)
62
+ else
63
+ raise "Unexpected type #{datetime.class} provided to DateTime initializer"
64
+ end
65
+ end
66
+
67
+ #
68
+ # Compare thes DateTime object to another
69
+ #
70
+ # @param [Object] other Other object to compare against
71
+ #
72
+ # @return [Integer] -1, 0 or 1 depending on the outcome
73
+ #
74
+ def <=>(other)
75
+ case other
76
+ when DateTime, DateTimeType, DateTimeItem
77
+ zoned_date_time.to_instant.compare_to(other.zoned_date_time.to_instant)
78
+ when TimeOfDay::TimeOfDay, TimeOfDay::TimeOfDayRangeElement
79
+ to_tod <=> other
80
+ when String
81
+ self <=> DateTime.parse(DATE_ONLY_REGEX =~ other ? "#{other}'T'00:00:00#{zone}" : other)
82
+ else
83
+ self <=> DateTime.from(other)
84
+ end
85
+ end
86
+
87
+ #
88
+ # Adds another object to this DateTime
89
+ #
90
+ # @param [Object] other Object to add to this. Can be a Numeric, another DateTime/Time/DateTimeType, a
91
+ # Duration or a String that can be parsed into a DateTimeType or Time object
92
+ #
93
+ # @return [DateTime] A new DateTime object representing the result of the calculation
94
+ #
95
+ def +(other)
96
+ logger.trace("Adding #{other} (#{other.class}) to #{self}")
97
+ case other
98
+ when Numeric then DateTime.from(to_time + other)
99
+ when DateTime, Time then self + other.to_f
100
+ when DateTimeType, String then self + DateTime.from(other).to_f
101
+ when Duration then DateTime.new(zoned_date_time.plus(other))
102
+ end
103
+ end
104
+
105
+ #
106
+ # Subtracts another object from this DateTime
107
+ #
108
+ # @param [Object] other Object to subtract fom this. Can be a Numeric, another DateTime/Time/DateTimeType, a
109
+ # Duration or a String that can be parsed into a DateTimeType or Time object
110
+ #
111
+ # @return [DateTime, Float] A new DateTime object representing the result of the calculation, or a Float
112
+ # representing the time difference in seconds if the subtraction is between two time objects
113
+ #
114
+ def -(other)
115
+ logger.trace("Subtracting #{other} (#{other.class}) from self")
116
+ case other
117
+ when Numeric then DateTime.from(to_time - other)
118
+ when String
119
+ dt = DateTime.parse(other)
120
+ TIME_ONLY_REGEX =~ other ? self - dt.to_f : time_diff(dt)
121
+ when Duration then DateTime.new(zoned_date_time.minus(other))
122
+ when Time, DateTime, DateTimeType, DateTimeItem then time_diff(other)
123
+ end
124
+ end
125
+
126
+ #
127
+ # Convert this DateTime to a ruby Time object
128
+ #
129
+ # @return [Time] A Time object representing the same instant and timezone
130
+ #
131
+ def to_time
132
+ Time.at(to_i, nsec, :nsec).localtime(utc_offset)
133
+ end
134
+
135
+ #
136
+ # Convert the time part of this DateTime to a TimeOfDay object
137
+ #
138
+ # @return [TimeOfDay] A TimeOfDay object representing the time
139
+ #
140
+ def to_time_of_day
141
+ TimeOfDay::TimeOfDay.new(h: hour, m: minute, s: second)
142
+ end
143
+
144
+ alias to_tod to_time_of_day
145
+
146
+ #
147
+ # Returns the value of time as a floating point number of seconds since the Epoch
148
+ #
149
+ # @return [Float] Number of seconds since the Epoch, with nanosecond presicion
150
+ #
151
+ def to_f
152
+ zoned_date_time.to_epoch_second + zoned_date_time.nano / 1_000_000_000
153
+ end
154
+
155
+ #
156
+ # The ZonedDateTime representing the state
157
+ #
158
+ # @return [Java::java::time::ZonedDateTime] ZonedDateTime representing the state
159
+ #
160
+ def zoned_date_time
161
+ @datetime.zonedDateTime
162
+ end
163
+
164
+ alias to_zdt zoned_date_time
165
+
166
+ #
167
+ # The offset in seconds from UTC
168
+ #
169
+ # @return [Integer] The offset from UTC, in seconds
170
+ #
171
+ def utc_offset
172
+ zoned_date_time.offset.total_seconds
173
+ end
174
+
175
+ #
176
+ # Returns true if time represents a time in UTC (GMT)
177
+ #
178
+ # @return [Boolean] true if utc_offset == 0, false otherwise
179
+ #
180
+ def utc?
181
+ utc_offset.zero?
182
+ end
183
+
184
+ #
185
+ # The timezone
186
+ #
187
+ # @return [String] The timezone in `[+-]hh:mm(:ss)` format ('Z' for UTC) or nil if the Item has no state
188
+ #
189
+ def zone
190
+ zoned_date_time.zone.id
191
+ end
192
+
193
+ #
194
+ # Check if missing method can be delegated to other contained objects
195
+ #
196
+ # @param [String, Symbol] meth the method name to check for
197
+ #
198
+ # @return [Boolean] true if DateTimeType, ZonedDateTime or Time responds to the method, false otherwise
199
+ #
200
+ def respond_to_missing?(meth, *)
201
+ @datetime.respond_to?(meth) ||
202
+ zoned_date_time.respond_to?(meth) ||
203
+ Time.instance_methods.include?(meth.to_sym)
204
+ end
205
+
206
+ #
207
+ # Forward missing methods to the OpenHAB DateTimeType, its ZonedDateTime object or a ruby Time
208
+ # object representing the same instant
209
+ #
210
+ # @param [String] meth method name
211
+ # @param [Array] args arguments for method
212
+ # @param [Proc] block <description>
213
+ #
214
+ # @return [Object] Value from delegated method in OpenHAB NumberItem
215
+ #
216
+ def method_missing(meth, *args, &block)
217
+ if @datetime.respond_to?(meth)
218
+ @datetime.__send__(meth, *args, &block)
219
+ elsif zoned_date_time.respond_to?(meth)
220
+ zoned_date_time.__send__(meth, *args, &block)
221
+ elsif Time.instance_methods.include?(meth.to_sym)
222
+ to_time.send(meth, *args, &block)
223
+ else
224
+ raise NoMethodError, "undefined method `#{meth}' for #{self.class}"
225
+ end
226
+ end
227
+
228
+ #
229
+ # Converts other objects to a DateTimeType
230
+ #
231
+ # @param [String, Numeric, Time] datetime an object that can be parsed or converted into
232
+ # a DateTimeType
233
+ #
234
+ # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
235
+ #
236
+ def self.from(datetime)
237
+ case datetime
238
+ when String
239
+ parse(datetime)
240
+ when Numeric
241
+ from_numeric(datetime)
242
+ when Time
243
+ from_time(datetime)
244
+ else
245
+ raise "Cannot convert #{datetime.class} to DateTime"
246
+ end
247
+ end
248
+
249
+ #
250
+ # Converts a Numeric into a DateTimeType
251
+ #
252
+ # @param [Numeric] numeric A Integer or Float representing the number of seconds since the epoch
253
+ #
254
+ # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
255
+ #
256
+ def self.from_numeric(numeric)
257
+ case numeric
258
+ when Integer
259
+ DateTime.new(ZonedDateTime.ofInstant(Instant.ofEpochSecond(datetime), ZoneId.systemDefault))
260
+ else
261
+ DateTime.new(ZonedDateTime.ofInstant(Instant.ofEpochSecond(datetime.to_i,
262
+ ((datetime % 1) * 1_000_000_000).to_i),
263
+ ZoneId.systemDefault))
264
+ end
265
+ end
266
+
267
+ #
268
+ # Converts a ruby Time object to an OpenHAB DateTimeType
269
+ #
270
+ # @param [Time] time The Time object to be converted
271
+ #
272
+ # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
273
+ #
274
+ def self.from_time(time)
275
+ instant = Instant.ofEpochSecond(time.to_i, time.nsec)
276
+ zone_id = ZoneId.of_offset('UTC', ZoneOffset.of_total_seconds(time.utc_offset))
277
+ DateTime.new(ZonedDateTime.ofInstant(instant, zone_id))
278
+ end
279
+
280
+ #
281
+ # Parses a string representing a time into an OpenHAB DateTimeType. First tries to parse it
282
+ # using the DateTimeType's parser, then falls back to the ruby Time.parse
283
+ #
284
+ # @param [String] time_string The string to be parsed
285
+ #
286
+ # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
287
+ #
288
+ def self.parse(time_string)
289
+ time_string += 'Z' if TIME_ONLY_REGEX =~ time_string
290
+ DateTime.new(DateTimeType.new(time_string))
291
+ rescue Java::JavaLang::StringIndexOutOfBoundsException, Java::JavaLang::IllegalArgumentException
292
+ # Try ruby's Time.parse if OpenHAB's DateTimeType parser fails
293
+ begin
294
+ time = Time.parse(time_string)
295
+ DateTime.from(time)
296
+ rescue ArgumentError
297
+ raise "Unable to parse #{time_string} into a DateTime"
298
+ end
299
+ end
300
+
301
+ private
302
+
303
+ #
304
+ # Calculates the difference in time between this instance and another time object
305
+ #
306
+ # @param [Time, DateTime, DateTimeItem, Java::org::openhab::core::library::types::DateTimeType] time_obj
307
+ # The other time object to subtract from self
308
+ #
309
+ # @return [Float] The time difference between the two objects, in seconds
310
+ #
311
+ def time_diff(time_obj)
312
+ logger.trace("Calculate time difference between #{self} and #{time_obj}")
313
+ case time_obj
314
+ when Time
315
+ to_time - time_obj
316
+ when DateTime, DateTimeItem
317
+ self - time_obj.to_time
318
+ when DateTimeType
319
+ self - DateTime.new(time_obj).to_time
320
+ end
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ # rubocop: enable Metrics/ClassLength
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '2.17.0'
8
+ VERSION = '2.19.3'
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.17.0
4
+ version: 2.19.3
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-12 00:00:00.000000000 Z
11
+ date: 2021-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,8 +39,10 @@ files:
39
39
  - lib/openhab/dsl/dsl.rb
40
40
  - lib/openhab/dsl/gems.rb
41
41
  - lib/openhab/dsl/group.rb
42
+ - lib/openhab/dsl/items/datetime_item.rb
42
43
  - lib/openhab/dsl/items/items.rb
43
44
  - lib/openhab/dsl/items/number_item.rb
45
+ - lib/openhab/dsl/items/rollershutter_item.rb
44
46
  - lib/openhab/dsl/items/string_item.rb
45
47
  - lib/openhab/dsl/monkey_patch/actions/actions.rb
46
48
  - lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb
@@ -59,12 +61,14 @@ files:
59
61
  - lib/openhab/dsl/monkey_patch/ruby/range.rb
60
62
  - lib/openhab/dsl/monkey_patch/ruby/ruby.rb
61
63
  - lib/openhab/dsl/monkey_patch/ruby/string.rb
64
+ - lib/openhab/dsl/monkey_patch/ruby/time.rb
62
65
  - lib/openhab/dsl/monkey_patch/types/decimal_type.rb
63
66
  - lib/openhab/dsl/monkey_patch/types/on_off_type.rb
64
67
  - lib/openhab/dsl/monkey_patch/types/open_closed_type.rb
65
68
  - lib/openhab/dsl/monkey_patch/types/percent_type.rb
66
69
  - lib/openhab/dsl/monkey_patch/types/quantity_type.rb
67
70
  - lib/openhab/dsl/monkey_patch/types/types.rb
71
+ - lib/openhab/dsl/monkey_patch/types/up_down_type.rb
68
72
  - lib/openhab/dsl/persistence.rb
69
73
  - lib/openhab/dsl/rules/automation_rule.rb
70
74
  - lib/openhab/dsl/rules/guard.rb
@@ -81,6 +85,7 @@ files:
81
85
  - lib/openhab/dsl/things.rb
82
86
  - lib/openhab/dsl/time_of_day.rb
83
87
  - lib/openhab/dsl/timers.rb
88
+ - lib/openhab/dsl/types/datetime.rb
84
89
  - lib/openhab/dsl/types/quantity.rb
85
90
  - lib/openhab/dsl/units.rb
86
91
  - lib/openhab/log/configuration.rb