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 +4 -4
- data/lib/openhab/dsl/actions.rb +2 -3
- data/lib/openhab/dsl/dsl.rb +2 -0
- data/lib/openhab/dsl/items/color_item.rb +60 -0
- data/lib/openhab/dsl/items/ensure.rb +93 -0
- data/lib/openhab/dsl/items/generic_item.rb +4 -27
- data/lib/openhab/dsl/items/group_item.rb +68 -0
- data/lib/openhab/dsl/items/item_equality.rb +36 -0
- data/lib/openhab/dsl/items/items.rb +12 -1
- data/lib/openhab/dsl/items/location_item.rb +54 -0
- data/lib/openhab/dsl/items/numeric_item.rb +3 -1
- data/lib/openhab/dsl/monkey_patch/ruby/number.rb +1 -1
- data/lib/openhab/dsl/rules/terse.rb +24 -0
- data/lib/openhab/dsl/types/hsb_type.rb +201 -0
- data/lib/openhab/dsl/types/percent_type.rb +2 -0
- data/lib/openhab/dsl/types/point_type.rb +151 -0
- data/lib/openhab/dsl/types/types.rb +2 -0
- data/lib/openhab/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9ccae52c29da91b7fadc2ac7ba2459e9870a257396849535458497ba48601e5
|
4
|
+
data.tar.gz: 0015aca73a5c79082adefb486afcbb545e324c0695d492e15397d2e0d691a204
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2db7c0a6f4182d3145871ab6936aa92d5acbe2a6d29e79f793a464d4fbb9514555021d9f0b103130ed99b04c9e149a414ea96df8f134f7db2fb71bade3824168
|
7
|
+
data.tar.gz: da447a4315a8d177db5fc6e476dd30ba93a071f06c6dc612a361f9d12a8539932f8a1659bdd919d8cdf61be2da759f720020d57fe399eaa1a2533bf5e1f56203
|
data/lib/openhab/dsl/actions.rb
CHANGED
@@ -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
|
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
|
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
|
data/lib/openhab/dsl/dsl.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
@@ -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
|
@@ -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'
|
data/lib/openhab/version.rb
CHANGED
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.
|
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-
|
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
|