openhab-scripting 5.16.0 → 5.18.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|