openhab-scripting 4.46.2 → 5.0.0
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/actions/audio.rb +47 -0
- data/lib/openhab/core/actions/ephemeris.rb +39 -0
- data/lib/openhab/core/actions/exec.rb +51 -0
- data/lib/openhab/core/actions/http.rb +80 -0
- data/lib/openhab/core/actions/ping.rb +30 -0
- data/lib/openhab/core/actions/transformation.rb +32 -0
- data/lib/openhab/core/actions/voice.rb +36 -0
- data/lib/openhab/core/actions.rb +82 -0
- data/lib/openhab/core/dependency_tracking.rb +34 -0
- data/lib/openhab/core/dto/item_channel_link.rb +33 -0
- data/lib/openhab/core/dto/thing.rb +27 -0
- data/lib/openhab/core/dto.rb +11 -0
- data/lib/openhab/core/entity_lookup.rb +152 -70
- data/lib/openhab/core/events/abstract_event.rb +18 -0
- data/lib/openhab/core/events/abstract_item_registry_event.rb +36 -0
- data/lib/openhab/core/events/abstract_thing_registry_event.rb +40 -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 +75 -0
- data/lib/openhab/core/events/item_state_event.rb +79 -0
- data/lib/openhab/core/events/thing_status_info_event.rb +55 -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 +59 -0
- data/lib/openhab/core/items/dimmer_item.rb +148 -0
- data/lib/openhab/core/items/generic_item.rb +292 -0
- data/lib/openhab/core/items/group_item.rb +176 -0
- data/lib/openhab/{dsl → core}/items/image_item.rb +35 -29
- data/lib/openhab/core/items/item.rb +273 -0
- data/lib/openhab/core/items/location_item.rb +34 -0
- data/lib/openhab/core/items/metadata/hash.rb +433 -0
- data/lib/openhab/core/items/metadata/namespace_hash.rb +475 -0
- data/lib/openhab/core/items/metadata/provider.rb +48 -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 +416 -0
- data/lib/openhab/core/items/player_item.rb +66 -0
- data/lib/openhab/core/items/provider.rb +44 -0
- data/lib/openhab/core/items/proxy.rb +136 -0
- data/lib/openhab/core/items/registry.rb +86 -0
- data/lib/openhab/core/items/rollershutter_item.rb +68 -0
- data/lib/openhab/core/items/semantics/enumerable.rb +177 -0
- data/lib/openhab/core/items/semantics.rb +473 -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 +108 -0
- data/lib/openhab/{dsl → core}/lazy_array.rb +9 -3
- data/lib/openhab/core/profile_factory.rb +132 -0
- data/lib/openhab/core/provider.rb +230 -0
- data/lib/openhab/core/proxy.rb +130 -0
- data/lib/openhab/core/registry.rb +40 -0
- data/lib/openhab/core/rules/module.rb +26 -0
- data/lib/openhab/core/rules/provider.rb +25 -0
- data/lib/openhab/core/rules/registry.rb +76 -0
- data/lib/openhab/core/rules/rule.rb +150 -0
- data/lib/openhab/core/rules.rb +25 -0
- data/lib/openhab/core/script_handling.rb +78 -20
- 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/links/provider.rb +78 -0
- data/lib/openhab/core/things/profile_callback.rb +52 -0
- data/lib/openhab/core/things/provider.rb +29 -0
- data/lib/openhab/core/things/proxy.rb +87 -0
- data/lib/openhab/core/things/registry.rb +73 -0
- data/lib/openhab/core/things/thing.rb +194 -0
- data/lib/openhab/core/things.rb +22 -0
- data/lib/openhab/core/timer.rb +148 -0
- data/lib/openhab/{dsl → core}/types/comparable_type.rb +5 -3
- data/lib/openhab/{dsl → core}/types/date_time_type.rb +55 -127
- data/lib/openhab/{dsl → core}/types/decimal_type.rb +50 -48
- data/lib/openhab/{dsl → core}/types/hsb_type.rb +35 -83
- 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/{dsl → core}/types/numeric_type.rb +20 -7
- 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/{dsl → core}/types/percent_type.rb +19 -20
- 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 +325 -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/{dsl → core}/types/string_type.rb +17 -28
- data/lib/openhab/{dsl → core}/types/type.rb +42 -40
- 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 +82 -0
- data/lib/openhab/{dsl → core}/uid.rb +4 -23
- data/lib/openhab/core/value_cache.rb +188 -0
- data/lib/openhab/core.rb +98 -0
- data/lib/openhab/core_ext/between.rb +32 -0
- data/lib/openhab/core_ext/ephemeris.rb +53 -0
- data/lib/openhab/core_ext/java/class.rb +34 -0
- data/lib/openhab/core_ext/java/duration.rb +142 -0
- data/lib/openhab/core_ext/java/list.rb +436 -0
- data/lib/openhab/core_ext/java/local_date.rb +104 -0
- data/lib/openhab/core_ext/java/local_time.rb +118 -0
- data/lib/openhab/core_ext/java/map.rb +66 -0
- data/lib/openhab/core_ext/java/month.rb +71 -0
- data/lib/openhab/core_ext/java/month_day.rb +119 -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 +62 -0
- data/lib/openhab/core_ext/java/unit.rb +15 -0
- data/lib/openhab/core_ext/java/zoned_date_time.rb +213 -0
- data/lib/openhab/core_ext/ruby/array.rb +21 -0
- data/lib/openhab/core_ext/ruby/date.rb +96 -0
- data/lib/openhab/core_ext/ruby/date_time.rb +55 -0
- data/lib/openhab/core_ext/ruby/module.rb +15 -0
- data/lib/openhab/core_ext/ruby/numeric.rb +195 -0
- data/lib/openhab/core_ext/ruby/range.rb +70 -0
- data/lib/openhab/core_ext/ruby/symbol.rb +7 -0
- data/lib/openhab/core_ext/ruby/time.rb +108 -0
- data/lib/openhab/core_ext.rb +18 -0
- data/lib/openhab/dsl/debouncer.rb +259 -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 +1 -1
- data/lib/openhab/dsl/items/builder.rb +578 -0
- data/lib/openhab/dsl/items/ensure.rb +73 -82
- data/lib/openhab/dsl/items/timed_command.rb +214 -159
- data/lib/openhab/dsl/rules/automation_rule.rb +126 -115
- data/lib/openhab/dsl/rules/builder.rb +1935 -0
- data/lib/openhab/dsl/rules/guard.rb +51 -114
- data/lib/openhab/dsl/rules/name_inference.rb +66 -25
- data/lib/openhab/dsl/rules/property.rb +48 -75
- data/lib/openhab/dsl/rules/rule_triggers.rb +22 -27
- data/lib/openhab/dsl/rules/terse.rb +58 -14
- data/lib/openhab/dsl/rules/triggers/changed.rb +48 -94
- data/lib/openhab/dsl/rules/triggers/channel.rb +9 -40
- data/lib/openhab/dsl/rules/triggers/command.rb +14 -63
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +34 -69
- data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +6 -14
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +48 -82
- data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +30 -47
- data/lib/openhab/dsl/rules/triggers/trigger.rb +7 -28
- data/lib/openhab/dsl/rules/triggers/updated.rb +21 -45
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +257 -102
- data/lib/openhab/dsl/rules/triggers.rb +12 -0
- data/lib/openhab/dsl/rules.rb +8 -0
- data/lib/openhab/dsl/things/builder.rb +299 -0
- data/lib/openhab/{core → dsl}/thread_local.rb +27 -17
- data/lib/openhab/dsl/timer_manager.rb +204 -0
- data/lib/openhab/dsl/version.rb +9 -0
- data/lib/openhab/dsl.rb +979 -0
- data/lib/openhab/log.rb +355 -0
- data/lib/openhab/osgi.rb +68 -0
- data/lib/openhab/rspec/configuration.rb +56 -0
- data/lib/openhab/rspec/example_group.rb +132 -0
- data/lib/openhab/rspec/helpers.rb +458 -0
- data/lib/openhab/rspec/hooks.rb +113 -0
- data/lib/openhab/rspec/jruby.rb +46 -0
- data/lib/openhab/rspec/karaf.rb +851 -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/instance_method_stasher.rb +22 -0
- data/lib/openhab/rspec/mocks/persistence_service.rb +155 -0
- data/lib/openhab/rspec/mocks/safe_caller.rb +40 -0
- data/lib/openhab/rspec/mocks/space.rb +23 -0
- data/lib/openhab/rspec/mocks/synchronous_executor.rb +63 -0
- data/lib/openhab/rspec/mocks/thing_handler.rb +76 -0
- data/lib/openhab/rspec/mocks/timer.rb +134 -0
- data/lib/openhab/rspec/openhab/core/actions.rb +38 -0
- data/lib/openhab/rspec/openhab/core/items/proxy.rb +15 -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 +50 -0
- data/lib/openhab/rspec.rb +26 -0
- data/lib/openhab/yard/base_helper.rb +19 -0
- data/lib/openhab/yard/cli/stats.rb +23 -0
- data/lib/openhab/yard/code_objects/group_object.rb +23 -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/coderay.rb +17 -0
- data/lib/openhab/yard/handlers/jruby/base.rb +58 -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 +30 -0
- data/lib/openhab/yard/handlers/jruby/mixin_handler.rb +23 -0
- data/lib/openhab/yard/html_helper.rb +78 -0
- data/lib/openhab/yard/markdown_helper.rb +148 -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 +38 -0
- metadata +475 -106
- data/lib/openhab/core/item_proxy.rb +0 -29
- data/lib/openhab/core/load_path.rb +0 -19
- data/lib/openhab/core/openhab_setup.rb +0 -29
- data/lib/openhab/core/osgi.rb +0 -58
- data/lib/openhab/core/services.rb +0 -24
- data/lib/openhab/dsl/actions.rb +0 -114
- data/lib/openhab/dsl/between.rb +0 -25
- data/lib/openhab/dsl/channel.rb +0 -43
- data/lib/openhab/dsl/dsl.rb +0 -59
- data/lib/openhab/dsl/group.rb +0 -54
- data/lib/openhab/dsl/imports.rb +0 -21
- data/lib/openhab/dsl/items/color_item.rb +0 -76
- data/lib/openhab/dsl/items/comparable_item.rb +0 -62
- data/lib/openhab/dsl/items/contact_item.rb +0 -41
- data/lib/openhab/dsl/items/date_time_item.rb +0 -65
- data/lib/openhab/dsl/items/dimmer_item.rb +0 -65
- data/lib/openhab/dsl/items/generic_item.rb +0 -229
- data/lib/openhab/dsl/items/group_item.rb +0 -127
- data/lib/openhab/dsl/items/item_equality.rb +0 -59
- data/lib/openhab/dsl/items/item_registry.rb +0 -54
- data/lib/openhab/dsl/items/items.rb +0 -109
- data/lib/openhab/dsl/items/location_item.rb +0 -59
- data/lib/openhab/dsl/items/metadata.rb +0 -326
- data/lib/openhab/dsl/items/number_item.rb +0 -17
- data/lib/openhab/dsl/items/numeric_item.rb +0 -87
- data/lib/openhab/dsl/items/persistence.rb +0 -307
- data/lib/openhab/dsl/items/player_item.rb +0 -58
- data/lib/openhab/dsl/items/rollershutter_item.rb +0 -51
- data/lib/openhab/dsl/items/semantics/enumerable.rb +0 -91
- data/lib/openhab/dsl/items/semantics.rb +0 -227
- data/lib/openhab/dsl/items/string_item.rb +0 -51
- data/lib/openhab/dsl/items/switch_item.rb +0 -70
- data/lib/openhab/dsl/monkey_patch/actions/actions.rb +0 -4
- data/lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb +0 -39
- data/lib/openhab/dsl/monkey_patch/events/events.rb +0 -7
- data/lib/openhab/dsl/monkey_patch/events/item_command.rb +0 -85
- data/lib/openhab/dsl/monkey_patch/events/item_event.rb +0 -28
- data/lib/openhab/dsl/monkey_patch/events/item_state.rb +0 -61
- data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +0 -60
- data/lib/openhab/dsl/monkey_patch/events/thing_status_info.rb +0 -33
- data/lib/openhab/dsl/monkey_patch/java/java.rb +0 -4
- data/lib/openhab/dsl/monkey_patch/java/local_time.rb +0 -44
- data/lib/openhab/dsl/monkey_patch/java/time_extensions.rb +0 -50
- data/lib/openhab/dsl/monkey_patch/java/zoned_date_time.rb +0 -45
- data/lib/openhab/dsl/monkey_patch/ruby/number.rb +0 -104
- data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +0 -6
- data/lib/openhab/dsl/monkey_patch/ruby/string.rb +0 -47
- data/lib/openhab/dsl/monkey_patch/ruby/time.rb +0 -61
- data/lib/openhab/dsl/openhab.rb +0 -30
- data/lib/openhab/dsl/persistence.rb +0 -27
- data/lib/openhab/dsl/rules/item_event.rb +0 -19
- data/lib/openhab/dsl/rules/rule.rb +0 -160
- data/lib/openhab/dsl/rules/rule_config.rb +0 -147
- data/lib/openhab/dsl/rules/triggers/generic.rb +0 -31
- data/lib/openhab/dsl/rules/triggers/triggers.rb +0 -11
- data/lib/openhab/dsl/rules/triggers/watch/watch.rb +0 -81
- data/lib/openhab/dsl/states.rb +0 -89
- data/lib/openhab/dsl/things.rb +0 -147
- data/lib/openhab/dsl/time/month_day.rb +0 -180
- data/lib/openhab/dsl/time/time_of_day.rb +0 -235
- data/lib/openhab/dsl/timers/manager.rb +0 -119
- data/lib/openhab/dsl/timers/reentrant_timer.rb +0 -38
- data/lib/openhab/dsl/timers/timer.rb +0 -132
- data/lib/openhab/dsl/timers.rb +0 -77
- data/lib/openhab/dsl/types/increase_decrease_type.rb +0 -23
- data/lib/openhab/dsl/types/next_previous_type.rb +0 -23
- data/lib/openhab/dsl/types/on_off_type.rb +0 -28
- data/lib/openhab/dsl/types/open_closed_type.rb +0 -29
- data/lib/openhab/dsl/types/play_pause_type.rb +0 -27
- data/lib/openhab/dsl/types/point_type.rb +0 -180
- data/lib/openhab/dsl/types/quantity_type.rb +0 -265
- data/lib/openhab/dsl/types/refresh_type.rb +0 -18
- data/lib/openhab/dsl/types/rewind_fastforward_type.rb +0 -33
- data/lib/openhab/dsl/types/stop_move_type.rb +0 -23
- data/lib/openhab/dsl/types/types.rb +0 -83
- data/lib/openhab/dsl/types/un_def_type.rb +0 -22
- data/lib/openhab/dsl/types/up_down_type.rb +0 -32
- data/lib/openhab/dsl/units.rb +0 -45
- data/lib/openhab/log/configuration.rb +0 -21
- data/lib/openhab/log/logger.rb +0 -282
- data/lib/openhab/version.rb +0 -9
- data/lib/openhab.rb +0 -36
|
@@ -1,108 +1,99 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require 'openhab/log/logger'
|
|
5
|
-
require_relative 'generic_item'
|
|
3
|
+
require "ruby2_keywords"
|
|
6
4
|
|
|
7
5
|
module OpenHAB
|
|
8
6
|
module DSL
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
yield
|
|
26
|
-
ensure
|
|
27
|
-
Thread.current[:ensure_states] = old
|
|
7
|
+
module Items
|
|
8
|
+
# Functionality to implement `ensure`/`ensure_states`
|
|
9
|
+
module Ensure
|
|
10
|
+
# Contains the `ensure` method mixed into {Item} and {GroupItem::Members}
|
|
11
|
+
module Ensurable
|
|
12
|
+
# Fluent method call that you can chain commands on to, that will
|
|
13
|
+
# then automatically ensure that the item is not in the command's
|
|
14
|
+
# state before sending the command.
|
|
15
|
+
#
|
|
16
|
+
# @example Turn switch on only if it's not on
|
|
17
|
+
# MySwitch.ensure.on
|
|
18
|
+
# @example Turn on all switches in a group that aren't already on
|
|
19
|
+
# MySwitchGroup.members.ensure.on
|
|
20
|
+
def ensure
|
|
21
|
+
ItemDelegate.new(self)
|
|
22
|
+
end
|
|
28
23
|
end
|
|
29
|
-
module_function :ensure_states
|
|
30
|
-
end
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
module Ensurable
|
|
34
|
-
# Fluent method call that you can chain commands on to, that will
|
|
35
|
-
# then automatically ensure that the item is not in the command's
|
|
36
|
-
# state before sending the command.
|
|
25
|
+
# Extensions for {::Item} to implement {Ensure}'s functionality
|
|
37
26
|
#
|
|
38
|
-
# @
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def ensure
|
|
43
|
-
GenericItemDelegate.new(self)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
27
|
+
# @see OpenHAB::DSL.ensure ensure
|
|
28
|
+
# @see OpenHAB::DSL.ensure_states ensure_states
|
|
29
|
+
module Item
|
|
30
|
+
include Ensurable
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
# functionality
|
|
49
|
-
module GenericItem
|
|
50
|
-
include Ensurable
|
|
32
|
+
Core::Items::GenericItem.prepend(self)
|
|
51
33
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return super(
|
|
34
|
+
# If `ensure_states` is active (by block or chained method), then
|
|
35
|
+
# check if this item is in the command's state before actually
|
|
36
|
+
# sending the command
|
|
37
|
+
%i[command update].each do |ensured_method|
|
|
38
|
+
# def command(state)
|
|
39
|
+
# return super(state) unless Thread.current[:openhab_ensure_states]
|
|
40
|
+
#
|
|
41
|
+
# formatted_state = format_command(state)
|
|
42
|
+
# logger.trace do
|
|
43
|
+
# "#{name} ensure #{state}, format_command: #{formatted_state}, current state: #{raw_state}"
|
|
44
|
+
# end
|
|
45
|
+
# return if raw_state == formatted_state
|
|
46
|
+
#
|
|
47
|
+
# super(formatted_state)
|
|
48
|
+
# end
|
|
49
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition
|
|
50
|
+
def #{ensured_method}(state)
|
|
51
|
+
return super(state) unless Thread.current[:openhab_ensure_states]
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
formatted_state = format_#{ensured_method}(state)
|
|
54
|
+
logger.trace do
|
|
55
|
+
"\#{name} ensure \#{state}, format_#{ensured_method}: \#{formatted_state}, current state: \#{raw_state}"
|
|
56
|
+
end
|
|
57
|
+
return if raw_state.as(formatted_state.class) == formatted_state
|
|
63
58
|
|
|
64
|
-
|
|
59
|
+
super(formatted_state)
|
|
60
|
+
end
|
|
61
|
+
RUBY
|
|
65
62
|
end
|
|
66
63
|
end
|
|
67
|
-
alias << command
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# "anonymous" class that wraps any method call in +ensure_states+
|
|
71
|
-
# before forwarding to the wrapped object
|
|
72
|
-
# @!visibility private
|
|
73
|
-
class GenericItemDelegate
|
|
74
|
-
def initialize(item)
|
|
75
|
-
@item = item
|
|
76
|
-
end
|
|
77
64
|
|
|
65
|
+
# "anonymous" class that wraps any method call in `ensure_states`
|
|
66
|
+
# before forwarding to the wrapped object
|
|
78
67
|
# @!visibility private
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
end
|
|
68
|
+
class ItemDelegate
|
|
69
|
+
def initialize(item)
|
|
70
|
+
@item = item
|
|
71
|
+
end
|
|
84
72
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
73
|
+
# @!visibility private
|
|
74
|
+
# this is explicitly defined, instead of aliased, because #command
|
|
75
|
+
# doesn't actually exist as a method, and will go through method_missing
|
|
76
|
+
def <<(command)
|
|
77
|
+
command(command)
|
|
78
|
+
end
|
|
88
79
|
|
|
89
|
-
ensure_states
|
|
90
|
-
|
|
80
|
+
# activate `ensure_states` before forwarding to the wrapped object
|
|
81
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
|
82
|
+
return super unless @item.respond_to?(method)
|
|
83
|
+
|
|
84
|
+
DSL.ensure_states do
|
|
85
|
+
@item.__send__(method, *args, &block)
|
|
86
|
+
end
|
|
91
87
|
end
|
|
92
|
-
end
|
|
93
88
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
# .
|
|
90
|
+
def respond_to_missing?(method, include_private = false)
|
|
91
|
+
@item.respond_to?(method, include_private) || super
|
|
92
|
+
end
|
|
97
93
|
end
|
|
98
94
|
end
|
|
99
|
-
end
|
|
100
95
|
|
|
101
|
-
|
|
102
|
-
GenericItem.prepend(OpenHAB::DSL::Ensure::GenericItem)
|
|
103
|
-
GroupItem::GroupMembers.include(OpenHAB::DSL::Ensure::Ensurable)
|
|
96
|
+
Core::Items::GroupItem::Members.include(Ensure::Ensurable)
|
|
104
97
|
end
|
|
105
98
|
end
|
|
106
99
|
end
|
|
107
|
-
|
|
108
|
-
Object.include OpenHAB::DSL::Ensure::EnsureStates
|
|
@@ -1,198 +1,253 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'openhab/dsl/timers'
|
|
4
|
-
require 'openhab/dsl/rules/rule_triggers'
|
|
5
|
-
require 'openhab/dsl/rules/triggers/triggers'
|
|
6
|
-
require 'openhab/log/logger'
|
|
7
|
-
require 'java'
|
|
8
|
-
|
|
9
|
-
require_relative 'generic_item'
|
|
10
|
-
|
|
11
3
|
module OpenHAB
|
|
12
4
|
module DSL
|
|
13
5
|
module Items
|
|
14
|
-
#
|
|
6
|
+
# Extensions for {Item} to implement timed commands
|
|
7
|
+
#
|
|
8
|
+
# All items have an implicit timer associated with them, enabling to
|
|
9
|
+
# easily set an item into a specific state for a specified duration and
|
|
10
|
+
# then at the expiration of that duration have the item automatically
|
|
11
|
+
# change to another state. These timed commands are reentrant, meaning
|
|
12
|
+
# if the same timed command is triggered while an outstanding timed
|
|
13
|
+
# command exist, that timed command will be rescheduled rather than
|
|
14
|
+
# creating a distinct timed command.
|
|
15
|
+
#
|
|
16
|
+
# Timed commands are initiated by using the 'for:' argument with the
|
|
17
|
+
# command. This is available on both the 'command' method and any
|
|
18
|
+
# command-specific methods, e.g. {SwitchItem#on}.
|
|
19
|
+
#
|
|
20
|
+
# The timer will be cancelled, and the item's state will not be changed
|
|
21
|
+
# to the on_expire state if:
|
|
22
|
+
# - The item receives any command within the timed command duration.
|
|
23
|
+
# - The item is updated to a different state, even if it is then updated
|
|
24
|
+
# back to the same state.
|
|
25
|
+
#
|
|
26
|
+
# For example, if you have a Switch on a timer and another rule sends
|
|
27
|
+
# a command to that item, even when it's commanded to the same state,
|
|
28
|
+
# the timer will be automatically canceled.
|
|
29
|
+
#
|
|
30
|
+
# Sending a different duration (for:) value for the timed
|
|
31
|
+
# command will reschedule the timed command for that new duration.
|
|
32
|
+
#
|
|
15
33
|
module TimedCommand
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
34
|
+
#
|
|
35
|
+
# Provides information about why the expiration block of a
|
|
36
|
+
# {TimedCommand#command timed command} is being called.
|
|
37
|
+
#
|
|
38
|
+
# @attr [Item] item
|
|
39
|
+
# @!visibility private
|
|
40
|
+
# @attr [Types::Type, Proc] on_expire
|
|
41
|
+
# @!visibility private
|
|
42
|
+
# @attr [Core::Timer] timer
|
|
43
|
+
# @!visibility private
|
|
44
|
+
# @attr [Symbol] resolution
|
|
45
|
+
# @!visibility private
|
|
46
|
+
# @attr [String] rule_uid
|
|
47
|
+
# @!visibility private
|
|
48
|
+
# @attr [Mutex] mutex
|
|
49
|
+
# @!visibility private
|
|
50
|
+
#
|
|
51
|
+
TimedCommandDetails = Struct.new(:item,
|
|
52
|
+
:on_expire,
|
|
53
|
+
:timer,
|
|
54
|
+
:resolution,
|
|
55
|
+
:rule_uid,
|
|
56
|
+
:mutex,
|
|
57
|
+
keyword_init: true) do
|
|
58
|
+
# @return [true, false]
|
|
19
59
|
def expired?
|
|
20
|
-
expired
|
|
60
|
+
resolution == :expired
|
|
21
61
|
end
|
|
22
62
|
|
|
23
|
-
|
|
24
|
-
|
|
63
|
+
# @return [true, false]
|
|
64
|
+
def cancelled?
|
|
65
|
+
resolution == :cancelled
|
|
25
66
|
end
|
|
26
67
|
end
|
|
27
68
|
|
|
28
|
-
@timed_commands =
|
|
69
|
+
@timed_commands = java.util.concurrent.ConcurrentHashMap.new
|
|
29
70
|
|
|
30
71
|
class << self
|
|
72
|
+
# @!visibility private
|
|
31
73
|
attr_reader :timed_commands
|
|
32
74
|
end
|
|
33
75
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
Core::Items::GenericItem.prepend(self)
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Sends command to an item for specified duration, then on timer expiration sends
|
|
80
|
+
# the expiration command to the item
|
|
81
|
+
#
|
|
82
|
+
# @note If a block is provided, and the timer is canceled because the
|
|
83
|
+
# item changed state while it was waiting, the block will still be
|
|
84
|
+
# executed. Be sure to check {TimedCommandDetails#expired? #expired?}
|
|
85
|
+
# and/or {TimedCommandDetails#cancelled? #cancelled?} to determine why
|
|
86
|
+
# the block was called.
|
|
87
|
+
#
|
|
88
|
+
# @param [Command] command to send to object
|
|
89
|
+
# @param [Duration] for duration for item to be in command state
|
|
90
|
+
# @param [Command] on_expire Command to send when duration expires
|
|
91
|
+
# @yield If a block is provided, `on_expire` is ignored and the block
|
|
92
|
+
# is expected to set the item to the desired state or carry out some
|
|
93
|
+
# other action.
|
|
94
|
+
# @yieldparam [TimedCommandDetails] timed_command
|
|
95
|
+
# @return [self]
|
|
96
|
+
#
|
|
97
|
+
# @example
|
|
98
|
+
# Switch.command(ON, for: 5.minutes)
|
|
99
|
+
# @example
|
|
100
|
+
# Switch.on for: 5.minutes
|
|
101
|
+
# @example
|
|
102
|
+
# Dimmer.on for: 5.minutes, on_expire: 50
|
|
103
|
+
# @example
|
|
104
|
+
# Dimmer.on(for: 5.minutes) { |event| Dimmer.off if Light.on? }
|
|
105
|
+
#
|
|
106
|
+
def command(command, for: nil, on_expire: nil, &block)
|
|
107
|
+
duration = binding.local_variable_get(:for)
|
|
108
|
+
return super(command) unless duration
|
|
109
|
+
|
|
110
|
+
on_expire = block if block
|
|
111
|
+
|
|
112
|
+
TimedCommand.timed_commands.compute(self) do |_key, timed_command_details|
|
|
113
|
+
if timed_command_details.nil?
|
|
114
|
+
# no prior timed command
|
|
115
|
+
on_expire ||= default_on_expire(command)
|
|
116
|
+
super(command)
|
|
117
|
+
create_timed_command(command, duration: duration, on_expire: on_expire)
|
|
118
|
+
else
|
|
119
|
+
timed_command_details.mutex.synchronize do
|
|
120
|
+
if timed_command_details.resolution
|
|
121
|
+
# timed command that finished, but hadn't removed itself from the map yet
|
|
122
|
+
# (it doesn't do so under the mutex to prevent a deadlock).
|
|
123
|
+
# just create a new one
|
|
124
|
+
on_expire ||= default_on_expire(command)
|
|
125
|
+
super(command)
|
|
126
|
+
create_timed_command(command, duration: duration, on_expire: on_expire)
|
|
127
|
+
else
|
|
128
|
+
# timed command still pending; reset it
|
|
129
|
+
logger.trace "Outstanding Timed Command #{timed_command_details} encountered - rescheduling"
|
|
130
|
+
timed_command_details.on_expire = on_expire unless on_expire.nil?
|
|
131
|
+
timed_command_details.timer.reschedule(duration)
|
|
132
|
+
# disable the cancel rule while we send the new command
|
|
133
|
+
DSL.rules[timed_command_details.rule_uid].disable
|
|
134
|
+
super(command)
|
|
135
|
+
DSL.rules[timed_command_details.rule_uid].enable
|
|
136
|
+
timed_command_details
|
|
137
|
+
end
|
|
64
138
|
end
|
|
65
139
|
end
|
|
66
|
-
|
|
67
|
-
self
|
|
68
140
|
end
|
|
69
|
-
# rubocop: enable Metrics/MethodLength
|
|
70
|
-
alias << command
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
# Creates a new timed command and places it in the TimedCommand hash
|
|
75
|
-
# rubocop: disable Metrics/AbcSize
|
|
76
|
-
# rubocop: disable Metrics/MethodLength
|
|
77
|
-
# There is no feasible way to break this method into smaller components
|
|
78
|
-
def create_timed_command(command:, duration:, semaphore:, on_expire:, &block)
|
|
79
|
-
on_expire ||= default_on_expire(command)
|
|
80
|
-
timed_command_details = TimedCommandDetails.new(item: self, command: command, was: state,
|
|
81
|
-
on_expire: on_expire, duration: duration)
|
|
82
|
-
|
|
83
|
-
# Send specified command after capturing current state
|
|
84
|
-
command(command)
|
|
85
|
-
|
|
86
|
-
timed_command_details.timer = timed_command_timer(timed_command_details, semaphore, &block)
|
|
87
|
-
timed_command_details.cancel_rule = TimedCommandCancelRule.new(timed_command_details, semaphore,
|
|
88
|
-
&block)
|
|
89
|
-
timed_command_details.rule_uid = OpenHAB::DSL::Rules::Rule.automation_manager
|
|
90
|
-
.addRule(timed_command_details.cancel_rule)
|
|
91
|
-
.getUID
|
|
92
|
-
logger.trace "Created Timed Command #{timed_command_details}"
|
|
93
|
-
TimedCommand.timed_commands[self] = timed_command_details
|
|
94
|
-
end
|
|
95
|
-
# rubocop: enable Metrics/AbcSize
|
|
96
|
-
# rubocop: enable Metrics/MethodLength
|
|
97
|
-
|
|
98
|
-
# Creates the timer to handle changing the item state when timer expires or invoking user supplied block
|
|
99
|
-
# @param [TimedCommandDetailes] timed_command_details details about the timed command
|
|
100
|
-
# @param [Mutex] semaphore Semaphore to lock on to prevent race condition between rule and timer
|
|
101
|
-
# @return [Timer] Timer
|
|
102
|
-
# rubocop: disable Metrics/MethodLength
|
|
103
|
-
# There is no feasible way to break this method into smaller components
|
|
104
|
-
def timed_command_timer(timed_command_details, semaphore, &block)
|
|
105
|
-
after(timed_command_details.duration, id: self) do
|
|
106
|
-
semaphore.synchronize do
|
|
107
|
-
logger.trace "Timed command expired - #{timed_command_details}"
|
|
108
|
-
cancel_timed_command_rule(timed_command_details)
|
|
109
|
-
timed_command_details.expired = true
|
|
110
|
-
if block
|
|
111
|
-
logger.trace "Invoking block #{block} after timed command for #{id} expired"
|
|
112
|
-
yield(timed_command_details)
|
|
113
|
-
else
|
|
114
|
-
command(timed_command_details.on_expire)
|
|
115
|
-
end
|
|
116
141
|
|
|
117
|
-
|
|
142
|
+
self
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
# Creates a new timed command and places it in the TimedCommand hash
|
|
148
|
+
def create_timed_command(command, duration:, on_expire:)
|
|
149
|
+
timed_command_details = TimedCommandDetails.new(item: self,
|
|
150
|
+
on_expire: on_expire,
|
|
151
|
+
mutex: Mutex.new)
|
|
152
|
+
|
|
153
|
+
timed_command_details.timer = timed_command_timer(timed_command_details, duration)
|
|
154
|
+
cancel_rule = TimedCommandCancelRule.new(command, timed_command_details)
|
|
155
|
+
unmanaged_rule = Core.automation_manager.add_unmanaged_rule(cancel_rule)
|
|
156
|
+
timed_command_details.rule_uid = unmanaged_rule.uid
|
|
157
|
+
Core::Rules::Provider.current.add(unmanaged_rule)
|
|
158
|
+
logger.trace "Created Timed Command #{timed_command_details}"
|
|
159
|
+
timed_command_details
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Creates the timer to handle changing the item state when timer expires or invoking user supplied block
|
|
163
|
+
# @param [TimedCommandDetailes] timed_command_details details about the timed command
|
|
164
|
+
# @return [Timer] Timer
|
|
165
|
+
def timed_command_timer(timed_command_details, duration)
|
|
166
|
+
DSL.after(duration) do
|
|
167
|
+
timed_command_details.mutex.synchronize do
|
|
168
|
+
logger.trace "Timed command expired - #{timed_command_details}"
|
|
169
|
+
DSL.rules.remove(timed_command_details.rule_uid)
|
|
170
|
+
timed_command_details.resolution = :expired
|
|
171
|
+
case timed_command_details.on_expire
|
|
172
|
+
when Proc
|
|
173
|
+
logger.trace "Invoking block #{timed_command_details.on_expire} after timed command for #{name} expired"
|
|
174
|
+
timed_command_details.on_expire.call(timed_command_details)
|
|
175
|
+
when Core::Types::UnDefType
|
|
176
|
+
update(timed_command_details.on_expire)
|
|
177
|
+
else
|
|
178
|
+
command(timed_command_details.on_expire)
|
|
118
179
|
end
|
|
119
180
|
end
|
|
181
|
+
TimedCommand.timed_commands.delete(timed_command_details.item)
|
|
120
182
|
end
|
|
121
|
-
|
|
183
|
+
end
|
|
122
184
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
end
|
|
185
|
+
#
|
|
186
|
+
# The default expire for ON/OFF is their inverse
|
|
187
|
+
#
|
|
188
|
+
def default_on_expire(command)
|
|
189
|
+
return !command if command.is_a?(Core::Types::OnOffType)
|
|
129
190
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
191
|
+
raw_state
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
#
|
|
195
|
+
# Rule to cancel timed commands
|
|
196
|
+
#
|
|
197
|
+
# @!visibility private
|
|
198
|
+
class TimedCommandCancelRule < org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRule
|
|
199
|
+
def initialize(command, timed_command_details)
|
|
200
|
+
super()
|
|
201
|
+
@timed_command_details = timed_command_details
|
|
202
|
+
# Capture rule name if known
|
|
203
|
+
@thread_locals = ThreadLocal.persist
|
|
204
|
+
self.name = "Cancel implicit timer for #{timed_command_details.item.name}"
|
|
205
|
+
self.triggers = [
|
|
206
|
+
Rules::RuleTriggers.trigger(
|
|
207
|
+
type: Rules::Triggers::Changed::ITEM_STATE_CHANGE,
|
|
208
|
+
config: {
|
|
209
|
+
"itemName" => timed_command_details.item.name,
|
|
210
|
+
"previousState" => timed_command_details.item.format_command(command).to_s
|
|
211
|
+
}
|
|
212
|
+
),
|
|
213
|
+
Rules::RuleTriggers.trigger(
|
|
214
|
+
type: Rules::Triggers::Command::ITEM_COMMAND,
|
|
215
|
+
config: {
|
|
216
|
+
"itemName" => timed_command_details.item.name
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
]
|
|
220
|
+
self.visibility = Core::Rules::Visibility::HIDDEN
|
|
139
221
|
end
|
|
140
222
|
|
|
141
223
|
#
|
|
142
|
-
#
|
|
224
|
+
# Execute the rule
|
|
143
225
|
#
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
config: { 'itemName' => timed_command_details.item.name,
|
|
159
|
-
'previousState' => timed_command_details.command.to_s }
|
|
160
|
-
)])
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
#
|
|
164
|
-
# Execute the rule
|
|
165
|
-
#
|
|
166
|
-
# @param [Map] _mod map provided by OpenHAB rules engine
|
|
167
|
-
# @param [Map] inputs map provided by OpenHAB rules engine containing event and other information
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
# rubocop: disable Metrics/MethodLength
|
|
171
|
-
# rubocop: disable Metrics/AbcSize
|
|
172
|
-
# There is no feasible way to break this method into smaller components
|
|
173
|
-
def execute(_mod = nil, inputs = nil)
|
|
174
|
-
OpenHAB::DSL.import_presets
|
|
175
|
-
@semaphore.synchronize do
|
|
176
|
-
thread_local(**@thread_locals) do
|
|
177
|
-
logger.trace "Canceling implicit timer #{@timed_command_details.timer} for " \
|
|
178
|
-
"#{@timed_command_details.item.id} because received event #{inputs}"
|
|
179
|
-
@timed_command_details.timer.cancel
|
|
180
|
-
# Disabled due to OpenHAB design
|
|
181
|
-
$scriptExtension.get('ruleRegistry').remove(@timed_command_details.rule_uid)
|
|
182
|
-
TimedCommand.timed_commands.delete(@timed_command_details.item)
|
|
183
|
-
if @block
|
|
184
|
-
logger.trace 'Executing user supplied block on timed command cancelation'
|
|
185
|
-
@block&.call(@timed_command_details)
|
|
186
|
-
end
|
|
226
|
+
# @param [java.util.Map] _mod map provided by openHAB rules engine
|
|
227
|
+
# @param [java.util.Map] inputs map provided by openHAB rules engine containing event and other information
|
|
228
|
+
#
|
|
229
|
+
def execute(_mod = nil, inputs = nil)
|
|
230
|
+
ThreadLocal.thread_local(**@thread_locals) do
|
|
231
|
+
@timed_command_details.mutex.synchronize do
|
|
232
|
+
logger.trace "Canceling implicit timer #{@timed_command_details.timer} for " \
|
|
233
|
+
"#{@timed_command_details.item.name} because received event #{inputs}"
|
|
234
|
+
@timed_command_details.timer.cancel
|
|
235
|
+
DSL.rules.remove(@timed_command_details.rule_uid)
|
|
236
|
+
@timed_command_details.resolution = :cancelled
|
|
237
|
+
if @timed_command_details.on_expire.is_a?(Proc)
|
|
238
|
+
logger.trace "Executing user supplied block on timed command cancelation"
|
|
239
|
+
@timed_command_details.on_expire.call(@timed_command_details)
|
|
187
240
|
end
|
|
188
241
|
end
|
|
242
|
+
TimedCommand.timed_commands.delete(@timed_command_details.item)
|
|
243
|
+
rescue Exception => e
|
|
244
|
+
raise if defined?(::RSpec)
|
|
245
|
+
|
|
246
|
+
logger.log_exception(e)
|
|
189
247
|
end
|
|
190
|
-
# rubocop: enable Metrics/MethodLength
|
|
191
|
-
# rubocop: enable Metrics/AbcSize
|
|
192
248
|
end
|
|
193
249
|
end
|
|
194
250
|
end
|
|
195
|
-
GenericItem.prepend(TimedCommand::GenericItem)
|
|
196
251
|
end
|
|
197
252
|
end
|
|
198
253
|
end
|