openhab-scripting 5.1.1 → 5.2.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 +2 -8
- data/lib/openhab/dsl/rules/builder.rb +23 -5
- data/lib/openhab/dsl/rules/rule_triggers.rb +2 -2
- data/lib/openhab/dsl/rules/triggers/changed.rb +19 -63
- data/lib/openhab/dsl/rules/triggers/command.rb +7 -67
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +16 -42
- data/lib/openhab/dsl/rules/triggers/conditions/generic.rb +59 -0
- data/lib/openhab/dsl/rules/triggers/conditions.rb +36 -0
- data/lib/openhab/dsl/rules/triggers/updated.rb +18 -51
- data/lib/openhab/dsl/version.rb +1 -1
- metadata +4 -3
- data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +0 -161
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d56223cd6766da527070ec31571d7a22cffa7d69ec754a1a1dbeb06c9354d56
|
4
|
+
data.tar.gz: c635cf86c119c54c4b665f28cd91b0804a58c868d23f7a99420d4183f60bf195
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79e7ac98695e1fb75a6bf100226a555d2d1d8f7a96efa0779b42439e262bfb63777ee99545782885f509c08f21dc77b2b504fd13078a5e5bc1d82ce456e3cca9
|
7
|
+
data.tar.gz: d735f987f2540cba7b358a4f0550ed723ef807b0a4c5e12ab21177cc844f65a2eec1080778b996e702cd72a5d744b1a7c97fe52ba5679a17a13b4988ccd2bf76
|
@@ -23,14 +23,8 @@ module OpenHAB
|
|
23
23
|
#
|
24
24
|
def play_sound(filename, sink: nil, volume: nil)
|
25
25
|
volume = PercentType.new(volume) unless volume.is_a?(PercentType) || volume.nil?
|
26
|
-
|
27
|
-
|
28
|
-
# and end up with argument type mismatched. So we need to give it a bit of help here.
|
29
|
-
if sink
|
30
|
-
playSound(sink.to_s, filename.to_s, volume)
|
31
|
-
else
|
32
|
-
playSound(filename.to_s, volume)
|
33
|
-
end
|
26
|
+
java_send :playSound, [java.lang.String, java.lang.String, PercentType.java_class],
|
27
|
+
sink, filename.to_s, volume
|
34
28
|
end
|
35
29
|
|
36
30
|
#
|
@@ -923,9 +923,9 @@ module OpenHAB
|
|
923
923
|
# triggering element was an item or a thing.
|
924
924
|
#
|
925
925
|
# @param [Item, GroupItem::Members, Thing] items Objects to create trigger for.
|
926
|
-
# @param [State, Array<State>,
|
926
|
+
# @param [State, Array<State>, #===, nil] from
|
927
927
|
# Only execute rule if previous state matches `from` state(s).
|
928
|
-
# @param [State, Array<State>,
|
928
|
+
# @param [State, Array<State>, #===, nil] to State(s) for
|
929
929
|
# Only execute rule if new state matches `to` state(s).
|
930
930
|
# @param [java.time.temporal.TemporalAmount] for
|
931
931
|
# Duration item must remain in the same state before executing the execution blocks.
|
@@ -982,6 +982,12 @@ module OpenHAB
|
|
982
982
|
# run { logger.info("Alarm Mode Updated") }
|
983
983
|
# end
|
984
984
|
#
|
985
|
+
# @example Works with regexes:
|
986
|
+
# rule "Execute when item state is changed to something matching a regex" do
|
987
|
+
# changed Alarm_Mode, to: /armed/
|
988
|
+
# run { logger.info("Alarm armed") }
|
989
|
+
# end
|
990
|
+
#
|
985
991
|
# @example Works with Things:
|
986
992
|
# rule "Execute rule when thing is changed" do
|
987
993
|
# changed things["astro:sun:home"], :from => :online, :to => :uninitialized
|
@@ -1299,8 +1305,8 @@ module OpenHAB
|
|
1299
1305
|
# {Core::Events::ItemCommandEvent}.
|
1300
1306
|
#
|
1301
1307
|
# @param [Item, GroupItem::Members] items Items to create trigger for
|
1302
|
-
# @param [Core::
|
1303
|
-
# @param [Array<Command>,
|
1308
|
+
# @param [Core::Types::Command, Array<Core::Types::Command>, #===, nil] command commands to match for trigger
|
1309
|
+
# @param [Array<Core::Types::Command>, #===, nil] commands Fluent alias for `command`
|
1304
1310
|
# @param [Object] attach object to be attached to the trigger
|
1305
1311
|
# @return [void]
|
1306
1312
|
#
|
@@ -1358,6 +1364,12 @@ module OpenHAB
|
|
1358
1364
|
# run { |event| logger.info("Item received command: #{event.command}" ) }
|
1359
1365
|
# end
|
1360
1366
|
#
|
1367
|
+
# @example Works with regexes
|
1368
|
+
# rule 'Execute rule when Alarm Mode command matches a substring' do
|
1369
|
+
# received_command Alarm_Mode, command: /arm/
|
1370
|
+
# run { |event| logger.info("Item received command: #{event.command}" ) }
|
1371
|
+
# end
|
1372
|
+
#
|
1361
1373
|
def received_command(*items, command: nil, commands: nil, attach: nil)
|
1362
1374
|
command_trigger = Command.new(rule_triggers: @rule_triggers)
|
1363
1375
|
|
@@ -1604,7 +1616,7 @@ module OpenHAB
|
|
1604
1616
|
#
|
1605
1617
|
# @param [Item, GroupItem::Members, Thing] items
|
1606
1618
|
# Objects to create trigger for.
|
1607
|
-
# @param [State, Array<State>,
|
1619
|
+
# @param [State, Array<State>, Symbol, String, #===, nil] to
|
1608
1620
|
# Only execute rule if the state matches `to` state(s). If the
|
1609
1621
|
# updated element is a {Core::Things::Thing}, the `to` accepts
|
1610
1622
|
# symbols and strings that match
|
@@ -1666,6 +1678,12 @@ module OpenHAB
|
|
1666
1678
|
# triggered { |item| logger.info("Group item #{item.name} updated")}
|
1667
1679
|
# end
|
1668
1680
|
#
|
1681
|
+
# @example Works with regexes:
|
1682
|
+
# rule 'Execute rule when member of group is changed to a substring' do
|
1683
|
+
# updated AlarmModes.members, to: /armed/
|
1684
|
+
# triggered { |item| logger.info("Group item #{item.name} updated")}
|
1685
|
+
# end
|
1686
|
+
#
|
1669
1687
|
# @example Works with things as well
|
1670
1688
|
# rule 'Execute rule when thing is updated' do
|
1671
1689
|
# updated things['astro:sun:home'], :to => :uninitialized
|
@@ -4,7 +4,7 @@ require "forwardable"
|
|
4
4
|
|
5
5
|
require "securerandom"
|
6
6
|
|
7
|
-
require_relative "triggers/conditions/
|
7
|
+
require_relative "triggers/conditions/generic"
|
8
8
|
|
9
9
|
module OpenHAB
|
10
10
|
module DSL
|
@@ -28,7 +28,7 @@ module OpenHAB
|
|
28
28
|
#
|
29
29
|
def initialize
|
30
30
|
@triggers = []
|
31
|
-
@trigger_conditions = Hash.new(Triggers::Conditions::
|
31
|
+
@trigger_conditions = Hash.new(Triggers::Conditions::Generic::ANY)
|
32
32
|
@attachments = {}
|
33
33
|
end
|
34
34
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "conditions/duration"
|
4
|
-
require_relative "conditions/
|
4
|
+
require_relative "conditions/generic"
|
5
5
|
require_relative "trigger"
|
6
6
|
|
7
7
|
module OpenHAB
|
@@ -17,8 +17,8 @@ module OpenHAB
|
|
17
17
|
# Create the trigger
|
18
18
|
#
|
19
19
|
# @param [Core::Items::Item, Core::Items::GroupItem::Members] item item to create trigger for
|
20
|
-
# @param [Core::Types::State,
|
21
|
-
# @param [Core::Types::State,
|
20
|
+
# @param [Core::Types::State, Symbol, #===, nil] from state to restrict trigger to
|
21
|
+
# @param [Core::Types::State, Symbol, #===, nil] to state to restrict trigger to
|
22
22
|
# @param [Duration, 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
|
#
|
@@ -26,13 +26,19 @@ module OpenHAB
|
|
26
26
|
#
|
27
27
|
def trigger(item:, from:, to:, duration:, attach:)
|
28
28
|
if duration
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
item_name = item.respond_to?(:name) ? item.name : item.to_s
|
30
|
+
logger.trace("Creating Changed Wait Change Trigger for Item(#{item_name}) Duration(#{duration}) " \
|
31
|
+
"To(#{to}) From(#{from}) Attach(#{attach})")
|
32
|
+
conditions = Conditions::Duration.new(to: to, from: from, duration: duration)
|
33
|
+
changed_trigger(item: item, from: nil, to: nil, attach: attach, conditions: conditions)
|
34
34
|
else
|
35
|
-
|
35
|
+
# swap from/to w/ nil if from/to need to be processed in Ruby
|
36
|
+
# rubocop:disable Style/ParallelAssignment
|
37
|
+
from_proc, from = from, nil unless Conditions.state?(from)
|
38
|
+
to_proc, to = to, nil unless Conditions.state?(to)
|
39
|
+
# rubocop:enable Style/ParallelAssignment
|
40
|
+
conditions = Conditions::Generic.new(from: from_proc, to: to_proc) unless from_proc.nil? && to_proc.nil?
|
41
|
+
changed_trigger(item: item, from: from, to: to, attach: attach, conditions: conditions)
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
@@ -40,71 +46,21 @@ module OpenHAB
|
|
40
46
|
|
41
47
|
# @return [String] A thing status Change trigger
|
42
48
|
THING_CHANGE = "core.ThingStatusChangeTrigger"
|
49
|
+
private_constant :THING_CHANGE
|
43
50
|
|
44
51
|
# @return [String] An item state change trigger
|
45
52
|
ITEM_STATE_CHANGE = "core.ItemStateChangeTrigger"
|
46
53
|
|
47
54
|
# @return [String] A group state change trigger for items in the group
|
48
55
|
GROUP_STATE_CHANGE = "core.GroupStateChangeTrigger"
|
49
|
-
|
50
|
-
#
|
51
|
-
# Create a TriggerDelay for for an item or group that is changed for a specific duration
|
52
|
-
#
|
53
|
-
# @param [Core::Items::Item, Core::Items::GroupItem::Members] item to create trigger delay for
|
54
|
-
# @param [Duration] duration to delay trigger for until condition is met
|
55
|
-
# @param [Core::Types::State, Array<Core::Types::State>, Range, Proc] to
|
56
|
-
# State item or group needs to change to
|
57
|
-
# @param [Core::Types::State, Array<Core::Types::State>, Range, Proc] from
|
58
|
-
# State item or group needs to be coming from
|
59
|
-
# @param [Object] attach object to be attached to the trigger
|
60
|
-
#
|
61
|
-
# @return [org.openhab.core.automation.Trigger]
|
62
|
-
#
|
63
|
-
def wait_trigger(item:, duration:, to: nil, from: nil, attach: nil)
|
64
|
-
item_name = item.respond_to?(:name) ? item.name : item.to_s
|
65
|
-
logger.trace("Creating Changed Wait Change Trigger for Item(#{item_name}) Duration(#{duration}) " \
|
66
|
-
"To(#{to}) From(#{from}) Attach(#{attach})")
|
67
|
-
conditions = Conditions::Duration.new(to: to, from: from, duration: duration)
|
68
|
-
changed_trigger(item: item, to: nil, from: nil, attach: attach, conditions: conditions)
|
69
|
-
end
|
70
|
-
|
71
|
-
#
|
72
|
-
# Creates a trigger with a range condition on either 'from' or 'to' field
|
73
|
-
# @param [Core::Items::Item, Core::Items::GroupItem::Members] item to create changed trigger on
|
74
|
-
# @param [Range] from state to restrict trigger to
|
75
|
-
# @param [Range] to state restrict trigger to
|
76
|
-
# @param [Object] attach object to be attached to the trigger
|
77
|
-
# @return [org.openhab.core.automation.Trigger]
|
78
|
-
#
|
79
|
-
def range_trigger(item:, from:, to:, attach:)
|
80
|
-
from, to = Conditions::Proc.range_procs(from, to)
|
81
|
-
proc_trigger(item: item, from: from, to: to, attach: attach)
|
82
|
-
end
|
83
|
-
|
84
|
-
#
|
85
|
-
# Creates a trigger with a proc condition on either 'from' or 'to' field
|
86
|
-
# @param [Core::Items::Item, Core::Items::GroupItem::Members] item to create changed trigger on
|
87
|
-
# @param [Proc] from state to restrict trigger to
|
88
|
-
# @param [Proc] to state restrict trigger to
|
89
|
-
# @param [Object] attach object to be attached to the trigger
|
90
|
-
# @return [org.openhab.core.automation.Trigger]
|
91
|
-
#
|
92
|
-
def proc_trigger(item:, from:, to:, attach:)
|
93
|
-
# swap from/to w/ nil if from/to is a proc
|
94
|
-
# rubocop:disable Style/ParallelAssignment
|
95
|
-
from_proc, from = from, nil if from.is_a?(Proc)
|
96
|
-
to_proc, to = to, nil if to.is_a?(Proc)
|
97
|
-
# rubocop:enable Style/ParallelAssignment
|
98
|
-
conditions = Conditions::Proc.new(to: to_proc, from: from_proc)
|
99
|
-
changed_trigger(item: item, from: from, to: to, attach: attach, conditions: conditions)
|
100
|
-
end
|
56
|
+
private_constant :GROUP_STATE_CHANGE
|
101
57
|
|
102
58
|
#
|
103
59
|
# Create a changed trigger
|
104
60
|
#
|
105
61
|
# @param [Core::Items::Item, Core::Items::GroupItem::Members] item to create changed trigger on
|
106
|
-
# @param [Core::
|
107
|
-
# @param [Core::
|
62
|
+
# @param [Core::Types::State, #===, nil] from state to restrict trigger to
|
63
|
+
# @param [Core::Types::State, #===, nil] to state restrict trigger to
|
108
64
|
# @param [Object] attach object to be attached to the trigger
|
109
65
|
# @return [org.openhab.core.automation.Trigger]
|
110
66
|
#
|
@@ -15,92 +15,32 @@ module OpenHAB
|
|
15
15
|
# Create a received command trigger
|
16
16
|
#
|
17
17
|
# @param [Object] item item to create trigger for
|
18
|
-
# @param [
|
18
|
+
# @param [Core::Types::State, Symbol, #===, nil] command to check against
|
19
19
|
# @param [Object] attach object to be attached to the trigger
|
20
20
|
#
|
21
21
|
# @return [org.openhab.core.automation.Trigger]
|
22
22
|
#
|
23
23
|
def trigger(item:, command:, attach:)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
else command_trigger(item: item, command: command, attach: attach)
|
24
|
+
unless Conditions.state?(command)
|
25
|
+
conditions = Conditions::Generic.new(command: command)
|
26
|
+
command = nil
|
28
27
|
end
|
29
|
-
end
|
30
|
-
|
31
|
-
#
|
32
|
-
# Creates a trigger with a range condition on the 'command' field
|
33
|
-
# @param [Object] item to create changed trigger on
|
34
|
-
# @param [Range] command to restrict trigger to
|
35
|
-
# @param [Object] attach object to be attached to the trigger
|
36
|
-
# @return [org.openhab.core.automation.Trigger]
|
37
|
-
#
|
38
|
-
def range_trigger(item:, command:, attach:)
|
39
|
-
command_range, * = Conditions::Proc.range_procs(command)
|
40
|
-
proc_trigger(item: item, command: command_range, attach: attach)
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# Creates a trigger with a proc condition on the 'command' field
|
45
|
-
# @param [Object] item to create changed trigger on
|
46
|
-
# @param [Object] command to restrict trigger to
|
47
|
-
# @param [Object] attach object to be attached to the trigger
|
48
|
-
# @return [org.openhab.core.automation.Trigger]
|
49
|
-
#
|
50
|
-
def proc_trigger(item:, command:, attach:)
|
51
|
-
conditions = Conditions::Proc.new(command: command)
|
52
|
-
command_trigger(item: item, command: nil, attach: attach, conditions: conditions)
|
53
|
-
end
|
54
28
|
|
55
|
-
#
|
56
|
-
# Create a received trigger based on item type
|
57
|
-
#
|
58
|
-
# @param [Object] item to create trigger for
|
59
|
-
# @param [String] command to create trigger for
|
60
|
-
# @param [Object] attach object to be attached to the trigger
|
61
|
-
# @return [org.openhab.core.automation.Trigger]
|
62
|
-
#
|
63
|
-
def command_trigger(item:, command:, attach: nil, conditions: nil)
|
64
29
|
type, config = if item.is_a?(GroupItem::Members)
|
65
|
-
group
|
30
|
+
[GROUP_COMMAND, { "groupName" => item.group.name }]
|
66
31
|
else
|
67
|
-
item
|
32
|
+
[ITEM_COMMAND, { "itemName" => item.name }]
|
68
33
|
end
|
69
34
|
config["command"] = command.to_s unless command.nil?
|
70
35
|
append_trigger(type: type, config: config, attach: attach, conditions: conditions)
|
71
36
|
end
|
72
37
|
|
73
|
-
private
|
74
|
-
|
75
38
|
# @return [String] item command trigger
|
76
39
|
ITEM_COMMAND = "core.ItemCommandTrigger"
|
77
40
|
|
78
41
|
# @return [String] A group command trigger for items in the group
|
79
42
|
GROUP_COMMAND = "core.GroupCommandTrigger"
|
80
|
-
|
81
|
-
#
|
82
|
-
# Create trigger for item commands
|
83
|
-
#
|
84
|
-
# @param [Item] item to create trigger for
|
85
|
-
#
|
86
|
-
# @return [Array<Hash,Trigger>] first element is hash of trigger config properties
|
87
|
-
# second element is trigger type
|
88
|
-
#
|
89
|
-
def item(item:)
|
90
|
-
[ITEM_COMMAND, { "itemName" => item.name }]
|
91
|
-
end
|
92
|
-
|
93
|
-
#
|
94
|
-
# Create trigger for group items
|
95
|
-
#
|
96
|
-
# @param [GroupItem::Members] group to create trigger for
|
97
|
-
#
|
98
|
-
# @return [Array<Hash,Trigger>] first element is hash of trigger config properties
|
99
|
-
# second element is trigger type
|
100
|
-
#
|
101
|
-
def group(group:)
|
102
|
-
[GROUP_COMMAND, { "groupName" => group.group.name }]
|
103
|
-
end
|
43
|
+
private_constant :GROUP_COMMAND
|
104
44
|
end
|
105
45
|
end
|
106
46
|
end
|
@@ -19,11 +19,9 @@ module OpenHAB
|
|
19
19
|
# @param [java.time.temporal.TemporalAmount] duration to state must stay at specific value before triggering
|
20
20
|
#
|
21
21
|
def initialize(to:, from:, duration:)
|
22
|
-
|
23
|
-
from = Conditions::Proc.from_value(from)
|
24
|
-
@conditions = Conditions::Proc.new(to: to, from: from)
|
22
|
+
@conditions = Generic.new(to: to, from: from)
|
25
23
|
@duration = duration
|
26
|
-
@
|
24
|
+
@timers = {}
|
27
25
|
logger.trace "Created Duration Condition To(#{to}) From(#{from}) " \
|
28
26
|
"Conditions(#{@conditions}) Duration(#{@duration})"
|
29
27
|
end
|
@@ -32,9 +30,10 @@ module OpenHAB
|
|
32
30
|
# @param [Hash] inputs inputs from trigger
|
33
31
|
#
|
34
32
|
def process(mod:, inputs:, &block)
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
timer = @timers[inputs["triggeringItem"]&.name]
|
34
|
+
if timer&.active?
|
35
|
+
process_active_timer(timer, inputs, mod, &block)
|
36
|
+
elsif @conditions.process(mod: mod, inputs: inputs)
|
38
37
|
logger.trace("Trigger Guards Matched for #{self}, delaying rule execution")
|
39
38
|
# Add timer and attach timer to delay object, and also state being tracked to so
|
40
39
|
# timer can be cancelled if state changes
|
@@ -49,38 +48,11 @@ module OpenHAB
|
|
49
48
|
#
|
50
49
|
# Cancels the timer, if it's active
|
51
50
|
def cleanup
|
52
|
-
@
|
51
|
+
@timers.each_value(&:cancel)
|
53
52
|
end
|
54
53
|
|
55
54
|
private
|
56
55
|
|
57
|
-
#
|
58
|
-
# Check if trigger guards prevent rule execution
|
59
|
-
#
|
60
|
-
# @param [java.util.Map] inputs map object describing rule trigger
|
61
|
-
#
|
62
|
-
# @return [true,false] True if the rule should execute, false if trigger guard prevents execution
|
63
|
-
#
|
64
|
-
def check_trigger_guards(inputs)
|
65
|
-
new_state, old_state = retrieve_states(inputs)
|
66
|
-
@conditions.check_from(state: old_state) && @conditions.check_to(state: new_state)
|
67
|
-
end
|
68
|
-
|
69
|
-
#
|
70
|
-
# Rerieve the newState and oldState, alternatively newStatus and oldStatus
|
71
|
-
# from the input map
|
72
|
-
#
|
73
|
-
# @param [java.util.Map] inputs map object describing rule trigger
|
74
|
-
#
|
75
|
-
# @return [Array] An array of the values for [newState, oldState] or [newStatus, oldStatus]
|
76
|
-
#
|
77
|
-
def retrieve_states(inputs)
|
78
|
-
new_state = inputs["newState"] || inputs["newStatus"]&.to_s&.downcase&.to_sym
|
79
|
-
old_state = inputs["oldState"] || inputs["oldStatus"]&.to_s&.downcase&.to_sym
|
80
|
-
|
81
|
-
[new_state, old_state]
|
82
|
-
end
|
83
|
-
|
84
56
|
#
|
85
57
|
# Creates a timer for trigger delays
|
86
58
|
#
|
@@ -90,13 +62,14 @@ module OpenHAB
|
|
90
62
|
#
|
91
63
|
def create_trigger_delay_timer(inputs, _mod)
|
92
64
|
logger.trace("Creating timer for trigger delay #{self}")
|
93
|
-
|
65
|
+
item_name = inputs["triggeringItem"]&.name
|
66
|
+
@timers[item_name] = DSL.after(@duration) do
|
94
67
|
logger.trace("Delay Complete for #{self}, executing rule")
|
95
|
-
@
|
68
|
+
@timers.delete(item_name)
|
96
69
|
yield
|
97
70
|
end
|
98
71
|
rule.on_removal(self)
|
99
|
-
|
72
|
+
@tracking_from = Conditions.old_state_from(inputs)
|
100
73
|
end
|
101
74
|
|
102
75
|
#
|
@@ -105,13 +78,14 @@ module OpenHAB
|
|
105
78
|
# @param [Hash] inputs rule trigger inputs
|
106
79
|
# @param [Hash] mod rule trigger mods
|
107
80
|
#
|
108
|
-
def process_active_timer(inputs, mod, &block)
|
109
|
-
|
110
|
-
|
81
|
+
def process_active_timer(timer, inputs, mod, &block)
|
82
|
+
old_state = Conditions.old_state_from(inputs)
|
83
|
+
new_state = Conditions.new_state_from(inputs)
|
84
|
+
if new_state != @tracking_from && @conditions.process(mod: nil, inputs: { "state" => new_state })
|
111
85
|
logger.trace("Item changed from #{old_state} to #{new_state} for #{self}, keep waiting.")
|
112
86
|
else
|
113
87
|
logger.trace("Item changed from #{old_state} to #{new_state} for #{self}, canceling timer.")
|
114
|
-
|
88
|
+
timer.cancel
|
115
89
|
# Reprocess trigger delay after canceling to track new state (if guards matched, etc)
|
116
90
|
process(mod: mod, inputs: inputs, &block)
|
117
91
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module DSL
|
5
|
+
module Rules
|
6
|
+
module Triggers
|
7
|
+
# @!visibility private
|
8
|
+
module Conditions
|
9
|
+
#
|
10
|
+
# This creates trigger conditions that work on procs
|
11
|
+
#
|
12
|
+
class Generic
|
13
|
+
#
|
14
|
+
# Create a new Condition that executes only if procs return true
|
15
|
+
# @param [#===, nil] from Value to check against `from` state
|
16
|
+
# @param [#===, nil] to Value to check against `to` state
|
17
|
+
# @param [#===, nil] command Value to check against received command
|
18
|
+
#
|
19
|
+
def initialize(from: nil, to: nil, command: nil)
|
20
|
+
@from = from
|
21
|
+
@to = to
|
22
|
+
@command = command
|
23
|
+
end
|
24
|
+
|
25
|
+
ANY = Generic.new.freeze # this needs to be defined _after_ initialize so its instance variables are set
|
26
|
+
|
27
|
+
#
|
28
|
+
# Process rule
|
29
|
+
# @param [Hash] inputs inputs from trigger
|
30
|
+
# @return [true, false] if the conditions passed (and therefore the block was run)
|
31
|
+
#
|
32
|
+
def process(mod:, inputs:) # rubocop:disable Lint/UnusedMethodArgument - mod is unused here but required
|
33
|
+
logger.trace("Checking #{inputs} against condition trigger #{self}")
|
34
|
+
unless check_value(Conditions.old_state_from(inputs), @from) &&
|
35
|
+
check_value(Conditions.new_state_from(inputs), @to) &&
|
36
|
+
check_value(inputs["command"], @command)
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
40
|
+
yield if block_given?
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def check_value(value, expected_value)
|
47
|
+
return true if value.nil?
|
48
|
+
|
49
|
+
return true if expected_value.nil?
|
50
|
+
|
51
|
+
# works for procs, ranges, regexes, etc.
|
52
|
+
expected_value === value # rubocop:disable Style/CaseEquality
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module DSL
|
5
|
+
module Rules
|
6
|
+
module Triggers
|
7
|
+
# @!visibility private
|
8
|
+
module Conditions
|
9
|
+
class << self
|
10
|
+
# If a given value can be passed directly to openHAB's trigger handler configuration
|
11
|
+
# @return [true, false]
|
12
|
+
def state?(value)
|
13
|
+
value.nil? ||
|
14
|
+
value.is_a?(Core::Types::Type) ||
|
15
|
+
value.is_a?(String) ||
|
16
|
+
value.is_a?(Symbol) ||
|
17
|
+
value.is_a?(Numeric)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Retrieves the previous item state or things status from inputs
|
21
|
+
# @return [Core::Types::Type, Symbol, nil]
|
22
|
+
def old_state_from(inputs)
|
23
|
+
inputs["oldState"] || inputs["oldStatus"]&.to_s&.downcase&.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieves the new item state or thing status from inputs
|
27
|
+
# @return [Core::Types::Type, Symbol, nil]
|
28
|
+
def new_state_from(inputs)
|
29
|
+
inputs["newState"] || inputs["state"] || inputs["newStatus"]&.to_s&.downcase&.to_sym
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -15,75 +15,42 @@ module OpenHAB
|
|
15
15
|
# Create the trigger
|
16
16
|
#
|
17
17
|
# @param [Object] item item to create trigger for
|
18
|
-
# @param [
|
18
|
+
# @param [Core::Types::State, Symbol, #===, nil] to state to restrict trigger to
|
19
19
|
# @param [Object] attach object to be attached to the trigger
|
20
20
|
#
|
21
21
|
# @return [org.openhab.core.automation.Trigger]
|
22
22
|
#
|
23
23
|
def trigger(item:, to:, attach:)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
else update_trigger(item: item, to: to, attach: attach)
|
24
|
+
unless Conditions.state?(to)
|
25
|
+
conditions = Conditions::Generic.new(to: to)
|
26
|
+
to = nil
|
28
27
|
end
|
28
|
+
|
29
|
+
type, config = case item
|
30
|
+
when GroupItem::Members
|
31
|
+
group_update(item: item, to: to)
|
32
|
+
when Core::Things::Thing,
|
33
|
+
Core::Things::ThingUID
|
34
|
+
thing_update(thing: item, to: to)
|
35
|
+
else
|
36
|
+
item_update(item: item, to: to)
|
37
|
+
end
|
38
|
+
append_trigger(type: type, config: config, attach: attach, conditions: conditions)
|
29
39
|
end
|
30
40
|
|
31
41
|
private
|
32
42
|
|
33
43
|
# @return [String] A thing status update trigger
|
34
44
|
THING_UPDATE = "core.ThingStatusUpdateTrigger"
|
45
|
+
private_constant :THING_UPDATE
|
35
46
|
|
36
47
|
# @return [String] An item state update trigger
|
37
48
|
ITEM_STATE_UPDATE = "core.ItemStateUpdateTrigger"
|
49
|
+
private_constant :ITEM_STATE_UPDATE
|
38
50
|
|
39
51
|
# @return [String] A group state update trigger for items in the group
|
40
52
|
GROUP_STATE_UPDATE = "core.GroupStateUpdateTrigger"
|
41
|
-
|
42
|
-
#
|
43
|
-
# Creates a trigger with a range condition on the 'to' field
|
44
|
-
# @param [Object] item to create changed trigger on
|
45
|
-
# @param [Object] to state restrict trigger to
|
46
|
-
# @param [Object] attach object to be attached to the trigger
|
47
|
-
# @return [org.openhab.core.automation.Trigger]
|
48
|
-
#
|
49
|
-
def range_trigger(item:, to:, attach:)
|
50
|
-
to, * = Conditions::Proc.range_procs(to)
|
51
|
-
proc_trigger(item: item, to: to, attach: attach)
|
52
|
-
end
|
53
|
-
|
54
|
-
#
|
55
|
-
# Creates a trigger with a proc condition on the 'to' field
|
56
|
-
# @param [Object] item to create changed trigger on
|
57
|
-
# @param [Object] to state restrict trigger to
|
58
|
-
# @param [Object] attach object to be attached to the trigger
|
59
|
-
# @return [org.openhab.core.automation.Trigger]
|
60
|
-
#
|
61
|
-
def proc_trigger(item:, to:, attach:)
|
62
|
-
conditions = Conditions::Proc.new(to: to)
|
63
|
-
update_trigger(item: item, to: nil, attach: attach, conditions: conditions)
|
64
|
-
end
|
65
|
-
|
66
|
-
#
|
67
|
-
# Create a trigger for updates
|
68
|
-
#
|
69
|
-
# @param [Object] item Type of item [Group,Thing,Item] to create update trigger for
|
70
|
-
# @param [State] to state restriction on trigger
|
71
|
-
# @param [Object] attach object to be attached to the trigger
|
72
|
-
#
|
73
|
-
# @return [org.openhab.core.automation.Trigger]
|
74
|
-
#
|
75
|
-
def update_trigger(item:, to:, attach: nil, conditions: nil)
|
76
|
-
type, config = case item
|
77
|
-
when GroupItem::Members
|
78
|
-
group_update(item: item, to: to)
|
79
|
-
when Core::Things::Thing,
|
80
|
-
Core::Things::ThingUID
|
81
|
-
thing_update(thing: item, to: to)
|
82
|
-
else
|
83
|
-
item_update(item: item, to: to)
|
84
|
-
end
|
85
|
-
append_trigger(type: type, config: config, attach: attach, conditions: conditions)
|
86
|
-
end
|
53
|
+
private_constant :GROUP_STATE_UPDATE
|
87
54
|
|
88
55
|
#
|
89
56
|
# Create an update trigger for an item
|
data/lib/openhab/dsl/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openhab-scripting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian O'Connell
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-
|
13
|
+
date: 2023-05-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -527,8 +527,9 @@ files:
|
|
527
527
|
- lib/openhab/dsl/rules/triggers/changed.rb
|
528
528
|
- lib/openhab/dsl/rules/triggers/channel.rb
|
529
529
|
- lib/openhab/dsl/rules/triggers/command.rb
|
530
|
+
- lib/openhab/dsl/rules/triggers/conditions.rb
|
530
531
|
- lib/openhab/dsl/rules/triggers/conditions/duration.rb
|
531
|
-
- lib/openhab/dsl/rules/triggers/conditions/
|
532
|
+
- lib/openhab/dsl/rules/triggers/conditions/generic.rb
|
532
533
|
- lib/openhab/dsl/rules/triggers/cron/cron.rb
|
533
534
|
- lib/openhab/dsl/rules/triggers/cron/cron_handler.rb
|
534
535
|
- lib/openhab/dsl/rules/triggers/trigger.rb
|
@@ -1,161 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module OpenHAB
|
4
|
-
module DSL
|
5
|
-
module Rules
|
6
|
-
module Triggers
|
7
|
-
# @!visibility private
|
8
|
-
module Conditions
|
9
|
-
#
|
10
|
-
# This creates trigger conditions that work on procs
|
11
|
-
# @param [Proc] from Proc
|
12
|
-
# @param [Proc] to Proc
|
13
|
-
#
|
14
|
-
class Proc
|
15
|
-
#
|
16
|
-
# Converts supplied ranges to procs that check range
|
17
|
-
# @param [Array] ranges objects to convert to range proc if they are ranges
|
18
|
-
# @return [Array] of procs or supplied arguments if argument was not of type Range
|
19
|
-
#
|
20
|
-
def self.range_procs(*ranges)
|
21
|
-
ranges.map { |range| range.is_a?(Range) ? range_proc(range) : range }
|
22
|
-
end
|
23
|
-
|
24
|
-
#
|
25
|
-
# Create a range proc for the supplied range object
|
26
|
-
# @param [Range] range to build proc for
|
27
|
-
#
|
28
|
-
def self.range_proc(range)
|
29
|
-
logger.trace("Creating range proc for #{range}")
|
30
|
-
lambda do |val|
|
31
|
-
logger.trace("Range proc checking if #{val} is in #{range}")
|
32
|
-
range.cover? val
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
#
|
37
|
-
# Create an equality proc for the supplied range object
|
38
|
-
# @param [State] value to build proc for
|
39
|
-
#
|
40
|
-
def self.equality_proc(value)
|
41
|
-
logger.trace("Creating equality proc for #{value}")
|
42
|
-
lambda do |state|
|
43
|
-
logger.trace("Equality proc comparing #{value} against #{state}")
|
44
|
-
value == state
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
#
|
49
|
-
# Constructs a proc for the specific value type
|
50
|
-
# if the value is a proc return the proc
|
51
|
-
# if the value is a range create a range proc
|
52
|
-
# if the value is nil, return nil
|
53
|
-
# otherwise create an equality proc
|
54
|
-
# @param [Object] value to construct proc from
|
55
|
-
def self.from_value(value)
|
56
|
-
logger.trace("Creating proc for Value(#{value})")
|
57
|
-
return value if value.nil?
|
58
|
-
return value if value.is_a?(::Proc)
|
59
|
-
return range_proc(value) if value.is_a?(Range)
|
60
|
-
|
61
|
-
equality_proc(value)
|
62
|
-
end
|
63
|
-
|
64
|
-
#
|
65
|
-
# Create a new Proc Condition that executes only if procs return true
|
66
|
-
# @param [Proc] from Proc to check against from value
|
67
|
-
# @param [Proc] to Proc to check against to value
|
68
|
-
#
|
69
|
-
def initialize(from: nil, to: nil, command: nil)
|
70
|
-
@from = from
|
71
|
-
@to = to
|
72
|
-
@command = command
|
73
|
-
end
|
74
|
-
|
75
|
-
# Proc that doesn't check any fields
|
76
|
-
ANY = Proc.new.freeze # this needs to be defined _after_ initialize so its instance variables are set
|
77
|
-
|
78
|
-
#
|
79
|
-
# Process rule
|
80
|
-
# @param [Hash] inputs inputs from trigger
|
81
|
-
#
|
82
|
-
def process(mod:, inputs:) # rubocop:disable Lint/UnusedMethodArgument - mod is unused here but required
|
83
|
-
logger.trace("Checking #{inputs} against condition trigger #{self}")
|
84
|
-
yield if check_procs(inputs: inputs)
|
85
|
-
end
|
86
|
-
|
87
|
-
#
|
88
|
-
# Check if command condition match the proc
|
89
|
-
# @param [Hash] inputs from trigger must be supplied if state is not supplied
|
90
|
-
# @return [true/false] depending on if from is set and matches supplied conditions
|
91
|
-
#
|
92
|
-
def check_command(inputs: nil)
|
93
|
-
command = input_state(inputs, "command")
|
94
|
-
logger.trace "Checking command(#{@command}) against command(#{command})"
|
95
|
-
check_proc(proc: @command, value: command)
|
96
|
-
end
|
97
|
-
|
98
|
-
#
|
99
|
-
# Check if from condition match the proc
|
100
|
-
# @param [Hash] inputs from trigger must be supplied if state is not supplied
|
101
|
-
# @param [String] state if supplied proc will be passed state value for comparision
|
102
|
-
# @return [true/false] depending on if from is set and matches supplied conditions
|
103
|
-
#
|
104
|
-
def check_from(inputs: nil, state: nil)
|
105
|
-
state ||= input_state(inputs, "oldState")
|
106
|
-
logger.trace "Checking from(#{@from}) against state(#{state})"
|
107
|
-
check_proc(proc: @from, value: state)
|
108
|
-
end
|
109
|
-
|
110
|
-
#
|
111
|
-
# Check if to conditions match the proc
|
112
|
-
# @param [Hash] inputs from trigger must be supplied if state is not supplied
|
113
|
-
# @param [String] state if supplied proc will be passed state value for comparision
|
114
|
-
# @return [true/false] depending on if from is set and matches supplied conditions
|
115
|
-
#
|
116
|
-
def check_to(inputs: nil, state: nil)
|
117
|
-
state ||= input_state(inputs, "newState", "state")
|
118
|
-
logger.trace "Checking to(#{@to}) against state(#{state})"
|
119
|
-
check_proc(proc: @to, value: state)
|
120
|
-
end
|
121
|
-
|
122
|
-
# Describe the Proc Condition as a string
|
123
|
-
# @return [String] string representation of proc condition
|
124
|
-
#
|
125
|
-
def to_s
|
126
|
-
"From:(#{@from}) To:(#{@to}) Command:(#{@command})"
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
#
|
132
|
-
# Check all procs
|
133
|
-
# @param [Hash] inputs from event
|
134
|
-
# @return [true/false] true if all procs return true, false otherwise
|
135
|
-
def check_procs(inputs:)
|
136
|
-
check_from(inputs: inputs) && check_to(inputs: inputs) && check_command(inputs: inputs)
|
137
|
-
end
|
138
|
-
|
139
|
-
# Check if a field matches the proc condition
|
140
|
-
# @param [Proc] proc to call
|
141
|
-
# @param [Hash] value to check
|
142
|
-
# @return [true,false] true if proc is nil or proc.call returns true, false otherwise
|
143
|
-
def check_proc(proc:, value:)
|
144
|
-
return true if proc.nil? || proc.call(value)
|
145
|
-
|
146
|
-
logger.trace("Skipped execution of rule because value #{value} evaluated false for (#{proc})")
|
147
|
-
false
|
148
|
-
end
|
149
|
-
|
150
|
-
# Get the first field from supplied fields in inputs
|
151
|
-
# @param [Hash] inputs containing fields
|
152
|
-
# @param [Array] fields array of fields to extract from inputs, first one found is returned
|
153
|
-
def input_state(inputs, *fields)
|
154
|
-
fields.map { |f| inputs[f] }.compact.first
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|