openhab-scripting 5.16.0 → 5.18.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/entity_lookup.rb +5 -5
- data/lib/openhab/core/events/item_state_updated_event.rb +11 -11
- data/lib/openhab/core/events/item_time_series_updated_event.rb +23 -0
- data/lib/openhab/core/events/timer_event.rb +32 -32
- data/lib/openhab/core/items/generic_item.rb +12 -0
- data/lib/openhab/core/items/numeric_item.rb +1 -1
- data/lib/openhab/core/items/persistence.rb +2 -4
- data/lib/openhab/core/items/registry.rb +1 -3
- data/lib/openhab/core/items/semantics/enumerable.rb +2 -2
- data/lib/openhab/core/items/semantics.rb +1 -4
- data/lib/openhab/core/profile_factory.rb +16 -1
- data/lib/openhab/core/rules/registry.rb +2 -1
- data/lib/openhab/core/rules/rule.rb +1 -0
- data/lib/openhab/core/sitemaps/provider.rb +3 -1
- data/lib/openhab/core/things/channel.rb +1 -1
- data/lib/openhab/core/things/profile_callback.rb +5 -0
- data/lib/openhab/core/things/thing.rb +6 -0
- data/lib/openhab/core/types/string_type.rb +1 -1
- data/lib/openhab/core/types/time_series.rb +131 -0
- data/lib/openhab/core.rb +14 -1
- data/lib/openhab/core_ext/java/instant.rb +14 -0
- data/lib/openhab/dsl/items/builder.rb +0 -1
- data/lib/openhab/dsl/items/timed_command.rb +1 -0
- data/lib/openhab/dsl/rules/builder.rb +140 -39
- data/lib/openhab/dsl/rules/name_inference.rb +16 -8
- data/lib/openhab/dsl/rules/property.rb +4 -1
- data/lib/openhab/dsl/rules/rule_triggers.rb +5 -3
- data/lib/openhab/dsl/rules/terse.rb +32 -15
- data/lib/openhab/dsl/rules/triggers/changed.rb +15 -7
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +3 -2
- data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +98 -100
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +2 -2
- data/lib/openhab/dsl/sitemaps/builder.rb +1 -1
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +30 -4
- data/lib/openhab/rspec/mocks/persistence_service.rb +10 -3
- data/lib/openhab/rspec/mocks/synchronous_executor.rb +2 -1
- data/lib/openhab/rspec/mocks/thing_handler.rb +4 -0
- metadata +6 -3
@@ -40,7 +40,17 @@ module OpenHAB
|
|
40
40
|
# The rule must have at least one trigger and one execution block.
|
41
41
|
# To create a "script" without any triggers, use {OpenHAB::DSL.script script}.
|
42
42
|
#
|
43
|
+
# When explicit `id` is not provided, the rule's ID will be inferred from the block's source location,
|
44
|
+
# and a suffix will be added to avoid clashing against existing rules.
|
45
|
+
#
|
46
|
+
# When an explicit `id` is provided and an existing rule with the same id already exists,
|
47
|
+
# the rule will not be created, and the method will return nil.
|
48
|
+
#
|
49
|
+
# To ensure that a rule is created even when the same id already exists, use {OpenHAB::DSL.rule!} or call
|
50
|
+
# {Core::Rules::Registry#remove rules.remove} to remove any existing rule prior to creating the new rule.
|
51
|
+
#
|
43
52
|
# @param [String] name The rule name
|
53
|
+
# @param [String] id The rule's ID. This can also be defined in the block using {Rules::BuilderDSL#uid uid}.
|
44
54
|
# @yield Block executed in the context of a {Rules::BuilderDSL}
|
45
55
|
# @yieldparam [Rules::BuilderDSL] rule
|
46
56
|
# Optional parameter to access the rule configuration from within execution blocks and guards.
|
@@ -48,20 +58,26 @@ module OpenHAB
|
|
48
58
|
#
|
49
59
|
# @see OpenHAB::DSL::Rules::BuilderDSL Rule BuilderDSL for details on rule triggers, guards and execution blocks
|
50
60
|
# @see Rules::Terse Terse Rules
|
61
|
+
# @see DSL.rule!
|
51
62
|
#
|
52
63
|
# @example
|
53
|
-
# require "openhab/dsl"
|
54
|
-
#
|
55
64
|
# rule "name" do
|
56
65
|
# <one or more triggers>
|
57
66
|
# <one or more execution blocks>
|
58
67
|
# <zero or more guards>
|
59
68
|
# end
|
60
69
|
#
|
61
|
-
|
70
|
+
# @example Create a rule with an explicit id, deleting any existing rule with the same id
|
71
|
+
# rule! "name", id: "my_happy_day_reminder" do
|
72
|
+
# every :day
|
73
|
+
# run { logger.info "Happy new day!" }
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
def rule(name = nil, id: nil, replace: false, script: nil, binding: nil, &block)
|
62
77
|
raise ArgumentError, "Block is required" unless block
|
63
78
|
|
64
|
-
|
79
|
+
inferred_id = nil
|
80
|
+
id ||= inferred_id = NameInference.infer_rule_id_from_block(block)
|
65
81
|
script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
|
66
82
|
|
67
83
|
builder = nil
|
@@ -70,6 +86,18 @@ module OpenHAB
|
|
70
86
|
builder = BuilderDSL.new(binding || block.binding)
|
71
87
|
builder.uid(id)
|
72
88
|
builder.instance_exec(builder, &block)
|
89
|
+
|
90
|
+
if replace
|
91
|
+
logger.debug { "Removing existing rule '#{builder.uid}'." } if DSL.rules.remove(builder.uid)
|
92
|
+
else
|
93
|
+
id_not_inferred = inferred_id.nil? || inferred_id != builder.uid
|
94
|
+
if id_not_inferred && (existing_rule = $rules.get(builder.uid))
|
95
|
+
logger.warn "Rule '#{builder.uid}' is not created because " \
|
96
|
+
"another rule/script/scene with the same id already exists: #{existing_rule.inspect}."
|
97
|
+
return nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
73
101
|
builder.guard = Guard.new(run_context: builder.caller,
|
74
102
|
only_if: builder.only_if,
|
75
103
|
not_if: builder.not_if)
|
@@ -101,7 +129,7 @@ module OpenHAB
|
|
101
129
|
# @param [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil] tags
|
102
130
|
# Fluent alias for `tag`
|
103
131
|
# @yield [] Block executed when the script is executed.
|
104
|
-
# @return [Core::Rules::Rule]
|
132
|
+
# @return [Core::Rules::Rule, nil]
|
105
133
|
#
|
106
134
|
# @example A simple script
|
107
135
|
# # return the script object into a variable
|
@@ -123,15 +151,26 @@ module OpenHAB
|
|
123
151
|
#
|
124
152
|
# rules.scripts["send_alert"].run(message: "The door is open!")
|
125
153
|
#
|
154
|
+
# @see DSL.rule
|
126
155
|
# @see Core::Rules::Rule#trigger
|
156
|
+
# @see DSL.script!
|
127
157
|
#
|
128
|
-
def script(name = nil, description: nil, id: nil, tag: nil, tags: nil, script: nil, &block)
|
158
|
+
def script(name = nil, description: nil, id: nil, tag: nil, tags: nil, replace: false, script: nil, &block)
|
129
159
|
raise ArgumentError, "Block is required" unless block
|
130
160
|
|
131
|
-
|
161
|
+
inferred_id = nil # rubocop:disable Lint/UselessAssignment it is used below
|
162
|
+
id ||= inferred_id = NameInference.infer_rule_id_from_block(block)
|
132
163
|
name ||= id
|
133
164
|
script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
|
134
165
|
|
166
|
+
if replace
|
167
|
+
logger.debug { "Removing existing rule '#{id}'." } if DSL.rules.remove(id)
|
168
|
+
elsif inferred_id.nil? && (existing_rule = $rules.get(id))
|
169
|
+
logger.warn "Script '#{id}' is not created because " \
|
170
|
+
"another script/scene/rule with the same id already exists: #{existing_rule.inspect}."
|
171
|
+
return nil
|
172
|
+
end
|
173
|
+
|
135
174
|
builder = nil
|
136
175
|
ThreadLocal.thread_local(openhab_rule_type: "script", openhab_rule_uid: id) do
|
137
176
|
builder = BuilderDSL.new(block.binding)
|
@@ -159,15 +198,27 @@ module OpenHAB
|
|
159
198
|
# @param [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil] tags
|
160
199
|
# Fluent alias for `tag`
|
161
200
|
# @yield [] Block executed when the script is executed.
|
162
|
-
# @return [Core::Rules::Rule]
|
201
|
+
# @return [Core::Rules::Rule, nil]
|
163
202
|
#
|
164
|
-
|
203
|
+
# @see DSL.rule
|
204
|
+
# @see DSL.scene!
|
205
|
+
#
|
206
|
+
def scene(name = nil, description: nil, id: nil, tag: nil, tags: nil, replace: false, script: nil, &block)
|
165
207
|
raise ArgumentError, "Block is required" unless block
|
166
208
|
|
167
|
-
|
209
|
+
inferred_id = nil # rubocop:disable Lint/UselessAssignment
|
210
|
+
id ||= inferred_id = NameInference.infer_rule_id_from_block(block)
|
168
211
|
name ||= id
|
169
212
|
script ||= block.source rescue nil # rubocop:disable Style/RescueModifier
|
170
213
|
|
214
|
+
if replace
|
215
|
+
logger.debug { "Removing existing rule '#{id}'." } if DSL.rules.remove(id)
|
216
|
+
elsif inferred_id.nil? && (existing_rule = $rules.get(id))
|
217
|
+
logger.warn "Scene '#{id}' is not created because " \
|
218
|
+
"another script/scene/rule with the same id already exists: #{existing_rule.inspect}."
|
219
|
+
return nil
|
220
|
+
end
|
221
|
+
|
171
222
|
builder = nil
|
172
223
|
ThreadLocal.thread_local(openhab_rule_type: "script", openhab_rule_uid: id) do
|
173
224
|
builder = BuilderDSL.new(block.binding)
|
@@ -400,7 +451,7 @@ module OpenHAB
|
|
400
451
|
# @param [String] id
|
401
452
|
# @return [void]
|
402
453
|
#
|
403
|
-
prop :
|
454
|
+
prop(:uid) { |id| Thread.current[:openhab_rule_uid] = id }
|
404
455
|
|
405
456
|
#
|
406
457
|
# @!method name(value)
|
@@ -994,13 +1045,20 @@ module OpenHAB
|
|
994
1045
|
# @param [Item, GroupItem::Members, Thing] items Objects to create trigger for.
|
995
1046
|
# @param [State, Array<State>, #===, nil] from
|
996
1047
|
# Only execute rule if previous state matches `from` state(s).
|
997
|
-
# @param [State, Array<State>, #===, nil] to
|
1048
|
+
# @param [State, Array<State>, #===, nil] to
|
998
1049
|
# Only execute rule if new state matches `to` state(s).
|
999
|
-
# @param [java.time.temporal.TemporalAmount] for
|
1000
|
-
# Duration item must remain in the same state before executing the execution blocks.
|
1001
|
-
#
|
1050
|
+
# @param [java.time.temporal.TemporalAmount, Proc, nil] for
|
1051
|
+
# Duration for which the item/thing must remain in the same state before executing the execution blocks.
|
1052
|
+
# When a proc is provided, it will be called when the rule is triggered to get the duration.
|
1053
|
+
# @param [Object, nil] attach object to be attached to the trigger
|
1002
1054
|
# @return [void]
|
1003
1055
|
#
|
1056
|
+
# @example Single item trigger
|
1057
|
+
# rule "Execute rule when a sensor changed" do
|
1058
|
+
# changed FrontMotion_Sensor
|
1059
|
+
# run { |event| logger.info("Motion detected by #{event.item.name}") }
|
1060
|
+
# end
|
1061
|
+
#
|
1004
1062
|
# @example Multiple items can be separated with a comma:
|
1005
1063
|
# rule "Execute rule when either sensor changed" do
|
1006
1064
|
# changed FrontMotion_Sensor, RearMotion_Sensor
|
@@ -1013,23 +1071,15 @@ module OpenHAB
|
|
1013
1071
|
# run { |event| logger.info("Motion detected by #{event.item.name}") }
|
1014
1072
|
# end
|
1015
1073
|
#
|
1016
|
-
# @example `
|
1017
|
-
#
|
1018
|
-
#
|
1019
|
-
# rule "Execute rule when item is changed for specified duration" do
|
1020
|
-
# changed Alarm_Mode, for: -> { Alarm_Delay.state }
|
1021
|
-
# run { logger.info("Alarm Mode Updated") }
|
1022
|
-
# end
|
1023
|
-
#
|
1024
|
-
# @example You can optionally provide `from` and `to` states to restrict the cases in which the rule executes:
|
1025
|
-
# rule "Execute rule when item is changed to specific number, from specific number, for specified duration" do
|
1026
|
-
# changed Alarm_Mode, from: 8, to: [14,12], for: 12.seconds
|
1074
|
+
# @example You can optionally provide `from` and/or `to` states to restrict the cases in which the rule executes:
|
1075
|
+
# rule "Execute rule when item is changed to specific number, from specific number" do
|
1076
|
+
# changed Alarm_Mode, from: 8, to: [14,12]
|
1027
1077
|
# run { logger.info("Alarm Mode Updated") }
|
1028
1078
|
# end
|
1029
1079
|
#
|
1030
1080
|
# @example Works with ranges:
|
1031
|
-
# rule "Execute when item changed to a range of numbers, from a range of numbers
|
1032
|
-
# changed Alarm_Mode, from: 8..10, to: 12..14
|
1081
|
+
# rule "Execute when item changed to a range of numbers, from a range of numbers" do
|
1082
|
+
# changed Alarm_Mode, from: 8..10, to: 12..14
|
1033
1083
|
# run { logger.info("Alarm Mode Updated") }
|
1034
1084
|
# end
|
1035
1085
|
#
|
@@ -1040,14 +1090,14 @@ module OpenHAB
|
|
1040
1090
|
# end
|
1041
1091
|
#
|
1042
1092
|
# @example Works with procs:
|
1043
|
-
# rule "Execute when item state is changed from an odd number, to an even number
|
1044
|
-
# changed Alarm_Mode, from: proc { |from| from.odd? }, to: proc {|to| to.even? }
|
1093
|
+
# rule "Execute when item state is changed from an odd number, to an even number" do
|
1094
|
+
# changed Alarm_Mode, from: proc { |from| from.odd? }, to: proc {|to| to.even? }
|
1045
1095
|
# run { logger.info("Alarm Mode Updated") }
|
1046
1096
|
# end
|
1047
1097
|
#
|
1048
1098
|
# @example Works with lambdas:
|
1049
|
-
# rule "Execute when item state is changed from an odd number, to an even number
|
1050
|
-
# changed Alarm_Mode, from: -> from { from.odd? }, to: -> to { to.even? }
|
1099
|
+
# rule "Execute when item state is changed from an odd number, to an even number" do
|
1100
|
+
# changed Alarm_Mode, from: -> from { from.odd? }, to: -> to { to.even? }
|
1051
1101
|
# run { logger.info("Alarm Mode Updated") }
|
1052
1102
|
# end
|
1053
1103
|
#
|
@@ -1057,6 +1107,22 @@ module OpenHAB
|
|
1057
1107
|
# run { logger.info("Alarm armed") }
|
1058
1108
|
# end
|
1059
1109
|
#
|
1110
|
+
# @example Delay the trigger until the item has been in the same state for 10 seconds
|
1111
|
+
# rule "Execute rule when item is changed for specified duration" do
|
1112
|
+
# changed Closet_Door, to: CLOSED, for: 10.seconds
|
1113
|
+
# run do
|
1114
|
+
# Closet_Light.off
|
1115
|
+
# end
|
1116
|
+
# end
|
1117
|
+
#
|
1118
|
+
# @example `for` parameter can be a proc that returns a duration:
|
1119
|
+
# Alarm_Delay << 20
|
1120
|
+
#
|
1121
|
+
# rule "Execute rule when item is changed for specified duration" do
|
1122
|
+
# changed Alarm_Mode, for: -> { Alarm_Delay.state.to_i.seconds }
|
1123
|
+
# run { logger.info("Alarm Mode Updated") }
|
1124
|
+
# end
|
1125
|
+
#
|
1060
1126
|
# @example Works with Things:
|
1061
1127
|
# rule "Execute rule when thing is changed" do
|
1062
1128
|
# changed things["astro:sun:home"], :from => :online, :to => :uninitialized
|
@@ -1089,7 +1155,7 @@ module OpenHAB
|
|
1089
1155
|
raise ArgumentError, "items must be an Item, GroupItem::Members, Thing, or ThingUID"
|
1090
1156
|
end
|
1091
1157
|
|
1092
|
-
logger.trace
|
1158
|
+
logger.trace { "Creating changed trigger for entity(#{item}), to(#{to.inspect}), from(#{from.inspect})" }
|
1093
1159
|
|
1094
1160
|
Array.wrap(from).each do |from_state|
|
1095
1161
|
Array.wrap(to).each do |to_state|
|
@@ -1381,7 +1447,7 @@ module OpenHAB
|
|
1381
1447
|
levels.each do |level|
|
1382
1448
|
logger.warn "Rule engine doesn't start until start level 40" if level < 40
|
1383
1449
|
config = { startlevel: level }
|
1384
|
-
logger.trace
|
1450
|
+
logger.trace { "Creating a SystemStartlevelTrigger with startlevel=#{level}" }
|
1385
1451
|
Triggers::Trigger.new(rule_triggers: @rule_triggers)
|
1386
1452
|
.append_trigger(type: "core.SystemStartlevelTrigger", config: config, attach: attach)
|
1387
1453
|
end
|
@@ -1480,7 +1546,7 @@ module OpenHAB
|
|
1480
1546
|
raise ArgumentError, "items must be an Item or GroupItem::Members"
|
1481
1547
|
end
|
1482
1548
|
commands.each do |cmd|
|
1483
|
-
logger.trace "Creating received command trigger for items #{item.inspect} and commands #{cmd.inspect}"
|
1549
|
+
logger.trace { "Creating received command trigger for items #{item.inspect} and commands #{cmd.inspect}" }
|
1484
1550
|
|
1485
1551
|
command_trigger.trigger(item: item, command: cmd, attach: attach)
|
1486
1552
|
end
|
@@ -1699,7 +1765,7 @@ module OpenHAB
|
|
1699
1765
|
# end
|
1700
1766
|
#
|
1701
1767
|
def trigger(type, attach: nil, **configuration)
|
1702
|
-
logger.trace
|
1768
|
+
logger.trace { "Creating trigger (#{type}) with configuration(#{configuration})" }
|
1703
1769
|
Triggers::Trigger.new(rule_triggers: @rule_triggers)
|
1704
1770
|
.append_trigger(type: type, config: configuration, attach: attach)
|
1705
1771
|
end
|
@@ -1802,13 +1868,48 @@ module OpenHAB
|
|
1802
1868
|
raise ArgumentError, "items must be an Item, GroupItem::Members, Thing, or ThingUID"
|
1803
1869
|
end
|
1804
1870
|
|
1805
|
-
logger.trace
|
1871
|
+
logger.trace { "Creating updated trigger for item(#{item}) to(#{to})" }
|
1806
1872
|
[to].flatten.map do |to_state|
|
1807
1873
|
updated.trigger(item: item, to: to_state, attach: attach)
|
1808
1874
|
end
|
1809
1875
|
end.flatten
|
1810
1876
|
end
|
1811
1877
|
|
1878
|
+
#
|
1879
|
+
# Creates a time series updated trigger
|
1880
|
+
#
|
1881
|
+
# The `event` passed to run blocks will be a {OpenHAB::Core::Events::ItemTimeSeriesUpdatedEvent}
|
1882
|
+
#
|
1883
|
+
# @param [Item] items Items to create trigger for.
|
1884
|
+
# @param [Object] attach Object to be attached to the trigger.
|
1885
|
+
# @return [void]
|
1886
|
+
#
|
1887
|
+
# @since openHAB 4.1
|
1888
|
+
# @see Core::Types::TimeSeries TimeSeries
|
1889
|
+
# @see Core::Items::GenericItem#time_series= GenericItem#time_series=
|
1890
|
+
#
|
1891
|
+
# @example
|
1892
|
+
# rule 'Execute rule when item time series is updated' do
|
1893
|
+
# time_series_updated MyItem
|
1894
|
+
# run do |event|
|
1895
|
+
# logger.info("Item time series updated: #{event.item.name}.")
|
1896
|
+
# logger.info(" TimeSeries size: #{event.time_series.size}, policy: #{event.time_series.policy}")
|
1897
|
+
# event.time_series.each do |entry|
|
1898
|
+
# timestamp = entry.timestamp.to_time.strftime("%Y-%m-%d %H:%M:%S")
|
1899
|
+
# logger.info(" Entry: #{timestamp}: State: #{entry.state}")
|
1900
|
+
# end
|
1901
|
+
# end
|
1902
|
+
# end
|
1903
|
+
#
|
1904
|
+
def time_series_updated(*items, attach: nil)
|
1905
|
+
@ruby_triggers << [:time_series_updated, items]
|
1906
|
+
items.map do |item|
|
1907
|
+
raise ArgumentError, "items must be an Item or GroupItem::Members" unless item.is_a?(Core::Items::Item)
|
1908
|
+
|
1909
|
+
event("openhab/items/#{item.name}/timeseriesupdated", types: "ItemTimeSeriesUpdatedEvent", attach: attach)
|
1910
|
+
end
|
1911
|
+
end
|
1912
|
+
|
1812
1913
|
#
|
1813
1914
|
# Create a trigger to watch a path
|
1814
1915
|
#
|
@@ -1987,7 +2088,7 @@ module OpenHAB
|
|
1987
2088
|
elsif !execution_blocks?
|
1988
2089
|
logger.warn "Rule '#{uid}' has no execution blocks, not creating rule"
|
1989
2090
|
elsif !enabled
|
1990
|
-
logger.trace "Rule '#{uid}' marked as disabled, not creating rule."
|
2091
|
+
logger.trace { "Rule '#{uid}' marked as disabled, not creating rule." }
|
1991
2092
|
else
|
1992
2093
|
return true
|
1993
2094
|
end
|
@@ -2024,7 +2125,7 @@ module OpenHAB
|
|
2024
2125
|
duplicate_index += 1
|
2025
2126
|
rule.uid = "#{base_uid} (#{duplicate_index})"
|
2026
2127
|
end
|
2027
|
-
logger.trace
|
2128
|
+
logger.trace { "Adding rule: #{rule}" }
|
2028
2129
|
unmanaged_rule = Core.automation_manager.add_unmanaged_rule(rule)
|
2029
2130
|
provider.add(unmanaged_rule)
|
2030
2131
|
unmanaged_rule
|
@@ -26,8 +26,9 @@ module OpenHAB
|
|
26
26
|
class << self
|
27
27
|
# get the block's source location, and simplify to a simple filename
|
28
28
|
def infer_rule_id_from_block(block)
|
29
|
-
file = File.basename(block.source_location.first)
|
30
|
-
"
|
29
|
+
file = File.basename(block.source_location.first, ".rb")
|
30
|
+
file = "script:#{$ctx["ruleUID"]}" if $ctx&.key?("ruleUID") && file == "<script>"
|
31
|
+
"#{file}:#{block.source_location.last}".tr(".", "_")
|
31
32
|
end
|
32
33
|
|
33
34
|
# formulate a readable rule name such as "TestSwitch received command ON" if possible
|
@@ -47,8 +48,6 @@ module OpenHAB
|
|
47
48
|
infer_rule_name_from_trigger(*config.ruby_triggers.first)
|
48
49
|
end
|
49
50
|
|
50
|
-
private
|
51
|
-
|
52
51
|
# formulate a readable rule name from a single trigger if possible
|
53
52
|
def infer_rule_name_from_trigger(trigger, items = nil, kwargs = {})
|
54
53
|
case trigger
|
@@ -64,11 +63,15 @@ module OpenHAB
|
|
64
63
|
infer_rule_name_from_item_registry_trigger(trigger)
|
65
64
|
when :thing_added, :thing_removed, :thing_updated
|
66
65
|
infer_rule_name_from_thing_trigger(trigger)
|
66
|
+
when :time_series_updated
|
67
|
+
infer_rule_name_from_time_series_trigger(items)
|
67
68
|
when :on_start
|
68
69
|
infer_rule_name_from_on_start_trigger(items)
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
73
|
+
private
|
74
|
+
|
72
75
|
# formulate a readable rule name from an item-type trigger
|
73
76
|
def infer_rule_name_from_item_trigger(trigger, items, kwargs)
|
74
77
|
kwargs.delete(:command) if kwargs[:command] == [nil]
|
@@ -83,10 +86,10 @@ module OpenHAB
|
|
83
86
|
|
84
87
|
trigger_name = trigger.to_s.tr("_", " ")
|
85
88
|
item_names = items.map do |item|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
89
|
+
case item
|
90
|
+
when GroupItem::Members then "#{item.group.name}.members"
|
91
|
+
when Core::Items::Item then item.name
|
92
|
+
else item.to_s
|
90
93
|
end
|
91
94
|
end
|
92
95
|
name = "#{format_array(item_names)} #{trigger_name}"
|
@@ -136,6 +139,11 @@ module OpenHAB
|
|
136
139
|
}[trigger]
|
137
140
|
end
|
138
141
|
|
142
|
+
# formulate a readable rule name from a time series updated trigger
|
143
|
+
def infer_rule_name_from_time_series_trigger(items)
|
144
|
+
"#{format_array(items.map(&:name))} time series updated"
|
145
|
+
end
|
146
|
+
|
139
147
|
# formulate a readable rule name from an on_start trigger
|
140
148
|
def infer_rule_name_from_on_start_trigger(levels)
|
141
149
|
levels = levels.map { |level| "#{level} (#{start_level_description(level)})" }
|
@@ -13,8 +13,10 @@ module OpenHAB
|
|
13
13
|
# and a setter with any number of arguments or a block.
|
14
14
|
#
|
15
15
|
# @param [String] name of the property
|
16
|
+
# @yield Block to call when the property is set
|
17
|
+
# @yieldparam [Object] value the value being set
|
16
18
|
#
|
17
|
-
def prop(name)
|
19
|
+
def prop(name, &assignment_block)
|
18
20
|
# rubocop rules are disabled because this method is dynamically defined on the calling
|
19
21
|
# object making calls to other methods in this module impossible, or if done on methods
|
20
22
|
# in this module than instance variable belong to the module not the calling class
|
@@ -30,6 +32,7 @@ module OpenHAB
|
|
30
32
|
elsif block
|
31
33
|
instance_variable_set(:"@#{name}", block)
|
32
34
|
end
|
35
|
+
assignment_block&.call(instance_variable_get(:"@#{name}"))
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
@@ -41,9 +41,9 @@ module OpenHAB
|
|
41
41
|
#
|
42
42
|
# @return [org.openhab.core.automation.Trigger] openHAB trigger
|
43
43
|
#
|
44
|
-
def append_trigger(type:, config:, attach: nil, conditions: nil)
|
44
|
+
def append_trigger(type:, config:, attach: nil, conditions: nil, label: nil)
|
45
45
|
config.transform_keys!(&:to_s)
|
46
|
-
RuleTriggers.trigger(type: type, config: config).tap do |trigger|
|
46
|
+
RuleTriggers.trigger(type: type, config: config, label: label).tap do |trigger|
|
47
47
|
logger.trace("Appending trigger (#{trigger.inspect}) attach (#{attach}) conditions(#{conditions})")
|
48
48
|
@triggers << trigger
|
49
49
|
@attachments[trigger.id] = attach if attach
|
@@ -56,15 +56,17 @@ module OpenHAB
|
|
56
56
|
#
|
57
57
|
# @param [String] type of trigger
|
58
58
|
# @param [Map] config map
|
59
|
+
# @param [String] label for the trigger
|
59
60
|
#
|
60
61
|
# @return [org.openhab.core.automation.Trigger] configured by type and supplied config
|
61
62
|
#
|
62
|
-
def self.trigger(type:, config:)
|
63
|
+
def self.trigger(type:, config:, label: nil)
|
63
64
|
logger.trace("Creating trigger of type '#{type}' config: #{config}")
|
64
65
|
org.openhab.core.automation.util.TriggerBuilder.create
|
65
66
|
.with_id(uuid)
|
66
67
|
.with_type_uid(type)
|
67
68
|
.with_configuration(Core::Configuration.new(config))
|
69
|
+
.with_label(label)
|
68
70
|
.build
|
69
71
|
end
|
70
72
|
|
@@ -20,29 +20,46 @@ module OpenHAB
|
|
20
20
|
class << self
|
21
21
|
# @!visibility private
|
22
22
|
# @!macro def_terse_rule
|
23
|
-
# @!method $1(
|
23
|
+
# @!method $1(
|
24
|
+
# *args,
|
25
|
+
# id: nil,
|
26
|
+
# name :nil,
|
27
|
+
# description: nil,
|
28
|
+
# tag: nil,
|
29
|
+
# tags: nil,
|
30
|
+
# on_load: false,
|
31
|
+
# **kwargs,
|
32
|
+
# &block)
|
24
33
|
# Create a new rule with a $1 trigger.
|
25
|
-
# @param name [String] The name for the rule.
|
26
34
|
# @param id [String] The ID for the rule.
|
35
|
+
# @param name [String] The name for the rule.
|
36
|
+
# @param description [String, nil] The description for the rule.
|
37
|
+
# @param tag [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil]
|
38
|
+
# Tags to assign to the script
|
39
|
+
# @param tags [String, Symbol, Semantics::Tag, Array<String, Symbol, Semantics::Tag>, nil]
|
40
|
+
# Fluent alias for `tag`
|
27
41
|
# @param on_load [true, false] If the rule should _also_ trigger immediately when the script loads.
|
28
42
|
# @yield The execution block for the rule.
|
29
43
|
# @return [void]
|
30
44
|
# @see BuilderDSL#$1
|
31
45
|
def def_terse_rule(trigger)
|
32
46
|
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
33
|
-
def #{trigger}(*args,
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
47
|
+
def #{trigger}(*args, id: nil, name: nil, description: nil, # def changed(*args, id: nil, name: nil, description: nil,
|
48
|
+
tag: nil, tags: nil, on_load: false, **kwargs, &block) # tag: nil, tags: nil, on_load: false, **kwargs, &block)
|
49
|
+
raise ArgumentError, "Block is required" unless block # raise ArgumentError, "Block is required" unless block
|
50
|
+
#
|
51
|
+
id ||= NameInference.infer_rule_id_from_block(block) # id ||= NameInference.infer_rule_id_from_block(block)
|
52
|
+
script = block.source rescue nil # script = block.source rescue nil
|
53
|
+
caller_binding = block.binding # caller_binding = block.binding
|
54
|
+
rule name, id: id, script: script, binding: caller_binding do # rule name, id: id, script: script, binding: caller_binding do
|
55
|
+
self.on_load if on_load # self.on_load if on_load
|
56
|
+
self.description(description) if description # self.description(description) if description
|
57
|
+
self.tags(*Array.wrap(tag), *Array.wrap(tags)) # self.tags(*Array.wrap(tag), *Array.wrap(tags))
|
58
|
+
#{trigger}(*args, **kwargs) # changed(*args, **kwargs)
|
59
|
+
run(&block) # run(&block)
|
60
|
+
end # end
|
61
|
+
end # end
|
62
|
+
module_function #{trigger.inspect} # module_function :changed
|
46
63
|
RUBY
|
47
64
|
end
|
48
65
|
end
|
@@ -19,18 +19,26 @@ module OpenHAB
|
|
19
19
|
# @param [Core::Items::Item, Core::Items::GroupItem::Members] item item to create trigger for
|
20
20
|
# @param [Core::Types::State, Symbol, #===, nil] from state to restrict trigger to
|
21
21
|
# @param [Core::Types::State, Symbol, #===, nil] to state to restrict trigger to
|
22
|
-
# @param [Duration, nil] duration duration to delay trigger until to state is met
|
22
|
+
# @param [Duration, Proc, nil] duration duration to delay trigger until to state is met
|
23
23
|
# @param [Object] attach object to be attached to the trigger
|
24
24
|
#
|
25
25
|
# @return [org.openhab.core.automation.Trigger] openHAB triggers
|
26
26
|
#
|
27
27
|
def trigger(item:, from:, to:, duration:, attach:)
|
28
28
|
if duration
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
if logger.trace?
|
30
|
+
item_name = item.respond_to?(:name) ? item.name : item.to_s
|
31
|
+
logger.trace("Creating Changed Wait Change Trigger for Item(#{item_name}) Duration(#{duration}) " \
|
32
|
+
"To(#{to}) From(#{from}) Attach(#{attach})")
|
33
|
+
end
|
32
34
|
conditions = Conditions::Duration.new(to: to, from: from, duration: duration)
|
33
|
-
|
35
|
+
label = NameInference.infer_rule_name_from_trigger(:changed,
|
36
|
+
[item],
|
37
|
+
from: from,
|
38
|
+
to: to,
|
39
|
+
duration: duration)
|
40
|
+
|
41
|
+
changed_trigger(item: item, from: nil, to: nil, attach: attach, conditions: conditions, label: label)
|
34
42
|
else
|
35
43
|
# swap from/to w/ nil if from/to need to be processed in Ruby
|
36
44
|
# rubocop:disable Style/ParallelAssignment
|
@@ -64,7 +72,7 @@ module OpenHAB
|
|
64
72
|
# @param [Object] attach object to be attached to the trigger
|
65
73
|
# @return [org.openhab.core.automation.Trigger]
|
66
74
|
#
|
67
|
-
def changed_trigger(item:, from:, to:, attach: nil, conditions: nil)
|
75
|
+
def changed_trigger(item:, from:, to:, attach: nil, conditions: nil, label: nil)
|
68
76
|
type, config = case item
|
69
77
|
when GroupItem::Members
|
70
78
|
group(group: item, from: from, to: to)
|
@@ -74,7 +82,7 @@ module OpenHAB
|
|
74
82
|
else
|
75
83
|
item(item: item, from: from, to: to)
|
76
84
|
end
|
77
|
-
append_trigger(type: type, config: config, attach: attach, conditions: conditions)
|
85
|
+
append_trigger(type: type, config: config, attach: attach, conditions: conditions, label: label)
|
78
86
|
end
|
79
87
|
|
80
88
|
#
|
@@ -12,7 +12,8 @@ module OpenHAB
|
|
12
12
|
#
|
13
13
|
class Cron < Trigger
|
14
14
|
# Trigger ID for Cron Triggers
|
15
|
-
|
15
|
+
# @deprecated OH 3.4
|
16
|
+
CRON_TRIGGER_MODULE_ID = if OpenHAB::Core.version >= OpenHAB::Core::V4_0
|
16
17
|
"timer.GenericCronTrigger"
|
17
18
|
else
|
18
19
|
# @deprecated OH3.4 We need to use a custom CronTrigger handler
|
@@ -211,7 +212,7 @@ module OpenHAB
|
|
211
212
|
#
|
212
213
|
def trigger(config:, attach:)
|
213
214
|
# @deprecated OH3.4 needs a custom CronTriggerHandlerFactory
|
214
|
-
if
|
215
|
+
if OpenHAB::Core.version < OpenHAB::Core::V4_0
|
215
216
|
CronHandler::CronTriggerHandlerFactory.instance # ensure it's registered
|
216
217
|
end
|
217
218
|
append_trigger(type: CRON_TRIGGER_MODULE_ID, config: config, attach: attach)
|