openhab-jrubyscripting 5.0.0.rc1
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/lib/openhab/core/actions.rb +163 -0
- data/lib/openhab/core/entity_lookup.rb +144 -0
- data/lib/openhab/core/events/abstract_event.rb +17 -0
- data/lib/openhab/core/events/item_channel_link.rb +36 -0
- data/lib/openhab/core/events/item_command_event.rb +78 -0
- data/lib/openhab/core/events/item_event.rb +22 -0
- data/lib/openhab/core/events/item_state_changed_event.rb +52 -0
- data/lib/openhab/core/events/item_state_event.rb +51 -0
- data/lib/openhab/core/events/thing.rb +29 -0
- data/lib/openhab/core/events/thing_status_info_event.rb +53 -0
- data/lib/openhab/core/events.rb +10 -0
- data/lib/openhab/core/items/accepted_data_types.rb +29 -0
- data/lib/openhab/core/items/color_item.rb +52 -0
- data/lib/openhab/core/items/contact_item.rb +52 -0
- data/lib/openhab/core/items/date_time_item.rb +58 -0
- data/lib/openhab/core/items/dimmer_item.rb +148 -0
- data/lib/openhab/core/items/generic_item.rb +344 -0
- data/lib/openhab/core/items/group_item.rb +174 -0
- data/lib/openhab/core/items/image_item.rb +109 -0
- data/lib/openhab/core/items/location_item.rb +34 -0
- data/lib/openhab/core/items/metadata/hash.rb +390 -0
- data/lib/openhab/core/items/metadata/namespace_hash.rb +469 -0
- data/lib/openhab/core/items/metadata.rb +11 -0
- data/lib/openhab/core/items/number_item.rb +62 -0
- data/lib/openhab/core/items/numeric_item.rb +22 -0
- data/lib/openhab/core/items/persistence.rb +327 -0
- data/lib/openhab/core/items/player_item.rb +66 -0
- data/lib/openhab/core/items/proxy.rb +59 -0
- data/lib/openhab/core/items/registry.rb +66 -0
- data/lib/openhab/core/items/rollershutter_item.rb +68 -0
- data/lib/openhab/core/items/semantics/enumerable.rb +152 -0
- data/lib/openhab/core/items/semantics.rb +476 -0
- data/lib/openhab/core/items/state_storage.rb +53 -0
- data/lib/openhab/core/items/string_item.rb +28 -0
- data/lib/openhab/core/items/switch_item.rb +78 -0
- data/lib/openhab/core/items.rb +114 -0
- data/lib/openhab/core/lazy_array.rb +52 -0
- data/lib/openhab/core/profile_factory.rb +118 -0
- data/lib/openhab/core/script_handling.rb +55 -0
- data/lib/openhab/core/things/channel.rb +48 -0
- data/lib/openhab/core/things/channel_uid.rb +51 -0
- data/lib/openhab/core/things/item_channel_link.rb +33 -0
- data/lib/openhab/core/things/profile_callback.rb +52 -0
- data/lib/openhab/core/things/proxy.rb +69 -0
- data/lib/openhab/core/things/registry.rb +46 -0
- data/lib/openhab/core/things/thing.rb +194 -0
- data/lib/openhab/core/things.rb +22 -0
- data/lib/openhab/core/timer.rb +128 -0
- data/lib/openhab/core/types/comparable_type.rb +23 -0
- data/lib/openhab/core/types/date_time_type.rb +259 -0
- data/lib/openhab/core/types/decimal_type.rb +192 -0
- data/lib/openhab/core/types/hsb_type.rb +183 -0
- data/lib/openhab/core/types/increase_decrease_type.rb +34 -0
- data/lib/openhab/core/types/next_previous_type.rb +34 -0
- data/lib/openhab/core/types/numeric_type.rb +52 -0
- data/lib/openhab/core/types/on_off_type.rb +46 -0
- data/lib/openhab/core/types/open_closed_type.rb +41 -0
- data/lib/openhab/core/types/percent_type.rb +95 -0
- data/lib/openhab/core/types/play_pause_type.rb +38 -0
- data/lib/openhab/core/types/point_type.rb +117 -0
- data/lib/openhab/core/types/quantity_type.rb +327 -0
- data/lib/openhab/core/types/raw_type.rb +26 -0
- data/lib/openhab/core/types/refresh_type.rb +27 -0
- data/lib/openhab/core/types/rewind_fastforward_type.rb +38 -0
- data/lib/openhab/core/types/stop_move_type.rb +34 -0
- data/lib/openhab/core/types/string_type.rb +76 -0
- data/lib/openhab/core/types/type.rb +117 -0
- data/lib/openhab/core/types/un_def_type.rb +38 -0
- data/lib/openhab/core/types/up_down_type.rb +50 -0
- data/lib/openhab/core/types.rb +69 -0
- data/lib/openhab/core/uid.rb +36 -0
- data/lib/openhab/core.rb +85 -0
- data/lib/openhab/core_ext/java/duration.rb +115 -0
- data/lib/openhab/core_ext/java/local_date.rb +93 -0
- data/lib/openhab/core_ext/java/local_time.rb +106 -0
- data/lib/openhab/core_ext/java/month.rb +59 -0
- data/lib/openhab/core_ext/java/month_day.rb +105 -0
- data/lib/openhab/core_ext/java/period.rb +103 -0
- data/lib/openhab/core_ext/java/temporal_amount.rb +34 -0
- data/lib/openhab/core_ext/java/time.rb +58 -0
- data/lib/openhab/core_ext/java/unit.rb +15 -0
- data/lib/openhab/core_ext/java/zoned_date_time.rb +116 -0
- data/lib/openhab/core_ext/ruby/array.rb +21 -0
- data/lib/openhab/core_ext/ruby/class.rb +15 -0
- data/lib/openhab/core_ext/ruby/date.rb +89 -0
- data/lib/openhab/core_ext/ruby/numeric.rb +190 -0
- data/lib/openhab/core_ext/ruby/range.rb +70 -0
- data/lib/openhab/core_ext/ruby/time.rb +104 -0
- data/lib/openhab/core_ext.rb +18 -0
- data/lib/openhab/dsl/events/watch_event.rb +18 -0
- data/lib/openhab/dsl/events.rb +9 -0
- data/lib/openhab/dsl/gems.rb +3 -0
- data/lib/openhab/dsl/items/builder.rb +618 -0
- data/lib/openhab/dsl/items/ensure.rb +93 -0
- data/lib/openhab/dsl/items/timed_command.rb +236 -0
- data/lib/openhab/dsl/rules/automation_rule.rb +308 -0
- data/lib/openhab/dsl/rules/builder.rb +1373 -0
- data/lib/openhab/dsl/rules/guard.rb +115 -0
- data/lib/openhab/dsl/rules/name_inference.rb +160 -0
- data/lib/openhab/dsl/rules/property.rb +76 -0
- data/lib/openhab/dsl/rules/rule_triggers.rb +96 -0
- data/lib/openhab/dsl/rules/terse.rb +63 -0
- data/lib/openhab/dsl/rules/triggers/changed.rb +169 -0
- data/lib/openhab/dsl/rules/triggers/channel.rb +57 -0
- data/lib/openhab/dsl/rules/triggers/command.rb +107 -0
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +161 -0
- data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +164 -0
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +195 -0
- data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +127 -0
- data/lib/openhab/dsl/rules/triggers/trigger.rb +56 -0
- data/lib/openhab/dsl/rules/triggers/updated.rb +130 -0
- data/lib/openhab/dsl/rules/triggers/watch/watch.rb +55 -0
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +155 -0
- data/lib/openhab/dsl/rules/triggers.rb +12 -0
- data/lib/openhab/dsl/rules.rb +29 -0
- data/lib/openhab/dsl/script_handling.rb +55 -0
- data/lib/openhab/dsl/things/builder.rb +263 -0
- data/lib/openhab/dsl/thread_local.rb +48 -0
- data/lib/openhab/dsl/timer_manager.rb +191 -0
- data/lib/openhab/dsl/version.rb +9 -0
- data/lib/openhab/dsl.rb +686 -0
- data/lib/openhab/log.rb +348 -0
- data/lib/openhab/osgi.rb +70 -0
- data/lib/openhab/rspec/configuration.rb +56 -0
- data/lib/openhab/rspec/example_group.rb +90 -0
- data/lib/openhab/rspec/helpers.rb +439 -0
- data/lib/openhab/rspec/hooks.rb +93 -0
- data/lib/openhab/rspec/jruby.rb +46 -0
- data/lib/openhab/rspec/karaf.rb +811 -0
- data/lib/openhab/rspec/mocks/bundle_install_support.rb +25 -0
- data/lib/openhab/rspec/mocks/bundle_resolver.rb +30 -0
- data/lib/openhab/rspec/mocks/event_admin.rb +146 -0
- data/lib/openhab/rspec/mocks/metadata_provider.rb +75 -0
- data/lib/openhab/rspec/mocks/persistence_service.rb +140 -0
- data/lib/openhab/rspec/mocks/safe_caller.rb +40 -0
- data/lib/openhab/rspec/mocks/synchronous_executor.rb +56 -0
- data/lib/openhab/rspec/mocks/thing_handler.rb +76 -0
- data/lib/openhab/rspec/mocks/timer.rb +95 -0
- data/lib/openhab/rspec/openhab/core/actions.rb +26 -0
- data/lib/openhab/rspec/openhab/core/items/proxy.rb +27 -0
- data/lib/openhab/rspec/openhab/core/things/proxy.rb +27 -0
- data/lib/openhab/rspec/shell.rb +31 -0
- data/lib/openhab/rspec/suspend_rules.rb +60 -0
- data/lib/openhab/rspec.rb +17 -0
- data/lib/openhab/yard/cli/stats.rb +23 -0
- data/lib/openhab/yard/code_objects/group_object.rb +17 -0
- data/lib/openhab/yard/code_objects/java/base.rb +31 -0
- data/lib/openhab/yard/code_objects/java/class_object.rb +11 -0
- data/lib/openhab/yard/code_objects/java/field_object.rb +15 -0
- data/lib/openhab/yard/code_objects/java/interface_object.rb +15 -0
- data/lib/openhab/yard/code_objects/java/package_object.rb +11 -0
- data/lib/openhab/yard/code_objects/java/proxy.rb +23 -0
- data/lib/openhab/yard/handlers/jruby/base.rb +49 -0
- data/lib/openhab/yard/handlers/jruby/class_handler.rb +18 -0
- data/lib/openhab/yard/handlers/jruby/constant_handler.rb +18 -0
- data/lib/openhab/yard/handlers/jruby/java_import_handler.rb +27 -0
- data/lib/openhab/yard/handlers/jruby/mixin_handler.rb +23 -0
- data/lib/openhab/yard/html_helper.rb +44 -0
- data/lib/openhab/yard/tags/constant_directive.rb +20 -0
- data/lib/openhab/yard/tags/group_directive.rb +24 -0
- data/lib/openhab/yard/tags/library.rb +3 -0
- data/lib/openhab/yard.rb +32 -0
- metadata +504 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "singleton"
|
|
4
|
+
|
|
5
|
+
module OpenHAB
|
|
6
|
+
module Core
|
|
7
|
+
module Things
|
|
8
|
+
#
|
|
9
|
+
# Provides access to all OpenHAB {Thing things}, and acts like an array.
|
|
10
|
+
#
|
|
11
|
+
class Registry
|
|
12
|
+
include LazyArray
|
|
13
|
+
include Singleton
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Gets a specific {Thing}
|
|
17
|
+
#
|
|
18
|
+
# @param [String, ThingUID] uid Thing UID in the format `binding_id:type_id:thing_id`
|
|
19
|
+
# or via the ThingUID
|
|
20
|
+
# @return [Thing, nil]
|
|
21
|
+
#
|
|
22
|
+
def [](uid)
|
|
23
|
+
EntityLookup.lookup_thing(uid)
|
|
24
|
+
end
|
|
25
|
+
alias_method :include?, :[]
|
|
26
|
+
alias_method :key?, :[]
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Explicit conversion to array
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Thing>]
|
|
32
|
+
#
|
|
33
|
+
def to_a
|
|
34
|
+
$things.all.map { |thing| Proxy.new(thing) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Enter the Thing Builder DSL.
|
|
38
|
+
# @yield Block executed in the context of a {DSL::Things::Builder}.
|
|
39
|
+
# @return [Object] The result of the block.
|
|
40
|
+
def build(&block)
|
|
41
|
+
DSL::Things::Builder.new.instance_eval(&block)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenHAB
|
|
4
|
+
module Core
|
|
5
|
+
module Things
|
|
6
|
+
# @interface
|
|
7
|
+
java_import org.openhab.core.thing.Thing
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# A {Thing} is a representation of a connected part (e.g. physical device
|
|
11
|
+
# or cloud service) from the real world. It contains a list of
|
|
12
|
+
# {Channel Channels}, which can be bound to {GenericItem Items}.
|
|
13
|
+
#
|
|
14
|
+
# @see OpenHAB::DSL.things things[]
|
|
15
|
+
# @see EntityLookup
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# thing = things["chromecast:audiogroup:dd9f8622-eee-4eaf-b33f-cdcdcdeee001121"]
|
|
19
|
+
# logger.info("Audiogroup Status: #{thing&.status}")
|
|
20
|
+
# logger.info("Audiogroup Online? #{thing&.online?}")
|
|
21
|
+
# logger.info("Channel ids: #{thing.channels.map(&:uid)}")
|
|
22
|
+
# logger.info("Items linked to volume channel: #{thing.channels['volume']&.items&.map(&:name)&.join(', ')}")
|
|
23
|
+
# logger.info("Item linked to volume channel: #{thing.channels['volume']&.item&.name}")
|
|
24
|
+
#
|
|
25
|
+
# @example Thing actions can be called directly through a Thing object
|
|
26
|
+
# things["mqtt:broker:mosquitto"].publish_mqtt("zigbee2mqttt/bridge/config/permit_join", "true")
|
|
27
|
+
# things["mail:smtp:local"].send_mail("me@example.com", "Subject", "Email body")
|
|
28
|
+
#
|
|
29
|
+
# @example Thing can be accessed directly through {EntityLookup entity lookup}
|
|
30
|
+
# # replace ':' with '_' in thing uid
|
|
31
|
+
# mqtt_broker_mosquitto.online? # is mqtt:broker:mosquitto thing online?
|
|
32
|
+
#
|
|
33
|
+
# @!attribute [r] status
|
|
34
|
+
# Return the {https://www.openhab.org/docs/concepts/things.html#thing-status thing status}
|
|
35
|
+
# @return [org.openhab.core.thing.ThingStatus]
|
|
36
|
+
#
|
|
37
|
+
# @!attribute [r] channels
|
|
38
|
+
# @return [ChannelArray]
|
|
39
|
+
#
|
|
40
|
+
module Thing
|
|
41
|
+
# Array wrapper class to allow searching a list of channels
|
|
42
|
+
# by channel id
|
|
43
|
+
class ChannelsArray < Array
|
|
44
|
+
# Allows indexing by both integer as an array or channel id acting like a hash.
|
|
45
|
+
# @param [Integer, String] index Numeric index or string channel id to search for.
|
|
46
|
+
def [](index)
|
|
47
|
+
if index.respond_to?(:to_str)
|
|
48
|
+
key = index.to_str
|
|
49
|
+
return find { |channel| channel.uid.id == key }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class << self
|
|
57
|
+
# @!visibility private
|
|
58
|
+
#
|
|
59
|
+
# Override to support Proxy
|
|
60
|
+
#
|
|
61
|
+
def ===(other)
|
|
62
|
+
other.is_a?(self)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# @!method uninitialized?
|
|
68
|
+
# Check if thing status == UNINITIALIZED
|
|
69
|
+
# @return [true,false]
|
|
70
|
+
#
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# @!method initialized?
|
|
74
|
+
# Check if thing status == INITIALIZED
|
|
75
|
+
# @return [true,false]
|
|
76
|
+
#
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# @!method unknown?
|
|
80
|
+
# Check if thing status == UNKNOWN
|
|
81
|
+
# @return [true,false]
|
|
82
|
+
#
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# @!method online?
|
|
86
|
+
# Check if thing status == ONLINE
|
|
87
|
+
# @return [true,false]
|
|
88
|
+
#
|
|
89
|
+
|
|
90
|
+
#
|
|
91
|
+
# @!method offline?
|
|
92
|
+
# Check if thing status == OFFLINE
|
|
93
|
+
# @return [true,false]
|
|
94
|
+
#
|
|
95
|
+
|
|
96
|
+
#
|
|
97
|
+
# @!method removing?
|
|
98
|
+
# Check if thing status == REMOVING
|
|
99
|
+
# @return [true,false]
|
|
100
|
+
#
|
|
101
|
+
|
|
102
|
+
#
|
|
103
|
+
# @!method removed?
|
|
104
|
+
# Check if thing status == REMOVED
|
|
105
|
+
# @return [true,false]
|
|
106
|
+
#
|
|
107
|
+
|
|
108
|
+
ThingStatus.constants.each do |thingstatus|
|
|
109
|
+
define_method("#{thingstatus.to_s.downcase}?") { status == ThingStatus.value_of(thingstatus) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
#
|
|
113
|
+
# Enable the Thing
|
|
114
|
+
#
|
|
115
|
+
# @param [true, false] enabled
|
|
116
|
+
# @return [void]
|
|
117
|
+
#
|
|
118
|
+
def enable(enabled: true)
|
|
119
|
+
Things.manager.set_enabled(uid, enabled)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
#
|
|
123
|
+
# Disable the Thing
|
|
124
|
+
#
|
|
125
|
+
# @return [void]
|
|
126
|
+
#
|
|
127
|
+
def disable
|
|
128
|
+
enable(enabled: false)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# @return [String]
|
|
132
|
+
def inspect
|
|
133
|
+
r = "#<OpenHAB::Core::Things::Thing #{uid}"
|
|
134
|
+
r += " #{label.inspect}" if label
|
|
135
|
+
r += " (#{location.inspect})" if location
|
|
136
|
+
r += " #{status}"
|
|
137
|
+
unless status_info.status_detail == org.openhab.core.thing.ThingStatusDetail::NONE
|
|
138
|
+
r += " (#{status_info.status_detail})"
|
|
139
|
+
end
|
|
140
|
+
r += " configuration=#{configuration.properties.to_h}" unless configuration.properties.empty?
|
|
141
|
+
r += " properties=#{properties.to_h}" unless properties.empty?
|
|
142
|
+
"#{r}>"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
#
|
|
146
|
+
# Return Thing's uid as a string
|
|
147
|
+
#
|
|
148
|
+
# @return [String]
|
|
149
|
+
#
|
|
150
|
+
def to_s
|
|
151
|
+
uid.to_s
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
#
|
|
155
|
+
# Fetches the actions available for this thing.
|
|
156
|
+
#
|
|
157
|
+
# Default scope actions are available directly on the thing object, via
|
|
158
|
+
# {#method_missing}.
|
|
159
|
+
#
|
|
160
|
+
# @param [String, nil] scope The action scope. Default's to the thing's binding.
|
|
161
|
+
# @return [Object, nil]
|
|
162
|
+
#
|
|
163
|
+
# @example
|
|
164
|
+
# things["max:thermostat:mybridge:thermostat"].actions("max-devices").delete_from_cube
|
|
165
|
+
#
|
|
166
|
+
# @example (see #method_missing)
|
|
167
|
+
#
|
|
168
|
+
def actions(scope = nil)
|
|
169
|
+
$actions.get(scope || uid.binding_id, uid.to_s)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
#
|
|
173
|
+
# Delegate missing methods to the thing's default actions scope.
|
|
174
|
+
#
|
|
175
|
+
# @example
|
|
176
|
+
# things['mail:smtp:local'].send_email('me@example.com', 'subject', 'message')
|
|
177
|
+
#
|
|
178
|
+
def method_missing(method, *args, &block)
|
|
179
|
+
return actions.public_send(method, *args, &block) if actions.respond_to?(method)
|
|
180
|
+
|
|
181
|
+
super
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# @!visibility private
|
|
185
|
+
def respond_to_missing?(method_name, _include_private = false)
|
|
186
|
+
logger.trace("Checking if Thing #{uid} supports #{method_name} action")
|
|
187
|
+
return true if actions.respond_to?(method_name)
|
|
188
|
+
|
|
189
|
+
super
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenHAB
|
|
4
|
+
module Core
|
|
5
|
+
#
|
|
6
|
+
# Contains the core {Thing} that bindings use to represent connected devices,
|
|
7
|
+
# as well as related infrastructure.
|
|
8
|
+
#
|
|
9
|
+
module Things
|
|
10
|
+
java_import org.openhab.core.thing.ThingStatus,
|
|
11
|
+
org.openhab.core.thing.ThingUID,
|
|
12
|
+
org.openhab.core.thing.ThingTypeUID
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# @!visibility private
|
|
16
|
+
def manager
|
|
17
|
+
@manager ||= OSGi.service("org.openhab.core.thing.ThingManager")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
5
|
+
module OpenHAB
|
|
6
|
+
module Core
|
|
7
|
+
#
|
|
8
|
+
# Timer allows you to administer the block of code that
|
|
9
|
+
# has been scheduled to run later with {OpenHAB::DSL.after after}.
|
|
10
|
+
#
|
|
11
|
+
# @!attribute [r] execution_time
|
|
12
|
+
# @return [ZonedDateTime] the scheduled execution time, or null if the timer was cancelled
|
|
13
|
+
class Timer
|
|
14
|
+
extend Forwardable
|
|
15
|
+
|
|
16
|
+
# @!method active?
|
|
17
|
+
# Check if the timer will execute in the future.
|
|
18
|
+
# @return [true,false]
|
|
19
|
+
|
|
20
|
+
# @!method cancelled?
|
|
21
|
+
# Check if the timer has been cancelled.
|
|
22
|
+
# @return [true,false]
|
|
23
|
+
|
|
24
|
+
# @!method running?
|
|
25
|
+
# Check if the timer code is currently running.
|
|
26
|
+
# @return [true,false]
|
|
27
|
+
|
|
28
|
+
# @!method terminated?
|
|
29
|
+
# Check if the timer has terminated.
|
|
30
|
+
# @return [true,false]
|
|
31
|
+
|
|
32
|
+
def_delegator :@timer, :has_terminated, :terminated?
|
|
33
|
+
def_delegators :@timer, :execution_time, :active?, :cancelled?, :running?
|
|
34
|
+
|
|
35
|
+
# @return [Object, nil]
|
|
36
|
+
attr_accessor :id
|
|
37
|
+
|
|
38
|
+
# @!visibility private
|
|
39
|
+
# @!visibility private
|
|
40
|
+
attr_reader :block
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Create a new Timer Object
|
|
44
|
+
#
|
|
45
|
+
# @param [java.time.temporal.TemporalAmount, #to_zoned_date_time, Proc] time When to execute the block
|
|
46
|
+
# @yield Block to execute when timer fires
|
|
47
|
+
# @yieldparam [self]
|
|
48
|
+
#
|
|
49
|
+
# @!visibility private
|
|
50
|
+
def initialize(time, id:, thread_locals:, block:)
|
|
51
|
+
@time = time
|
|
52
|
+
@id = id
|
|
53
|
+
@thread_locals = thread_locals
|
|
54
|
+
@block = block
|
|
55
|
+
@timer = org.openhab.core.model.script.actions.ScriptExecution.create_timer(
|
|
56
|
+
# create it far enough in the future so it won't execute until we finish setting it up
|
|
57
|
+
1.minute.from_now,
|
|
58
|
+
# when running in rspec, it may have troubles finding this class
|
|
59
|
+
# for auto-conversion of block to interface, so use .impl
|
|
60
|
+
org.eclipse.xtext.xbase.lib.Procedures::Procedure0.impl { execute }
|
|
61
|
+
)
|
|
62
|
+
reschedule(@time)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [String]
|
|
66
|
+
def inspect
|
|
67
|
+
r = "#<#{self.class.name} #{"#{id.inspect} " if id}#{block.source_location.join(":")}"
|
|
68
|
+
if cancelled?
|
|
69
|
+
r += " (cancelled)"
|
|
70
|
+
else
|
|
71
|
+
r += " @ #{execution_time}"
|
|
72
|
+
r += " (executed)" if terminated?
|
|
73
|
+
end
|
|
74
|
+
"#{r}>"
|
|
75
|
+
end
|
|
76
|
+
alias_method :to_s, :inspect
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Reschedule timer
|
|
80
|
+
#
|
|
81
|
+
# @param [java.time.temporal.TemporalAmount, ZonedDateTime, Proc, nil] time When to reschedule the timer for.
|
|
82
|
+
# If unspecified, the original time is used.
|
|
83
|
+
#
|
|
84
|
+
# @return [self]
|
|
85
|
+
#
|
|
86
|
+
def reschedule(time = nil)
|
|
87
|
+
DSL.timers.add(self)
|
|
88
|
+
@timer.reschedule(new_execution_time(time || @time))
|
|
89
|
+
self
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# Cancel timer
|
|
94
|
+
#
|
|
95
|
+
# @return [true,false] True if cancel was successful, false otherwise
|
|
96
|
+
#
|
|
97
|
+
def cancel
|
|
98
|
+
DSL.timers.delete(self)
|
|
99
|
+
@timer.cancel
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
#
|
|
105
|
+
# Calls the block with thread locals set up, and cleans up after itself
|
|
106
|
+
#
|
|
107
|
+
# @return [void]
|
|
108
|
+
#
|
|
109
|
+
def execute
|
|
110
|
+
last_execution_time = execution_time
|
|
111
|
+
DSL::ThreadLocal.thread_local(**@thread_locals) do
|
|
112
|
+
@block.call(self)
|
|
113
|
+
end
|
|
114
|
+
# don't remove ourselves if we were rescheduled in the block
|
|
115
|
+
DSL.timers.delete(self) if execution_time == last_execution_time
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
#
|
|
119
|
+
# @return [ZonedDateTime]
|
|
120
|
+
#
|
|
121
|
+
def new_execution_time(time)
|
|
122
|
+
time = time.call if time.is_a?(Proc)
|
|
123
|
+
time = time.from_now if time.is_a?(java.time.temporal.TemporalAmount)
|
|
124
|
+
time.to_zoned_date_time
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "type"
|
|
4
|
+
|
|
5
|
+
module OpenHAB
|
|
6
|
+
module Core
|
|
7
|
+
# `Comparable#==` is overwritten by Type, because {DecimalType} etc.
|
|
8
|
+
# inherit from `Comparable` on the Java side, so it's in the wrong place
|
|
9
|
+
# in the ancestor list
|
|
10
|
+
# @!visibility private
|
|
11
|
+
module ComparableType
|
|
12
|
+
# re-implement
|
|
13
|
+
# @!visibility private
|
|
14
|
+
def ==(other)
|
|
15
|
+
r = self <=> other
|
|
16
|
+
|
|
17
|
+
return false if r.nil?
|
|
18
|
+
|
|
19
|
+
r.zero?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require "time"
|
|
5
|
+
|
|
6
|
+
require_relative "type"
|
|
7
|
+
|
|
8
|
+
module OpenHAB
|
|
9
|
+
module Core
|
|
10
|
+
module Types
|
|
11
|
+
DateTimeType = org.openhab.core.library.types.DateTimeType
|
|
12
|
+
|
|
13
|
+
# {DateTimeType} uses a {ZonedDateTime} internally.
|
|
14
|
+
class DateTimeType
|
|
15
|
+
# @!parse include Command, State
|
|
16
|
+
|
|
17
|
+
# remove the JRuby default == so that we can inherit the Ruby method
|
|
18
|
+
remove_method :==
|
|
19
|
+
|
|
20
|
+
extend Forwardable
|
|
21
|
+
include Comparable
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# Regex expression to identify strings defining a time in hours, minutes and optionally seconds
|
|
25
|
+
#
|
|
26
|
+
TIME_ONLY_REGEX = /\A(?<hours>\d\d):(?<minutes>\d\d)(?<seconds>:\d\d)?\Z/.freeze
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Regex expression to identify strings defining a time in year, month, and day
|
|
30
|
+
#
|
|
31
|
+
DATE_ONLY_REGEX = /\A\d{4}-\d\d-\d\d\Z/.freeze
|
|
32
|
+
private_constant :TIME_ONLY_REGEX, :DATE_ONLY_REGEX
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
#
|
|
36
|
+
# Parses a String representing a time into an OpenHAB DateTimeType. First tries to parse it
|
|
37
|
+
# using java's DateTimeType's parser, then falls back to the Ruby Time.parse
|
|
38
|
+
#
|
|
39
|
+
# @param [String] time_string
|
|
40
|
+
#
|
|
41
|
+
# @return [DateTimeType]
|
|
42
|
+
#
|
|
43
|
+
def parse(time_string)
|
|
44
|
+
time_string = "#{time_string}Z" if TIME_ONLY_REGEX.match?(time_string)
|
|
45
|
+
DateTimeType.new(time_string)
|
|
46
|
+
rescue java.lang.StringIndexOutOfBoundsException, java.lang.IllegalArgumentException => e
|
|
47
|
+
# Try Ruby's Time.parse if OpenHAB's DateTimeType parser fails
|
|
48
|
+
begin
|
|
49
|
+
DateTimeType.new(::Time.parse(time_string))
|
|
50
|
+
rescue ArgumentError
|
|
51
|
+
raise ArgumentError, e.message
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @param [ZonedDateTime, nil] context
|
|
57
|
+
# A {ZonedDateTime} used to fill in missing
|
|
58
|
+
# fields during conversion. Not used in this class.
|
|
59
|
+
# @return [ZonedTimeTime]
|
|
60
|
+
def to_zoned_date_time(context = nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
61
|
+
zoned_date_time
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# act like a Ruby Time
|
|
65
|
+
def_delegator :zoned_date_time, :month_value, :month
|
|
66
|
+
def_delegator :zoned_date_time, :day_of_month, :mday
|
|
67
|
+
def_delegator :zoned_date_time, :day_of_year, :yday
|
|
68
|
+
def_delegator :zoned_date_time, :minute, :min
|
|
69
|
+
def_delegator :zoned_date_time, :second, :sec
|
|
70
|
+
def_delegator :zoned_date_time, :nano, :nsec
|
|
71
|
+
def_delegator :zoned_date_time, :to_epoch_second, :to_i
|
|
72
|
+
def_delegator :zoned_date_time, :to_time
|
|
73
|
+
|
|
74
|
+
alias_method :day, :mday
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Create a new instance of DateTimeType
|
|
78
|
+
#
|
|
79
|
+
# @param value [#to_zoned_date_time, #to_time, #to_str, #to_d, nil]
|
|
80
|
+
#
|
|
81
|
+
def initialize(value = nil)
|
|
82
|
+
if value.respond_to?(:to_zoned_date_time)
|
|
83
|
+
super(value.to_zoned_date_time)
|
|
84
|
+
return
|
|
85
|
+
elsif value.respond_to?(:to_time)
|
|
86
|
+
super(value.to_time.to_zoned_date_time)
|
|
87
|
+
return
|
|
88
|
+
elsif value.respond_to?(:to_str)
|
|
89
|
+
# strings respond_do?(:to_d), but we want to avoid that conversion
|
|
90
|
+
super(value.to_str)
|
|
91
|
+
return
|
|
92
|
+
elsif value.respond_to?(:to_d)
|
|
93
|
+
super(Time.at(value.to_d).to_zoned_date_time)
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
super
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
#
|
|
101
|
+
# Check equality without type conversion
|
|
102
|
+
#
|
|
103
|
+
# @return [true,false] if the same value is represented, without type
|
|
104
|
+
# conversion
|
|
105
|
+
def eql?(other)
|
|
106
|
+
return false unless other.instance_of?(self.class)
|
|
107
|
+
|
|
108
|
+
zoned_date_time.compare_to(other.zoned_date_time).zero?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# Comparison
|
|
113
|
+
#
|
|
114
|
+
# @param [Object] other object to compare to
|
|
115
|
+
#
|
|
116
|
+
# @return [Integer, nil] -1, 0, +1 depending on whether `other` is
|
|
117
|
+
# less than, equal to, or greater than self
|
|
118
|
+
#
|
|
119
|
+
# `nil` is returned if the two values are incomparable.
|
|
120
|
+
#
|
|
121
|
+
def <=>(other)
|
|
122
|
+
logger.trace("(#{self.class}) #{self} <=> #{other} (#{other.class})")
|
|
123
|
+
if other.is_a?(self.class)
|
|
124
|
+
zoned_date_time <=> other.zoned_date_time
|
|
125
|
+
elsif other.respond_to?(:to_time)
|
|
126
|
+
to_time <=> other.to_time
|
|
127
|
+
elsif other.respond_to?(:coerce)
|
|
128
|
+
return nil unless (lhs, rhs = other.coerce(self))
|
|
129
|
+
|
|
130
|
+
lhs <=> rhs
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
#
|
|
135
|
+
# Type Coercion
|
|
136
|
+
#
|
|
137
|
+
# Coerce object to a DateTimeType
|
|
138
|
+
#
|
|
139
|
+
# @param [Time] other object to coerce to a DateTimeType
|
|
140
|
+
#
|
|
141
|
+
# @return [[DateTimeType, DateTimeType], nil]
|
|
142
|
+
#
|
|
143
|
+
def coerce(other)
|
|
144
|
+
logger.trace("Coercing #{self} as a request from #{other.class}")
|
|
145
|
+
return [other, zoned_date_time] if other.respond_to?(:to_zoned_date_time)
|
|
146
|
+
return [DateTimeType.new(other), self] if other.respond_to?(:to_time)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
#
|
|
150
|
+
# Returns the value of time as a floating point number of seconds since the Epoch
|
|
151
|
+
#
|
|
152
|
+
# @return [Float] Number of seconds since the Epoch, with nanosecond presicion
|
|
153
|
+
#
|
|
154
|
+
def to_f
|
|
155
|
+
zoned_date_time.to_epoch_second + (zoned_date_time.nano / 1_000_000_000)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# The offset in seconds from UTC
|
|
160
|
+
#
|
|
161
|
+
# @return [Integer] The offset from UTC, in seconds
|
|
162
|
+
#
|
|
163
|
+
def utc_offset
|
|
164
|
+
zoned_date_time.offset.total_seconds
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
#
|
|
168
|
+
# Returns true if time represents a time in UTC (GMT)
|
|
169
|
+
#
|
|
170
|
+
# @return [true,false] true if utc_offset == 0, false otherwise
|
|
171
|
+
#
|
|
172
|
+
def utc?
|
|
173
|
+
utc_offset.zero?
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
#
|
|
177
|
+
# Returns an integer representing the day of the week, 0..6, with Sunday == 0.
|
|
178
|
+
#
|
|
179
|
+
# @return [Integer] The day of week
|
|
180
|
+
#
|
|
181
|
+
def wday
|
|
182
|
+
zoned_date_time.day_of_week.value % 7
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
#
|
|
186
|
+
# The timezone
|
|
187
|
+
#
|
|
188
|
+
# @return [String] The timezone in `[+-]hh:mm(:ss)` format (`Z` for UTC)
|
|
189
|
+
#
|
|
190
|
+
def zone
|
|
191
|
+
zoned_date_time.zone.id
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @!visibility private
|
|
195
|
+
def respond_to_missing?(method, _include_private = false)
|
|
196
|
+
return true if zoned_date_time.respond_to?(method)
|
|
197
|
+
return true if ::Time.instance_methods.include?(method.to_sym)
|
|
198
|
+
|
|
199
|
+
super
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
#
|
|
203
|
+
# Forward missing methods to the `ZonedDateTime` object or a ruby `Time`
|
|
204
|
+
# object representing the same instant
|
|
205
|
+
#
|
|
206
|
+
def method_missing(method, *args, &block)
|
|
207
|
+
return zoned_date_time.send(method, *args, &block) if zoned_date_time.respond_to?(method)
|
|
208
|
+
return to_time.send(method, *args, &block) if ::Time.instance_methods.include?(method.to_sym)
|
|
209
|
+
|
|
210
|
+
super
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Add other to self
|
|
214
|
+
#
|
|
215
|
+
# @param other [Duration, Numeric]
|
|
216
|
+
#
|
|
217
|
+
# @return [DateTimeType]
|
|
218
|
+
def +(other)
|
|
219
|
+
if other.is_a?(Duration)
|
|
220
|
+
DateTimeType.new(zoned_date_time.plus(other))
|
|
221
|
+
elsif other.respond_to?(:to_d)
|
|
222
|
+
DateTimeType.new(zoned_date_time.plus_nanos((other.to_d * 1_000_000_000).to_i))
|
|
223
|
+
elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(to_d))
|
|
224
|
+
lhs + rhs
|
|
225
|
+
else
|
|
226
|
+
raise TypeError, "\#{other.class} can't be coerced into \#{self.class}"
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Subtract other from self
|
|
231
|
+
#
|
|
232
|
+
# if other is a Duration-like object, the result is a new
|
|
233
|
+
# {DateTimeType} of duration seconds earlier in time.
|
|
234
|
+
#
|
|
235
|
+
# if other is a DateTime-like object, the result is a Duration
|
|
236
|
+
# representing how long between the two instants in time.
|
|
237
|
+
#
|
|
238
|
+
# @param other [Duration, Time, Numeric]
|
|
239
|
+
#
|
|
240
|
+
# @return [DateTimeType, Duration]
|
|
241
|
+
def -(other)
|
|
242
|
+
if other.is_a?(Duration)
|
|
243
|
+
DateTimeType.new(zoned_date_time.minus(other))
|
|
244
|
+
elsif other.respond_to?(:to_time)
|
|
245
|
+
to_time - other.to_time
|
|
246
|
+
elsif other.respond_to?(:to_d)
|
|
247
|
+
DateTimeType.new(zoned_date_time.minus_nanos((other.to_d * 1_000_000_000).to_i))
|
|
248
|
+
elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(to_d))
|
|
249
|
+
lhs - rhs
|
|
250
|
+
else
|
|
251
|
+
raise TypeError, "\#{other.class} can't be coerced into \#{self.class}"
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# @!parse DateTimeType = OpenHAB::Core::Types::DateTimeType
|