openhab-scripting 4.4.0 → 4.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/openhab/core/entity_lookup.rb +2 -3
- data/lib/openhab/core/script_handling.rb +39 -0
- data/lib/openhab/core/thread_local.rb +25 -0
- data/lib/openhab/dsl/items/color_item.rb +60 -0
- data/lib/openhab/dsl/items/items.rb +9 -4
- data/lib/openhab/dsl/items/location_item.rb +54 -0
- data/lib/openhab/dsl/items/numeric_item.rb +12 -1
- data/lib/openhab/dsl/monkey_patch/ruby/number.rb +1 -1
- data/lib/openhab/dsl/rules/automation_rule.rb +13 -0
- data/lib/openhab/dsl/rules/rule.rb +14 -0
- data/lib/openhab/dsl/rules/rule_config.rb +1 -1
- data/lib/openhab/dsl/time_of_day.rb +1 -0
- data/lib/openhab/dsl/timers.rb +49 -5
- 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 +7 -1
- data/lib/openhab/version.rb +1 -1
- data/lib/openhab.rb +6 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 287e243222ea07f7a3157b208722d47f489f14456713ad86401292f6b2fda942
|
4
|
+
data.tar.gz: 44968c29cf24415646ebb27ce64c3894966c4e9f9707edcd303eb89d4a4b1f04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12ce91f43449208a374b04ab92171a93c4ab3b68f2fee8ce7f948f7bf21f2be4a8d967b8f5758be957f5ca36cac831ebcb5f184204d650ed50d1fb345b1c2f7a
|
7
|
+
data.tar.gz: d7da5a64ab6aef028308a998ea83a77da1d77d12cbccb24c34875f6e51a9c6360e204efd75287de4d4f1fbc17b9bcd722057da227821f519452945fb17fd1666
|
@@ -4,6 +4,8 @@ require 'pp'
|
|
4
4
|
require 'java'
|
5
5
|
require 'set'
|
6
6
|
|
7
|
+
require 'openhab/log/logger'
|
8
|
+
|
7
9
|
# Automation lookup and injection of OpenHab entities
|
8
10
|
|
9
11
|
module OpenHAB
|
@@ -24,9 +26,6 @@ module OpenHAB
|
|
24
26
|
# @return [Object] Item or Thing if found in registry
|
25
27
|
#
|
26
28
|
def method_missing(method, *args, &block)
|
27
|
-
return if method.to_s == 'scriptLoaded'
|
28
|
-
return if method.to_s == 'scriptUnloaded'
|
29
|
-
|
30
29
|
logger.trace("method missing, performing OpenHab Lookup for: #{method}")
|
31
30
|
EntityLookup.lookup_entity(method) || super
|
32
31
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openhab/log/logger'
|
4
|
+
require 'openhab/dsl/rules/rule'
|
5
|
+
require 'openhab/dsl/timers'
|
6
|
+
|
7
|
+
# OpenHAB main module
|
8
|
+
module OpenHAB
|
9
|
+
module Core
|
10
|
+
#
|
11
|
+
# Manages script loading and unloading
|
12
|
+
#
|
13
|
+
module ScriptHandling
|
14
|
+
include OpenHAB::Log
|
15
|
+
|
16
|
+
#
|
17
|
+
# Executed when OpenHAB unloads a script file
|
18
|
+
#
|
19
|
+
# rubocop:disable Naming/MethodName
|
20
|
+
# method name dictacted by OpenHAB
|
21
|
+
def scriptUnloaded
|
22
|
+
logger.trace('Script unloaded')
|
23
|
+
OpenHAB::DSL::Rules.cleanup_rules
|
24
|
+
OpenHAB::DSL::Timers.cancel_all
|
25
|
+
end
|
26
|
+
# rubocop:enable Naming/MethodName
|
27
|
+
|
28
|
+
#
|
29
|
+
# Executed when OpenHAB loads a script file
|
30
|
+
#
|
31
|
+
# rubocop:disable Naming/MethodName
|
32
|
+
# method name dictacted by OpenHAB
|
33
|
+
def scriptLoaded(filename)
|
34
|
+
logger.trace("Script loaded: #{filename}")
|
35
|
+
end
|
36
|
+
# rubocop:enable Naming/MethodName
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# OpenHAB main module
|
4
|
+
module OpenHAB
|
5
|
+
module Core
|
6
|
+
#
|
7
|
+
# Manages thread local varaibles for access inside of blocks
|
8
|
+
#
|
9
|
+
module ThreadLocal
|
10
|
+
#
|
11
|
+
# Execute the supplied block with the supplied values set for the currently running thread
|
12
|
+
# The previous values for each key are restored after the block is executed
|
13
|
+
#
|
14
|
+
# @param [Hash] Keys and values to set for running thread
|
15
|
+
#
|
16
|
+
def thread_local(**values)
|
17
|
+
old_values = values.map { |key, _value| [key, Thread.current[key]] }.to_h
|
18
|
+
values.each { |key, value| Thread.current[key] = value }
|
19
|
+
yield
|
20
|
+
ensure
|
21
|
+
old_values.each { |key, value| Thread.current[key] = value }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -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
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'openhab/dsl/monkey_patch/events/item_command'
|
4
|
+
require 'openhab/dsl/types/types'
|
4
5
|
|
5
6
|
require_relative 'item_registry'
|
6
7
|
|
@@ -10,9 +11,11 @@ require_relative 'switch_item'
|
|
10
11
|
require_relative 'date_time_item'
|
11
12
|
require_relative 'dimmer_item'
|
12
13
|
|
14
|
+
require_relative 'color_item'
|
13
15
|
require_relative 'contact_item'
|
14
16
|
require_relative 'group_item'
|
15
17
|
require_relative 'image_item'
|
18
|
+
require_relative 'location_item'
|
16
19
|
require_relative 'number_item'
|
17
20
|
require_relative 'player_item'
|
18
21
|
require_relative 'rollershutter_item'
|
@@ -25,6 +28,8 @@ module OpenHAB
|
|
25
28
|
# Contains all OpenHAB *Item classes, as well as associated support
|
26
29
|
# modules
|
27
30
|
module Items
|
31
|
+
include OpenHAB::Log
|
32
|
+
|
28
33
|
class << self
|
29
34
|
private
|
30
35
|
|
@@ -42,7 +47,7 @@ module OpenHAB
|
|
42
47
|
_command_predicate, state_predicate = Types::PREDICATE_ALIASES[state.to_s]
|
43
48
|
next if klass.instance_methods.include?(state_predicate)
|
44
49
|
|
45
|
-
|
50
|
+
logger.trace("Defining #{klass}##{state_predicate} for #{state}")
|
46
51
|
klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
47
52
|
def #{state_predicate} # def on?
|
48
53
|
raw_state == #{state} # raw_state == ON
|
@@ -58,21 +63,21 @@ module OpenHAB
|
|
58
63
|
command = Types::COMMAND_ALIASES[value.to_s]
|
59
64
|
next if klass.instance_methods.include?(command)
|
60
65
|
|
61
|
-
|
66
|
+
logger.trace("Defining #{klass}##{command} for #{value}")
|
62
67
|
klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
63
68
|
def #{command} # def on
|
64
69
|
command(#{value}) # command(ON)
|
65
70
|
end # end
|
66
71
|
RUBY
|
67
72
|
|
68
|
-
|
73
|
+
logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
|
69
74
|
GroupItem::GroupMembers.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
70
75
|
def #{command} # def on
|
71
76
|
each(&:#{command}) # each(&:on)
|
72
77
|
end # end
|
73
78
|
RUBY
|
74
79
|
|
75
|
-
|
80
|
+
logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
|
76
81
|
MonkeyPatch::Events::ItemCommandEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
77
82
|
def #{command}? # def refresh?
|
78
83
|
command == #{value} # command == 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
|
@@ -15,10 +15,11 @@ module OpenHAB
|
|
15
15
|
include ComparableItem
|
16
16
|
|
17
17
|
# apply meta-programming methods to including class
|
18
|
+
# @!visibility private
|
18
19
|
def self.included(klass)
|
19
20
|
klass.prepend ItemEquality # make sure this is first
|
20
21
|
klass.extend Forwardable
|
21
|
-
klass.delegate %i[+ - * / % |
|
22
|
+
klass.delegate %i[+ - * / % | to_d to_f to_i to_int] => :state
|
22
23
|
# remove the JRuby default == so that we can inherit the Ruby method
|
23
24
|
klass.remove_method :==
|
24
25
|
end
|
@@ -62,6 +63,16 @@ module OpenHAB
|
|
62
63
|
|
63
64
|
super
|
64
65
|
end
|
66
|
+
|
67
|
+
%i[positive? negative? zero?].each do |predicate|
|
68
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
69
|
+
def #{predicate} # def positive?
|
70
|
+
return false unless state? # return false unless state?
|
71
|
+
#
|
72
|
+
state.#{predicate} # state.positive?
|
73
|
+
end # end
|
74
|
+
RUBY
|
75
|
+
end
|
65
76
|
end
|
66
77
|
end
|
67
78
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'java'
|
4
|
+
require 'set'
|
5
|
+
require 'openhab/core/thread_local'
|
6
|
+
require 'openhab/log/logger'
|
4
7
|
|
5
8
|
module OpenHAB
|
6
9
|
module DSL
|
@@ -16,6 +19,7 @@ module OpenHAB
|
|
16
19
|
# way of breaking it up into multiple classes
|
17
20
|
class AutomationRule < Java::OrgOpenhabCoreAutomationModuleScriptRulesupportSharedSimple::SimpleRule
|
18
21
|
include OpenHAB::Log
|
22
|
+
include OpenHAB::Core::ThreadLocal
|
19
23
|
include OpenHAB::DSL::TimeOfDay
|
20
24
|
java_import java.time.ZonedDateTime
|
21
25
|
|
@@ -24,6 +28,7 @@ module OpenHAB
|
|
24
28
|
#
|
25
29
|
# @param [Config] config Rule configuration
|
26
30
|
#
|
31
|
+
# Constructor sets a number of variables, no further decomposition necessary
|
27
32
|
def initialize(config:)
|
28
33
|
super()
|
29
34
|
set_name(config.name)
|
@@ -59,6 +64,14 @@ module OpenHAB
|
|
59
64
|
end
|
60
65
|
end
|
61
66
|
|
67
|
+
#
|
68
|
+
# Cleanup any resources associated with automation rule
|
69
|
+
#
|
70
|
+
def cleanup
|
71
|
+
logger.trace "Cancelling #{@trigger_delays.length} Trigger Delays(s) for rule '#{name}'"
|
72
|
+
@trigger_delays.each_value { |trigger_delay| trigger_delay.timer&.cancel }
|
73
|
+
end
|
74
|
+
|
62
75
|
private
|
63
76
|
|
64
77
|
#
|
@@ -13,6 +13,12 @@ module OpenHAB
|
|
13
13
|
# Creates and manages OpenHAB Rules
|
14
14
|
#
|
15
15
|
module Rules
|
16
|
+
@script_rules = []
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_reader :script_rules
|
20
|
+
end
|
21
|
+
|
16
22
|
#
|
17
23
|
# Create a new rule
|
18
24
|
#
|
@@ -45,6 +51,13 @@ module OpenHAB
|
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
54
|
+
#
|
55
|
+
# Cleanup rules in this script file
|
56
|
+
#
|
57
|
+
def self.cleanup_rules
|
58
|
+
@script_rules.each(&:cleanup)
|
59
|
+
end
|
60
|
+
|
48
61
|
private
|
49
62
|
|
50
63
|
#
|
@@ -67,6 +80,7 @@ module OpenHAB
|
|
67
80
|
return unless create_rule?(config)
|
68
81
|
|
69
82
|
rule = AutomationRule.new(config: config)
|
83
|
+
Rules.script_rules << rule
|
70
84
|
add_rule(rule)
|
71
85
|
rule.execute if config.on_start?
|
72
86
|
end
|
@@ -26,7 +26,7 @@ module OpenHAB
|
|
26
26
|
class RuleConfig
|
27
27
|
include OpenHAB::Log
|
28
28
|
include OpenHAB::Core::EntityLookup
|
29
|
-
|
29
|
+
prepend OpenHAB::DSL::Rules::Triggers
|
30
30
|
include OpenHAB::DSL::Rules::Guard
|
31
31
|
include OpenHAB::DSL::Rules::Property
|
32
32
|
extend OpenHAB::DSL
|
data/lib/openhab/dsl/timers.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'java'
|
4
4
|
require 'delegate'
|
5
5
|
require 'forwardable'
|
6
|
+
require 'openhab/log/logger'
|
6
7
|
|
7
8
|
module OpenHAB
|
8
9
|
module DSL
|
@@ -10,15 +11,23 @@ module OpenHAB
|
|
10
11
|
# Provides access to and ruby wrappers around OpenHAB timers
|
11
12
|
#
|
12
13
|
module Timers
|
14
|
+
include OpenHAB::Log
|
13
15
|
java_import org.openhab.core.model.script.actions.ScriptExecution
|
14
16
|
java_import java.time.ZonedDateTime
|
15
17
|
|
18
|
+
# Tracks active timers
|
19
|
+
@timers = Set.new
|
20
|
+
class << self
|
21
|
+
attr_accessor :timers
|
22
|
+
end
|
23
|
+
|
16
24
|
# Ruby wrapper for OpenHAB Timer
|
17
25
|
# This class implements delegator to delegate methods to the OpenHAB timer
|
18
26
|
#
|
19
27
|
# @author Brian O'Connell
|
20
28
|
# @since 2.0.0
|
21
29
|
class Timer < SimpleDelegator
|
30
|
+
include OpenHAB::Log
|
22
31
|
extend Forwardable
|
23
32
|
|
24
33
|
def_delegator :@timer, :is_active, :active?
|
@@ -31,20 +40,19 @@ module OpenHAB
|
|
31
40
|
# @param [Duration] duration Duration until timer should fire
|
32
41
|
# @param [Block] block Block to execute when timer fires
|
33
42
|
#
|
34
|
-
def initialize(duration
|
43
|
+
def initialize(duration:, &block)
|
35
44
|
@duration = duration
|
36
45
|
|
37
46
|
# A semaphore is used to prevent a race condition in which calling the block from the timer thread
|
38
47
|
# occurs before the @timer variable can be set resulting in @timer being nil
|
39
48
|
semaphore = Mutex.new
|
40
49
|
|
41
|
-
timer_block = proc { semaphore.synchronize { yield(self) } }
|
42
|
-
|
43
50
|
semaphore.synchronize do
|
44
51
|
@timer = ScriptExecution.createTimer(
|
45
|
-
ZonedDateTime.now.plus(@duration), timer_block
|
52
|
+
ZonedDateTime.now.plus(@duration), timer_block(semaphore, &block)
|
46
53
|
)
|
47
54
|
super(@timer)
|
55
|
+
Timers.timers << self
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
@@ -53,12 +61,40 @@ module OpenHAB
|
|
53
61
|
#
|
54
62
|
# @param [Duration] duration
|
55
63
|
#
|
56
|
-
# @return [
|
64
|
+
# @return [Timer] Rescheduled timer instances
|
57
65
|
#
|
58
66
|
def reschedule(duration = nil)
|
59
67
|
duration ||= @duration
|
68
|
+
Timers.timers << self
|
60
69
|
@timer.reschedule(ZonedDateTime.now.plus(duration))
|
61
70
|
end
|
71
|
+
|
72
|
+
# Cancel timer
|
73
|
+
#
|
74
|
+
# @return [Boolean] True if cancel was successful, false otherwise
|
75
|
+
#
|
76
|
+
def cancel
|
77
|
+
Timers.timers.delete(self)
|
78
|
+
@timer.cancel
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
#
|
84
|
+
# Constructs a block to execute timer within
|
85
|
+
#
|
86
|
+
# @param [Semaphore] Semaphore to obtain before executing
|
87
|
+
#
|
88
|
+
# @return [Proc] Block for timer to execute
|
89
|
+
#
|
90
|
+
def timer_block(semaphore)
|
91
|
+
proc {
|
92
|
+
semaphore.synchronize do
|
93
|
+
Timers.timers.delete(self)
|
94
|
+
yield(self)
|
95
|
+
end
|
96
|
+
}
|
97
|
+
end
|
62
98
|
end
|
63
99
|
|
64
100
|
#
|
@@ -72,6 +108,14 @@ module OpenHAB
|
|
72
108
|
def after(duration, &block)
|
73
109
|
Timer.new(duration: duration, &block)
|
74
110
|
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Cancels all active timers
|
114
|
+
#
|
115
|
+
def self.cancel_all
|
116
|
+
logger.trace("Cancelling #{@timers.length} timers")
|
117
|
+
@timers.each(&:cancel)
|
118
|
+
end
|
75
119
|
end
|
76
120
|
end
|
77
121
|
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
|
@@ -1,15 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'openhab/log/logger'
|
4
|
+
|
3
5
|
require_relative 'type'
|
4
6
|
|
5
7
|
require_relative 'date_time_type'
|
6
8
|
require_relative 'decimal_type'
|
9
|
+
require_relative 'hsb_type'
|
7
10
|
require_relative 'increase_decrease_type'
|
8
11
|
require_relative 'next_previous_type'
|
9
12
|
require_relative 'open_closed_type'
|
10
13
|
require_relative 'on_off_type'
|
11
14
|
require_relative 'percent_type'
|
12
15
|
require_relative 'play_pause_type'
|
16
|
+
require_relative 'point_type'
|
13
17
|
require_relative 'quantity_type'
|
14
18
|
require_relative 'refresh_type'
|
15
19
|
require_relative 'rewind_fastforward_type'
|
@@ -25,6 +29,8 @@ module OpenHAB
|
|
25
29
|
# modules
|
26
30
|
#
|
27
31
|
module Types
|
32
|
+
include OpenHAB::Log
|
33
|
+
|
28
34
|
# Hash taking a Enum value, and returning two symbols of
|
29
35
|
# predicates to be defined for it. the first is the "command" form,
|
30
36
|
# which should be defined on ItemCommandEvent, and on the Type itself.
|
@@ -63,7 +69,7 @@ module OpenHAB
|
|
63
69
|
states = PREDICATE_ALIASES[value.to_s]
|
64
70
|
|
65
71
|
([command] | states).each do |method|
|
66
|
-
|
72
|
+
logger.trace("Defining #{klass}##{method} for #{value}")
|
67
73
|
klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
68
74
|
def #{method} # def on?
|
69
75
|
self == #{value} # self == ON
|
data/lib/openhab/version.rb
CHANGED
data/lib/openhab.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'openhab/core/load_path'
|
4
|
+
require 'openhab/core/entity_lookup'
|
5
|
+
require 'openhab/core/script_handling'
|
4
6
|
require 'openhab/core/openhab_setup'
|
5
7
|
require 'openhab/log/logger'
|
6
8
|
require 'openhab/dsl/dsl'
|
@@ -17,9 +19,12 @@ module OpenHAB
|
|
17
19
|
# @param [Object] base Object to decorate with DSL and helper methods
|
18
20
|
#
|
19
21
|
#
|
22
|
+
# rubocop:disable Metrics/MethodLength
|
23
|
+
# Number of extensions and includes requires more lines
|
20
24
|
def self.extended(base)
|
21
25
|
OpenHAB::Core.wait_till_openhab_ready
|
22
26
|
base.extend Log
|
27
|
+
base.extend OpenHAB::Core::ScriptHandling
|
23
28
|
base.extend OpenHAB::Core::EntityLookup
|
24
29
|
base.extend OpenHAB::DSL
|
25
30
|
base.extend OpenHAB::DSL::TimeOfDay
|
@@ -31,6 +36,7 @@ module OpenHAB
|
|
31
36
|
|
32
37
|
OpenHAB::Core.add_rubylib_to_load_path
|
33
38
|
end
|
39
|
+
# rubocop:enable Metrics/MethodLength
|
34
40
|
end
|
35
41
|
|
36
42
|
# Extend caller with OpenHAB methods
|
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.2
|
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-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -50,10 +50,13 @@ files:
|
|
50
50
|
- lib/openhab/core/load_path.rb
|
51
51
|
- lib/openhab/core/openhab_setup.rb
|
52
52
|
- lib/openhab/core/osgi.rb
|
53
|
+
- lib/openhab/core/script_handling.rb
|
54
|
+
- lib/openhab/core/thread_local.rb
|
53
55
|
- lib/openhab/dsl/actions.rb
|
54
56
|
- lib/openhab/dsl/dsl.rb
|
55
57
|
- lib/openhab/dsl/gems.rb
|
56
58
|
- lib/openhab/dsl/group.rb
|
59
|
+
- lib/openhab/dsl/items/color_item.rb
|
57
60
|
- lib/openhab/dsl/items/comparable_item.rb
|
58
61
|
- lib/openhab/dsl/items/contact_item.rb
|
59
62
|
- lib/openhab/dsl/items/date_time_item.rb
|
@@ -65,6 +68,7 @@ files:
|
|
65
68
|
- lib/openhab/dsl/items/item_equality.rb
|
66
69
|
- lib/openhab/dsl/items/item_registry.rb
|
67
70
|
- lib/openhab/dsl/items/items.rb
|
71
|
+
- lib/openhab/dsl/items/location_item.rb
|
68
72
|
- lib/openhab/dsl/items/metadata.rb
|
69
73
|
- lib/openhab/dsl/items/number_item.rb
|
70
74
|
- lib/openhab/dsl/items/numeric_item.rb
|
@@ -105,6 +109,7 @@ files:
|
|
105
109
|
- lib/openhab/dsl/types/comparable_type.rb
|
106
110
|
- lib/openhab/dsl/types/date_time_type.rb
|
107
111
|
- lib/openhab/dsl/types/decimal_type.rb
|
112
|
+
- lib/openhab/dsl/types/hsb_type.rb
|
108
113
|
- lib/openhab/dsl/types/increase_decrease_type.rb
|
109
114
|
- lib/openhab/dsl/types/next_previous_type.rb
|
110
115
|
- lib/openhab/dsl/types/numeric_type.rb
|
@@ -112,6 +117,7 @@ files:
|
|
112
117
|
- lib/openhab/dsl/types/open_closed_type.rb
|
113
118
|
- lib/openhab/dsl/types/percent_type.rb
|
114
119
|
- lib/openhab/dsl/types/play_pause_type.rb
|
120
|
+
- lib/openhab/dsl/types/point_type.rb
|
115
121
|
- lib/openhab/dsl/types/quantity_type.rb
|
116
122
|
- lib/openhab/dsl/types/refresh_type.rb
|
117
123
|
- lib/openhab/dsl/types/rewind_fastforward_type.rb
|