openhab-scripting 5.1.1 → 5.3.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/core_ext/ruby/object.rb +30 -0
- data/lib/openhab/dsl/items/builder.rb +68 -3
- 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
- data/lib/openhab/dsl.rb +3 -0
- metadata +5 -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: a914cbf39d73f385d8f250fb88a72737cabec9106871009f0b4679176251680a
|
|
4
|
+
data.tar.gz: 402616a86763701e48146d24581c340287c060bb8e86fb28e9c2e1947e19b129
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a860c8a2969e3a10b513650f265a3291f1cc5b91fa0b9d1775f40e254904175fe6e077881cb24ebef13677085705c3ae2248420064154da61a7ced4af4a91c67
|
|
7
|
+
data.tar.gz: 13e3da787706aee119334f4e768a9af3d2eaefc38afb8b2e6618e74e6591bc8cfcfa7ff137fa514d2bed2831e416f6112d8a27b7a6a8a205fdf8eefdbaafff31
|
|
@@ -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
|
#
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenHAB
|
|
4
|
+
module CoreExt
|
|
5
|
+
module Ruby
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Object
|
|
8
|
+
class << self
|
|
9
|
+
attr_reader :top_self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @!visibility private
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# capture methods defined at top level (which get added to Object)
|
|
15
|
+
def method_added(method)
|
|
16
|
+
return super unless equal?(::Object)
|
|
17
|
+
|
|
18
|
+
if DSL.private_instance_methods.include?(method)
|
|
19
|
+
# Duplicate methods that conflict with DSL onto `main`'s singleton class,
|
|
20
|
+
# so that they'll take precedence over DSL's method.
|
|
21
|
+
Object.top_self.singleton_class.define_method(method, instance_method(method))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -22,6 +22,12 @@ module OpenHAB
|
|
|
22
22
|
# group_item Equipment, tags: Semantics::HVAC, thing: "binding:thing"
|
|
23
23
|
# string_item Mode, tags: Semantics::Control, channel: "mode"
|
|
24
24
|
# end
|
|
25
|
+
#
|
|
26
|
+
# # dimension Temperature inferred
|
|
27
|
+
# number_item OutdoorTemp, format: "%.1f %unit%", unit: "°F"
|
|
28
|
+
#
|
|
29
|
+
# # unit lx, dimension Illuminance, format "%s %unit%" inferred
|
|
30
|
+
# number_item OutdoorBrightness, state: 10_000 | "lx"
|
|
25
31
|
# end
|
|
26
32
|
#
|
|
27
33
|
module Builder
|
|
@@ -156,9 +162,22 @@ module OpenHAB
|
|
|
156
162
|
# @return [String, nil]
|
|
157
163
|
attr_accessor :label
|
|
158
164
|
# Unit dimension (for number items only)
|
|
165
|
+
#
|
|
166
|
+
# If {unit} is provided, and {dimension} is not, it will be inferred.
|
|
167
|
+
#
|
|
159
168
|
# @return [String, nil]
|
|
160
169
|
attr_accessor :dimension
|
|
170
|
+
# Unit (for number items only)
|
|
171
|
+
#
|
|
172
|
+
# Due to {format} inference, setting the unit is cross-compatible with
|
|
173
|
+
# openHAB 3.4 and 4.0.
|
|
174
|
+
#
|
|
175
|
+
# @return [String, nil]
|
|
176
|
+
attr_reader :unit
|
|
161
177
|
# The formatting pattern for the item's state
|
|
178
|
+
#
|
|
179
|
+
# If {unit} is provided, and {format} is not, it will be inferred.
|
|
180
|
+
#
|
|
162
181
|
# @return [String, nil]
|
|
163
182
|
attr_accessor :format
|
|
164
183
|
# The icon to be associated with the item
|
|
@@ -179,13 +198,16 @@ module OpenHAB
|
|
|
179
198
|
# @return [Core::Items::Metadata::NamespaceHash]
|
|
180
199
|
attr_reader :metadata
|
|
181
200
|
# Initial state
|
|
201
|
+
#
|
|
202
|
+
# If {state} is set to a {QuantityType}, and {unit} is not set, it will be inferred.
|
|
203
|
+
#
|
|
182
204
|
# @return [Core::Types::State]
|
|
183
|
-
|
|
205
|
+
attr_reader :state
|
|
184
206
|
|
|
185
207
|
class << self
|
|
186
208
|
# @!visibility private
|
|
187
209
|
def item_factory
|
|
188
|
-
@item_factory ||= org.openhab.core.
|
|
210
|
+
@item_factory ||= OpenHAB::OSGi.service("org.openhab.core.items.ItemFactory")
|
|
189
211
|
end
|
|
190
212
|
|
|
191
213
|
#
|
|
@@ -214,6 +236,7 @@ module OpenHAB
|
|
|
214
236
|
end
|
|
215
237
|
|
|
216
238
|
# @param dimension [Symbol, nil] The unit dimension for a {NumberItem} (see {ItemBuilder#dimension})
|
|
239
|
+
# @param unit [Symbol, String, nil] The unit for a {NumberItem} (see {ItemBuilder#unit})
|
|
217
240
|
# @param format [String, nil] The formatting pattern for the item's state (see {ItemBuilder#format})
|
|
218
241
|
# @param icon [Symbol, nil] The icon to be associated with the item (see {ItemBuilder#icon})
|
|
219
242
|
# @param group [String,
|
|
@@ -246,6 +269,7 @@ module OpenHAB
|
|
|
246
269
|
def initialize(type, name = nil, label = nil,
|
|
247
270
|
provider:,
|
|
248
271
|
dimension: nil,
|
|
272
|
+
unit: nil,
|
|
249
273
|
format: nil,
|
|
250
274
|
icon: nil,
|
|
251
275
|
group: nil,
|
|
@@ -274,6 +298,7 @@ module OpenHAB
|
|
|
274
298
|
@label = label
|
|
275
299
|
@dimension = dimension
|
|
276
300
|
@format = format
|
|
301
|
+
self.unit = unit
|
|
277
302
|
@icon = icon
|
|
278
303
|
@groups = []
|
|
279
304
|
@tags = []
|
|
@@ -291,7 +316,7 @@ module OpenHAB
|
|
|
291
316
|
self.alexa(alexa) if alexa
|
|
292
317
|
self.ga(ga) if ga
|
|
293
318
|
self.homekit(homekit) if homekit
|
|
294
|
-
|
|
319
|
+
self.state = state
|
|
295
320
|
|
|
296
321
|
self.group(*group)
|
|
297
322
|
self.group(*groups)
|
|
@@ -434,6 +459,39 @@ module OpenHAB
|
|
|
434
459
|
@expire += ",command=#{command}" if command
|
|
435
460
|
end
|
|
436
461
|
|
|
462
|
+
# @!attribute [w] unit
|
|
463
|
+
#
|
|
464
|
+
# Unit (for number items only).
|
|
465
|
+
#
|
|
466
|
+
# If dimension or format are not yet set, they will be inferred.
|
|
467
|
+
#
|
|
468
|
+
# @return [String, nil]
|
|
469
|
+
def unit=(unit)
|
|
470
|
+
@unit = unit
|
|
471
|
+
|
|
472
|
+
self.dimension ||= unit && org.openhab.core.types.util.UnitUtils.parse_unit(unit)&.then do |u|
|
|
473
|
+
org.openhab.core.types.util.UnitUtils.get_dimension_name(u)
|
|
474
|
+
end
|
|
475
|
+
self.format ||= unit && (if Gem::Version.new(Core::VERSION) >= Gem::Version.new("4.0.0.M3")
|
|
476
|
+
"%s %unit%"
|
|
477
|
+
else
|
|
478
|
+
"%s #{unit.gsub("%", "%%")}"
|
|
479
|
+
end)
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# @!attribute [w] state
|
|
483
|
+
#
|
|
484
|
+
# Initial state
|
|
485
|
+
#
|
|
486
|
+
# If {state} is set to a {QuantityType}, and {unit} is not set, it will be inferred.
|
|
487
|
+
#
|
|
488
|
+
# @return [Core::Types::State]
|
|
489
|
+
def state=(state)
|
|
490
|
+
@state = state
|
|
491
|
+
|
|
492
|
+
self.unit ||= state.unit.to_s if state.is_a?(QuantityType)
|
|
493
|
+
end
|
|
494
|
+
|
|
437
495
|
# @!visibility private
|
|
438
496
|
def build
|
|
439
497
|
item = create_item
|
|
@@ -450,6 +508,7 @@ module OpenHAB
|
|
|
450
508
|
item.metadata["autoupdate"] = autoupdate.to_s unless autoupdate.nil?
|
|
451
509
|
item.metadata["expire"] = expire if expire
|
|
452
510
|
item.metadata["stateDescription"] = { "pattern" => format } if format
|
|
511
|
+
item.metadata["unit"] = unit if unit
|
|
453
512
|
item.state = item.format_update(state) unless state.nil?
|
|
454
513
|
item
|
|
455
514
|
end
|
|
@@ -488,6 +547,12 @@ module OpenHAB
|
|
|
488
547
|
class GroupItemBuilder < ItemBuilder
|
|
489
548
|
include Builder
|
|
490
549
|
|
|
550
|
+
# This has to be duplicated here, since {Builder} includes DSL, so DSL#unit
|
|
551
|
+
# will be seen first, but we really want ItemBuilder#unit
|
|
552
|
+
|
|
553
|
+
# (see ItemBuilder#unit)
|
|
554
|
+
attr_reader :unit
|
|
555
|
+
|
|
491
556
|
Builder.public_instance_methods.each do |m|
|
|
492
557
|
next unless Builder.instance_method(m).owner == Builder
|
|
493
558
|
|
|
@@ -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
data/lib/openhab/dsl.rb
CHANGED
|
@@ -975,5 +975,8 @@ OpenHAB::Core::Items.import_into_global_namespace
|
|
|
975
975
|
|
|
976
976
|
# Extend `main` with DSL methods
|
|
977
977
|
singleton_class.include(OpenHAB::DSL)
|
|
978
|
+
# Patch Object to work around https://github.com/openhab/openhab-jruby/issues/4
|
|
979
|
+
Object.extend(OpenHAB::CoreExt::Ruby::Object::ClassMethods)
|
|
980
|
+
OpenHAB::CoreExt::Ruby::Object.instance_variable_set(:@top_self, self)
|
|
978
981
|
|
|
979
982
|
logger.debug "openHAB JRuby Scripting Library Version #{OpenHAB::DSL::VERSION} Loaded"
|
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.3.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-31 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: bundler
|
|
@@ -504,6 +504,7 @@ files:
|
|
|
504
504
|
- lib/openhab/core_ext/ruby/date_time.rb
|
|
505
505
|
- lib/openhab/core_ext/ruby/module.rb
|
|
506
506
|
- lib/openhab/core_ext/ruby/numeric.rb
|
|
507
|
+
- lib/openhab/core_ext/ruby/object.rb
|
|
507
508
|
- lib/openhab/core_ext/ruby/range.rb
|
|
508
509
|
- lib/openhab/core_ext/ruby/symbol.rb
|
|
509
510
|
- lib/openhab/core_ext/ruby/time.rb
|
|
@@ -527,8 +528,9 @@ files:
|
|
|
527
528
|
- lib/openhab/dsl/rules/triggers/changed.rb
|
|
528
529
|
- lib/openhab/dsl/rules/triggers/channel.rb
|
|
529
530
|
- lib/openhab/dsl/rules/triggers/command.rb
|
|
531
|
+
- lib/openhab/dsl/rules/triggers/conditions.rb
|
|
530
532
|
- lib/openhab/dsl/rules/triggers/conditions/duration.rb
|
|
531
|
-
- lib/openhab/dsl/rules/triggers/conditions/
|
|
533
|
+
- lib/openhab/dsl/rules/triggers/conditions/generic.rb
|
|
532
534
|
- lib/openhab/dsl/rules/triggers/cron/cron.rb
|
|
533
535
|
- lib/openhab/dsl/rules/triggers/cron/cron_handler.rb
|
|
534
536
|
- 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
|