openhab-scripting 4.6.0 → 4.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9ccae52c29da91b7fadc2ac7ba2459e9870a257396849535458497ba48601e5
4
- data.tar.gz: 0015aca73a5c79082adefb486afcbb545e324c0695d492e15397d2e0d691a204
3
+ metadata.gz: e5e39f0dd326751e6c61fcf44a85f6a9033c72fc6196f899d59305f7e77ff2cf
4
+ data.tar.gz: 207a22d5633a711bdc333d1fb94befa787a6fa63a1b1050607c9f7665e1149f7
5
5
  SHA512:
6
- metadata.gz: 2db7c0a6f4182d3145871ab6936aa92d5acbe2a6d29e79f793a464d4fbb9514555021d9f0b103130ed99b04c9e149a414ea96df8f134f7db2fb71bade3824168
7
- data.tar.gz: da447a4315a8d177db5fc6e476dd30ba93a071f06c6dc612a361f9d12a8539932f8a1659bdd919d8cdf61be2da759f720020d57fe399eaa1a2533bf5e1f56203
6
+ metadata.gz: cc744a57eaad8487ffcc3bb31584bfd484ee27de0948c07a1ac47be5953e5ee2fda4a1a0713f49fda4c289ffb298908d32d69741ce83ee3c526f0bec7c5ae173
7
+ data.tar.gz: 42a1fa4aa68bc0d81399f02de37761598005bed645b105f85f14af6d3419578938a3cbd33cd8a6c03b0fed46031c25730dca23074063d98ba76cc0eea43ccf24
@@ -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
@@ -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
 
@@ -27,6 +28,8 @@ module OpenHAB
27
28
  # Contains all OpenHAB *Item classes, as well as associated support
28
29
  # modules
29
30
  module Items
31
+ include OpenHAB::Log
32
+
30
33
  class << self
31
34
  private
32
35
 
@@ -44,7 +47,7 @@ module OpenHAB
44
47
  _command_predicate, state_predicate = Types::PREDICATE_ALIASES[state.to_s]
45
48
  next if klass.instance_methods.include?(state_predicate)
46
49
 
47
- OpenHAB::Core.logger.trace("Defining #{klass}##{state_predicate} for #{state}")
50
+ logger.trace("Defining #{klass}##{state_predicate} for #{state}")
48
51
  klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
49
52
  def #{state_predicate} # def on?
50
53
  raw_state == #{state} # raw_state == ON
@@ -60,21 +63,21 @@ module OpenHAB
60
63
  command = Types::COMMAND_ALIASES[value.to_s]
61
64
  next if klass.instance_methods.include?(command)
62
65
 
63
- OpenHAB::Core.logger.trace("Defining #{klass}##{command} for #{value}")
66
+ logger.trace("Defining #{klass}##{command} for #{value}")
64
67
  klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
65
68
  def #{command} # def on
66
69
  command(#{value}) # command(ON)
67
70
  end # end
68
71
  RUBY
69
72
 
70
- OpenHAB::Core.logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
73
+ logger.trace("Defining GroupItem::GroupMembers##{command} for #{value}")
71
74
  GroupItem::GroupMembers.class_eval <<~RUBY, __FILE__, __LINE__ + 1
72
75
  def #{command} # def on
73
76
  each(&:#{command}) # each(&:on)
74
77
  end # end
75
78
  RUBY
76
79
 
77
- OpenHAB::Core.logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
80
+ logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
78
81
  MonkeyPatch::Events::ItemCommandEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
79
82
  def #{command}? # def refresh?
80
83
  command == #{value} # command == REFRESH
@@ -25,6 +25,7 @@ module OpenHAB
25
25
  extend Forwardable
26
26
 
27
27
  def_delegator :@metadata, :value
28
+ def_delegator :__getobj__, :to_h, :to_hash
28
29
 
29
30
  def initialize(metadata: nil, key: nil, value: nil, config: nil)
30
31
  @metadata = metadata || Metadata.new(key || MetadataKey.new('', ''), value&.to_s, config)
@@ -68,6 +69,7 @@ module OpenHAB
68
69
  # @return [Java::Org::openhab::core::items::Metadata] the old metadata
69
70
  #
70
71
  def config=(config)
72
+ config = config.to_hash if config.respond_to?(:to_hash)
71
73
  raise ArgumentError, 'Configuration must be a hash' unless config.is_a? Hash
72
74
 
73
75
  metadata = Metadata.new(@metadata&.uID, @metadata&.value, config)
@@ -158,7 +160,7 @@ module OpenHAB
158
160
  meta_value, configuration = update_from_value(value)
159
161
 
160
162
  key = MetadataKey.new(namespace, @item_name)
161
- metadata = Metadata.new(key, meta_value&.to_s, configuration)
163
+ metadata = Metadata.new(key, meta_value&.to_s, configuration.to_h)
162
164
  # registry.get can be omitted, but registry.update will log a warning for nonexistent metadata
163
165
  if NamespaceAccessor.registry.get(key)
164
166
  NamespaceAccessor.registry.update(metadata)
@@ -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[+ - * / % | positive? negative? to_d to_f to_i to_int zero?] => :state
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
  #
@@ -39,12 +45,19 @@ module OpenHAB
39
45
  #
40
46
  def logger
41
47
  if @rule_name
42
- Log.logger(@rule_name.chomp.gsub(/\s+/, '_'))
48
+ Log.logger_for(@rule_name.chomp.gsub(/\s+/, '_'))
43
49
  else
44
50
  super
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
- include OpenHAB::DSL::Rules::Triggers
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
@@ -127,7 +127,7 @@ module OpenHAB
127
127
  #
128
128
  def logger
129
129
  if name
130
- Log.logger(name.chomp.gsub(/\s+/, '_'))
130
+ Log.logger_for(name.chomp.gsub(/\s+/, '_'))
131
131
  else
132
132
  super
133
133
  end
@@ -39,7 +39,7 @@ module OpenHAB
39
39
  else
40
40
  # Place in array and flatten to support multiple to elements or single or nil
41
41
  [to].flatten.each do |to_state|
42
- create_changed_trigger(item, from, to_state)
42
+ [from].flatten.each { |from_state| create_changed_trigger(item, from_state, to_state) }
43
43
  end
44
44
  end
45
45
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'openhab/log/logger'
4
4
  require 'openhab/dsl/types/date_time_type'
5
+ require 'openhab/dsl/items/items'
5
6
  require 'time'
6
7
 
7
8
  module OpenHAB
@@ -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 [<Type>] <description>
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
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'java'
3
4
  require_relative 'percent_type'
4
5
 
5
6
  module OpenHAB
@@ -65,6 +66,10 @@ module OpenHAB
65
66
  end
66
67
  end
67
68
 
69
+ # Convert strings using java class
70
+ return value_of(args.first) if args.length == 1 && args.first.is_a?(String)
71
+
72
+ # use super constructor for empty args
68
73
  return super unless args.length == 3
69
74
 
70
75
  # convert from several numeric-like types to the exact types
@@ -1,5 +1,7 @@
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'
@@ -27,6 +29,8 @@ module OpenHAB
27
29
  # modules
28
30
  #
29
31
  module Types
32
+ include OpenHAB::Log
33
+
30
34
  # Hash taking a Enum value, and returning two symbols of
31
35
  # predicates to be defined for it. the first is the "command" form,
32
36
  # which should be defined on ItemCommandEvent, and on the Type itself.
@@ -65,7 +69,7 @@ module OpenHAB
65
69
  states = PREDICATE_ALIASES[value.to_s]
66
70
 
67
71
  ([command] | states).each do |method|
68
- OpenHAB::Core.logger.trace("Defining #{klass}##{method} for #{value}")
72
+ logger.trace("Defining #{klass}##{method} for #{value}")
69
73
  klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
70
74
  def #{method} # def on?
71
75
  self == #{value} # self == ON
@@ -137,31 +137,36 @@ module OpenHAB
137
137
  # @return [Logger] for the current class
138
138
  #
139
139
  def logger
140
- Log.logger(self.class.name)
140
+ Log.logger(self.class)
141
141
  end
142
142
 
143
143
  class << self
144
144
  #
145
145
  # Injects a logger into the base class
146
146
  #
147
- # @param [String] name of the logger
147
+ # @param [Class] class the logger is for
148
148
  #
149
149
  # @return [Logger] for the supplied name
150
150
  #
151
- def logger(name)
152
- name ||= self.class.name
151
+ def logger(klass)
152
+ if klass.respond_to?(:java_class) &&
153
+ klass.java_class &&
154
+ !klass.java_class.name.start_with?('org.jruby.Ruby')
155
+ klass = klass.java_class
156
+ end
157
+ name = klass.name
153
158
  @loggers[name] ||= Log.logger_for(name)
154
159
  end
155
160
 
156
161
  #
157
162
  # Configure a logger for the supplied class name
158
163
  #
159
- # @param [String] classname to configure logger for
164
+ # @param [String] name to configure logger for
160
165
  #
161
166
  # @return [Logger] for the supplied classname
162
167
  #
163
- def logger_for(classname)
164
- configure_logger_for(classname)
168
+ def logger_for(name)
169
+ configure_logger_for(name)
165
170
  end
166
171
 
167
172
  private
@@ -173,10 +178,10 @@ module OpenHAB
173
178
  #
174
179
  # @return [Logger] Logger for the supplied classname
175
180
  #
176
- def configure_logger_for(classname)
181
+ def configure_logger_for(name)
177
182
  log_prefix = Configuration.log_prefix
178
- log_prefix += if classname
179
- ".#{classname}"
183
+ log_prefix += if name
184
+ ".#{name}"
180
185
  else
181
186
  ".#{log_caller}"
182
187
  end
@@ -207,7 +212,7 @@ module OpenHAB
207
212
  def self.included(base)
208
213
  class << base
209
214
  def logger
210
- Log.logger(self.class.name)
215
+ Log.logger(self)
211
216
  end
212
217
  end
213
218
  end
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module OpenHAB
7
7
  # @return [String] Version of OpenHAB helper libraries
8
- VERSION = '4.6.0'
8
+ VERSION = '4.7.1'
9
9
  end
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.6.0
4
+ version: 4.7.1
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-20 00:00:00.000000000 Z
11
+ date: 2021-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -50,6 +50,8 @@ 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