openhab-scripting 2.15.0 → 2.16.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab.rb +12 -16
  3. data/lib/openhab/core/entity_lookup.rb +162 -0
  4. data/lib/openhab/core/openhab_setup.rb +31 -0
  5. data/lib/openhab/core/osgi.rb +61 -0
  6. data/lib/openhab/dsl/actions.rb +105 -0
  7. data/lib/openhab/dsl/dsl.rb +47 -0
  8. data/lib/openhab/{core/dsl → dsl}/gems.rb +0 -1
  9. data/lib/openhab/dsl/group.rb +100 -0
  10. data/lib/openhab/dsl/items/items.rb +46 -0
  11. data/lib/openhab/dsl/items/number_item.rb +352 -0
  12. data/lib/openhab/dsl/items/string_item.rb +120 -0
  13. data/lib/openhab/dsl/monkey_patch/actions/actions.rb +4 -0
  14. data/lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb +32 -0
  15. data/lib/openhab/dsl/monkey_patch/events/events.rb +5 -0
  16. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +23 -0
  17. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +35 -0
  18. data/lib/openhab/dsl/monkey_patch/events/thing_status_info.rb +33 -0
  19. data/lib/openhab/dsl/monkey_patch/items/contact_item.rb +61 -0
  20. data/lib/openhab/dsl/monkey_patch/items/dimmer_item.rb +193 -0
  21. data/lib/openhab/dsl/monkey_patch/items/group_item.rb +37 -0
  22. data/lib/openhab/dsl/monkey_patch/items/items.rb +133 -0
  23. data/lib/openhab/dsl/monkey_patch/items/metadata.rb +281 -0
  24. data/lib/openhab/dsl/monkey_patch/items/persistence.rb +70 -0
  25. data/lib/openhab/dsl/monkey_patch/items/switch_item.rb +95 -0
  26. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +39 -0
  27. data/lib/openhab/dsl/monkey_patch/ruby/range.rb +47 -0
  28. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +7 -0
  29. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +41 -0
  30. data/lib/openhab/dsl/monkey_patch/types/decimal_type.rb +70 -0
  31. data/lib/openhab/dsl/monkey_patch/types/on_off_type.rb +51 -0
  32. data/lib/openhab/dsl/monkey_patch/types/open_closed_type.rb +36 -0
  33. data/lib/openhab/dsl/monkey_patch/types/percent_type.rb +32 -0
  34. data/lib/openhab/dsl/monkey_patch/types/quantity_type.rb +69 -0
  35. data/lib/openhab/dsl/monkey_patch/types/types.rb +8 -0
  36. data/lib/openhab/dsl/persistence.rb +25 -0
  37. data/lib/openhab/dsl/rules/automation_rule.rb +342 -0
  38. data/lib/openhab/dsl/rules/guard.rb +134 -0
  39. data/lib/openhab/dsl/rules/property.rb +102 -0
  40. data/lib/openhab/dsl/rules/rule.rb +116 -0
  41. data/lib/openhab/dsl/rules/rule_config.rb +151 -0
  42. data/lib/openhab/dsl/rules/triggers/changed.rb +143 -0
  43. data/lib/openhab/dsl/rules/triggers/channel.rb +53 -0
  44. data/lib/openhab/dsl/rules/triggers/command.rb +104 -0
  45. data/lib/openhab/dsl/rules/triggers/cron.rb +177 -0
  46. data/lib/openhab/dsl/rules/triggers/trigger.rb +124 -0
  47. data/lib/openhab/dsl/rules/triggers/updated.rb +98 -0
  48. data/lib/openhab/dsl/states.rb +61 -0
  49. data/lib/openhab/dsl/things.rb +91 -0
  50. data/lib/openhab/dsl/time_of_day.rb +228 -0
  51. data/lib/openhab/dsl/timers.rb +77 -0
  52. data/lib/openhab/dsl/types/quantity.rb +290 -0
  53. data/lib/openhab/dsl/units.rb +39 -0
  54. data/lib/openhab/log/configuration.rb +21 -0
  55. data/lib/openhab/log/logger.rb +172 -0
  56. data/lib/openhab/version.rb +1 -1
  57. metadata +55 -56
  58. data/lib/openhab/configuration.rb +0 -16
  59. data/lib/openhab/core/cron.rb +0 -27
  60. data/lib/openhab/core/debug.rb +0 -34
  61. data/lib/openhab/core/dsl.rb +0 -51
  62. data/lib/openhab/core/dsl/actions.rb +0 -107
  63. data/lib/openhab/core/dsl/entities.rb +0 -140
  64. data/lib/openhab/core/dsl/group.rb +0 -93
  65. data/lib/openhab/core/dsl/items/items.rb +0 -51
  66. data/lib/openhab/core/dsl/items/number_item.rb +0 -318
  67. data/lib/openhab/core/dsl/items/string_item.rb +0 -120
  68. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +0 -4
  69. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +0 -22
  70. data/lib/openhab/core/dsl/monkey_patch/events.rb +0 -5
  71. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +0 -13
  72. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +0 -25
  73. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +0 -26
  74. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +0 -54
  75. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +0 -167
  76. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +0 -27
  77. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +0 -132
  78. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +0 -283
  79. data/lib/openhab/core/dsl/monkey_patch/items/persistence.rb +0 -72
  80. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +0 -87
  81. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +0 -41
  82. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +0 -47
  83. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +0 -6
  84. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +0 -24
  85. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +0 -41
  86. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +0 -25
  87. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +0 -23
  88. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +0 -7
  89. data/lib/openhab/core/dsl/persistence.rb +0 -27
  90. data/lib/openhab/core/dsl/property.rb +0 -96
  91. data/lib/openhab/core/dsl/rule/automation_rule.rb +0 -348
  92. data/lib/openhab/core/dsl/rule/guard.rb +0 -136
  93. data/lib/openhab/core/dsl/rule/rule.rb +0 -117
  94. data/lib/openhab/core/dsl/rule/rule_config.rb +0 -153
  95. data/lib/openhab/core/dsl/rule/triggers/changed.rb +0 -145
  96. data/lib/openhab/core/dsl/rule/triggers/channel.rb +0 -55
  97. data/lib/openhab/core/dsl/rule/triggers/command.rb +0 -106
  98. data/lib/openhab/core/dsl/rule/triggers/cron.rb +0 -160
  99. data/lib/openhab/core/dsl/rule/triggers/trigger.rb +0 -126
  100. data/lib/openhab/core/dsl/rule/triggers/updated.rb +0 -100
  101. data/lib/openhab/core/dsl/states.rb +0 -63
  102. data/lib/openhab/core/dsl/things.rb +0 -93
  103. data/lib/openhab/core/dsl/time_of_day.rb +0 -229
  104. data/lib/openhab/core/dsl/timers.rb +0 -79
  105. data/lib/openhab/core/dsl/types/quantity.rb +0 -292
  106. data/lib/openhab/core/dsl/units.rb +0 -41
  107. data/lib/openhab/core/log.rb +0 -170
  108. data/lib/openhab/core/patch_load_path.rb +0 -7
  109. data/lib/openhab/core/startup_delay.rb +0 -23
  110. data/lib/openhab/osgi.rb +0 -59
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'java'
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ module Rules
9
+ #
10
+ # Module holds rule triggers
11
+ #
12
+ module Triggers
13
+ #
14
+ # Create a trigger for a thing
15
+ #
16
+ # @param [Thing] thing to create trigger for
17
+ # @param [Trigger] trigger to map with thing
18
+ # @param [State] to for thing
19
+ # @param [State] from state of thing
20
+ #
21
+ # @return [Array] Trigger and config for thing
22
+ #
23
+ def trigger_for_thing(thing, trigger, to = nil, from = nil)
24
+ config = { 'thingUID' => thing.uid.to_s }
25
+ config['status'] = trigger_state_from_symbol(to).to_s if to
26
+ config['previousStatus'] = trigger_state_from_symbol(from).to_s if from
27
+ [trigger, config]
28
+ end
29
+
30
+ #
31
+ # converts object to upcase string if its a symbol
32
+ #
33
+ # @param [sym] sym potential symbol to convert
34
+ #
35
+ # @return [String] Upcased symbol as string
36
+ #
37
+ def trigger_state_from_symbol(sym)
38
+ sym.to_s.upcase if (sym.is_a? Symbol) || sym
39
+ end
40
+
41
+ #
42
+ # Append a trigger to the list of triggeres
43
+ #
44
+ # @param [String] type of trigger to create
45
+ # @param [Map] config map describing trigger configuration
46
+ #
47
+ # @return [Trigger] OpenHAB trigger
48
+ #
49
+ def append_trigger(type, config)
50
+ logger.trace("Creating trigger of type #{type} for #{config}")
51
+ trigger = Trigger.trigger(type: type, config: config)
52
+ @triggers << trigger
53
+ trigger
54
+ end
55
+
56
+ #
57
+ # Class for creating and managing triggers
58
+ #
59
+ class Trigger
60
+ java_import org.openhab.core.automation.util.TriggerBuilder
61
+ java_import org.openhab.core.config.core.Configuration
62
+
63
+ # @return [String] A channel event trigger
64
+ CHANNEL_EVENT = 'core.ChannelEventTrigger'
65
+
66
+ # @return [String] A thing status Change trigger
67
+ THING_CHANGE = 'core.ThingStatusChangeTrigger'
68
+
69
+ # @return [String] A thing status update trigger
70
+ THING_UPDATE = 'core.ThingStatusUpdateTrigger'
71
+
72
+ # @return [String] An item command trigger
73
+ ITEM_COMMAND = 'core.ItemCommandTrigger'
74
+
75
+ # @return [String] An item state update trigger
76
+ ITEM_STATE_UPDATE = 'core.ItemStateUpdateTrigger'
77
+
78
+ # @return [String] An item state change trigger
79
+ ITEM_STATE_CHANGE = 'core.ItemStateChangeTrigger'
80
+
81
+ # @return [String] A group state change trigger for items in the group
82
+ GROUP_STATE_CHANGE = 'core.GroupStateChangeTrigger'
83
+
84
+ # @return [String] A group state update trigger for items in the group
85
+ GROUP_STATE_UPDATE = 'core.GroupStateUpdateTrigger'
86
+
87
+ # @return [String] A group command trigger for items in the group
88
+ GROUP_COMMAND = 'core.GroupCommandTrigger'
89
+
90
+ # @return [String] A time of day trigger
91
+ TIME_OF_DAY = 'timer.TimeOfDayTrigger'
92
+
93
+ # @return [String] A cron trigger
94
+ CRON = 'timer.GenericCronTrigger'
95
+
96
+ #
97
+ # Create a trigger
98
+ #
99
+ # @param [String] type of trigger
100
+ # @param [Map] config map
101
+ #
102
+ # @return [OpenHAB Trigger] configured by type and supplied config
103
+ #
104
+ def self.trigger(type:, config:)
105
+ TriggerBuilder.create
106
+ .with_id(uuid)
107
+ .with_type_uid(type)
108
+ .with_configuration(Configuration.new(config))
109
+ .build
110
+ end
111
+
112
+ #
113
+ # Generate a UUID for triggers
114
+ #
115
+ # @return [String] UUID
116
+ #
117
+ def self.uuid
118
+ SecureRandom.uuid
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/log/logger'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module Rules
8
+ #
9
+ # Module holds rule triggers
10
+ #
11
+ module Triggers
12
+ include OpenHAB::Log
13
+
14
+ #
15
+ # Create a trigger when item, group or thing is updated
16
+ #
17
+ # @param [Array] items array to trigger on updated
18
+ # @param [State] to to match for tigger
19
+ #
20
+ # @return [Trigger] Trigger for updated entity
21
+ #
22
+ def updated(*items, to: nil)
23
+ items.flatten.each do |item|
24
+ logger.trace("Creating updated trigger for item(#{item}) to(#{to})")
25
+ [to].flatten.each do |to_state|
26
+ trigger, config = create_update_trigger(item, to_state)
27
+ append_trigger(trigger, config)
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ #
35
+ # Create a trigger for updates
36
+ #
37
+ # @param [Object] item Type of item [Group,Thing,Item] to create update trigger for
38
+ # @param [State] to_state state restriction on trigger
39
+ #
40
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
41
+ # second element is a Hash configuring trigger
42
+ #
43
+ def create_update_trigger(item, to_state)
44
+ case item
45
+ when GroupItems then group_update(item, to_state)
46
+ when Thing then thing_update(item, to_state)
47
+ else item_update(item, to_state)
48
+ end
49
+ end
50
+
51
+ #
52
+ # Create an update trigger for an item
53
+ #
54
+ # @param [Item] item to create trigger for
55
+ # @param [State] to_state optional state restriction for target
56
+ #
57
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
58
+ # second element is a Hash configuring trigger
59
+ #
60
+ def item_update(item, to_state)
61
+ config = { 'itemName' => item.name }
62
+ config['state'] = to_state.to_s unless to_state.nil?
63
+ trigger = Trigger::ITEM_STATE_UPDATE
64
+ [trigger, config]
65
+ end
66
+
67
+ #
68
+ # Create an update trigger for a group
69
+ #
70
+ # @param [Item] item to create trigger for
71
+ # @param [State] to_state optional state restriction for target
72
+ #
73
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
74
+ # second element is a Hash configuring trigger
75
+ #
76
+ def group_update(item, to_state)
77
+ config = { 'groupName' => item.group.name }
78
+ config['state'] = to_state.to_s unless to_state.nil?
79
+ trigger = Trigger::GROUP_STATE_UPDATE
80
+ [trigger, config]
81
+ end
82
+
83
+ #
84
+ # Create an update trigger for a thing
85
+ #
86
+ # @param [Thing] thing to create trigger for
87
+ # @param [State] to_state optional state restriction for target
88
+ #
89
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
90
+ # second element is a Hash configuring trigger
91
+ #
92
+ def thing_update(thing, to_state)
93
+ trigger_for_thing(thing, Trigger::THING_UPDATE, to_state)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ #
8
+ # Manages storing and restoring item state
9
+ #
10
+ module States
11
+ java_import org.openhab.core.model.script.actions.BusEvent
12
+
13
+ #
14
+ # Delegates state storage to a Hash providing methods to operate with states
15
+ #
16
+ class StateStorage < SimpleDelegator
17
+ #
18
+ # Restore the stored states of all items
19
+ #
20
+ #
21
+ def restore
22
+ BusEvent.restoreStates(to_h)
23
+ end
24
+
25
+ #
26
+ # Restore states for items that have changed
27
+ #
28
+ #
29
+ def restore_changes
30
+ BusEvent.restoreStates(select { |item, value| item != value })
31
+ end
32
+
33
+ #
34
+ # Detect if any item have changed states since being stored
35
+ #
36
+ # @return [Boolean] True if any items have changed states, false otherwise
37
+ #
38
+ def changed?
39
+ any? { |item, value| item != value }
40
+ end
41
+ end
42
+
43
+ #
44
+ # Store states of supplied items
45
+ #
46
+ # @param [Array] items to store states of
47
+ #
48
+ # @return [StateStorage] item states
49
+ #
50
+ def store_states(*items)
51
+ items = items.flatten.map { |item| item.is_a?(Group) ? item.group : item }
52
+ states = StateStorage.new(BusEvent.storeStates(*items).to_h)
53
+ if block_given?
54
+ yield
55
+ states.restore
56
+ end
57
+ states
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'openhab/log/logger'
5
+ require 'openhab/dsl/actions'
6
+ require 'delegate'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ #
11
+ # Support for OpenHAB Things
12
+ #
13
+ module Things
14
+ include OpenHAB::Log
15
+
16
+ #
17
+ # Ruby Delegator for Thing
18
+ #
19
+ class Thing < SimpleDelegator
20
+ include OpenHAB::DSL::Actions
21
+ include OpenHAB::Log
22
+
23
+ def initialize(thing)
24
+ super
25
+ define_action_methods
26
+ end
27
+
28
+ private
29
+
30
+ java_import 'org.openhab.core.automation.annotation.RuleAction'
31
+
32
+ #
33
+ # Define methods from actions mapped to this thing
34
+ #
35
+ #
36
+ def define_action_methods
37
+ actions_for_thing(uid).each do |action|
38
+ methods = action.java_class.declared_instance_methods
39
+ methods.select { |method| method.annotation_present?(RuleAction.java_class) }
40
+ .each { |method| define_action_method(action: action, method: method.name) }
41
+ end
42
+ end
43
+
44
+ #
45
+ # Define a method, delegating to supplied action class
46
+ #
47
+ # @param [Object] action object to delegate method to
48
+ # @param [String] method Name of method to delegate
49
+ #
50
+ #
51
+ def define_action_method(action:, method:)
52
+ logger.trace("Adding action method '#{method}' to thing '#{uid}'")
53
+ define_singleton_method(method) do |*args|
54
+ action.public_send(method, *args)
55
+ end
56
+ end
57
+ end
58
+
59
+ #
60
+ # Wraps all Things in a delegator to underlying set and provides lookup method
61
+ #
62
+ class Things < SimpleDelegator
63
+ java_import org.openhab.core.thing.ThingUID
64
+
65
+ # Gets a specific thing by name in the format binding_id:type_id:thing_id
66
+ # @return Thing specified by name or nil if name does not exist in thing registry
67
+ def[](uid)
68
+ thing_uid = ThingUID.new(*uid.split(':'))
69
+ # rubocop: disable Style/GlobalVars
70
+ thing = $things.get(thing_uid)
71
+ # rubocop: enable Style/GlobalVars
72
+ return unless thing
73
+
74
+ logger.trace("Retrieved Thing(#{thing}) from registry for uid: #{uid}")
75
+ Thing.new(thing)
76
+ end
77
+ end
78
+
79
+ #
80
+ # Get all things known to OpenHAB
81
+ #
82
+ # @return [Set] of all Thing objects known to openhab
83
+ #
84
+ def things
85
+ # rubocop: disable Style/GlobalVars
86
+ Things.new($things.getAll.map { |thing| Thing.new(thing) }.to_set)
87
+ # rubocop: enable Style/GlobalVars
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'openhab/log/logger'
5
+ require 'time'
6
+ require 'date'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ # Times without specific dates e.g. 6:00:00
11
+ # @author Brian O'Connell
12
+ # @since 0.0.1
13
+ module TimeOfDay
14
+ java_import java.time.LocalTime
15
+ java_import java.time.format.DateTimeFormatterBuilder
16
+ java_import java.util.Locale
17
+
18
+ # Class that encapsulates a Time of Day, often viewed as hour-minute-second
19
+ # @author Brian O'Connell
20
+ # @since 0.0.1
21
+ class TimeOfDay
22
+ include Comparable
23
+
24
+ # Immutable Java object containing Time Of Day
25
+ # @return [Java.Time.LocalTime] reprsenting the Time Of Day
26
+ attr_reader :local_time
27
+
28
+ # Constructs a TimeOfDay representing the time when called
29
+ # @since 0.0.1
30
+ # @return [TimeOfDay] representing time when method was invoked
31
+ def self.now
32
+ now = LocalTime.now()
33
+ TimeOfDay.new(h: now.hour, m: now.minute, s: now.second)
34
+ end
35
+
36
+ # Constructs a TimeOfDay representing midnight
37
+ # @since 0.0.1
38
+ # @return [TimeOfDay] representing midnight
39
+ def self.midnight
40
+ TimeOfDay.new(h: 0, m: 0, s: 0)
41
+ end
42
+
43
+ # Constructs a TimeOfDay representing noon
44
+ # @since 0.0.1
45
+ # @return [TimeOfDay] representing noon
46
+ def self.noon
47
+ TimeOfDay.new(h: 12, m: 0, s: 0)
48
+ end
49
+
50
+ # Constructs a TimeOfDay representing the time when called
51
+ # @since 0.0.1
52
+ # @param [String] string representation of TimeOfDay. Valid formats include "HH:MM:SS", "HH:MM",
53
+ # "H:MM", "HH", "H", "H:MM am"
54
+ # @return [TimeOfDay] object created by parsing supplied string
55
+ def self.parse(string)
56
+ format = /(am|pm)$/i.match?(string) ? 'h[:mm[:ss]][ ]a' : 'H[:mm[:ss]]'
57
+ local_time = LocalTime.parse(string, DateTimeFormatterBuilder.new
58
+ .parseCaseInsensitive.appendPattern(format).toFormatter(Locale::ENGLISH))
59
+ TimeOfDay.new(h: local_time.hour, m: local_time.minute, s: local_time.second)
60
+ rescue java.time.format.DateTimeParseException => e
61
+ raise ArgumentError, e.message
62
+ end
63
+
64
+ # Constructs a TimeOfDay representing the time when called
65
+ # @since 0.0.1
66
+ # @option opts [Number] :h Hour of the day, defaults to 0
67
+ # @option opts [Number] :m Minute of the day, defaults to 0
68
+ # @option opts [Number] :s Second of the day, defaults to 0
69
+ # @return [TimeOfDay] representing time when method was invoked
70
+ # rubocop: disable Naming/MethodParameterName
71
+ # This method has a better feel with short parameter names
72
+ def initialize(h: 0, m: 0, s: 0)
73
+ @local_time = LocalTime.of(h, m, s)
74
+ freeze
75
+ end
76
+ # rubocop: enable Naming/MethodParameterName
77
+
78
+ # Returns true if the time falls within a range
79
+ def between?(range)
80
+ between(range).cover? self
81
+ end
82
+
83
+ # Returns the hour of the TimeOfDay
84
+ # @since 0.0.1
85
+ # @return [Number] Hour of the day, from 0 to 23
86
+ def hour
87
+ @local_time.hour
88
+ end
89
+
90
+ # Returns the minute of the TimeOfDay
91
+ # @since 0.0.1
92
+ # @return [Number] minute of the day, from 0 to 59
93
+ def minute
94
+ @local_time.minute
95
+ end
96
+
97
+ # Returns the second of the TimeOfDay
98
+ # @since 0.0.1
99
+ # @return [Number] second of the day, from 0 to 59
100
+ def second
101
+ @local_time.second
102
+ end
103
+
104
+ # Returns the string representation of the TimeOfDay
105
+ # @since 0.0.1
106
+ # @return [String] in any of the following formats depending on time representation HH:mm, HH:mm:ss,
107
+ # HH:mm:ss.SSS, HH:mm:ss.SSSSSS, HH:mm:ss.SSSSSSSSS
108
+ def to_s
109
+ @local_time.to_s
110
+ end
111
+
112
+ # Compares one TimeOfDay to another
113
+ # @since 0.0.1
114
+ # @return [Number, nil] -1,0,1 if other TimeOfDay is less than, equal to, or greater than this TimeOfDay
115
+ # or nil if an object other than TimeOfDay is provided
116
+ def <=>(other)
117
+ case other
118
+ when TimeOfDay
119
+ @local_time.compare_to(other.local_time)
120
+ when String
121
+ @local_time.compare_to(TimeOfDay.parse(other).local_time)
122
+ else
123
+ -(other <=> self)
124
+ end
125
+ end
126
+ end
127
+
128
+ # Modules that refines the Ruby Range object cover? and include? methods to support TimeOfDay ranges
129
+ class TimeOfDayRangeElement < Numeric
130
+ include Comparable
131
+ include OpenHAB::Log
132
+
133
+ NUM_SECONDS_IN_DAY = (60 * 60 * 24)
134
+
135
+ attr_reader :sod
136
+
137
+ def initialize(sod:, range_begin:)
138
+ @sod = sod
139
+ @range_begin = range_begin
140
+ super()
141
+ end
142
+
143
+ # Returns the current second of day advanced by 1 second
144
+ def succ
145
+ TimeOfDayRangeElement.new(sod: @sod + 1, range_begin: @range_begin)
146
+ end
147
+
148
+ # Compares one TimeOfDayRangeElement to another
149
+ # @since 2.4.0
150
+ # @return [Number, nil] -1,0,1 if other is less than, equal to, or greater than this TimeOfDay
151
+ def <=>(other)
152
+ other_second_of_day = to_second_of_day(other)
153
+ logger.trace do
154
+ "SOD(#{sod}) "\
155
+ "other SOD(#{other_second_of_day}) "\
156
+ "Other Class (#{other.class}) "\
157
+ "Result (#{sod <=> other_second_of_day})"
158
+ end
159
+ sod <=> other_second_of_day
160
+ end
161
+
162
+ private
163
+
164
+ #
165
+ # Convert object to the seconds of a day they reprsent
166
+ #
167
+ # @param [Object] object TimeofDay,String,Time, or TimeOfDayRangeElement to convert
168
+ #
169
+ # @return [Integer] seconds of day represented by supplied object
170
+ #
171
+ def to_second_of_day(object)
172
+ case object
173
+ when TimeOfDay then adjust_second_of_day(object.local_time.to_second_of_day)
174
+ 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)
177
+ when TimeOfDayRangeElement then object.sod
178
+ else raise ArgumentError, 'Supplied argument cannot be converted into Time Of Day Object'
179
+ end
180
+ end
181
+
182
+ def adjust_second_of_day(second_of_day)
183
+ second_of_day += NUM_SECONDS_IN_DAY if second_of_day < @range_begin
184
+ second_of_day
185
+ end
186
+ end
187
+
188
+ # Creates a range that can be compared against time of day objects or strings
189
+ # to see if they are within the range
190
+ # @since 2.4.0
191
+ # @return Range object representing a TimeOfDay Range
192
+ module_function
193
+
194
+ def between(range)
195
+ raise ArgumentError, 'Supplied object must be a range' unless range.is_a? Range
196
+
197
+ start = to_time_of_day(range.begin)
198
+ ending = to_time_of_day(range.end)
199
+
200
+ start_sod = start.local_time.to_second_of_day
201
+ ending_sod = ending.local_time.to_second_of_day
202
+ ending_sod += TimeOfDayRangeElement::NUM_SECONDS_IN_DAY if ending_sod < start_sod
203
+
204
+ start_range = TimeOfDayRangeElement.new(sod: start_sod, range_begin: start_sod)
205
+ ending_range = TimeOfDayRangeElement.new(sod: ending_sod, range_begin: start_sod)
206
+ range.exclude_end? ? (start_range...ending_range) : (start_range..ending_range)
207
+ end
208
+
209
+ #
210
+ # Convert object to TimeOfDay object
211
+ #
212
+ # @param [Object] object TimeOfDay or String to be converted
213
+ #
214
+ # @return [TimeOfDay] TimeOfDay created from supplied object
215
+ #
216
+ private_class_method def to_time_of_day(object)
217
+ case object
218
+ when String then TimeOfDay.parse(object)
219
+ else object
220
+ end
221
+ end
222
+
223
+ MIDNIGHT = TimeOfDay.midnight
224
+ NOON = TimeOfDay.noon
225
+ ALL_DAY = between(TimeOfDay.new(h: 0, m: 0, s: 0)..TimeOfDay.new(h: 23, m: 59, s: 59))
226
+ end
227
+ end
228
+ end