openhab-scripting 2.25.2 → 3.0.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: f3deb9da52443a92a787b19c30a5e540bf45ffa1f2ce69e7b47554190468e311
4
- data.tar.gz: eae005970cf7f0c47f896fa9e2ab194c1a8c23b8901b535cde8b66efcc864e1c
3
+ metadata.gz: 7eb19f2aa4bac30a6fb3b4f07953a9b78a54419795d4845c073432d803fa8629
4
+ data.tar.gz: 7528671d2c2db7a58ecdc46b33f9b94656ff2cfc878ab76bc2703fcff4c49a7b
5
5
  SHA512:
6
- metadata.gz: 5fc8e075065e222e388a0c8b83a53644ea0b6d909f7c7c1109450f4be535a91e77319fa4d73e950df6ad9023bfc8051a242dcafcf51a1ff96934c6a43a9a8b51
7
- data.tar.gz: b869685445af147f35ce27a793c8f533fdc39af25842935cd1c3265610383d0332830fae97edb4746a49dc96fd7f351debcb7e1eb28646c174dff03cef5e1c7f
6
+ metadata.gz: 6ef8331db3b6985bcc1ebb3b3b16fb251b61a482e10fc586e1d6bb2f7460ca197ecf8e38492613effd7fe6ff3f62f3975b443879f698373083c0b6ec192542d5
7
+ data.tar.gz: 20451cc85edb7a50ad3d5f7d80415b6b769129d5ce5b9cd246f98d51f1c588036340a7c1c9211184c396b1919a44c8d49fa303b3637d6182964b28cf76ca6edb
@@ -9,9 +9,9 @@ require 'openhab/dsl/items/number_item'
9
9
  require 'openhab/dsl/items/string_item'
10
10
  require 'openhab/dsl/items/datetime_item'
11
11
  require 'openhab/dsl/items/rollershutter_item'
12
+ require 'openhab/dsl/items/group_item'
12
13
 
13
14
  # Automation lookup and injection of OpenHab entities
14
- java_import org.openhab.core.items.GroupItem
15
15
 
16
16
  module OpenHAB
17
17
  module Core
@@ -87,25 +87,25 @@ module OpenHAB
87
87
  # @return [Object] the ruby wrapper for the item
88
88
  #
89
89
  # rubocop: disable Metrics/MethodLength
90
- # rubocop: disable Metrics/AbcSize
91
90
  # Disabled line length and branch size - case dispatch pattern
92
- private_class_method def self.decorate_item(item)
91
+ def self.decorate_item(item)
93
92
  case item
94
- when GroupItem
95
- decorate_group(item)
96
- when Java::Org.openhab.core.library.items::NumberItem
93
+ when Java::OrgOpenhabCoreItems::GroupItem
94
+ OpenHAB::DSL::Items::GroupItem.new(item)
95
+ when Java::OrgOpenhabCoreLibraryItems::NumberItem
97
96
  OpenHAB::DSL::Items::NumberItem.new(item)
98
- when Java::Org.openhab.core.library.items::StringItem
97
+ when Java::OrgOpenhabCoreLibraryItems::StringItem
99
98
  OpenHAB::DSL::Items::StringItem.new(item)
100
- when Java::Org.openhab.core.library.items::DateTimeItem
99
+ when Java::OrgOpenhabCoreLibraryItems::DateTimeItem
101
100
  OpenHAB::DSL::Items::DateTimeItem.new(item)
102
- when Java::Org.openhab.core.library.items::RollershutterItem
101
+ when Java::OrgOpenhabCoreLibraryItems::RollershutterItem
103
102
  OpenHAB::DSL::Items::RollershutterItem.new(item)
103
+ when Java::OrgOpenhabCoreLibraryItems::PlayerItem
104
+ OpenHAB::DSL::Items::PlayerItem.new(item)
104
105
  else
105
106
  item
106
107
  end
107
108
  end
108
- # rubocop: enable Metrics/AbcSize
109
109
  # rubocop: enable Metrics/MethodLength
110
110
 
111
111
  #
@@ -144,19 +144,6 @@ module OpenHAB
144
144
  # rubocop: enable Style/GlobalVars
145
145
  decorate_item(item)
146
146
  end
147
-
148
- #
149
- # Decorate a group from an item base
150
- #
151
- # @param [OpenHAB item] item item to convert to a group item
152
- #
153
- # @return [OpenHAB::DSL::Groups::Group] Group created from supplied item
154
- #
155
- private_class_method def self.decorate_group(item)
156
- group = OpenHAB::DSL::Groups::Group.new(Set.new(decorate_items(item.all_members.to_a)))
157
- group.group = item
158
- group
159
- end
160
147
  end
161
148
  end
162
149
  end
@@ -15,6 +15,8 @@ require 'openhab/dsl/things'
15
15
  require 'openhab/dsl/items/items'
16
16
  require 'openhab/dsl/items/datetime_item'
17
17
  require 'openhab/dsl/items/number_item'
18
+ require 'openhab/dsl/items/player_item'
19
+ require 'openhab/dsl/items/group_item'
18
20
  require 'openhab/dsl/time_of_day'
19
21
  require 'openhab/dsl/gems'
20
22
  require 'openhab/dsl/persistence'
@@ -3,6 +3,7 @@
3
3
  require 'delegate'
4
4
  require 'forwardable'
5
5
  require 'openhab/core/entity_lookup'
6
+ require 'openhab/dsl/items/group_item'
6
7
 
7
8
  module OpenHAB
8
9
  module DSL
@@ -10,11 +11,6 @@ module OpenHAB
10
11
  # Provides access to OpenHAB Groups
11
12
  #
12
13
  module Groups
13
- #
14
- # Indicator struct interpreted by rules to trigger based on items contained in a group
15
- #
16
- GroupItems = Struct.new(:group, keyword_init: true)
17
-
18
14
  #
19
15
  # Provide access to groups as a set
20
16
  #
@@ -27,7 +23,7 @@ module OpenHAB
27
23
  #
28
24
  def[](name)
29
25
  group = OpenHAB::Core::EntityLookup.lookup_item(name)
30
- group.is_a?(Group) ? group : nil
26
+ group.is_a?(OpenHAB::DSL::Items::GroupItem) ? group : nil
31
27
  end
32
28
  end
33
29
 
@@ -38,64 +34,9 @@ module OpenHAB
38
34
  #
39
35
  def groups
40
36
  # rubocop: disable Style/GlobalVars
41
- Groups.new(OpenHAB::Core::EntityLookup.decorate_items($ir.items.select { |item| item.is_a? GroupItem }))
37
+ Groups.new(OpenHAB::Core::EntityLookup.decorate_items($ir.items.grep(Java::OrgOpenhabCoreItems::GroupItem)))
42
38
  # rubocop: enable Style/GlobalVars
43
39
  end
44
-
45
- # Group class that provides access to OpenHAB group object and delegates other methods to
46
- # a set of group items
47
- class Group < SimpleDelegator
48
- extend Forwardable
49
-
50
- java_import Java::OrgOpenhabCoreItems::GroupItem
51
-
52
- # @return [org.openhab.core.items.GroupItem] OpenHAB Java Group Item
53
- attr_accessor :group
54
-
55
- # @!macro [attach] def_delegators
56
- # @!method $2
57
- # Forwards to org.openhab.core.items.GroupItem
58
- # @see org::openhab::core::items::GroupItem
59
- %i[name label << command].each do |method|
60
- def_delegator :@group, method
61
- end
62
-
63
- #
64
- # Gets members of this group that are themselves a group
65
- #
66
- # @return [Set] Set of members that are of type group
67
- #
68
- def groups
69
- group.members.grep(GroupItem)
70
- end
71
-
72
- #
73
- # Wraps the group in a struct, this method is intended to be called
74
- # as an indicator to the rule method that the user wishes to trigger
75
- # based on changes to group items
76
- #
77
- # @return [GroupItems] Indicator struct used by rules engine to trigger based on item changes
78
- #
79
- def items
80
- GroupItems.new(group: group)
81
- end
82
-
83
- #
84
- # @return [String] List of groups seperated by commas
85
- #
86
- def to_s
87
- "[#{map(&:to_s).join(',')}]"
88
- end
89
-
90
- #
91
- # Get an ID for the group, using the label if set, otherwise group name
92
- #
93
- # @return [String] label if set otherwise name
94
- #
95
- def id
96
- label || name
97
- end
98
- end
99
40
  end
100
41
  end
101
42
  end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+ require 'forwardable'
5
+ require 'java'
6
+ require 'openhab/dsl/items/item_command'
7
+ require 'openhab/dsl/items/item_delegate'
8
+ require 'openhab/core/entity_lookup'
9
+
10
+ module OpenHAB
11
+ module DSL
12
+ module Items
13
+ #
14
+ # Class for indicating to triggers that a group trigger should be used
15
+ #
16
+ class GroupMembers < SimpleDelegator
17
+ attr_reader :group
18
+
19
+ #
20
+ # Create a new GroupMembers instance from a GroupItem
21
+ #
22
+ # @param [GroupItem] group_item GroupItem to use as trigger
23
+ #
24
+ def initialize(group_item)
25
+ @group = group_item
26
+ super(OpenHAB::Core::EntityLookup.decorate_items(@group.members.to_a))
27
+ end
28
+ end
29
+
30
+ #
31
+ # Delegator to OpenHAB Group Item
32
+ #
33
+ class GroupItem
34
+ extend OpenHAB::DSL::Items::ItemCommand
35
+ extend OpenHAB::DSL::Items::ItemDelegate
36
+ include Enumerable
37
+ include Comparable
38
+
39
+ def_item_delegator :@group_item
40
+
41
+ #
42
+ # @return [Hash] A hash of lambdas with default filters for `all_members`
43
+ #
44
+ DEFAULT_FILTERS = {
45
+ groups: ->(item) { item.is_a?(Java::OrgOpenhabCoreItems::GroupItem) },
46
+ all: -> { true }
47
+ }.freeze
48
+
49
+ private_constant :DEFAULT_FILTERS
50
+
51
+ #
52
+ # Create a new GroupItem
53
+ #
54
+ # @param [Java::Org::openhab::core::items::GroupItem] group_item OpenHAB GroupItem to delegate to
55
+ #
56
+ def initialize(group_item)
57
+ @group_item = group_item
58
+
59
+ item_missing_delegate { @group_item }
60
+ item_missing_delegate { OpenHAB::Core::EntityLookup.decorate_item(base_item) }
61
+ end
62
+
63
+ #
64
+ # Create a GroupMembers object for use in triggers
65
+ #
66
+ # @return [GroupMembers] A GroupMembers object
67
+ #
68
+ def members
69
+ GroupMembers.new(@group_item)
70
+ end
71
+
72
+ #
73
+ # Iterates through the direct members of the Group
74
+ #
75
+ def each(&block)
76
+ OpenHAB::Core::EntityLookup.decorate_items(@group_item.members.to_a).each(&block)
77
+ end
78
+
79
+ #
80
+ # Get all members of the group recursively. Optionally filter the items to only return
81
+ # Groups or regular Items
82
+ #
83
+ # @param [Symbol] filter Either :groups or :items
84
+ #
85
+ # @return [Array] An Array containing all descendants of the Group, optionally filtered
86
+ #
87
+ def all_members(filter = nil, &block)
88
+ predicate = DEFAULT_FILTERS[filter] || block
89
+
90
+ return OpenHAB::Core::EntityLookup.decorate_items(@group_item.all_members.to_a) unless predicate
91
+
92
+ OpenHAB::Core::EntityLookup.decorate_items(@group_item.get_members(&predicate).to_a)
93
+ end
94
+
95
+ #
96
+ # Test for equality
97
+ #
98
+ # @param [Object] other Other object to compare against
99
+ #
100
+ # @return [Boolean] true if self and other can be considered equal, false otherwise
101
+ #
102
+ def ==(other)
103
+ if other.respond_to?(:java_class) && accepted_data_types.include?(other.java_class)
104
+ get_state_as(other.class) == other
105
+ elsif other.respond_to?(:state)
106
+ base_item ? OpenHAB::Core::EntityLookup.decorate_item(base_item) == other.state : self == other.state
107
+ else
108
+ super
109
+ end
110
+ end
111
+
112
+ #
113
+ # Compare GroupItem to supplied object
114
+ #
115
+ # @param [Object] other object to compare to
116
+ #
117
+ # @return [Integer] -1,0,1 or nil depending on value supplied,
118
+ # nil comparison to supplied object is not possible.
119
+ #
120
+ def <=>(other)
121
+ if base_item
122
+ OpenHAB::Core::EntityLookup.decorate_item(base_item) <=> other
123
+ elsif state?
124
+ -(other <=> state)
125
+ else
126
+ super
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'java'
4
+ require 'openhab/log/logger'
4
5
 
5
6
  module OpenHAB
6
7
  module DSL
@@ -9,19 +10,25 @@ module OpenHAB
9
10
  # Holds methods to automatically generate commands and
10
11
  # accessors for items
11
12
  module ItemCommand
13
+ include OpenHAB::Log
14
+
12
15
  #
13
16
  # For every value in the supplied enumeration create a corresponding method mapped to the lowercase
14
17
  # string representation of the enum value For example, an enum with values of STOP and START
15
18
  # would create methods stop() and start() that send the corresponding STOP and START commands to the item
16
19
  #
17
20
  # @param [Java::JavaLang::Enum] command_enum Enumeration to create commands for
21
+ # @param [Hash] optional hash in which if a generated method name mactches a key, the value of that key
22
+ # will be used as the method name instead, for example `:play? => :playing?`
18
23
  #
19
24
  #
20
- def item_command(command_enum)
25
+ def item_command(command_enum, methods = {})
21
26
  # rubocop:disable Style/HashEachMethods
22
27
  # Disable rule because Java enum does not support each_value
23
28
  command_enum.values.each do |command|
24
29
  command_method = command.to_s.downcase
30
+ command_method = methods.transform_keys(&:to_sym).fetch(command_method.to_sym, command_method)
31
+ logger.trace("Creating command method (#{command_method}) for #{self.class}")
25
32
  define_method(command_method) do
26
33
  self.command(command)
27
34
  end
@@ -37,14 +44,17 @@ module OpenHAB
37
44
  #
38
45
  # @param [Java::JavaLang::Enum] command_enum Enumeration to create methods for each value
39
46
  # to check if current state matches that enum
40
- # @yield [state] Optional block that can be used to transform state prior to comparison
47
+ # @param [Hash] optional hash in which if a generated method name mactches a key, the value of that key
48
+ # will be used as the method name instead, for example `:play? => :playing?`
41
49
  #
42
50
  #
43
- def item_state(command_enum)
51
+ def item_state(command_enum, methods = {})
44
52
  # rubocop:disable Style/HashEachMethods
45
53
  # Disable rule because Java enum does not support each_value
46
54
  command_enum.values.each do |command|
47
55
  status_method = "#{command.to_s.downcase}?"
56
+ status_method = methods.transform_keys(&:to_sym).fetch(status_method.to_sym, status_method)
57
+ logger.trace("Creating status method (#{status_method}) for #{self.class}")
48
58
  define_method(status_method) do
49
59
  state? && state.as(command_enum) == command
50
60
  end
@@ -57,14 +67,18 @@ module OpenHAB
57
67
  # Item class and pass them to item_state/item_command
58
68
  #
59
69
  # @param [Java::JavaLang::Class] item_class a Class that implements Java::OrgOpenhabCoreItems::Item
70
+ # @param [Hash] optional hash in which if a generated method name mactches a key, the value of that key
71
+ # will be used as the method name instead, for example `:play? => :playing?`
60
72
  #
61
- def item_type(item_class)
73
+ def item_type(item_class, methods = {})
62
74
  item_class.field_reader(:ACCEPTED_DATA_TYPES)
63
75
  item_class.field_reader(:ACCEPTED_COMMAND_TYPES)
64
- item_class.ACCEPTED_DATA_TYPES.select(&:is_enum).grep_v(UnDefType).each { |type| item_state(type.ruby_class) }
65
- item_class.ACCEPTED_COMMAND_TYPES.select(&:is_enum).grep_v(UnDefType).each do |type|
66
- item_command(type.ruby_class)
67
- end
76
+ item_class.ACCEPTED_DATA_TYPES.select(&:is_enum)
77
+ .grep_v(UnDefType)
78
+ .each { |type| item_state(type.ruby_class, methods) }
79
+ item_class.ACCEPTED_COMMAND_TYPES.select(&:is_enum)
80
+ .grep_v(UnDefType)
81
+ .each { |type| item_command(type.ruby_class, methods) }
68
82
  end
69
83
  end
70
84
  end
@@ -33,12 +33,11 @@ module OpenHAB
33
33
  alias key? include?
34
34
  end
35
35
 
36
- java_import org.openhab.core.items.GroupItem
37
36
  # Fetches all non-group items from the item registry
38
37
  # @return [OpenHAB::DSL::Items::Items]
39
38
  def items
40
39
  # rubocop: disable Style/GlobalVars
41
- Items.new(OpenHAB::Core::EntityLookup.decorate_items($ir.items.reject { |item| item.is_a? GroupItem }))
40
+ Items.new(OpenHAB::Core::EntityLookup.decorate_items($ir.items.grep_v(Java::OrgOpenhabCoreItems::GroupItem)))
42
41
  # rubocop: enable Style/GlobalVars
43
42
  end
44
43
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'java'
5
+ require 'openhab/dsl/items/item_command'
6
+ require 'openhab/dsl/items/item_delegate'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ module Items
11
+ #
12
+ # Delegator to OpenHAB Player Item
13
+ #
14
+ class PlayerItem
15
+ extend OpenHAB::DSL::Items::ItemCommand
16
+ extend OpenHAB::DSL::Items::ItemDelegate
17
+ extend Forwardable
18
+
19
+ def_item_delegator :@player_item
20
+
21
+ item_type Java::OrgOpenhabCoreLibraryItems::PlayerItem, :play? => :playing?,
22
+ :pause? => :paused?,
23
+ :rewind? => :rewinding?,
24
+ :fastforward? => :fastforwarding?
25
+
26
+ # rubocop: disable Style/Alias
27
+ # Disabled because 'alias' does not work with the dynamically defined methods
28
+ alias_method :fast_forward, :fastforward
29
+ alias_method :fast_forwarding?, :fastforwarding?
30
+ # rubocop: enable Style/Alias
31
+
32
+ #
33
+ # Creates a new PlayerItem
34
+ #
35
+ # @param [Java::OrgOpenhabCoreLibraryItems::PlayerItem] player_item
36
+ # The OpenHAB PlayerItem to delegate to
37
+ #
38
+ def initialize(player_item)
39
+ logger.trace("Wrapping #{player_item}")
40
+ @player_item = player_item
41
+
42
+ item_missing_delegate { @player_item }
43
+
44
+ super()
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -10,7 +10,6 @@ require 'openhab/dsl/monkey_patch/items/persistence'
10
10
  require 'openhab/dsl/monkey_patch/items/contact_item'
11
11
  require 'openhab/dsl/monkey_patch/items/dimmer_item'
12
12
  require 'openhab/dsl/monkey_patch/items/switch_item'
13
- require 'openhab/dsl/monkey_patch/items/group_item'
14
13
 
15
14
  module OpenHAB
16
15
  module DSL
@@ -103,8 +103,7 @@ module OpenHAB
103
103
  # @return [OpenHAB::DSL::MonkeyPatch::Items::MetadataItem], or nil if the namespace doesn't exist
104
104
  #
105
105
  def [](namespace)
106
- logger.trace("Namespaces (#{NamespaceAccessor.registry.getAll})")
107
- logger.trace("Namespace (#{NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))})")
106
+ logger.trace("Getting metadata for item: #{@item_name}, namespace '#{namespace}'")
108
107
  metadata = NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))
109
108
  MetadataItem.new(metadata: metadata) if metadata
110
109
  end
@@ -8,6 +8,7 @@ module OpenHAB
8
8
  # Persistence extension for Items
9
9
  #
10
10
  module Persistence
11
+ java_import Java::OrgOpenhabCoreTypesUtil::UnitUtils
11
12
  # All persistence methods that could return a Quantity
12
13
  QUANTITY_METHODS = %i[average_since
13
14
  delta_since
@@ -81,9 +82,10 @@ module OpenHAB
81
82
  # @return [Object] Quantity or the original value
82
83
  #
83
84
  def quantify(value)
84
- if value.is_a?(Java::OrgOpenhabCoreLibraryTypes::DecimalType) && respond_to?(:unit) && unit
85
- logger.trace("Unitizing #{value} with unit #{unit}")
86
- Quantity.new(Java::OrgOpenhabCoreLibraryTypes::QuantityType.new(value.to_big_decimal, unit))
85
+ if value.is_a?(Java::OrgOpenhabCoreLibraryTypes::DecimalType) && state_description&.pattern
86
+ item_unit = UnitUtils.parse_unit(state_description.pattern)
87
+ logger.trace("Unitizing #{value} with unit #{item_unit}")
88
+ Quantity.new(Java::OrgOpenhabCoreLibraryTypes::QuantityType.new(value.to_big_decimal, item_unit))
87
89
  else
88
90
  value
89
91
  end
@@ -25,9 +25,13 @@ module OpenHAB
25
25
  # @return [Boolean] True if the other object is a ContactItem and has the same state
26
26
  #
27
27
  def ===(other)
28
- super unless other.is_a? ContactItem
29
-
30
- self == other.state
28
+ if other.respond_to?(:state)
29
+ self == other.state
30
+ elsif other.is_a? OpenClosedType
31
+ self == other
32
+ else
33
+ super
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -22,9 +22,13 @@ module OpenHAB
22
22
  # @return [Boolean] True if the other object is a RollershutterItem and has the same state
23
23
  #
24
24
  def ===(other)
25
- super unless other.is_a? OpenHAB::DSL::Items::RollershutterItem
26
-
27
- equals(other.state.as(UpDownType))
25
+ if other.respond_to?(:state)
26
+ self == other.state&.as(UpDownType)
27
+ elsif other.is_a? UpDownType
28
+ self == other
29
+ else
30
+ super
31
+ end
28
32
  end
29
33
  end
30
34
  end
@@ -255,13 +255,28 @@ module OpenHAB
255
255
  event = inputs&.dig('event')
256
256
 
257
257
  while (task = run_queue.shift)
258
- case task
259
- when RuleConfig::Run then process_run_task(event, task)
260
- when RuleConfig::Trigger then process_trigger_task(event, task)
261
- when RuleConfig::Delay then process_delay_task(inputs, mod, run_queue, task)
262
- when RuleConfig::Otherwise then process_otherwise_task(event, task)
258
+ if task.is_a? RuleConfig::Delay
259
+ process_delay_task(inputs, mod, run_queue, task)
260
+ else
261
+ process_task(event, task)
263
262
  end
264
263
  end
264
+ rescue StandardError => e
265
+ print_backtrace(e)
266
+ end
267
+
268
+ #
269
+ # Dispatch execution block tasks to different methods
270
+ #
271
+ # @param [OpenHab Event] event that triggered the rule
272
+ # @param [Task] task task containing otherwise block to execute
273
+ #
274
+ def process_task(event, task)
275
+ case task
276
+ when RuleConfig::Run then process_run_task(event, task)
277
+ when RuleConfig::Trigger then process_trigger_task(event, task)
278
+ when RuleConfig::Otherwise then process_otherwise_task(event, task)
279
+ end
265
280
  end
266
281
 
267
282
  #
@@ -316,6 +331,16 @@ module OpenHAB
316
331
  task.block.call(event)
317
332
  end
318
333
 
334
+ #
335
+ # Print error and stack trace without calls to internal classes
336
+ #
337
+ # @param [Exception] error A rescued error
338
+ #
339
+ def print_backtrace(error)
340
+ error = logger.clean_backtrace(error)
341
+ logger.error { "#{error.message} (#{error.class})\nIn rule: #{name}\n#{error.backtrace&.join("\n")}" }
342
+ end
343
+
319
344
  #
320
345
  # Create a new hash in which all elements are converted to strings
321
346
  #
@@ -59,7 +59,8 @@ module OpenHAB
59
59
  #
60
60
  def should_run?(event)
61
61
  logger.trace("Checking guards #{self}")
62
- check(@only_if, check_type: :only_if, event: event) && check(@not_if, check_type: :not_if, event: event)
62
+ check(@only_if, :check_type => :only_if,
63
+ :event => event) && check(@not_if, :check_type => :not_if, :event => event)
63
64
  end
64
65
 
65
66
  private
@@ -79,7 +80,7 @@ module OpenHAB
79
80
  procs, items = conditions.flatten.partition { |condition| condition.is_a? Proc }
80
81
  logger.trace("Procs: #{procs} Items: #{items}")
81
82
 
82
- items.each { |item| logger.trace("#{item} truthy? #{item.truthy?}") }
83
+ items.each { |item| logger.trace { "#{item} truthy? #{item.truthy?}" } }
83
84
 
84
85
  process_check(check_type: check_type, event: event, items: items, procs: procs)
85
86
  end
@@ -27,6 +27,8 @@ module OpenHAB
27
27
  config.guard = Guard::Guard.new(only_if: config.only_if, not_if: config.not_if)
28
28
  logger.trace { config.inspect }
29
29
  process_rule_config(config)
30
+ rescue StandardError => e
31
+ re_raise_with_backtrace(e)
30
32
  end
31
33
 
32
34
  #
@@ -44,6 +46,16 @@ module OpenHAB
44
46
 
45
47
  private
46
48
 
49
+ #
50
+ # Re-raises a rescued error to OpenHAB with added rule name and stack trace
51
+ #
52
+ # @param [Exception] error A rescued error
53
+ #
54
+ def re_raise_with_backtrace(error)
55
+ error = logger.clean_backtrace(error)
56
+ raise error, "#{error.message}\nIn rule: #{@rule_name}\n#{error.backtrace.join("\n")}"
57
+ end
58
+
47
59
  #
48
60
  # Process a rule based on the supplied configuration
49
61
  #
@@ -31,8 +31,6 @@ module OpenHAB
31
31
  include OpenHAB::DSL::Rules::Property
32
32
  extend OpenHAB::DSL
33
33
 
34
- java_import org.openhab.core.library.items.SwitchItem
35
-
36
34
  # @return [Array] Of triggers
37
35
  attr_reader :triggers
38
36
 
@@ -62,10 +60,10 @@ module OpenHAB
62
60
  #
63
61
  Delay = Struct.new(:duration)
64
62
 
65
- prop_array :run, array_name: :run_queue, wrapper: Run
66
- prop_array :triggered, array_name: :run_queue, wrapper: Trigger
67
- prop_array :delay, array_name: :run_queue, wrapper: Delay
68
- prop_array :otherwise, array_name: :run_queue, wrapper: Otherwise
63
+ prop_array :run, :array_name => :run_queue, :wrapper => Run
64
+ prop_array :triggered, :array_name => :run_queue, :wrapper => Trigger
65
+ prop_array :delay, :array_name => :run_queue, :wrapper => Delay
66
+ prop_array :otherwise, :array_name => :run_queue, :wrapper => Otherwise
69
67
 
70
68
  prop :name
71
69
  prop :description
@@ -31,7 +31,7 @@ module OpenHAB
31
31
  # @return [Trigger] OpenHAB trigger
32
32
  #
33
33
  def changed(*items, to: nil, from: nil, for: nil)
34
- items.flatten.each do |item|
34
+ separate_groups(items).each do |item|
35
35
  logger.trace("Creating changed trigger for entity(#{item}), to(#{to}), from(#{from})")
36
36
  # for is a reserved word in ruby, so use local_variable_get :for
37
37
  if (wait_duration = binding.local_variable_get(:for))
@@ -73,7 +73,8 @@ module OpenHAB
73
73
  #
74
74
  def create_changed_trigger(item, from, to)
75
75
  trigger, config = case item
76
- when GroupItems then create_group_changed_trigger(item, from, to)
76
+ when OpenHAB::DSL::Items::GroupItem::GroupMembers
77
+ create_group_changed_trigger(item, from, to)
77
78
  when Thing then create_thing_changed_trigger(item, from, to)
78
79
  else create_item_changed_trigger(item, from, to)
79
80
  end
@@ -22,7 +22,7 @@ module OpenHAB
22
22
  #
23
23
  #
24
24
  def received_command(*items, command: nil, commands: nil)
25
- items.flatten.each do |item|
25
+ separate_groups(items).flatten.each do |item|
26
26
  logger.trace("Creating received command trigger for item(#{item})"\
27
27
  "command(#{command}) commands(#{commands})")
28
28
 
@@ -43,7 +43,7 @@ module OpenHAB
43
43
  #
44
44
  def create_received_trigger(commands, item)
45
45
  commands.each do |command|
46
- if item.is_a? GroupItems
46
+ if item.is_a? OpenHAB::DSL::Items::GroupItem::GroupMembers
47
47
  config, trigger = create_group_command_trigger(item)
48
48
  else
49
49
  config, trigger = create_item_command_trigger(item)
@@ -53,6 +53,20 @@ module OpenHAB
53
53
  trigger
54
54
  end
55
55
 
56
+ #
57
+ # Separates groups from items, and flattens any nested arrays of items
58
+ #
59
+ # @param [Array] item_array Array of items passed to a trigger
60
+ #
61
+ # @return [Array] A new flat array with any GroupMembers object left intact
62
+ #
63
+ def separate_groups(item_array)
64
+ return item_array if item_array.length <= 1 && item_array.grep(Array).length.zero?
65
+
66
+ groups, items = item_array.partition { |item| item.is_a? OpenHAB::DSL::Items::GroupItem::GroupMembers }
67
+ groups + separate_groups(items.flatten(1))
68
+ end
69
+
56
70
  #
57
71
  # Class for creating and managing triggers
58
72
  #
@@ -20,7 +20,7 @@ module OpenHAB
20
20
  # @return [Trigger] Trigger for updated entity
21
21
  #
22
22
  def updated(*items, to: nil)
23
- items.flatten.each do |item|
23
+ separate_groups(items).flatten.each do |item|
24
24
  logger.trace("Creating updated trigger for item(#{item}) to(#{to})")
25
25
  [to].flatten.each do |to_state|
26
26
  trigger, config = create_update_trigger(item, to_state)
@@ -42,7 +42,7 @@ module OpenHAB
42
42
  #
43
43
  def create_update_trigger(item, to_state)
44
44
  case item
45
- when GroupItems then group_update(item, to_state)
45
+ when OpenHAB::DSL::Items::GroupItem::GroupMembers then group_update(item, to_state)
46
46
  when Thing then thing_update(item, to_state)
47
47
  else item_update(item, to_state)
48
48
  end
@@ -48,8 +48,7 @@ module OpenHAB
48
48
  # @return [StateStorage] item states
49
49
  #
50
50
  def store_states(*items)
51
- items = items.flatten.map { |item| item.is_a?(Group) ? item.group : item }
52
- states = StateStorage.new(BusEvent.storeStates(*items).to_h)
51
+ states = StateStorage.new(BusEvent.storeStates(*items.flatten).to_h)
53
52
  if block_given?
54
53
  yield
55
54
  states.restore
@@ -144,8 +144,10 @@ module OpenHAB
144
144
 
145
145
  OPERATIONS.each do |operation, method|
146
146
  define_method(operation) do |other|
147
- logger.trace("Executing math operation '#{operation}' on quantity #{inspect} "\
148
- "with other type #{other.class} and value #{other.inspect}")
147
+ logger.trace do
148
+ "Executing math operation '#{operation}' on quantity #{inspect} "\
149
+ "with other type #{other.class} and value #{other.inspect}"
150
+ end
149
151
 
150
152
  a, b = to_qt(coerce(other).reverse)
151
153
  logger.trace("Coerced a='#{a}' with b='#{b}'")
@@ -16,7 +16,14 @@ module OpenHAB
16
16
  java_import org.slf4j.LoggerFactory
17
17
 
18
18
  # @return [Array] Supported logging levels
19
- LEVELS = %i[TRACE DEBUG WARN INFO ERROR].freeze
19
+ LEVELS = %i[trace debug warn info error].freeze
20
+ private_constant :LEVELS
21
+
22
+ #
23
+ # Regex for matching internal calls in a stack trace
24
+ #
25
+ INTERNAL_CALL_REGEX = %r{(openhab-scripting-.*/lib)|(org/jruby/)}.freeze
26
+ private_constant :INTERNAL_CALL_REGEX
20
27
 
21
28
  #
22
29
  # Create a new logger
@@ -32,11 +39,30 @@ module OpenHAB
32
39
  # def <level>(msg=nil, &block)
33
40
  # log(severity: <level>, msg: msg, &block)
34
41
  # end
42
+ #
43
+ # Also creates methods to check if the different logging levels are enabled
44
+ #
35
45
  LEVELS.each do |level|
36
- method = level.to_s.downcase
37
- define_method(method.to_s) do |msg = nil, &block|
46
+ define_method(level) do |msg = nil, &block|
38
47
  log(severity: level, msg: msg, &block)
39
48
  end
49
+ define_method("#{level}_enabled?") { @sl4fj_logger.send("is_#{level}_enabled") }
50
+ end
51
+
52
+ #
53
+ # Cleans the backtrace of an error to remove internal calls. If logging is set
54
+ # to debug or lower, the full backtrace is kept
55
+ #
56
+ # @param [Exception] error An exception to be cleaned
57
+ #
58
+ # @return [Exception] the exception, potentially with a cleaned backtrace.
59
+ #
60
+ def clean_backtrace(error)
61
+ return error if debug_enabled?
62
+
63
+ backtrace = error.backtrace_locations.reject { |line| INTERNAL_CALL_REGEX.match? line.to_s }
64
+ error.set_backtrace(backtrace.map(&:to_s))
65
+ error
40
66
  end
41
67
 
42
68
  private
@@ -54,7 +80,7 @@ module OpenHAB
54
80
  raise ArgumentError, "Unknown Severity #{severity}" unless LEVELS.include? severity
55
81
 
56
82
  # Dynamically check enablement of underlying logger, this expands to "is_<level>_enabled"
57
- return unless @sl4fj_logger.send("is_#{severity.to_s.downcase}_enabled")
83
+ return unless send("#{severity}_enabled?")
58
84
 
59
85
  # Process block if no message provided
60
86
  msg = yield if msg.nil? && block_given?
@@ -62,7 +88,7 @@ module OpenHAB
62
88
  msg = message_to_string(msg: msg)
63
89
 
64
90
  # Dynamically invoke underlying logger, this expands to "<level>(message)"
65
- @sl4fj_logger.send(severity.to_s.downcase, msg)
91
+ @sl4fj_logger.send(severity, msg)
66
92
  end
67
93
 
68
94
  #
@@ -121,7 +147,7 @@ module OpenHAB
121
147
  configure_logger_for(classname)
122
148
  end
123
149
 
124
- private
150
+ private
125
151
 
126
152
  #
127
153
  # Configure a logger for the supplied classname
@@ -153,7 +179,7 @@ module OpenHAB
153
179
  .first
154
180
  .yield_self { |caller| File.basename(caller, '.*') }
155
181
  end
156
- end
182
+ end
157
183
 
158
184
  #
159
185
  # Add logger method to the object that includes this module
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '2.25.2'
8
+ VERSION = '3.0.0'
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.25.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian O'Connell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-28 00:00:00.000000000 Z
11
+ date: 2021-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -40,10 +40,12 @@ files:
40
40
  - lib/openhab/dsl/gems.rb
41
41
  - lib/openhab/dsl/group.rb
42
42
  - lib/openhab/dsl/items/datetime_item.rb
43
+ - lib/openhab/dsl/items/group_item.rb
43
44
  - lib/openhab/dsl/items/item_command.rb
44
45
  - lib/openhab/dsl/items/item_delegate.rb
45
46
  - lib/openhab/dsl/items/items.rb
46
47
  - lib/openhab/dsl/items/number_item.rb
48
+ - lib/openhab/dsl/items/player_item.rb
47
49
  - lib/openhab/dsl/items/rollershutter_item.rb
48
50
  - lib/openhab/dsl/items/string_item.rb
49
51
  - lib/openhab/dsl/monkey_patch/actions/actions.rb
@@ -56,7 +58,6 @@ files:
56
58
  - lib/openhab/dsl/monkey_patch/events/thing_status_info.rb
57
59
  - lib/openhab/dsl/monkey_patch/items/contact_item.rb
58
60
  - lib/openhab/dsl/monkey_patch/items/dimmer_item.rb
59
- - lib/openhab/dsl/monkey_patch/items/group_item.rb
60
61
  - lib/openhab/dsl/monkey_patch/items/items.rb
61
62
  - lib/openhab/dsl/monkey_patch/items/metadata.rb
62
63
  - lib/openhab/dsl/monkey_patch/items/persistence.rb
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenHAB
4
- module DSL
5
- module MonkeyPatch
6
- #
7
- # Patches OpenHAB items
8
- #
9
- module Items
10
- java_import Java::OrgOpenhabCoreItems::GroupItem
11
-
12
- #
13
- # Monkey patch Group Item
14
- #
15
- class GroupItem
16
- #
17
- # Get all items in a group
18
- #
19
- # @return [Array] Array of items in the group
20
- #
21
- def items
22
- to_a
23
- end
24
-
25
- #
26
- # Get all items in the group as an Array
27
- #
28
- # @return [Array] All items in the group
29
- #
30
- def to_a
31
- all_members.each_with_object([]) { |item, arr| arr << item }
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end