openhab-scripting 4.37.1 → 4.38.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e405e19fe5977dfbe708699abaf9fe3e0e953d2d16450da5b10879b6e0d3494b
4
- data.tar.gz: c1ed131f668cd5e214f56164ff10a3e9938df4aaa5f6a55efde4ba23db164f82
3
+ metadata.gz: 249167484484abf9fb6c7128e5e697fd4e1d767576ad52b22005ee473d52776e
4
+ data.tar.gz: 6825c83f1cdd668882c3409c0cc828c69e259e553ba736eb9291a0ec1370c57d
5
5
  SHA512:
6
- metadata.gz: d970bd8b607aad49f59d0746ba56711dcf34a0c199547b76008e3e7f375b6836d06841c8cbdb86f056c4f58704690950583f20b76ae1e641515ea332f594f710
7
- data.tar.gz: 7cbc491b62553a735e02f25f690a1244801fc2eac7d2a179dd1777d608a34752e5b549ecb41b73df6765c83ef717fe40d030414bb41291d1372872acaa89c9bb
6
+ metadata.gz: 7d8c8f1f4aab62fecedbe0b8e6693f263e3a21c2ddbb188e5f16cffaf59643d1ffc27c71bb1c14cd256f1852ab6187890c4289791d862ef8e6dcfb1e8f06d096
7
+ data.tar.gz: ed683ceab7adbcdfb6882409f8c52fac4e06b15c23662f108488cc192594f21d13d1614b4e645f9c00dec94739321d931fa2c7cfcb1c78ebc6157882c0cdaff3
@@ -73,6 +73,13 @@ module OpenHAB
73
73
  @item = item
74
74
  end
75
75
 
76
+ # @!visibility private
77
+ # this is explicitly defined, instead of aliased, because #command
78
+ # doesn't actually exist as a method, and will go through method_missing
79
+ def <<(command)
80
+ command(command)
81
+ end
82
+
76
83
  # activate +ensure_states+ before forwarding to the wrapped object
77
84
  def method_missing(method, *args, &block)
78
85
  return super unless @item.respond_to?(method)
@@ -92,6 +99,7 @@ module OpenHAB
92
99
  module Items
93
100
  GenericItem.prepend(OpenHAB::DSL::Ensure::GenericItem)
94
101
  GroupItem::GroupMembers.include(OpenHAB::DSL::Ensure::Ensurable)
102
+ Enumerable.include(OpenHAB::DSL::Ensure::Ensurable)
95
103
  end
96
104
  end
97
105
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'openhab/dsl/items/metadata'
4
4
  require 'openhab/dsl/items/persistence'
5
+ require 'openhab/dsl/items/semantics'
5
6
 
6
7
  require_relative 'item_equality'
7
8
 
@@ -10,14 +11,17 @@ module OpenHAB
10
11
  module Items
11
12
  java_import org.openhab.core.items.GenericItem
12
13
 
13
- # Adds methods to core OpenHAB DimmerItem type to make it more natural in
14
+ # Adds methods to core OpenHAB GenericItem type to make it more natural in
14
15
  # Ruby
16
+ #
17
+ # @see https://www.openhab.org/javadoc/latest/org/openhab/core/items/genericitem
15
18
  class GenericItem
16
19
  include Log
17
20
  include ItemEquality
18
21
 
19
22
  prepend Metadata
20
23
  prepend Persistence
24
+ include Semantics
21
25
 
22
26
  # rubocop:disable Naming/MethodName these mimic Java fields, which are
23
27
  # actually methods
@@ -39,73 +39,7 @@ module OpenHAB
39
39
  group.name
40
40
  end
41
41
 
42
- # Send a command to each member of the group
43
- #
44
- # @return [GroupMembers] +self+
45
- def command(command)
46
- each { |item| item << command }
47
- end
48
42
  alias << command
49
-
50
- # @!method refresh
51
- # Send the +REFRESH+ command to each member of the group
52
- # @return [GroupMembers] +self+
53
-
54
- # @!method on
55
- # Send the +ON+ command to each member of the group
56
- # @return [GroupMembers] +self+
57
-
58
- # @!method off
59
- # Send the +OFF+ command to each member of the group
60
- # @return [GroupMembers] +self+
61
-
62
- # @!method up
63
- # Send the +UP+ command to each member of the group
64
- # @return [GroupMembers] +self+
65
-
66
- # @!method down
67
- # Send the +DOWN+ command to each member of the group
68
- # @return [GroupMembers] +self+
69
-
70
- # @!method stop
71
- # Send the +STOP+ command to each member of the group
72
- # @return [GroupMembers] +self+
73
-
74
- # @!method move
75
- # Send the +MOVE+ command to each member of the group
76
- # @return [GroupMembers] +self+
77
-
78
- # @!method increase
79
- # Send the +INCREASE+ command to each member of the group
80
- # @return [GroupMembers] +self+
81
-
82
- # @!method desrease
83
- # Send the +DECREASE+ command to each member of the group
84
- # @return [GroupMembers] +self+
85
-
86
- # @!method play
87
- # Send the +PLAY+ command to each member of the group
88
- # @return [GroupMembers] +self+
89
-
90
- # @!method pause
91
- # Send the +PAUSE+ command to each member of the group
92
- # @return [GroupMembers] +self+
93
-
94
- # @!method rewind
95
- # Send the +REWIND+ command to each member of the group
96
- # @return [GroupMembers] +self+
97
-
98
- # @!method fast_forward
99
- # Send the +FASTFORWARD+ command to each member of the group
100
- # @return [GroupMembers] +self+
101
-
102
- # @!method next
103
- # Send the +NEXT+ command to each member of the group
104
- # @return [GroupMembers] +self+
105
-
106
- # @!method previous
107
- # Send the +PREVIOUS+ command to each member of the group
108
- # @return [GroupMembers] +self+
109
43
  end
110
44
 
111
45
  include Enumerable
@@ -113,6 +47,17 @@ module OpenHAB
113
47
 
114
48
  remove_method :==
115
49
 
50
+ # Override Enumerable because we want to send them to the base item if possible
51
+ #
52
+ # @return [GroupMembers] +self+
53
+ %i[command update].each do |method|
54
+ define_method(method) do |command|
55
+ return base_item.__send__(method, command) if base_item
56
+
57
+ super(command)
58
+ end
59
+ end
60
+
116
61
  #
117
62
  # Get an Array-like object representing the members of the group
118
63
  #
@@ -167,6 +112,7 @@ module OpenHAB
167
112
  super
168
113
  end
169
114
 
115
+ # Is this ever called?
170
116
  # give the base item type a chance to format commands
171
117
  # @!visibility private
172
118
  def format_type(command)
@@ -69,13 +69,20 @@ module OpenHAB
69
69
  end # end
70
70
  RUBY
71
71
 
72
- logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
73
- GroupItem::GroupMembers.class_eval <<~RUBY, __FILE__, __LINE__ + 1
72
+ logger.trace("Defining Enumerable##{command} for #{value}")
73
+ Enumerable.class_eval <<~RUBY, __FILE__, __LINE__ + 1
74
74
  def #{command} # def on
75
75
  each(&:#{command}) # each(&:on)
76
76
  end # end
77
77
  RUBY
78
78
 
79
+ # Override the inherited methods from Enumerable and send it to the base_item
80
+ GroupItem.class_eval <<~RUBY, __FILE__, __LINE__ + 1
81
+ def #{command} # def on
82
+ method_missing(:#{command}) # method_missing(:on)
83
+ end # end
84
+ RUBY
85
+
79
86
  logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
80
87
  MonkeyPatch::Events::ItemCommandEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
81
88
  def #{command}? # def refresh?
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Additions to Enumerable to allow easily filtering and commanding groups of items
4
+ module Enumerable
5
+ # Returns a new array of items that have at least one of the given tags
6
+ def tagged(*tags)
7
+ reject { |i| (tags & i.tags.to_a).empty? }
8
+ end
9
+
10
+ # Returns a new array of items that do not have any of the given tags
11
+ def not_tagged(*tags)
12
+ select { |i| (tags & i.tags.to_a).empty? }
13
+ end
14
+
15
+ # Returns a new array of items that are a member of at least one of the given groups
16
+ def member_of(*groups)
17
+ reject { |i| (groups.map(&:name) & i.group_names).empty? }
18
+ end
19
+
20
+ # Returns a new array of items that are not a member of any of the given groups
21
+ def not_member_of(*groups)
22
+ select { |i| (groups.map(&:name) & i.group_names).empty? }
23
+ end
24
+
25
+ # Send a command to every item in the collection
26
+ def command(command)
27
+ each { |i| i.command(command) }
28
+ end
29
+
30
+ # Update the state of every item in the collection
31
+ def update(state)
32
+ each { |i| i.update(state) }
33
+ end
34
+
35
+ # @!method refresh
36
+ # Send the +REFRESH+ command to every item in the collection
37
+
38
+ # @!method on
39
+ # Send the +ON+ command to every item in the collection
40
+
41
+ # @!method off
42
+ # Send the +OFF+ command to every item in the collection
43
+
44
+ # @!method up
45
+ # Send the +UP+ command to every item in the collection
46
+
47
+ # @!method down
48
+ # Send the +DOWN+ command to every item in the collection
49
+
50
+ # @!method stop
51
+ # Send the +STOP+ command to every item in the collection
52
+
53
+ # @!method move
54
+ # Send the +MOVE+ command to every item in the collection
55
+
56
+ # @!method increase
57
+ # Send the +INCREASE+ command to every item in the collection
58
+
59
+ # @!method decrease
60
+ # Send the +DECREASE+ command to every item in the collection
61
+
62
+ # @!method play
63
+ # Send the +PLAY+ command to every item in the collection
64
+
65
+ # @!method pause
66
+ # Send the +pause+ command to every item in the collection
67
+
68
+ # @!method rewind
69
+ # Send the +REWIND+ command to every item in the collection
70
+
71
+ # @!method fast_forward
72
+ # Send the +FAST_FORWARD+ command to every item in the collection
73
+
74
+ # @!method next
75
+ # Send the +NEXT+ command to every item in the collection
76
+
77
+ # @!method previous
78
+ # Send the +PREVIOUS+ command to every item in the collection
79
+ end
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'semantics/enumerable'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ # Module for implementing semantics helper methods on [GenericItem]
8
+ #
9
+ # Wraps https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/semantics,
10
+ # as well as adding a few additional convenience methods.
11
+ # Also includes Classes for each semantic tag.
12
+ #
13
+ # Be warned that the Semantic model is stricter than can actually be
14
+ # described by tags and groups on an Item. It makes assumptions that any
15
+ # given item only belongs to one semantic type (Location, Equipment, Point).
16
+ #
17
+ # See https://github.com/openhab/openhab-core/blob/main/bundles/org.openhab.core.semantics/model/SemanticTags.csv
18
+ module Semantics
19
+ # @!visibility private
20
+ # import the actual semantics action
21
+ SemanticsAction = org.openhab.core.model.script.actions.Semantics
22
+ private_constant :SemanticsAction
23
+
24
+ # import all the semantics constants
25
+ [org.openhab.core.semantics.model.point.Points,
26
+ org.openhab.core.semantics.model.property.Properties,
27
+ org.openhab.core.semantics.model.equipment.Equipments,
28
+ org.openhab.core.semantics.model.location.Locations].each do |parent_tag|
29
+ parent_tag.stream.for_each do |tag|
30
+ const_set(tag.simple_name.to_sym, tag.ruby_class)
31
+ end
32
+ end
33
+
34
+ # put ourself into the global namespace, replacing the action
35
+ ::Semantics = self # rubocop:disable Naming/ConstantName
36
+
37
+ # Checks if this Item is a Location
38
+ #
39
+ # This is implemented as checking if the item's semantic_type
40
+ # is a Location. I.e. an Item has a single semantic_type.
41
+ #
42
+ # @return [true, false]
43
+ def location?
44
+ SemanticsAction.location?(self)
45
+ end
46
+
47
+ # Checks if this Item is an Equipment
48
+ #
49
+ # This is implemented as checking if the item's semantic_type
50
+ # is an Equipment. I.e. an Item has a single semantic_type.
51
+ #
52
+ # @return [true, false]
53
+ def equipment?
54
+ SemanticsAction.equipment?(self)
55
+ end
56
+
57
+ # Checks if this Item is a Point
58
+ #
59
+ # This is implemented as checking if the item's semantic_type
60
+ # is a Point. I.e. an Item has a single semantic_type.
61
+ #
62
+ # @return [true, false]
63
+ def point?
64
+ SemanticsAction.point?(self)
65
+ end
66
+
67
+ # Checks if this Item has any semantic tags
68
+ # @return [true, false]
69
+ def semantic?
70
+ !!semantic_type
71
+ end
72
+
73
+ # Gets the related Location Item of this Item.
74
+ #
75
+ # Returns +self+ if this Item is a Location. Otherwise, checks ancestor
76
+ # groups one level at a time, returning the first Location Item found.
77
+ #
78
+ # @return [GenericItem, nil]
79
+ def location
80
+ SemanticsAction.get_location(self)
81
+ end
82
+
83
+ # Returns the sub-class of [Location] related to this Item.
84
+ #
85
+ # In other words, the semantic_type of this Item's Location.
86
+ #
87
+ # @return [Class]
88
+ def location_type
89
+ SemanticsAction.get_location_type(self)&.ruby_class
90
+ end
91
+
92
+ # Gets the related Equipment Item of this Item.
93
+ #
94
+ # Returns +self+ if this Item is an Equipment. Otherwise, checks ancestor
95
+ # groups one level at a time, returning the first Equipment Item found.
96
+ #
97
+ # @return [GenericItem, nil]
98
+ def equipment
99
+ SemanticsAction.get_equipment(self)
100
+ end
101
+
102
+ # Returns the sub-class of [Equipment] related to this Item.
103
+ #
104
+ # In other words, the semantic_type of this Item's Equipment.
105
+ #
106
+ # @return [Class]
107
+ def equipment_type
108
+ SemanticsAction.get_equipment_type(self)&.ruby_class
109
+ end
110
+
111
+ # Returns the sub-class of [Point] this Item is tagged with.
112
+ #
113
+ # @return [Class]
114
+ def point_type
115
+ SemanticsAction.get_point_type(self)&.ruby_class
116
+ end
117
+
118
+ # Returns the sub-class of [Property] this Item is tagged with.
119
+ # @return [Class]
120
+ def property_type
121
+ SemanticsAction.get_property_type(self)&.ruby_class
122
+ end
123
+
124
+ # Returns the sub-class of [Tag] this Item is tagged with.
125
+ #
126
+ # It will only return the first applicable Tag, preferring
127
+ # a sub-class of [Location], [Equipment], or [Point] first,
128
+ # and if none of those are found, looks for a [Property].
129
+ # @return [Class]
130
+ def semantic_type
131
+ SemanticsAction.get_semantic_type(self)&.ruby_class
132
+ end
133
+
134
+ # Return the related Point Items.
135
+ #
136
+ # Searches this Equipment Item for Points that are tagged appropriately.
137
+ #
138
+ # If called on a Point Item, it will automatically search for sibling Points
139
+ # (and remove itself if found).
140
+ #
141
+ # @example Get all points for a TV
142
+ # eGreatTV.points
143
+ # @example Search an Equipment item for its switch
144
+ # eGuestFan.points(Semantics::Switch) # => [GuestFan_Dimmer]
145
+ # @example Search a Thermostat item for its current temperature item
146
+ # eFamilyThermostat.points(Semantics::Status, Semantics::Temperature)
147
+ # # => [FamilyThermostat_AmbTemp]
148
+ # @example Search a Thermostat item for is setpoints
149
+ # eFamilyThermostat.points(Semantics::Control, Semantics::Temperature)
150
+ # # => [FamilyThermostat_HeatingSetpoint, FamilyThermostat_CoolingSetpoint]
151
+ # @example Given a A/V receiver's input item, search for it's power item
152
+ # FamilyReceiver_Input.points(Semantics::Switch) # => FamilyReceiver_Switch
153
+ #
154
+ # @param [Class] point_or_property_types
155
+ # Pass 1 or 2 classes that are sub-classes of [Point] or [Property].
156
+ # Note that when comparing against semantic tags, it does a sub-class check.
157
+ # So if you search for [Control], you'll get items tagged with [Switch].
158
+ # @return [Array<GenericItem>]
159
+ def points(*point_or_property_types)
160
+ # automatically search the parent equipment (or location?!) for sibling points
161
+ unless equipment? || location?
162
+ result = (equipment || location)&.points(*point_or_property_types) || []
163
+ # remove self. but avoid state comparisons
164
+ result.delete_if { |item| item.eql?(self) }
165
+ return result
166
+ end
167
+
168
+ members.points(*point_or_property_types)
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ # Additions to Enumerable to allow easily filtering groups of items based on the semantic model
175
+ module Enumerable
176
+ # Returns a new array of items that are a semantics Location (optionally of the given type)
177
+ def sublocations(type = nil)
178
+ raise ArgumentError, 'type must be a subclass of Location' if type && !(type < OpenHAB::DSL::Semantics::Location)
179
+
180
+ result = select(&:location?)
181
+ result.select! { |i| i.location_type <= type } if type
182
+
183
+ result
184
+ end
185
+
186
+ # Returns a new array of items that are a semantics equipment (optionally of the given type)
187
+ #
188
+ # @example Get all TVs in a room
189
+ # lGreatRoom.equipments(Semantics::Screen)
190
+ def equipments(type = nil)
191
+ raise ArgumentError, 'type must be a subclass of Equipment' if type && !(type < OpenHAB::DSL::Semantics::Equipment)
192
+
193
+ result = select(&:equipment?)
194
+ result.select! { |i| i.equipment_type <= type } if type
195
+
196
+ result
197
+ end
198
+
199
+ # Returns a new array of items that are semantics points (optionally of a given type)
200
+ #
201
+ # @example Get all the power switch items for every equipment in a room
202
+ # lGreatRoom.equipments.flat_map(&:members).points(Semantics::Switch)
203
+ def points(*point_or_property_types) # rubocop:disable Metrics
204
+ unless (0..2).cover?(point_or_property_types.length)
205
+ raise ArgumentError, "wrong number of arguments (given #{point_or_property_types.length}, expected 0..2)"
206
+ end
207
+ unless point_or_property_types.all? do |tag|
208
+ tag < OpenHAB::DSL::Semantics::Point || tag < OpenHAB::DSL::Semantics::Property
209
+ end
210
+ raise ArgumentError, 'point_or_property_types must all be a subclass of Point or Property'
211
+ end
212
+ if point_or_property_types.count { |tag| tag < OpenHAB::DSL::Semantics::Point } > 1 ||
213
+ point_or_property_types.count { |tag| tag < OpenHAB::DSL::Semantics::Property } > 1
214
+ raise ArgumentError, 'point_or_property_types cannot both be a subclass of Point or Property'
215
+ end
216
+
217
+ select do |point|
218
+ next unless point.point?
219
+
220
+ point_or_property_types.all? do |tag|
221
+ (tag < OpenHAB::DSL::Semantics::Point && point.point_type&.<=(tag)) ||
222
+ (tag < OpenHAB::DSL::Semantics::Property && point.property_type&.<=(tag))
223
+ end
224
+ end
225
+ end
226
+ end
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '4.37.1'
8
+ VERSION = '4.38.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: 4.37.1
4
+ version: 4.38.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: 2022-04-09 00:00:00.000000000 Z
11
+ date: 2022-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,8 @@ files:
80
80
  - lib/openhab/dsl/items/persistence.rb
81
81
  - lib/openhab/dsl/items/player_item.rb
82
82
  - lib/openhab/dsl/items/rollershutter_item.rb
83
+ - lib/openhab/dsl/items/semantics.rb
84
+ - lib/openhab/dsl/items/semantics/enumerable.rb
83
85
  - lib/openhab/dsl/items/string_item.rb
84
86
  - lib/openhab/dsl/items/switch_item.rb
85
87
  - lib/openhab/dsl/items/timed_command.rb