openhab-scripting 2.16.4 → 2.19.2
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 +4 -4
- data/lib/openhab/core/entity_lookup.rb +11 -0
- data/lib/openhab/dsl/dsl.rb +2 -0
- data/lib/openhab/dsl/items/datetime_item.rb +97 -0
- data/lib/openhab/dsl/items/rollershutter_item.rb +179 -0
- data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +1 -0
- data/lib/openhab/dsl/monkey_patch/ruby/time.rb +32 -0
- data/lib/openhab/dsl/monkey_patch/types/types.rb +1 -0
- data/lib/openhab/dsl/monkey_patch/types/up_down_type.rb +33 -0
- data/lib/openhab/dsl/rules/automation_rule.rb +6 -7
- data/lib/openhab/dsl/time_of_day.rb +7 -3
- data/lib/openhab/dsl/types/datetime.rb +326 -0
- data/lib/openhab/dsl/units.rb +1 -1
- data/lib/openhab/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74777515cf7cb008bb80d87ad05a1af9dcd8a260ebeb458b7d9ee24c4aa63453
|
4
|
+
data.tar.gz: 28bd0a8950695ac78e91177fe3884e86f278efdba8d695e1cf7f4637a36571a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87f8af88c6f73b7498c054253544a4ac71940f634f1fa45a80c7bc1518c6c9906d3e099a5f0013afa0b4f454f3c06239479507c81afe000ed07e1f5bd052b75f
|
7
|
+
data.tar.gz: 5b2b7560d230a1d04725a5635f923b919439bc2156be7fc10474c2f9396c87823939f0cb590db8feb978577c6880e059ed2eb0cf83edd64c04ae915693ccb532
|
@@ -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 ':'
|
data/lib/openhab/dsl/dsl.rb
CHANGED
@@ -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
|
@@ -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
|
@@ -145,16 +145,14 @@ module OpenHAB
|
|
145
145
|
#
|
146
146
|
#
|
147
147
|
def process_trigger_delay(trigger_delay, mod, inputs)
|
148
|
-
if
|
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
|
-
|
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
|
-
|
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
|
176
|
-
|
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
|
data/lib/openhab/dsl/units.rb
CHANGED
data/lib/openhab/version.rb
CHANGED
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.
|
4
|
+
version: 2.19.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-
|
11
|
+
date: 2021-02-16 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
|