openhab-scripting 2.9.1
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 +7 -0
- data/.github/workflows/workflow.yml +327 -0
- data/.gitignore +17 -0
- data/.java-version +1 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +113 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +245 -0
- data/Guardfile +35 -0
- data/LICENSE +277 -0
- data/README.md +23 -0
- data/Rakefile +406 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/config/userdata/config/org/openhab/restauth.config +3 -0
- data/cucumber.yml +1 -0
- data/docs/_config.yml +135 -0
- data/docs/contributing/index.md +47 -0
- data/docs/examples/conversions.md +123 -0
- data/docs/examples/index.md +61 -0
- data/docs/index.md +19 -0
- data/docs/installation/index.md +26 -0
- data/docs/motivation/index.md +27 -0
- data/docs/usage/execution.md +9 -0
- data/docs/usage/execution/delay.md +48 -0
- data/docs/usage/execution/otherwise.md +30 -0
- data/docs/usage/execution/run.md +70 -0
- data/docs/usage/execution/triggered.md +48 -0
- data/docs/usage/guards.md +51 -0
- data/docs/usage/guards/between.md +30 -0
- data/docs/usage/guards/not_if.md +41 -0
- data/docs/usage/guards/only_if.md +40 -0
- data/docs/usage/index.md +11 -0
- data/docs/usage/items.md +66 -0
- data/docs/usage/items/contact.md +84 -0
- data/docs/usage/items/dimmer.md +147 -0
- data/docs/usage/items/groups.md +76 -0
- data/docs/usage/items/number.md +225 -0
- data/docs/usage/items/string.md +49 -0
- data/docs/usage/items/switch.md +85 -0
- data/docs/usage/misc.md +7 -0
- data/docs/usage/misc/actions.md +108 -0
- data/docs/usage/misc/duration.md +21 -0
- data/docs/usage/misc/gems.md +25 -0
- data/docs/usage/misc/logging.md +21 -0
- data/docs/usage/misc/metadata.md +128 -0
- data/docs/usage/misc/store_states.md +42 -0
- data/docs/usage/misc/time_of_day.md +69 -0
- data/docs/usage/misc/timers.md +67 -0
- data/docs/usage/rule.md +43 -0
- data/docs/usage/things.md +29 -0
- data/docs/usage/triggers.md +8 -0
- data/docs/usage/triggers/changed.md +57 -0
- data/docs/usage/triggers/channel.md +54 -0
- data/docs/usage/triggers/command.md +69 -0
- data/docs/usage/triggers/cron.md +19 -0
- data/docs/usage/triggers/every.md +76 -0
- data/docs/usage/triggers/updated.md +78 -0
- data/lib/openhab.rb +39 -0
- data/lib/openhab/configuration.rb +16 -0
- data/lib/openhab/core/cron.rb +27 -0
- data/lib/openhab/core/debug.rb +34 -0
- data/lib/openhab/core/dsl.rb +47 -0
- data/lib/openhab/core/dsl/actions.rb +107 -0
- data/lib/openhab/core/dsl/entities.rb +103 -0
- data/lib/openhab/core/dsl/gems.rb +29 -0
- data/lib/openhab/core/dsl/group.rb +91 -0
- data/lib/openhab/core/dsl/items/items.rb +39 -0
- data/lib/openhab/core/dsl/items/number_item.rb +217 -0
- data/lib/openhab/core/dsl/items/string_item.rb +102 -0
- data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +4 -0
- data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +22 -0
- data/lib/openhab/core/dsl/monkey_patch/events.rb +5 -0
- data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +13 -0
- data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +25 -0
- data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +26 -0
- data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +54 -0
- data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +125 -0
- data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +27 -0
- data/lib/openhab/core/dsl/monkey_patch/items/items.rb +130 -0
- data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +259 -0
- data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +86 -0
- data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +69 -0
- data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +46 -0
- data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +5 -0
- data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +24 -0
- data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +41 -0
- data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +25 -0
- data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +23 -0
- data/lib/openhab/core/dsl/monkey_patch/types/types.rb +7 -0
- data/lib/openhab/core/dsl/property.rb +85 -0
- data/lib/openhab/core/dsl/rule/channel.rb +41 -0
- data/lib/openhab/core/dsl/rule/cron.rb +115 -0
- data/lib/openhab/core/dsl/rule/guard.rb +99 -0
- data/lib/openhab/core/dsl/rule/item.rb +207 -0
- data/lib/openhab/core/dsl/rule/rule.rb +374 -0
- data/lib/openhab/core/dsl/rule/triggers.rb +77 -0
- data/lib/openhab/core/dsl/states.rb +63 -0
- data/lib/openhab/core/dsl/things.rb +93 -0
- data/lib/openhab/core/dsl/time_of_day.rb +203 -0
- data/lib/openhab/core/dsl/timers.rb +85 -0
- data/lib/openhab/core/dsl/types/quantity.rb +255 -0
- data/lib/openhab/core/dsl/units.rb +41 -0
- data/lib/openhab/core/duration.rb +69 -0
- data/lib/openhab/core/log.rb +175 -0
- data/lib/openhab/core/patch_load_path.rb +7 -0
- data/lib/openhab/core/startup_delay.rb +22 -0
- data/lib/openhab/osgi.rb +52 -0
- data/lib/openhab/version.rb +9 -0
- data/openhab-scripting.gemspec +30 -0
- data/openhab_rules/warmup.rb +5 -0
- metadata +157 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module OpenHAB
|
|
6
|
+
module Core
|
|
7
|
+
module DSL
|
|
8
|
+
module Rule
|
|
9
|
+
#
|
|
10
|
+
# Class for creating and managing triggers
|
|
11
|
+
#
|
|
12
|
+
class Trigger
|
|
13
|
+
java_import org.openhab.core.automation.util.TriggerBuilder
|
|
14
|
+
java_import org.openhab.core.config.core.Configuration
|
|
15
|
+
|
|
16
|
+
# @return [String] A channel event trigger
|
|
17
|
+
CHANNEL_EVENT = 'core.ChannelEventTrigger'
|
|
18
|
+
|
|
19
|
+
# @return [String] A thing status Change trigger
|
|
20
|
+
THING_CHANGE = 'core.ThingStatusChangeTrigger'
|
|
21
|
+
|
|
22
|
+
# @return [String] A thing status update trigger
|
|
23
|
+
THING_UPDATE = 'core.ThingStatusUpdateTrigger'
|
|
24
|
+
|
|
25
|
+
# @return [String] An item command trigger
|
|
26
|
+
ITEM_COMMAND = 'core.ItemCommandTrigger'
|
|
27
|
+
|
|
28
|
+
# @return [String] An item state update trigger
|
|
29
|
+
ITEM_STATE_UPDATE = 'core.ItemStateUpdateTrigger'
|
|
30
|
+
|
|
31
|
+
# @return [String] An item state change trigger
|
|
32
|
+
ITEM_STATE_CHANGE = 'core.ItemStateChangeTrigger'
|
|
33
|
+
|
|
34
|
+
# @return [String] A group state change trigger for items in the group
|
|
35
|
+
GROUP_STATE_CHANGE = 'core.GroupStateChangeTrigger'
|
|
36
|
+
|
|
37
|
+
# @return [String] A group state update trigger for items in the group
|
|
38
|
+
GROUP_STATE_UPDATE = 'core.GroupStateUpdateTrigger'
|
|
39
|
+
|
|
40
|
+
# @return [String] A group command trigger for items in the group
|
|
41
|
+
GROUP_COMMAND = 'core.GroupCommandTrigger'
|
|
42
|
+
|
|
43
|
+
# @return [String] A time of day trigger
|
|
44
|
+
TIME_OF_DAY = 'timer.TimeOfDayTrigger'
|
|
45
|
+
|
|
46
|
+
# @return [String] A cron trigger
|
|
47
|
+
CRON = 'timer.GenericCronTrigger'
|
|
48
|
+
|
|
49
|
+
#
|
|
50
|
+
# Create a trigger
|
|
51
|
+
#
|
|
52
|
+
# @param [String] type of trigger
|
|
53
|
+
# @param [Map] config map
|
|
54
|
+
#
|
|
55
|
+
# @return [OpenHAB Trigger] configured by type and supplied config
|
|
56
|
+
#
|
|
57
|
+
def self.trigger(type:, config:)
|
|
58
|
+
TriggerBuilder.create
|
|
59
|
+
.with_id(uuid)
|
|
60
|
+
.with_type_uid(type)
|
|
61
|
+
.with_configuration(Configuration.new(config))
|
|
62
|
+
.build
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Generate a UUID for triggers
|
|
67
|
+
#
|
|
68
|
+
# @return [String] UUID
|
|
69
|
+
#
|
|
70
|
+
def self.uuid
|
|
71
|
+
SecureRandom.uuid
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'delegate'
|
|
4
|
+
|
|
5
|
+
module OpenHAB
|
|
6
|
+
module Core
|
|
7
|
+
module DSL
|
|
8
|
+
#
|
|
9
|
+
# Manages storing and restoring item state
|
|
10
|
+
#
|
|
11
|
+
module States
|
|
12
|
+
java_import org.openhab.core.model.script.actions.BusEvent
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# Delegates state storage to a Hash providing methods to operate with states
|
|
16
|
+
#
|
|
17
|
+
class StateStorage < SimpleDelegator
|
|
18
|
+
#
|
|
19
|
+
# Restore the stored states of all items
|
|
20
|
+
#
|
|
21
|
+
#
|
|
22
|
+
def restore
|
|
23
|
+
BusEvent.restoreStates(to_h)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Restore states for items that have changed
|
|
28
|
+
#
|
|
29
|
+
#
|
|
30
|
+
def restore_changes
|
|
31
|
+
BusEvent.restoreStates(select { |item, value| item != value })
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# Detect if any item have changed states since being stored
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean] True if any items have changed states, false otherwise
|
|
38
|
+
#
|
|
39
|
+
def changed?
|
|
40
|
+
any? { |item, value| item != value }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
#
|
|
45
|
+
# Store states of supplied items
|
|
46
|
+
#
|
|
47
|
+
# @param [Array] items to store states of
|
|
48
|
+
#
|
|
49
|
+
# @return [StateStorage] item states
|
|
50
|
+
#
|
|
51
|
+
def store_states(*items)
|
|
52
|
+
items = items.flatten.map { |item| item.is_a?(Group) ? item.group : item }
|
|
53
|
+
states = StateStorage.new(BusEvent.storeStates(*items).to_h)
|
|
54
|
+
if block_given?
|
|
55
|
+
yield
|
|
56
|
+
states.restore
|
|
57
|
+
end
|
|
58
|
+
states
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'java'
|
|
4
|
+
require 'core/log'
|
|
5
|
+
require 'core/dsl/actions'
|
|
6
|
+
require 'delegate'
|
|
7
|
+
|
|
8
|
+
module OpenHAB
|
|
9
|
+
module Core
|
|
10
|
+
module DSL
|
|
11
|
+
#
|
|
12
|
+
# Support for OpenHAB Things
|
|
13
|
+
#
|
|
14
|
+
module Things
|
|
15
|
+
include Logging
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Ruby Delegator for Thing
|
|
19
|
+
#
|
|
20
|
+
class Thing < SimpleDelegator
|
|
21
|
+
include OpenHAB::Core::DSL::Actions
|
|
22
|
+
include Logging
|
|
23
|
+
|
|
24
|
+
def initialize(thing)
|
|
25
|
+
super
|
|
26
|
+
define_action_methods
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
java_import 'org.openhab.core.automation.annotation.RuleAction'
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# Define methods from actions mapped to this thing
|
|
35
|
+
#
|
|
36
|
+
#
|
|
37
|
+
def define_action_methods
|
|
38
|
+
actions_for_thing(uid).each do |action|
|
|
39
|
+
methods = action.java_class.declared_instance_methods
|
|
40
|
+
methods.select { |method| method.annotation_present?(RuleAction.java_class) }
|
|
41
|
+
.each { |method| define_action_method(action: action, method: method.name) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#
|
|
46
|
+
# Define a method, delegating to supplied action class
|
|
47
|
+
#
|
|
48
|
+
# @param [Object] action object to delegate method to
|
|
49
|
+
# @param [String] method Name of method to delegate
|
|
50
|
+
#
|
|
51
|
+
#
|
|
52
|
+
def define_action_method(action:, method:)
|
|
53
|
+
logger.trace("Adding action method '#{method}' to thing '#{uid}'")
|
|
54
|
+
define_singleton_method(method) do |*args|
|
|
55
|
+
action.public_send(method, *args)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Wraps all Things in a delegator to underlying set and provides lookup method
|
|
62
|
+
#
|
|
63
|
+
class Things < SimpleDelegator
|
|
64
|
+
java_import org.openhab.core.thing.ThingUID
|
|
65
|
+
|
|
66
|
+
# Gets a specific thing by name in the format binding_id:type_id:thing_id
|
|
67
|
+
# @return Thing specified by name or nil if name does not exist in thing registry
|
|
68
|
+
def[](uid)
|
|
69
|
+
thing_uid = ThingUID.new(*uid.split(':'))
|
|
70
|
+
# rubocop: disable Style/GlobalVars
|
|
71
|
+
thing = $things.get(thing_uid)
|
|
72
|
+
# rubocop: enable Style/GlobalVars
|
|
73
|
+
return unless thing
|
|
74
|
+
|
|
75
|
+
logger.trace("Retrieved Thing(#{thing}) from registry for uid: #{uid}")
|
|
76
|
+
Thing.new(thing)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
# Get all things known to OpenHAB
|
|
82
|
+
#
|
|
83
|
+
# @return [Set] of all Thing objects known to openhab
|
|
84
|
+
#
|
|
85
|
+
def things
|
|
86
|
+
# rubocop: disable Style/GlobalVars
|
|
87
|
+
Things.new($things.getAll.map { |thing| Thing.new(thing) }.to_set)
|
|
88
|
+
# rubocop: enable Style/GlobalVars
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'java'
|
|
4
|
+
require 'core/log'
|
|
5
|
+
require 'time'
|
|
6
|
+
require 'date'
|
|
7
|
+
|
|
8
|
+
module OpenHAB
|
|
9
|
+
module Core
|
|
10
|
+
module DSL
|
|
11
|
+
# Namespace for classes and modules that handle Time Of Day - Times without specific dates e.g. 6:00:00
|
|
12
|
+
# @author Brian O'Connell
|
|
13
|
+
# @since 0.0.1
|
|
14
|
+
module Tod
|
|
15
|
+
java_import java.time.LocalTime
|
|
16
|
+
java_import java.time.format.DateTimeFormatterBuilder
|
|
17
|
+
java_import java.util.Locale
|
|
18
|
+
|
|
19
|
+
# Class that encapsulates a Time of Day, often viewed as hour-minute-second
|
|
20
|
+
# @author Brian O'Connell
|
|
21
|
+
# @since 0.0.1
|
|
22
|
+
class TimeOfDay
|
|
23
|
+
include Comparable
|
|
24
|
+
|
|
25
|
+
# Immutable Java object containing Time Of Day
|
|
26
|
+
# @return [Java.Time.LocalTime] reprsenting the Time Of Day
|
|
27
|
+
attr_reader :local_time
|
|
28
|
+
|
|
29
|
+
# Constructs a TimeOfDay representing the time when called
|
|
30
|
+
# @since 0.0.1
|
|
31
|
+
# @return [TimeOfDay] representing time when method was invoked
|
|
32
|
+
def self.now
|
|
33
|
+
now = LocalTime.now()
|
|
34
|
+
TimeOfDay.new(h: now.hour, m: now.minute, s: now.second)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Constructs a TimeOfDay representing midnight
|
|
38
|
+
# @since 0.0.1
|
|
39
|
+
# @return [TimeOfDay] representing midnight
|
|
40
|
+
def self.midnight
|
|
41
|
+
TimeOfDay.new(h: 0, m: 0, s: 0)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Constructs a TimeOfDay representing noon
|
|
45
|
+
# @since 0.0.1
|
|
46
|
+
# @return [TimeOfDay] representing noon
|
|
47
|
+
def self.noon
|
|
48
|
+
TimeOfDay.new(h: 12, m: 0, s: 0)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Constructs a TimeOfDay representing the time when called
|
|
52
|
+
# @since 0.0.1
|
|
53
|
+
# @param [String] string representation of TimeOfDay. Valid formats include "HH:MM:SS", "HH:MM", "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
|
+
def initialize(h: 0, m: 0, s: 0)
|
|
71
|
+
@local_time = LocalTime.of(h, m, s)
|
|
72
|
+
freeze
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Returns true if the time falls within a range
|
|
76
|
+
def between?(range)
|
|
77
|
+
between(range).cover? self
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns the hour of the TimeOfDay
|
|
81
|
+
# @since 0.0.1
|
|
82
|
+
# @return [Number] Hour of the day, from 0 to 23
|
|
83
|
+
def hour
|
|
84
|
+
@local_time.hour
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns the minute of the TimeOfDay
|
|
88
|
+
# @since 0.0.1
|
|
89
|
+
# @return [Number] minute of the day, from 0 to 59
|
|
90
|
+
def minute
|
|
91
|
+
@local_time.minute
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns the second of the TimeOfDay
|
|
95
|
+
# @since 0.0.1
|
|
96
|
+
# @return [Number] second of the day, from 0 to 59
|
|
97
|
+
def second
|
|
98
|
+
@local_time.second
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Returns the string representation of the TimeOfDay
|
|
102
|
+
# @since 0.0.1
|
|
103
|
+
# @return [String] in any of the following formats depending on time representation HH:mm, HH:mm:ss, HH:mm:ss.SSS, HH:mm:ss.SSSSSS, HH:mm:ss.SSSSSSSSS
|
|
104
|
+
def to_s
|
|
105
|
+
@local_time.to_s
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Compares one TimeOfDay to another
|
|
109
|
+
# @since 0.0.1
|
|
110
|
+
# @return [Number, nil] -1,0,1 if other TimeOfDay is less than, equal to, or greater than this TimeOfDay or nil if an object other than TimeOfDay is provided
|
|
111
|
+
def <=>(other)
|
|
112
|
+
case other
|
|
113
|
+
when TimeOfDay
|
|
114
|
+
@local_time.compare_to(other.local_time)
|
|
115
|
+
when String
|
|
116
|
+
@local_time.compare_to(TimeOfDay.parse(other).local_time)
|
|
117
|
+
else
|
|
118
|
+
-(other <=> self)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Modules that refines the Ruby Range object cover? and include? methods to support TimeOfDay ranges
|
|
124
|
+
class TimeOfDayRangeElement
|
|
125
|
+
include Comparable
|
|
126
|
+
include Logging
|
|
127
|
+
|
|
128
|
+
NUM_SECONDS_IN_DAY = (60 * 60 * 24)
|
|
129
|
+
|
|
130
|
+
attr_reader :sod
|
|
131
|
+
|
|
132
|
+
def initialize(sod:, range_begin:)
|
|
133
|
+
@sod = sod
|
|
134
|
+
@range_begin = range_begin
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Returns the current second of day advanced by 1 second
|
|
138
|
+
def succ
|
|
139
|
+
TimeOfDayRangeElement.new(sod: @sod + 1, range_begin: @range_begin)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Compares one TimeOfDayRangeElement to another
|
|
143
|
+
# @since 2.4.0
|
|
144
|
+
# @return [Number, nil] -1,0,1 if other is less than, equal to, or greater than this TimeOfDay
|
|
145
|
+
def <=>(other)
|
|
146
|
+
other_second_of_day = case other
|
|
147
|
+
when TimeOfDay
|
|
148
|
+
adjust_second_of_day(other.local_time.to_second_of_day)
|
|
149
|
+
when String
|
|
150
|
+
adjust_second_of_day(TimeOfDay.parse(other).local_time.to_second_of_day)
|
|
151
|
+
when Time
|
|
152
|
+
adjust_second_of_day(TimeOfDay.new(h: other.hour, m: other.min,
|
|
153
|
+
s: other.sec).local_time.to_second_of_day)
|
|
154
|
+
when TimeOfDayRangeElement
|
|
155
|
+
other.sod
|
|
156
|
+
else
|
|
157
|
+
raise ArgumentError, 'Supplied argument cannot be converted into Time Of Day Object'
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
logger.trace do
|
|
161
|
+
"SOD(#{sod}) other SOD(#{other_second_of_day}) Other Class (#{other.class}) Result (#{sod <=> other_second_of_day})"
|
|
162
|
+
end
|
|
163
|
+
sod <=> other_second_of_day
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
private
|
|
167
|
+
|
|
168
|
+
def adjust_second_of_day(second_of_day)
|
|
169
|
+
second_of_day += NUM_SECONDS_IN_DAY if second_of_day < @range_begin
|
|
170
|
+
second_of_day
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Creates a range that can be compared against time of day objects or strings
|
|
175
|
+
# to see if they are within the range
|
|
176
|
+
# @since 2.4.0
|
|
177
|
+
# @return Range object representing a TimeOfDay Range
|
|
178
|
+
def between(range)
|
|
179
|
+
raise ArgumentError, 'Supplied object must be a range' unless range.is_a? Range
|
|
180
|
+
|
|
181
|
+
start = range.begin
|
|
182
|
+
ending = range.end
|
|
183
|
+
|
|
184
|
+
start = TimeOfDay.parse(start) if start.is_a? String
|
|
185
|
+
ending = TimeOfDay.parse(ending) if ending.is_a? String
|
|
186
|
+
|
|
187
|
+
start_sod = start.local_time.to_second_of_day
|
|
188
|
+
ending_sod = ending.local_time.to_second_of_day
|
|
189
|
+
ending_sod += TimeOfDayRangeElement::NUM_SECONDS_IN_DAY if ending_sod < start_sod
|
|
190
|
+
|
|
191
|
+
start_range = TimeOfDayRangeElement.new(sod: start_sod, range_begin: start_sod)
|
|
192
|
+
ending_range = TimeOfDayRangeElement.new(sod: ending_sod, range_begin: start_sod)
|
|
193
|
+
range.exclude_end? ? (start_range...ending_range) : (start_range..ending_range)
|
|
194
|
+
end
|
|
195
|
+
module_function :between
|
|
196
|
+
|
|
197
|
+
MIDNIGHT = TimeOfDay.midnight
|
|
198
|
+
NOON = TimeOfDay.noon
|
|
199
|
+
ALL_DAY = between(TimeOfDay.new(h: 0, m: 0, s: 0)..TimeOfDay.new(h: 23, m: 59, s: 59))
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'java'
|
|
4
|
+
require 'delegate'
|
|
5
|
+
require 'forwardable'
|
|
6
|
+
|
|
7
|
+
require 'core/duration'
|
|
8
|
+
|
|
9
|
+
module OpenHAB
|
|
10
|
+
module Core
|
|
11
|
+
module DSL
|
|
12
|
+
#
|
|
13
|
+
# Provides access to and ruby wrappers around OpenHAB timers
|
|
14
|
+
#
|
|
15
|
+
module Timers
|
|
16
|
+
java_import org.openhab.core.model.script.actions.ScriptExecution
|
|
17
|
+
java_import java.time.ZonedDateTime
|
|
18
|
+
|
|
19
|
+
# Ruby wrapper for OpenHAB Timer
|
|
20
|
+
# This class implements delegator to delegate methods to the OpenHAB timer
|
|
21
|
+
#
|
|
22
|
+
# @author Brian O'Connell
|
|
23
|
+
# @since 2.0.0
|
|
24
|
+
class Timer < SimpleDelegator
|
|
25
|
+
extend Forwardable
|
|
26
|
+
|
|
27
|
+
def_delegator :@timer, :is_active, :active?
|
|
28
|
+
def_delegator :@timer, :is_running, :running?
|
|
29
|
+
def_delegator :@timer, :has_terminated, :terminated?
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Create a new Timer Object
|
|
33
|
+
#
|
|
34
|
+
# @param [Duration] duration Duration until timer should fire
|
|
35
|
+
# @param [Block] block Block to execute when timer fires
|
|
36
|
+
#
|
|
37
|
+
def initialize(duration:, &block)
|
|
38
|
+
@duration = duration
|
|
39
|
+
|
|
40
|
+
# A semaphore is used to prevent a race condition in which calling the block from the timer thread
|
|
41
|
+
# occurs before the @timer variable can be set resulting in @timer being nil
|
|
42
|
+
semaphore = Mutex.new
|
|
43
|
+
|
|
44
|
+
@block = proc do
|
|
45
|
+
semaphore.synchronize do
|
|
46
|
+
block.call(self)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
semaphore.synchronize do
|
|
51
|
+
@timer = ScriptExecution.createTimer(
|
|
52
|
+
ZonedDateTime.now.plus(Java::JavaTime::Duration.ofMillis(@duration.to_ms)), @block
|
|
53
|
+
)
|
|
54
|
+
super(@timer)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# Reschedule timer
|
|
60
|
+
#
|
|
61
|
+
# @param [Duration] duration
|
|
62
|
+
#
|
|
63
|
+
# @return [<Type>] <description>
|
|
64
|
+
#
|
|
65
|
+
def reschedule(duration = nil)
|
|
66
|
+
duration ||= @duration
|
|
67
|
+
@timer.reschedule(ZonedDateTime.now.plus(Java::JavaTime::Duration.ofMillis(duration.to_ms)))
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# Execute the supplied block after the specified duration
|
|
73
|
+
#
|
|
74
|
+
# @param [Duration] duration after which to execute the block
|
|
75
|
+
# @param [Block] block to execute, block is passed a Timer object
|
|
76
|
+
#
|
|
77
|
+
# @return [Timer] Timer object
|
|
78
|
+
#
|
|
79
|
+
def after(duration, &block)
|
|
80
|
+
Timer.new(duration: duration, &block)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|