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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17db43cc91f70e705ab8002d2653afe72cad963ad92907d9535ee906082cca97
4
- data.tar.gz: 0cf4c4c56fbf427fbf37a47571b20294176b29a89140428cb2b6f29c495c5a92
3
+ metadata.gz: 3d56223cd6766da527070ec31571d7a22cffa7d69ec754a1a1dbeb06c9354d56
4
+ data.tar.gz: c635cf86c119c54c4b665f28cd91b0804a58c868d23f7a99420d4183f60bf195
5
5
  SHA512:
6
- metadata.gz: 0a20f62e3c416f1801d92216a64495737cacb017257644506040c8412908ffa15575356707c947757160b9d03ff340a6c8abeab25924bdca2f79979f63b0a148
7
- data.tar.gz: ce9de9508194ae985223f92457184bb1c42af089605171950d13cdbf93d132a1955dcd8d9773a9749272ec13a3c956d4b0788e1cc632e50900204568c0276181
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
- # JRuby calls the wrong overloaded method when volume is given, but sink is nil
27
- # will call playSound(String, String, float) instead of playSound(String, String, PercentType)
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>, Range, Proc] from
926
+ # @param [State, Array<State>, #===, nil] from
927
927
  # Only execute rule if previous state matches `from` state(s).
928
- # @param [State, Array<State>, Range, Proc] to State(s) for
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::TypesCommand, Array<Command>, Range, Proc] command commands to match for trigger
1303
- # @param [Array<Command>, Range, Proc] commands Fluent alias for `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>, Range, Proc, Symbol, String] to
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/proc"
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::Proc::ANY)
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/proc"
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, Array<Core::Types::State>, Range, Proc] from state to restrict trigger to
21
- # @param [Core::Types::State, Array<Core::Types::State>, Range, Proc] to state to restrict trigger to
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
- wait_trigger(item: item, from: from, to: to, duration: duration, attach: attach)
30
- elsif [to, from].grep(Range).any?
31
- range_trigger(item: item, from: from, to: to, attach: attach)
32
- elsif [to, from].grep(Proc).any?
33
- proc_trigger(item: item, from: from, to: to, attach: attach)
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
- changed_trigger(item: item, from: from, to: to, attach: attach)
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::Items::State, Array<Core::Items::State>] from state to restrict trigger to
107
- # @param [Core::Items::State, Array<Core::Items::State>] to state restrict trigger to
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 [Object] command to check against
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
- case command
25
- when Range then range_trigger(item: item, command: command, attach: attach)
26
- when Proc then proc_trigger(item: item, command: command, attach: attach)
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(group: item)
30
+ [GROUP_COMMAND, { "groupName" => item.group.name }]
66
31
  else
67
- item(item: 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
- to = Conditions::Proc.from_value(to)
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
- @timer = nil
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
- if @timer&.active?
36
- process_active_timer(inputs, mod, &block)
37
- elsif check_trigger_guards(inputs)
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
- @timer&.cancel
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
- @timer = DSL.after(@duration) do
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
- @timer = nil
68
+ @timers.delete(item_name)
96
69
  yield
97
70
  end
98
71
  rule.on_removal(self)
99
- _, @tracking_from = retrieve_states(inputs)
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
- new_state, old_state = retrieve_states(inputs)
110
- if new_state != @tracking_from && @conditions.check_to(inputs: {})
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
- @timer.cancel
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 [Item State] to state to restrict trigger to
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
- case to
25
- when Range then range_trigger(item: item, to: to, attach: attach)
26
- when Proc then proc_trigger(item: item, to: to, attach: attach)
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
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of openHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.1.1"
7
+ VERSION = "5.2.0"
8
8
  end
9
9
  end
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.1.1
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-04-23 00:00:00.000000000 Z
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/proc.rb
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