openhab-scripting 4.2.0 → 4.6.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: 4ebe32d36d3366345d28b81bc71d9cd315d1d84feb4a4f1745c882209b1fdbe2
4
- data.tar.gz: 95331e97286e86bc993eb979531c5e3f80bc203e752e97aa9f3a60698fd56274
3
+ metadata.gz: a9ccae52c29da91b7fadc2ac7ba2459e9870a257396849535458497ba48601e5
4
+ data.tar.gz: 0015aca73a5c79082adefb486afcbb545e324c0695d492e15397d2e0d691a204
5
5
  SHA512:
6
- metadata.gz: e406fa7d011a733376bb5977293f44d20b893f1f990486f342c541f8d287c453736b75007ba586bfc5e6801638ac71bc6d294ad1b4a436a83247bee157150eb0
7
- data.tar.gz: d4fad57e6ad4f71a969b8f8c6791c4240854a74800647a4bed770123221eb2491c251c2a28bcbcd1649225d348aadd91b0efc188adba16a56aa7115620224028
6
+ metadata.gz: 2db7c0a6f4182d3145871ab6936aa92d5acbe2a6d29e79f793a464d4fbb9514555021d9f0b103130ed99b04c9e149a414ea96df8f134f7db2fb71bade3824168
7
+ data.tar.gz: da447a4315a8d177db5fc6e476dd30ba93a071f06c6dc612a361f9d12a8539932f8a1659bdd919d8cdf61be2da759f720020d57fe399eaa1a2533bf5e1f56203
@@ -9,7 +9,6 @@ module OpenHAB
9
9
  # Module to import and streamline access to OpenHAB actions
10
10
  #
11
11
  module Actions
12
- java_import org.openhab.core.library.types.PercentType
13
12
  include OpenHAB::Log
14
13
 
15
14
  OpenHAB::Core::OSGI.services('org.openhab.core.model.script.engine.action.ActionService')&.each do |service|
@@ -83,7 +82,7 @@ module OpenHAB
83
82
  # @return [void]
84
83
  #
85
84
  def say(text, voice: nil, sink: nil, volume: nil)
86
- volume = PercentType.new(volume&.to_i) unless volume.is_a?(PercentType) || volume.nil?
85
+ volume = Types::PercentType.new(volume) unless volume.is_a?(Types::PercentType) || volume.nil?
87
86
  Voice.say text, voice, sink, volume
88
87
  end
89
88
 
@@ -97,7 +96,7 @@ module OpenHAB
97
96
  # @return [void]
98
97
  #
99
98
  def play_sound(filename, sink: nil, volume: nil)
100
- volume = PercentType.new(volume&.to_i) unless volume.is_a?(PercentType) || volume.nil?
99
+ volume = Types::PercentType.new(volume) unless volume.is_a?(Types::PercentType) || volume.nil?
101
100
  Audio.playSound sink, filename, volume
102
101
  end
103
102
  end
@@ -10,6 +10,7 @@ require 'openhab/dsl/monkey_patch/ruby/ruby'
10
10
  require 'openhab/dsl/monkey_patch/events/events'
11
11
  require 'openhab/dsl/monkey_patch/actions/actions'
12
12
  require 'openhab/dsl/rules/rule'
13
+ require 'openhab/dsl/rules/terse'
13
14
  require 'openhab/dsl/actions'
14
15
  require 'openhab/dsl/timers'
15
16
  require 'openhab/dsl/group'
@@ -34,6 +35,7 @@ module OpenHAB
34
35
  base.send :include, OpenHAB::DSL::Items
35
36
  base.send :include, OpenHAB::DSL::Persistence
36
37
  base.send :include, OpenHAB::DSL::Rules
38
+ base.send :include, OpenHAB::DSL::Rules::Terse
37
39
  base.send :include, OpenHAB::DSL::States
38
40
  base.send :include, OpenHAB::DSL::Things
39
41
  base.send :include, OpenHAB::DSL::Timers
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ require_relative 'comparable_item'
6
+ require 'openhab/dsl/types/hsb_type'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ module Items
11
+ java_import org.openhab.core.library.items.ColorItem
12
+
13
+ # Adds methods to core OpenHAB ColorItem type to make it more natural in
14
+ # Ruby
15
+ class ColorItem < DimmerItem
16
+ extend Forwardable
17
+ include ComparableItem
18
+
19
+ # !@visibility private
20
+ def ==(other)
21
+ # need to check if we're referring to the same item before
22
+ # forwarding to <=> (and thus checking equality with state)
23
+ return true if equal?(other) || eql?(other)
24
+
25
+ super
26
+ end
27
+
28
+ #
29
+ # Type Coercion
30
+ #
31
+ # Coerce object to a HSBType
32
+ #
33
+ # @param [Types::HSBType, String] other object to coerce to a
34
+ # HSBType
35
+ #
36
+ # @return [[Types::HSBType, Types::HSBType]]
37
+ #
38
+ def coerce(other)
39
+ logger.trace("Coercing #{self} as a request from #{other.class}")
40
+ return [other, nil] unless state?
41
+ return [other, state] if other.is_a?(Types::HSBType) || other.respond_to?(:to_str)
42
+
43
+ raise TypeError, "can't convert #{other.class} into #{self.class}"
44
+ end
45
+
46
+ # any method that exists on {Types::HSBType} gets forwarded to +state+
47
+ delegate (Types::HSBType.instance_methods - instance_methods) => :state
48
+
49
+ # string commands aren't allowed on ColorItems, so try to implicitly
50
+ # convert it to an HSBType
51
+ # @!visibility private
52
+ def format_type(command)
53
+ return Types::HSBType.new(command) if command.respond_to?(:to_str)
54
+
55
+ super
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'generic_item'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module Items
8
+ # Functionality to implement +ensure+/+ensure_states+
9
+ module Ensure
10
+ # Contains the global +ensure_states+ method
11
+ module EnsureStates
12
+ # Global method that takes a block and for the duration of the block
13
+ # all commands sent will check if the item is in the command's state
14
+ # before sending the command.
15
+ #
16
+ # @example Turn on several switches only if they're not already on
17
+ # ensure_states do
18
+ # Switch1.on
19
+ # Switch2.on
20
+ # end
21
+ def ensure_states
22
+ old = Thread.current[:ensure_states]
23
+ Thread.current[:ensure_states] = true
24
+ yield
25
+ ensure
26
+ Thread.current[:ensure_states] = old
27
+ end
28
+ module_function :ensure_states
29
+ end
30
+
31
+ # Contains the +ensure+ method mixed into {GenericItem} and {GroupItem::GroupMembers}
32
+ module Ensurable
33
+ # Fluent method call that you can chain commands on to, that will
34
+ # then automatically ensure that the item is not in the command's
35
+ # state before sending the command.
36
+ #
37
+ # @example Turn switch on only if it's not on
38
+ # MySwitch.ensure.on
39
+ # @example Turn on all switches in a group that aren't already on
40
+ # MySwitchGroup.members.ensure.on
41
+ def ensure
42
+ GenericItemDelegate.new(self)
43
+ end
44
+ end
45
+
46
+ # Extensions for {Items::GenericItem} to implement {Ensure}'s
47
+ # functionality
48
+ module GenericItem
49
+ include Ensurable
50
+
51
+ # If +ensure_states+ is active (by block or chained method), then
52
+ # check if this item is in the command's state before actually
53
+ # sending the command
54
+ def command(command)
55
+ return super unless Thread.current[:ensure_states]
56
+ return if command == state
57
+
58
+ super
59
+ end
60
+ alias << command
61
+ end
62
+
63
+ # "anonymous" class that wraps any method call in +ensure_states+
64
+ # before forwarding to the wrapped object
65
+ # @!visibility private
66
+ class GenericItemDelegate
67
+ def initialize(item)
68
+ @item = item
69
+ end
70
+
71
+ # activate +ensure_states+ before forwarding to the wrapped object
72
+ def method_missing(method, *args, &block)
73
+ return super unless @item.respond_to?(method)
74
+
75
+ ensure_states do
76
+ @item.__send__(method, *args, &block)
77
+ end
78
+ end
79
+
80
+ # .
81
+ def respond_to_missing?(method, include_private = false)
82
+ @item.respond_to?(method, include_private) || super
83
+ end
84
+ end
85
+ end
86
+
87
+ GenericItem.prepend(Ensure::GenericItem)
88
+ GroupItem::GroupMembers.include(Ensure::Ensurable)
89
+ end
90
+ end
91
+ end
92
+
93
+ Object.include OpenHAB::DSL::Items::Ensure::EnsureStates
@@ -3,6 +3,8 @@
3
3
  require 'openhab/dsl/items/metadata'
4
4
  require 'openhab/dsl/items/persistence'
5
5
 
6
+ require_relative 'item_equality'
7
+
6
8
  module OpenHAB
7
9
  module DSL
8
10
  module Items
@@ -12,6 +14,8 @@ module OpenHAB
12
14
  # Ruby
13
15
  class GenericItem
14
16
  include Log
17
+ include ItemEquality
18
+
15
19
  prepend Metadata
16
20
  prepend Persistence
17
21
 
@@ -135,33 +139,6 @@ module OpenHAB
135
139
  other.instance_of?(self.class) && hash == other.hash
136
140
  end
137
141
 
138
- #
139
- # Check equality, with type conversions
140
- #
141
- # @param [GenericItem, Types::Type, Object] other object to
142
- # compare to
143
- #
144
- # If this item is +NULL+ or +UNDEF+, and +other+ is nil, they are
145
- # considered equal
146
- #
147
- # If this item is +NULL+ or +UNDEF+, and other is a {GenericItem}, they
148
- # are only considered equal if the other item is in the exact same
149
- # state (i.e. +NULL+ != +UNDEF+)
150
- #
151
- # Otherwise, the state of this item is compared with +other+
152
- #
153
- # @return [Boolean]
154
- #
155
- def ==(other)
156
- logger.trace("(#{self.class}) #{self} == #{other} (#{other.class})")
157
- return true if equal?(other) || eql?(other)
158
- return true if !state? && other.nil?
159
-
160
- return raw_state == other.raw_state if other.is_a?(GenericItem)
161
-
162
- state == other
163
- end
164
-
165
142
  # @!method null?
166
143
  # Check if the item state == +NULL+
167
144
  # @return [Boolean]
@@ -31,6 +31,74 @@ module OpenHAB
31
31
  def to_a
32
32
  group.get_members.to_a
33
33
  end
34
+
35
+ # Send a command to each member of the group
36
+ #
37
+ # @return [GroupMembers] +self+
38
+ def command(command)
39
+ each { |item| item << command }
40
+ end
41
+ alias << command
42
+
43
+ # @!method refresh
44
+ # Send the +REFRESH+ command to each member of the group
45
+ # @return [GroupMembers] +self+
46
+
47
+ # @!method on
48
+ # Send the +ON+ command to each member of the group
49
+ # @return [GroupMembers] +self+
50
+
51
+ # @!method off
52
+ # Send the +OFF+ command to each member of the group
53
+ # @return [GroupMembers] +self+
54
+
55
+ # @!method up
56
+ # Send the +UP+ command to each member of the group
57
+ # @return [GroupMembers] +self+
58
+
59
+ # @!method down
60
+ # Send the +DOWN+ command to each member of the group
61
+ # @return [GroupMembers] +self+
62
+
63
+ # @!method stop
64
+ # Send the +STOP+ command to each member of the group
65
+ # @return [GroupMembers] +self+
66
+
67
+ # @!method move
68
+ # Send the +MOVE+ command to each member of the group
69
+ # @return [GroupMembers] +self+
70
+
71
+ # @!method increase
72
+ # Send the +INCREASE+ command to each member of the group
73
+ # @return [GroupMembers] +self+
74
+
75
+ # @!method desrease
76
+ # Send the +DECREASE+ command to each member of the group
77
+ # @return [GroupMembers] +self+
78
+
79
+ # @!method play
80
+ # Send the +PLAY+ command to each member of the group
81
+ # @return [GroupMembers] +self+
82
+
83
+ # @!method pause
84
+ # Send the +PAUSE+ command to each member of the group
85
+ # @return [GroupMembers] +self+
86
+
87
+ # @!method rewind
88
+ # Send the +REWIND+ command to each member of the group
89
+ # @return [GroupMembers] +self+
90
+
91
+ # @!method fast_forward
92
+ # Send the +FASTFORWARD+ command to each member of the group
93
+ # @return [GroupMembers] +self+
94
+
95
+ # @!method next
96
+ # Send the +NEXT+ command to each member of the group
97
+ # @return [GroupMembers] +self+
98
+
99
+ # @!method previous
100
+ # Send the +PREVIOUS+ command to each member of the group
101
+ # @return [GroupMembers] +self+
34
102
  end
35
103
 
36
104
  include Enumerable
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Items
6
+ # Shared method for checking item equality by delegating to state
7
+ module ItemEquality
8
+ # Check equality, with type conversions
9
+ #
10
+ # @param [GenericItem, Types::Type, Object] other object to
11
+ # compare to
12
+ #
13
+ # If this item is +NULL+ or +UNDEF+, and +other+ is nil, they are
14
+ # considered equal
15
+ #
16
+ # If this item is +NULL+ or +UNDEF+, and other is a {GenericItem}, they
17
+ # are only considered equal if the other item is in the exact same
18
+ # state (i.e. +NULL+ != +UNDEF+)
19
+ #
20
+ # Otherwise, the state of this item is compared with +other+
21
+ #
22
+ # @return [Boolean]
23
+ #
24
+ def ==(other)
25
+ logger.trace("(#{self.class}) #{self} == #{other} (#{other.class})")
26
+ return true if equal?(other) || eql?(other)
27
+ return true if !state? && other.nil?
28
+
29
+ return raw_state == other.raw_state if other.is_a?(GenericItem)
30
+
31
+ state == other
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -10,14 +10,18 @@ require_relative 'switch_item'
10
10
  require_relative 'date_time_item'
11
11
  require_relative 'dimmer_item'
12
12
 
13
+ require_relative 'color_item'
13
14
  require_relative 'contact_item'
14
15
  require_relative 'group_item'
15
16
  require_relative 'image_item'
17
+ require_relative 'location_item'
16
18
  require_relative 'number_item'
17
19
  require_relative 'player_item'
18
20
  require_relative 'rollershutter_item'
19
21
  require_relative 'string_item'
20
22
 
23
+ require_relative 'ensure'
24
+
21
25
  module OpenHAB
22
26
  module DSL
23
27
  # Contains all OpenHAB *Item classes, as well as associated support
@@ -51,7 +55,7 @@ module OpenHAB
51
55
 
52
56
  # defined methods for commanding an item to one of the Enum states
53
57
  # as well as predicates for if an ItemCommandEvent is one of those commands
54
- def def_command_methods(klass) # rubocop:disable Metrics/MethodLength method has single purpose
58
+ def def_command_methods(klass) # rubocop:disable Metrics method has single purpose
55
59
  values_for_enums(klass.ACCEPTED_COMMAND_TYPES).each do |value|
56
60
  command = Types::COMMAND_ALIASES[value.to_s]
57
61
  next if klass.instance_methods.include?(command)
@@ -63,6 +67,13 @@ module OpenHAB
63
67
  end # end
64
68
  RUBY
65
69
 
70
+ OpenHAB::Core.logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
71
+ GroupItem::GroupMembers.class_eval <<~RUBY, __FILE__, __LINE__ + 1
72
+ def #{command} # def on
73
+ each(&:#{command}) # each(&:on)
74
+ end # end
75
+ RUBY
76
+
66
77
  OpenHAB::Core.logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
67
78
  MonkeyPatch::Events::ItemCommandEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
68
79
  def #{command}? # def refresh?
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ require_relative 'comparable_item'
6
+ require 'openhab/dsl/types/point_type'
7
+
8
+ module OpenHAB
9
+ module DSL
10
+ module Items
11
+ java_import org.openhab.core.library.items.LocationItem
12
+
13
+ # Adds methods to core OpenHAB NumberItem type to make it more natural in
14
+ # Ruby
15
+ class LocationItem < GenericItem
16
+ extend Forwardable
17
+ include ComparableItem
18
+
19
+ # !@visibility private
20
+ def ==(other)
21
+ # need to check if we're referring to the same item before
22
+ # forwarding to <=> (and thus checking equality with state)
23
+ return true if equal?(other) || eql?(other)
24
+
25
+ super
26
+ end
27
+
28
+ #
29
+ # Type Coercion
30
+ #
31
+ # Coerce object to a PointType
32
+ #
33
+ # @param [Types::PointType, String] other object to coerce to a
34
+ # PointType
35
+ #
36
+ # @return [[Types::PointType, Types::PointType]]
37
+ #
38
+ def coerce(other)
39
+ logger.trace("Coercing #{self} as a request from #{other.class}")
40
+ return [other, nil] unless state?
41
+ return [other, state] if other.is_a?(Types::PointType) || other.respond_to?(:to_str)
42
+
43
+ raise TypeError, "can't convert #{other.class} into #{self.class}"
44
+ end
45
+
46
+ # OpenHAB has this method, but it _only_ accepts PointType, so remove it and delegate
47
+ remove_method :distance_from
48
+
49
+ # any method that exists on {Types::PointType} gets forwarded to +state+
50
+ delegate (Types::PointType.instance_methods - instance_methods) => :state
51
+ end
52
+ end
53
+ end
54
+ end
@@ -2,7 +2,8 @@
2
2
 
3
3
  require 'forwardable'
4
4
 
5
- require 'openhab/dsl/items/comparable_item'
5
+ require_relative 'comparable_item'
6
+ require_relative 'item_equality'
6
7
 
7
8
  module OpenHAB
8
9
  module DSL
@@ -15,6 +16,7 @@ module OpenHAB
15
16
 
16
17
  # apply meta-programming methods to including class
17
18
  def self.included(klass)
19
+ klass.prepend ItemEquality # make sure this is first
18
20
  klass.extend Forwardable
19
21
  klass.delegate %i[+ - * / % | positive? negative? to_d to_f to_i to_int zero?] => :state
20
22
  # remove the JRuby default == so that we can inherit the Ruby method
@@ -91,7 +91,7 @@ module OpenHAB
91
91
 
92
92
  return super unless other.is_a?(javax.measure.Unit)
93
93
 
94
- QuantityType.new(to_d.to_java, other)
94
+ Types::QuantityType.new(to_d.to_java, other)
95
95
  end
96
96
  end
97
97
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Rules
6
+ # Module containing terse rule stubs
7
+ module Terse
8
+ %i[changed channel cron every updated received_command].each do |trigger|
9
+ class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
10
+ def #{trigger}(*args, name: nil, **kwargs, &block) # def changed(*args, name: nil, **kwargs, &block)
11
+ # if no name is given, just default to the name of the rules file # # if no name is given, just default to the name of the rules file
12
+ name ||= File.basename(caller_locations.last.path) # name ||= File.basename(caller_locations.last.path)
13
+ rule name do # rule name do
14
+ #{trigger}(*args, **kwargs) # changed(*args, **kwargs)
15
+ run(&block) # run(&block)
16
+ end # end
17
+ end # end
18
+ module_function #{trigger.inspect} # module_function :changed
19
+ RUBY
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'percent_type'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module Types
8
+ java_import org.openhab.core.library.types.HSBType
9
+
10
+ # global alias
11
+ ::HSBType = HSBType
12
+
13
+ # Adds methods to core OpenHAB HSBType to make it more natural in Ruby
14
+ class HSBType < PercentType
15
+ # @!parse BLACK = BLACK # @return [HSBType]
16
+ # @!parse WHITE = WHITE # @return [HSBType]
17
+ # @!parse RED = RED # @return [HSBType]
18
+ # @!parse GREEN = GREEN # @return [HSBType]
19
+ # @!parse BLUE = BLUE # @return [HSBType]
20
+
21
+ # conversion to QuantityType doesn't make sense on HSBType
22
+ undef_method :|
23
+
24
+ remove_method :==
25
+
26
+ # r, g, b as an array of symbols
27
+ RGB_KEYS = %i[r g b].freeze
28
+ private_constant :RGB_KEYS
29
+
30
+ class << self
31
+ # @!method from_rgb(r, g, b)
32
+ # Create HSBType from RGB values
33
+ # @param r [Integer] Red component (0-255)
34
+ # @param g [Integer] Green component (0-255)
35
+ # @param b [Integer] Blue component (0-255)
36
+ # @return [HSBType]
37
+
38
+ # @!method from_xy(x, y)
39
+ # Create HSBType representing the provided xy color values in CIE XY color model
40
+ # @param x [Float]
41
+ # @param y [Float]
42
+ # @return [HSBType]
43
+
44
+ # Create HSBType from hue, saturation, and brightness values
45
+ # @param hue [DecimalType, QuantityType, Numeric] Hue component (0-360º)
46
+ # @param saturation [PercentType, Numeric] Saturation component (0-100%)
47
+ # @param brightness [PercentType, Numeric] Brightness component (0-100%)
48
+ # @return [HSBType]
49
+ def from_hsv(hue, saturation, brightness)
50
+ new(hue, saturation, brightness)
51
+ end
52
+
53
+ # add additional "overloads" to the constructor
54
+ # @!visibility private
55
+ def new(*args) # rubocop:disable Metrics
56
+ if args.length == 1 && args.first.respond_to?(:to_str)
57
+ value = args.first.to_str
58
+
59
+ # parse some formats OpenHAB doesn't understand
60
+ # in this case, HTML hex format for rgb
61
+ if (match = value.match(/^#(\h{2})(\h{2})(\h{2})$/))
62
+ rgb = match.to_a[1..3].map { |v| v.to_i(16) }
63
+ logger.trace("creating from rgb #{rgb.inspect}")
64
+ return from_rgb(*rgb)
65
+ end
66
+ end
67
+
68
+ return super unless args.length == 3
69
+
70
+ # convert from several numeric-like types to the exact types
71
+ # OpenHAB needs
72
+ hue = args[0]
73
+ args[0] = if hue.is_a?(DecimalType)
74
+ hue
75
+ elsif hue.is_a?(QuantityType)
76
+ DecimalType.new(hue.to_unit(::Units::DEGREE_ANGLE).to_big_decimal)
77
+ elsif hue.respond_to?(:to_d)
78
+ DecimalType.new(hue)
79
+ end
80
+ args[1..2] = args[1..2].map do |v|
81
+ if v.is_a?(PercentType)
82
+ v
83
+ elsif v.respond_to?(:to_d)
84
+ PercentType.new(v)
85
+ end
86
+ end
87
+
88
+ super(*args)
89
+ end
90
+ end
91
+
92
+ #
93
+ # Comparison
94
+ #
95
+ # @param [NumericType, Items::NumericItem, Items::ColorItem, Numeric, String]
96
+ # other object to compare to
97
+ #
98
+ # @return [Integer, nil] -1, 0, +1 depending on whether +other+ is
99
+ # less than, equal to, or greater than self
100
+ #
101
+ # nil is returned if the two values are incomparable
102
+ #
103
+ def <=>(other)
104
+ logger.trace("(#{self.class}) #{self} <=> #{other} (#{other.class})")
105
+ if other.is_a?(Items::ColorItem) ||
106
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(ColorItem))
107
+ return false unless other.state?
108
+
109
+ self <=> other.state
110
+ elsif other.respond_to?(:to_str)
111
+ self <=> HSBType.new(other)
112
+ else
113
+ super
114
+ end
115
+ end
116
+
117
+ #
118
+ # Type Coercion
119
+ #
120
+ # Coerce object to a HSBType
121
+ #
122
+ # @param [NumericType, Items::NumericItem, Items::ColorItem, Numeric, String]
123
+ # other object to coerce to a HSBType
124
+ #
125
+ # @return [[HSBType, HSBType]]
126
+ #
127
+ def coerce(other)
128
+ logger.trace("Coercing #{self} as a request from #{other.class}")
129
+ if other.is_a?(Items::NumericItem) ||
130
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(Items::NumericItem))
131
+ raise TypeError, "can't convert #{UnDefType} into #{self.class}" unless other.state?
132
+
133
+ [other.state, self]
134
+ elsif other.respond_to?(:to_str)
135
+ [HSBType.new(other.to_str), self]
136
+ else
137
+ super
138
+ end
139
+ end
140
+
141
+ # rename raw methods so we can overwrite them
142
+ # @!visibility private
143
+ alias raw_hue hue
144
+
145
+ # @!attribute [r] hue
146
+ # @return [QuantityType]
147
+ def hue
148
+ QuantityType.new(raw_hue.to_big_decimal, ::Units::DEGREE_ANGLE)
149
+ end
150
+
151
+ # Convert to a packed 32-bit RGB value representing the color in the default sRGB color model.
152
+ #
153
+ # The alpha component is always 100%.
154
+ #
155
+ # @return [Integer]
156
+ alias argb rgb
157
+
158
+ # Convert to a packed 24-bit RGB value representing the color in the default sRGB color model.
159
+ # @return [Integer]
160
+ def rgb
161
+ argb & 0xffffff
162
+ end
163
+
164
+ # Convert to an HTML-style string of 6 hex characters in the default sRGB color model.
165
+ # @return [String] +'#xxxxxx'+
166
+ def to_hex
167
+ Kernel.format('#%06x', rgb)
168
+ end
169
+
170
+ # include units
171
+ # @!visibility private
172
+ def to_s
173
+ "#{hue},#{saturation},#{brightness}"
174
+ end
175
+
176
+ # @!attribute [r] saturation
177
+ # @return [PercentType]
178
+
179
+ # @!attribute [r] brightness
180
+ # @return [PercentType]
181
+
182
+ # @!attribute [r] red
183
+ # @return [PercentType]
184
+
185
+ # @!attribute [r] green
186
+ # @return [PercentType]
187
+
188
+ # @!attribute [r] blue
189
+ # @return [PercentType]
190
+
191
+ # @!method to_rgb
192
+ # Convert to RGB values representing the color in the default sRGB color model
193
+ # @return [[PercentType, PercentType, PercentType]]
194
+
195
+ # @!method to_xy
196
+ # Convert to the xyY values representing this object's color in CIE XY color model
197
+ # @return [[PercentType, PercentType]]
198
+ end
199
+ end
200
+ end
201
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'decimal_type'
4
+
3
5
  module OpenHAB
4
6
  module DSL
5
7
  module Types
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.library.types.PointType
7
+
8
+ # global scope
9
+ # @!visibility private
10
+ ::PointType = PointType
11
+
12
+ # Adds methods to core OpenHAB PointType to make it more natural in Ruby
13
+ class PointType
14
+ # @!parse include PrimitiveType
15
+
16
+ # @param latitude [DecimalType, QuantityType, StringType, Numeric]
17
+ # @param longitude [DecimalType, QuantityType, StringType, Numeric]
18
+ # @param altitude [DecimalType, QuantityType, StringType, Numeric]
19
+ def initialize(*args) # rubocop:disable Metrics
20
+ if (2..3).cover?(args.length)
21
+ args = args.each_with_index.map do |value, index|
22
+ if value.is_a?(DecimalType) || value.is_a?(StringType)
23
+ value
24
+ elsif value.is_a?(QuantityType)
25
+ unit = index == 2 ? Units.unit || SIUnits::METRE : Units::DEGREE_ANGLE
26
+ DecimalType.new(value.to_unit(unit).to_big_decimal)
27
+ elsif value.respond_to?(:to_str)
28
+ StringType.new(value.to_str)
29
+ elsif value.respond_to?(:to_d)
30
+ DecimalType.new(value)
31
+ end
32
+ end
33
+ end
34
+
35
+ super(*args)
36
+ end
37
+
38
+ #
39
+ # Check equality without type conversion
40
+ #
41
+ # @return [Boolean] if the same value is represented, without type
42
+ # conversion
43
+ def eql?(other)
44
+ return false unless other.instance_of?(self.class)
45
+
46
+ equals(other.to_s).zero?
47
+ end
48
+
49
+ #
50
+ # Check equality with type conversion
51
+ #
52
+ # @param [PointType, Items::LocationItem, String]
53
+ # other object to compare to
54
+ #
55
+ # @return [Boolean]
56
+ #
57
+ def ==(other) # rubocop:disable Metrics
58
+ logger.trace("(#{self.class}) #{self} == #{other} (#{other.class})")
59
+ if other.is_a?(Items::LocationItem) ||
60
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(LocationItem))
61
+ return false unless other.state?
62
+
63
+ self == other.state
64
+ elsif other.respond_to?(:to_str)
65
+ self == PointType.new(other)
66
+ elsif other.respond_to?(:coerce)
67
+ lhs, rhs = other.coerce(self)
68
+ lhs == rhs
69
+ end
70
+ end
71
+
72
+ #
73
+ # Type Coercion
74
+ #
75
+ # Coerce object to a PointType
76
+ #
77
+ # @param [Items::LocationItem, String] other object to coerce to a
78
+ # PointType
79
+ #
80
+ # @return [[PointType, PointType]]
81
+ #
82
+ def coerce(other)
83
+ [coerce_single(other), self]
84
+ end
85
+
86
+ # rename raw methods so we can overwrite them
87
+ # @!visibility private
88
+ alias raw_latitude latitude
89
+ # .
90
+ # @!visibility private
91
+ alias raw_longitude longitude
92
+ # .
93
+ # @!visibility private
94
+ alias raw_altitude altitude
95
+ # .
96
+ # @!visibility private
97
+ alias raw_distance_from distance_from
98
+
99
+ # @!attribute [r] latitude
100
+ # @return [QuantityType]
101
+ def latitude
102
+ QuantityType.new(raw_latitude.to_big_decimal, SIUnits::DEGREE_ANGLE)
103
+ end
104
+
105
+ # @!attribute [r] longitude
106
+ # @return [QuantityType]
107
+ def longitude
108
+ QuantityType.new(raw_longitude.to_big_decimal, SIUnits::DEGREE_ANGLE)
109
+ end
110
+
111
+ # @!attribute [r] altitude
112
+ # @return [QuantityType]
113
+ def altitude
114
+ QuantityType.new(raw_altitude.to_big_decimal, Units::METRE)
115
+ end
116
+
117
+ #
118
+ # Calculate the distance in meters from other, ignoring altitude.
119
+ #
120
+ # This algorithm also ignores the oblate spheroid shape of Earth and
121
+ # assumes a perfect sphere, so results are inexact.
122
+ #
123
+ # @return [QuantityType]
124
+ def distance_from(other)
125
+ logger.trace("(#{self}).distance_from(#{other} (#{other.class})")
126
+ QuantityType.new(raw_distance_from(coerce_single(other)), SIUnits::METRE)
127
+ end
128
+ alias - distance_from
129
+
130
+ private
131
+
132
+ # coerce an object to a PointType
133
+ # @return [PointType]
134
+ def coerce_single(other) # rubocop:disable Metrics/MethodLength
135
+ logger.trace("Coercing #{self} as a request from #{other.class}")
136
+ if other.is_a?(PointType)
137
+ other
138
+ elsif other.is_a?(Items::LocationItem)
139
+ raise TypeError, "can't convert #{other.raw_state} into #{self.class}" unless other.state?
140
+
141
+ other.state
142
+ elsif other.respond_to?(:to_str)
143
+ PointType.new(other.to_str)
144
+ else
145
+ raise TypeError, "can't convert #{other.class} into #{self.class}"
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -4,12 +4,14 @@ require_relative 'type'
4
4
 
5
5
  require_relative 'date_time_type'
6
6
  require_relative 'decimal_type'
7
+ require_relative 'hsb_type'
7
8
  require_relative 'increase_decrease_type'
8
9
  require_relative 'next_previous_type'
9
10
  require_relative 'open_closed_type'
10
11
  require_relative 'on_off_type'
11
12
  require_relative 'percent_type'
12
13
  require_relative 'play_pause_type'
14
+ require_relative 'point_type'
13
15
  require_relative 'quantity_type'
14
16
  require_relative 'refresh_type'
15
17
  require_relative 'rewind_fastforward_type'
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '4.2.0'
8
+ VERSION = '4.6.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.2.0
4
+ version: 4.6.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-10-18 00:00:00.000000000 Z
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -54,15 +54,19 @@ files:
54
54
  - lib/openhab/dsl/dsl.rb
55
55
  - lib/openhab/dsl/gems.rb
56
56
  - lib/openhab/dsl/group.rb
57
+ - lib/openhab/dsl/items/color_item.rb
57
58
  - lib/openhab/dsl/items/comparable_item.rb
58
59
  - lib/openhab/dsl/items/contact_item.rb
59
60
  - lib/openhab/dsl/items/date_time_item.rb
60
61
  - lib/openhab/dsl/items/dimmer_item.rb
62
+ - lib/openhab/dsl/items/ensure.rb
61
63
  - lib/openhab/dsl/items/generic_item.rb
62
64
  - lib/openhab/dsl/items/group_item.rb
63
65
  - lib/openhab/dsl/items/image_item.rb
66
+ - lib/openhab/dsl/items/item_equality.rb
64
67
  - lib/openhab/dsl/items/item_registry.rb
65
68
  - lib/openhab/dsl/items/items.rb
69
+ - lib/openhab/dsl/items/location_item.rb
66
70
  - lib/openhab/dsl/items/metadata.rb
67
71
  - lib/openhab/dsl/items/number_item.rb
68
72
  - lib/openhab/dsl/items/numeric_item.rb
@@ -89,6 +93,7 @@ files:
89
93
  - lib/openhab/dsl/rules/property.rb
90
94
  - lib/openhab/dsl/rules/rule.rb
91
95
  - lib/openhab/dsl/rules/rule_config.rb
96
+ - lib/openhab/dsl/rules/terse.rb
92
97
  - lib/openhab/dsl/rules/triggers/changed.rb
93
98
  - lib/openhab/dsl/rules/triggers/channel.rb
94
99
  - lib/openhab/dsl/rules/triggers/command.rb
@@ -102,6 +107,7 @@ files:
102
107
  - lib/openhab/dsl/types/comparable_type.rb
103
108
  - lib/openhab/dsl/types/date_time_type.rb
104
109
  - lib/openhab/dsl/types/decimal_type.rb
110
+ - lib/openhab/dsl/types/hsb_type.rb
105
111
  - lib/openhab/dsl/types/increase_decrease_type.rb
106
112
  - lib/openhab/dsl/types/next_previous_type.rb
107
113
  - lib/openhab/dsl/types/numeric_type.rb
@@ -109,6 +115,7 @@ files:
109
115
  - lib/openhab/dsl/types/open_closed_type.rb
110
116
  - lib/openhab/dsl/types/percent_type.rb
111
117
  - lib/openhab/dsl/types/play_pause_type.rb
118
+ - lib/openhab/dsl/types/point_type.rb
112
119
  - lib/openhab/dsl/types/quantity_type.rb
113
120
  - lib/openhab/dsl/types/refresh_type.rb
114
121
  - lib/openhab/dsl/types/rewind_fastforward_type.rb