openhab-scripting 5.11.0 → 5.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e7d078cc73659d0f435950d36438b67759b2e3b5c0abf80f258a36101792a0d
4
- data.tar.gz: 2a76c20015d6320b64a2a9ea79557c7133b1101a8514fabba9241f91b455615d
3
+ metadata.gz: 35d0d28ba4dd272f12cd989761c2d615836d25dbafbc2af2b60692f8a535d5c1
4
+ data.tar.gz: 4d51dd07a43f5ff7a7ad43bc66cbb1d63b320486a82036d1a8cbfb22412a061b
5
5
  SHA512:
6
- metadata.gz: bc54b1fae7be3bee15b1af2c27526cf942a13741404dd1c0e61034b82d2d472703bfb48ef921d25ed608dbe3d9c964abbded85ab1d3adfd855847229c6bf2447
7
- data.tar.gz: c454623c911c90be03464391f885b8ccebfd2789b5e9dbbe32a6f8309fdf7e1f948e2c0730373d383bf7892271ab752bf9d8c2197ed541cff7f33a692ea296ec
6
+ metadata.gz: 76c075f22df43c0ecfe37775e297f496d2f55fe60e6da95bbece311d92fe3e37e50d867a23f6f52c3ebeb690771e7eb5512c357ca3b0745d83d03a8df892cad7
7
+ data.tar.gz: 93eb532732729b91437a669fbbe9b0b024397332faa435c82ebe17d50c4ea4a29576108c819010c0a497a5912d74eaa95e87fc0d98b01f9fa0987fbb52b5fa7b
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module Events
6
+ java_import org.openhab.core.thing.events.ChannelTriggeredEvent
7
+
8
+ #
9
+ # {AbstractEvent} sent when a channel triggers.
10
+ #
11
+ class ChannelTriggeredEvent < AbstractEvent
12
+ extend Forwardable
13
+
14
+ # @!attribute [r] channel_uid
15
+ # @return [Things::ChannelUID] The UID of the {Things::Channel Channel} that triggered this event.
16
+ alias_method :channel_uid, :get_channel
17
+
18
+ # @!attribute [r] channel
19
+ # @return [Things::Channel, nil] The channel that triggered this event.
20
+
21
+ # @!attribute [r] thing
22
+ # @return [Things::Thing, nil] The thing that triggered this event.
23
+ def_delegators :channel_uid, :thing, :channel
24
+
25
+ # @!attribute [r] event
26
+ # @return [String] The event data
27
+ end
28
+ end
29
+ end
30
+ end
@@ -5,17 +5,18 @@ require_relative "item_state_event"
5
5
  module OpenHAB
6
6
  module Core
7
7
  module Events
8
- begin
8
+ # @deprecated OH3.4 if guard only needed in OH 3.4
9
+ if Gem::Version.new(OpenHAB::Core::VERSION) >= Gem::Version.new("4.0.0")
9
10
  java_import org.openhab.core.items.events.ItemStateUpdatedEvent
10
11
 
11
12
  #
12
13
  # {AbstractEvent} sent when an item's state has updated.
13
14
  #
15
+ # @since openHAB 4.0
16
+ #
14
17
  class ItemStateUpdatedEvent < ItemEvent
15
18
  include ItemState
16
19
  end
17
- rescue NameError
18
- # @deprecated OH3.4 OH3 will raise an error ItemStateUpdatedEvent is only in OH4
19
20
  end
20
21
  end
21
22
  end
@@ -102,7 +102,7 @@ module OpenHAB
102
102
  #
103
103
  def dim(amount = 1)
104
104
  target = [state&.-(amount), 0].compact.max
105
- command(target)
105
+ command!(target)
106
106
  target
107
107
  end
108
108
 
@@ -121,7 +121,7 @@ module OpenHAB
121
121
  #
122
122
  def brighten(amount = 1)
123
123
  target = [state&.+(amount), 100].compact.min
124
- command(target)
124
+ command!(target)
125
125
  target
126
126
  end
127
127
 
@@ -133,16 +133,6 @@ module OpenHAB
133
133
  # Send the {DECREASE} command to the item
134
134
  # @return [DimmerItem] `self`
135
135
 
136
- # @!method increase!
137
- # Send the {INCREASE} command to the item, even when
138
- # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
139
- # @return [DimmerItem] `self`
140
-
141
- # @!method decrease!
142
- # Send the {DECREASE} command to the item, even when
143
- # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
144
- # @return [DimmerItem] `self`
145
-
146
136
  # raw numbers translate directly to PercentType, not a DecimalType
147
137
  # @!visibility private
148
138
  def format_type(command)
@@ -55,7 +55,7 @@ module OpenHAB
55
55
  # Send the {REWIND} command to the item
56
56
  # @return [PlayerItem] `self`
57
57
 
58
- # @!method rewind
58
+ # @!method rewind!
59
59
  # Send the {REWIND} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
60
60
  # @return [PlayerItem] `self`
61
61
 
@@ -72,18 +72,9 @@ module OpenHAB
72
72
  # Send the {NEXT} command to the item
73
73
  # @return [PlayerItem] `self`
74
74
 
75
- # @!method next!
76
- # Send the {NEXT} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
77
- # @return [PlayerItem] `self`
78
-
79
75
  # @!method previous
80
76
  # Send the {PREVIOUS} command to the item
81
77
  # @return [PlayerItem] `self`
82
-
83
- # @!method previous!
84
- # Send the {PREVIOUS} command to the item, even when
85
- # {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
86
- # @return [PlayerItem] `self`
87
78
  end
88
79
  end
89
80
  end
@@ -57,18 +57,10 @@ module OpenHAB
57
57
  # Send the {STOP} command to the item
58
58
  # @return [RollershutterItem] `self`
59
59
 
60
- # @!method stop!
61
- # Send the {STOP} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
62
- # @return [RollershutterItem] `self`
63
-
64
60
  # @!method move
65
61
  # Send the {MOVE} command to the item
66
62
  # @return [RollershutterItem] `self`
67
63
 
68
- # @!method move!
69
- # Send the {MOVE} command to the item, even when {OpenHAB::DSL.ensure_states! ensure_states!} is in effect.
70
- # @return [RollershutterItem] `self`
71
-
72
64
  # raw numbers translate directly to PercentType, not a DecimalType
73
65
  # @!visibility private
74
66
  def format_type(command)
@@ -50,9 +50,9 @@ module OpenHAB
50
50
  # @return [self]
51
51
  #
52
52
  def toggle
53
- return on unless state?
53
+ return on! unless state?
54
54
 
55
- command(!state)
55
+ command!(!state)
56
56
  end
57
57
 
58
58
  # @!method on?
@@ -60,25 +60,43 @@ module OpenHAB
60
60
  command = Types::COMMAND_ALIASES[value.to_s]
61
61
  next if klass.instance_methods.include?(command)
62
62
 
63
- logger.trace("Defining #{klass}##{command} for #{value}")
64
- klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
65
- ruby2_keywords def #{command}(*args, &block) # ruby2_keywords def on(*args, &block)
66
- command(#{value}, *args, &block) # command(ON, *args, &block)
67
- end # end
68
- ruby2_keywords def #{command}!(*args, &block) # ruby2_keywords def on!(*args, &block)
69
- command!(#{value}, *args, &block) # command!(ON, *args, &block)
70
- end # end
71
- RUBY
63
+ if value.is_a?(Types::State)
64
+ logger.trace("Defining #{klass}/Enumerable##{command}/#{command}! for #{value}")
72
65
 
73
- logger.trace("Defining Enumerable##{command} for #{value}")
74
- Enumerable.class_eval <<~RUBY, __FILE__, __LINE__ + 1
75
- def #{command} # def on
76
- each(&:#{command}) # each(&:on)
77
- end # end
78
- def #{command}! # def on!
79
- each(&:#{command}!) # each(&:on!)
80
- end # end
81
- RUBY
66
+ klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
67
+ ruby2_keywords def #{command}(*args, &block) # ruby2_keywords def on(*args, &block)
68
+ command(#{value}, *args, &block) # command(ON, *args, &block)
69
+ end # end
70
+ #
71
+ ruby2_keywords def #{command}!(*args, &block) # ruby2_keywords def on!(*args, &block)
72
+ command!(#{value}, *args, &block) # command!(ON, *args, &block)
73
+ end # end
74
+ RUBY
75
+
76
+ Enumerable.class_eval <<~RUBY, __FILE__, __LINE__ + 1
77
+ def #{command} # def on
78
+ each(&:#{command}) # each(&:on)
79
+ end # end
80
+ #
81
+ def #{command}! # def on!
82
+ each(&:#{command}!) # each(&:on!)
83
+ end # end
84
+ RUBY
85
+ else
86
+ logger.trace("Defining #{klass}/Enumerable##{command} for #{value}")
87
+
88
+ klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
89
+ ruby2_keywords def #{command}(*args, &block) # ruby2_keywords def refresh(*args, &block)
90
+ command!(#{value}, *args, &block) # command!(REFRESH, *args, &block)
91
+ end # end
92
+ RUBY
93
+
94
+ Enumerable.class_eval <<~RUBY, __FILE__, __LINE__ + 1
95
+ def #{command} # def refresh
96
+ each(&:#{command}) # each(&:refresh)
97
+ end # end
98
+ RUBY
99
+ end
82
100
 
83
101
  logger.trace("Defining ItemCommandEvent##{command}? for #{value}")
84
102
  Events::ItemCommandEvent.class_eval <<~RUBY, __FILE__, __LINE__ + 1
@@ -6,12 +6,14 @@ require_relative "script_handling"
6
6
 
7
7
  module OpenHAB
8
8
  module Core
9
+ # rubocop:disable Naming/MethodName
9
10
  # @!visibility private
10
11
  class ProfileFactory
12
+ include org.openhab.core.config.core.ConfigDescriptionProvider # This needs to be included first
11
13
  include org.openhab.core.thing.profiles.ProfileFactory
14
+ include org.openhab.core.thing.profiles.ProfileTypeProvider
12
15
  include Singleton
13
16
 
14
- # rubocop:disable Naming/MethodName
15
17
  class Profile
16
18
  include org.openhab.core.thing.profiles.StateProfile
17
19
 
@@ -96,10 +98,10 @@ module OpenHAB
96
98
  end
97
99
  end
98
100
  private_constant :Profile
99
- # rubocop:enable Naming/MethodName
100
101
 
101
102
  def initialize
102
103
  @profiles = {}
104
+ @uri_to_uid = {}
103
105
 
104
106
  @registration = OSGi.register_service(self)
105
107
  ScriptHandling.script_unloaded { unregister }
@@ -116,17 +118,56 @@ module OpenHAB
116
118
  end
117
119
 
118
120
  # @!visibility private
119
- def register(uid, block)
120
- @profiles[uid] = [DSL::ThreadLocal.persist, block]
121
+ def register(id, block, label: nil, config_description: nil)
122
+ uid = org.openhab.core.thing.profiles.ProfileTypeUID.new("ruby", id)
123
+ uri = java.net.URI.new("profile", uid.to_s, nil)
124
+ if config_description && config_description.uid != uri
125
+ config_description = org.openhab.core.config.core.ConfigDescriptionBuilder.create(uri)
126
+ .with_parameters(config_description.parameters)
127
+ .with_parameter_groups(config_description.parameter_groups)
128
+ .build
129
+ end
130
+
131
+ @profiles[uid] = {
132
+ thread_locals: DSL::ThreadLocal.persist,
133
+ label: label,
134
+ config_description: config_description,
135
+ block: block
136
+ }
137
+ @uri_to_uid[uri] = uid
121
138
  end
122
139
 
123
- def createProfile(type, callback, context) # rubocop:disable Naming/MethodName
124
- @profiles[type].then { |(thread_locals, block)| Profile.new(callback, context, type, thread_locals, block) }
140
+ # @!visibility private
141
+ def createProfile(uid, callback, context)
142
+ profile = @profiles[uid]
143
+ Profile.new(callback, context, uid, profile[:thread_locals], profile[:block])
125
144
  end
126
145
 
127
- def getSupportedProfileTypeUIDs # rubocop:disable Naming/MethodName
146
+ # @!visibility private
147
+ def getSupportedProfileTypeUIDs
128
148
  @profiles.keys
129
149
  end
150
+
151
+ # @!visibility private
152
+ def getProfileTypes(_locale)
153
+ @profiles.map do |uid, profile|
154
+ next if profile[:label].nil?
155
+
156
+ org.openhab.core.thing.profiles.ProfileTypeBuilder.new_state(uid, "RUBY #{profile[:label]}").build
157
+ end.compact
158
+ end
159
+
160
+ # @!visibility private
161
+ def getConfigDescriptions(_locale)
162
+ @profiles.values.map { |profile| profile[:config_description] if profile[:label] }.compact
163
+ end
164
+
165
+ # @!visibility private
166
+ def getConfigDescription(uri, _locale)
167
+ uid = @uri_to_uid[uri]
168
+ @profiles.dig(uid, :config_description)
169
+ end
130
170
  end
171
+ # rubocop:enable Naming/MethodName
131
172
  end
132
173
  end
@@ -70,13 +70,17 @@ module OpenHAB
70
70
  # text label: "Climate", icon: "if:mdi:home-thermometer-outline" do
71
71
  # frame label: "Main Floor" do
72
72
  # text item: MainFloor_AmbTemp
73
- # switch item: MainFloorThermostat_TargetMode, label: "Mode", mappings: %w[off auto cool heat]
73
+ # # colors are set with a hash, with key being condition, and value being the color
74
+ # switch item: MainFloorThermostat_TargetMode, label: "Mode", mappings: %w[off auto cool heat], label_color: { "==heat" => "red", "" => "black" }
75
+ # # an array of conditions are OR'd together
76
+ # switch item: MainFloorThermostat_TargetMode, label: "Mode", mappings: %w[off auto cool heat], label_color: { ["==heat", "==cool"], => "green" }
74
77
  # setpoint item: MainFloorThermostat_SetPoint, label: "Set Point", visibility: "MainFloorThermostat_TargetMode!=off"
75
78
  # end
76
79
  # frame label: "Basement" do
77
80
  # text item: Basement_AmbTemp
78
81
  # switch item: BasementThermostat_TargetMode, label: "Mode", mappings: { OFF: "off", COOL: "cool", HEAT: "heat" }
79
- # setpoint item: BasementThermostat_SetPoint, label: "Set Point", visibility: "BasementThermostat_TargetMode!=off"
82
+ # # nested arrays are conditions that are AND'd together, instead of OR'd (requires openHAB 4.1)
83
+ # setpoint item: BasementThermostat_SetPoint, label: "Set Point", visibility: [["BasementThermostat_TargetMode!=off", "Vacation_Switch!=OFF"]]
80
84
  # end
81
85
  # end
82
86
  # end
@@ -22,6 +22,16 @@ module OpenHAB
22
22
  EntityLookup.lookup_thing(thing_uid)
23
23
  end
24
24
 
25
+ # @attribute [r] channel
26
+ #
27
+ # Return the channel object for this channel
28
+ #
29
+ # @return [Channel, nil]
30
+ #
31
+ def channel
32
+ thing.channels[self]
33
+ end
34
+
25
35
  #
26
36
  # @attribute [r] item
27
37
  #
@@ -72,6 +72,7 @@ module OpenHAB
72
72
  # Allows indexing by both integer as an array or channel id acting like a hash.
73
73
  # @param [Integer, String, ChannelUID] index
74
74
  # Numeric index, string channel id, or a {ChannelUID} to search for.
75
+ # @return [Channel, nil]
75
76
  def [](index)
76
77
  return @thing.get_channel(index) if index.is_a?(ChannelUID)
77
78
  return @thing.get_channel(index.to_str) if index.respond_to?(:to_str)
@@ -70,7 +70,7 @@ module OpenHAB
70
70
  #
71
71
  # Convert DecimalType to a QuantityType
72
72
  #
73
- # @param [String, javax.measure.units.Unit] other
73
+ # @param [String, javax.measure.Unit] other
74
74
  #
75
75
  # @return [QuantityType] `self` as a {QuantityType} of the supplied Unit
76
76
  #
@@ -106,7 +106,7 @@ module OpenHAB
106
106
  # #
107
107
  # # Convert this {QuantityType} into another unit.
108
108
  # #
109
- # # @param [String, javax.measure.units.Unit] unit
109
+ # # @param [String, javax.measure.Unit] unit
110
110
  # # @return [QuantityType]
111
111
  # #
112
112
  # # @example
@@ -287,7 +287,7 @@ module OpenHAB
287
287
  end
288
288
  end
289
289
 
290
- # if unit is {org.openhab.core.library.unit.Units.ONE}, return a plain
290
+ # if unit is {org.openhab.core.library.unit.Units::ONE}, return a plain
291
291
  # Java BigDecimal
292
292
  # @!visibility private
293
293
  def deunitize
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ #
6
+ # Contains the DSL for creating {org.openhab.core.config.core.ConfigDescription} instances.
7
+ #
8
+ module ConfigDescription
9
+ #
10
+ # A ConfigDescriptionBuilder is used to create a {org.openhab.core.config.core.ConfigDescription}
11
+ # instance.
12
+ #
13
+ # @see DSL.config_description config_description
14
+ #
15
+ class Builder
16
+ def initialize
17
+ @parameters = []
18
+ @parameter_groups = []
19
+ @current_group = nil
20
+ end
21
+
22
+ #
23
+ # Create a parameter group.
24
+ #
25
+ # @param [String, Symbol] name The group name. This name will be referred to by {parameter}.
26
+ # @param [String, nil] label The group label
27
+ # @param [String, nil] description The group description
28
+ # @param [Boolean] advanced Whether the group is advanced
29
+ # @param [<Type>] context Context for the group
30
+ #
31
+ # @yield Block executed in the context of this group. Any {parameter} calls within the block will
32
+ # automatically be added to this group, unless it specifies a different group name.
33
+ #
34
+ # @return [void]
35
+ #
36
+ def group(name, label: nil, description: nil, advanced: false, context: nil, &block)
37
+ raise ArgumentError, "Groups cannot be nested" if @current_group
38
+
39
+ name = name.to_s
40
+ @parameter_groups << org.openhab.core.config.core.ConfigDescriptionParameterGroupBuilder
41
+ .create(name)
42
+ .with_label(label)
43
+ .with_description(description)
44
+ .with_advanced(advanced)
45
+ .with_context(context)
46
+ .build
47
+
48
+ @current_group = name
49
+ instance_eval(&block) if block
50
+ ensure
51
+ @current_group = nil
52
+ end
53
+
54
+ #
55
+ # Adds a parameter to the config description.
56
+ #
57
+ # @param [String, Symbol] name Parameter name
58
+ # @param [:text, :integer, :decimal, :boolean] type
59
+ # Parameter type. See {org.openhab.core.config.core.ConfigDescriptionParameter.Type}
60
+ # @param [String, nil] label Parameter label
61
+ # @param [String, nil] description Parameter description
62
+ # @param [Numeric, nil] min Minimum value for numeric types
63
+ # @param [Numeric, nil] max Maximum value for numeric types
64
+ # @param [Numeric, nil] step Step size for numeric types
65
+ # @param [String, nil] pattern Regular expression pattern for string types
66
+ # @param [true, false] required Whether the parameter is required
67
+ # @param [true, false] read_only Whether the parameter is read only
68
+ # @param [true, false] multiple Whether the parameter is a list of values
69
+ # @param [String, nil] context Context for the parameter
70
+ # @param [Object, nil] default Default value for the parameter
71
+ # @param [Hash] options Options for the parameter
72
+ # @param [Hash] filter_criteria Filter criteria for the parameter
73
+ # @param [String, nil] group_name Parameter group name.
74
+ # When nil, it will be inferred when this method is called inside a {group} block.
75
+ # @param [true, false] advanced Whether the parameter is advanced
76
+ # @param [true, false] limit_to_options Whether the parameter is limited to the given options
77
+ # @param [Integer, nil] multiple_limit Maximum number of values for a multiple parameter
78
+ # @param [String, nil] unit Parameter unit
79
+ # @param [String, nil] unit_label Parameter unit label
80
+ # @param [true, false] verify Whether the parameter value should be verified
81
+ #
82
+ # @return [void]
83
+ #
84
+ # @see org.openhab.core.config.core.ConfigDescriptionParameter
85
+ #
86
+ def parameter(name,
87
+ type,
88
+ label: nil,
89
+ description: nil,
90
+ min: nil,
91
+ max: nil,
92
+ step: nil,
93
+ pattern: nil,
94
+ required: false,
95
+ read_only: false,
96
+ multiple: false,
97
+ context: nil,
98
+ default: nil,
99
+ options: {},
100
+ filter_criteria: {},
101
+ group_name: nil,
102
+ advanced: false,
103
+ limit_to_options: false,
104
+ multiple_limit: nil,
105
+ unit: nil,
106
+ unit_label: nil,
107
+ verify: false)
108
+ # Extract the named arguments into a hash
109
+ @parameters << method(__method__).parameters
110
+ .select { |param_type, _| param_type == :key }
111
+ .to_h { |_, key| [key, binding.local_variable_get(key)] }
112
+ .then do |p|
113
+ p[:options] = p[:options].map do |opt_value, opt_label|
114
+ org.openhab.core.config.core.ParameterOption.new(opt_value, opt_label)
115
+ end
116
+ p[:filter_criteria] = p[:filter_criteria].map do |filter_name, filter_value|
117
+ org.openhab.core.config.core.FilterCriteria.new(filter_name, filter_value)
118
+ end
119
+ p[:minimum] = p.delete(:min)&.to_d&.to_java
120
+ p[:maximum] = p.delete(:max)&.to_d&.to_java
121
+ p[:step] = p.delete(:step)&.to_d&.to_java
122
+ p[:group_name] ||= @current_group
123
+ type = org.openhab.core.config.core.ConfigDescriptionParameter::Type.value_of(type.to_s.upcase)
124
+
125
+ parameter = org.openhab.core.config.core.ConfigDescriptionParameterBuilder.create(name.to_s, type)
126
+
127
+ p.each do |key, value|
128
+ parameter.send("with_#{key}", value) unless value.nil?
129
+ end
130
+ parameter.build
131
+ end
132
+ end
133
+
134
+ #
135
+ # Build the config description
136
+ #
137
+ # @param [String, java.net.URI] uri The URI for the config description. When nil, it will default to `dummy:uri`
138
+ # @yield Block executed in the context of this builder. Inside the block, you can call {parameter} and {group}.
139
+ #
140
+ # @return [org.openhab.core.config.core.ConfigDescription] The created ConfigDescription object
141
+ #
142
+ def build(uri = nil, &block)
143
+ instance_eval(&block) if block
144
+ raise ArgumentError, "No parameters defined" if @parameters.empty?
145
+
146
+ uri ||= "dummy:uri"
147
+ uri = java.net.URI.new(uri.to_s) unless uri.is_a?(java.net.URI)
148
+ org.openhab.core.config.core.ConfigDescriptionBuilder
149
+ .create(uri)
150
+ .with_parameters(@parameters)
151
+ .with_parameter_groups(@parameter_groups)
152
+ .build
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -36,6 +36,8 @@ module OpenHAB
36
36
  # sending the command
37
37
  %i[command update].each do |ensured_method|
38
38
  # def command(state)
39
+ # # immediately send the command if it's a command, but not a state (like REFRESH)
40
+ # return super(state) if state.is_a?(Command) && !state.is_a?(State)
39
41
  # return super(state) unless Thread.current[:openhab_ensure_states]
40
42
  #
41
43
  # formatted_state = format_command(state)
@@ -48,6 +50,8 @@ module OpenHAB
48
50
  # end
49
51
  class_eval <<~RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition
50
52
  def #{ensured_method}(state)
53
+ # immediately send the command if it's a command, but not a state (like REFRESH)
54
+ #{"return super(state) if state.is_a?(Command) && !state.is_a?(State)" if ensured_method == :command}
51
55
  return super(state) unless Thread.current[:openhab_ensure_states]
52
56
 
53
57
  formatted_state = format_#{ensured_method}(state)
@@ -36,12 +36,9 @@ module OpenHAB
36
36
  # Base class for all widgets
37
37
  # @see org.openhab.core.model.sitemap.sitemap.Widget
38
38
  class WidgetBuilder
39
- # rubocop:disable Layout/LineLength, Lint/MixedRegexpCaptureTypes
40
- # These are copied directly out of UIComponentSitemapProvider.java
41
- VISIBILITY_PATTERN = /(?<item>[A-Za-z]\w*)\s*(?<condition>==|!=|<=|>=|<|>)\s*(?<sign>\+|-)?(?<state>\S+)/.freeze
42
- COLOR_PATTERN = /((?<item>[A-Za-z]\w*)?\s*((?<condition>==|!=|<=|>=|<|>)\s*(?<sign>\+|-)?(?<state>\S+))?\s*=)?\s*(?<arg>\S+)/.freeze
43
- # rubocop:enable Layout/LineLength, Lint/MixedRegexpCaptureTypes
44
- private_constant :VISIBILITY_PATTERN, :COLOR_PATTERN
39
+ # This is copied directly out of UIComponentSitemapProvider.java
40
+ CONDITION_PATTERN = /(?<item>[A-Za-z]\w*)?\s*(?<condition>==|!=|<=|>=|<|>)?\s*(?<sign>\+|-)?(?<state>.+)/.freeze
41
+ private_constant :CONDITION_PATTERN
45
42
 
46
43
  # @return [String, nil]
47
44
  attr_accessor :label
@@ -52,15 +49,15 @@ module OpenHAB
52
49
  # @see https://www.openhab.org/docs/ui/sitemaps.html#icons
53
50
  attr_accessor :icon
54
51
  # Label color rules
55
- # @return [Array<String>]
52
+ # @return [Hash<String, String>]
56
53
  # @see https://www.openhab.org/docs/ui/sitemaps.html#label-value-and-icon-colors
57
54
  attr_reader :label_colors
58
55
  # Value color rules
59
- # @return [Array<String>]
56
+ # @return [Hash<String, String>]
60
57
  # @see https://www.openhab.org/docs/ui/sitemaps.html#label-value-and-icon-colors
61
58
  attr_reader :value_colors
62
59
  # Icon color rules
63
- # @return [Array<String>]
60
+ # @return [Hash<String, String>]
64
61
  # @see https://www.openhab.org/docs/ui/sitemaps.html#label-value-and-icon-colors
65
62
  attr_reader :icon_colors
66
63
  # Visibility rules
@@ -94,32 +91,32 @@ module OpenHAB
94
91
  @label = label
95
92
  @icon = icon
96
93
  @visibilities = []
97
- @label_colors = []
98
- @value_colors = []
99
- @icon_colors = []
94
+ @label_colors = {}
95
+ @value_colors = {}
96
+ @icon_colors = {}
100
97
 
101
- self.label_color(*label_color) if label_color
102
- self.value_color(*value_color) if value_color
103
- self.icon_color(*icon_color) if icon_color
98
+ self.label_color(label_color) if label_color
99
+ self.value_color(value_color) if value_color
100
+ self.icon_color(icon_color) if icon_color
104
101
  self.visibility(*visibility) if visibility
105
102
  end
106
103
 
107
104
  # Adds one or more new rules for setting the label color
108
- # @return [Array<String>] the current rules
109
- def label_color(*rules)
110
- @label_colors.concat(rules)
105
+ # @return [Hash<String, String>] the current rules
106
+ def label_color(rules)
107
+ @label_colors.merge!(rules)
111
108
  end
112
109
 
113
110
  # Adds one or more new rules for setting the value color
114
- # @return [Array<String>] the current rules
115
- def value_color(*rules)
116
- @value_colors.concat(rules)
111
+ # @return [Hash<String, String>] the current rules
112
+ def value_color(rules)
113
+ @value_colors.merge!(rules)
117
114
  end
118
115
 
119
116
  # Adds one or more new rules for setting the icon color
120
- # @return [Array<String>] the current rules
121
- def icon_color(*rules)
122
- @icon_colors.concat(rules)
117
+ # @return [Hash<String, String>] the current rules
118
+ def icon_color(rules)
119
+ @icon_colors.merge!(rules)
123
120
  end
124
121
 
125
122
  # Adds one or more new visibility rules
@@ -137,21 +134,28 @@ module OpenHAB
137
134
  widget.label = @label
138
135
  widget.icon = @icon
139
136
 
140
- add_color(widget.label_color, label_colors) unless label_colors.empty?
141
- add_color(widget.value_color, value_colors) unless value_colors.empty?
142
- add_color(widget.icon_color, icon_colors) unless icon_colors.empty?
137
+ add_colors(widget, :label_color, label_colors)
138
+ add_colors(widget, :value_color, value_colors)
139
+ add_colors(widget, :icon_color, icon_colors)
143
140
 
144
- visibilities.each do |v|
145
- unless (match = VISIBILITY_PATTERN.match(v))
146
- raise ArgumentError, "Syntax error in visibility rule #{v.inspect}"
141
+ # @deprecated OH 4.1
142
+ if SitemapBuilder.factory.respond_to?(:create_condition)
143
+ add_conditions(widget, :visibility, visibilities, :create_visibility_rule)
144
+ else
145
+ visibilities.each do |v|
146
+ raise ArgumentError, "AND conditions not supported prior to openHAB 4.1" if v.is_a?(Array)
147
+
148
+ unless (match = CONDITION_PATTERN.match(v))
149
+ raise ArgumentError, "Syntax error in visibility rule #{v.inspect}"
150
+ end
151
+
152
+ rule = SitemapBuilder.factory.create_visibility_rule
153
+ rule.item = match["item"]
154
+ rule.condition = match["condition"]
155
+ rule.sign = match["sign"]
156
+ rule.state = match["state"]
157
+ widget.visibility.add(rule)
147
158
  end
148
-
149
- rule = SitemapBuilder.factory.create_visibility_rule
150
- rule.item = match["item"]
151
- rule.condition = match["condition"]
152
- rule.sign = match["sign"]
153
- rule.state = match["state"]
154
- widget.visibility.add(rule)
155
159
  end
156
160
 
157
161
  widget
@@ -169,19 +173,51 @@ module OpenHAB
169
173
 
170
174
  private
171
175
 
172
- def add_color(widget_color, colors)
173
- colors.each do |c|
174
- unless (match = COLOR_PATTERN.match(c))
175
- raise ArgumentError, "Syntax error in color rule #{c.inspect}"
176
+ def add_colors(widget, method, conditions)
177
+ conditions.each do |condition, color|
178
+ condition = [condition] unless condition.is_a?(Array)
179
+ add_conditions(widget, method, condition, :create_color_array) do |color_array|
180
+ color_array.arg = color
181
+ end
182
+ end
183
+ end
184
+
185
+ def add_conditions(widget, method, conditions, container_method)
186
+ return if conditions.empty?
187
+
188
+ object = widget.send(method)
189
+ has_and_conditions = conditions.any?(Array)
190
+ # @deprecated OH 4.1
191
+ if !SitemapBuilder.factory.respond_to?(:create_condition) && has_and_conditions
192
+ raise ArgumentError, "AND conditions not supported prior to openHAB 4.1"
193
+ end
194
+
195
+ conditions = [conditions] unless has_and_conditions
196
+
197
+ conditions.each do |sub_conditions|
198
+ container = SitemapBuilder.factory.send(container_method)
199
+
200
+ add_conditions_to_container(container, sub_conditions)
201
+ yield container if block_given?
202
+ object.add(container)
203
+ end
204
+ end
205
+
206
+ def add_conditions_to_container(container, conditions)
207
+ # @deprecated OH 4.1
208
+ supports_and_conditions = SitemapBuilder.factory.respond_to?(:create_condition)
209
+
210
+ Array.wrap(conditions).each do |c|
211
+ unless (match = CONDITION_PATTERN.match(c))
212
+ raise ArgumentError, "Syntax error in condition #{c.inspect}"
176
213
  end
177
214
 
178
- rule = SitemapBuilder.factory.create_color_array
179
- rule.item = match["item"]
180
- rule.condition = match["condition"]
181
- rule.sign = match["sign"]
182
- rule.state = match["state"]
183
- rule.arg = match["arg"]
184
- widget_color.add(color)
215
+ condition = supports_and_conditions ? SitemapBuilder.factory.create_condition : container
216
+ condition.item = match["item"]
217
+ condition.condition = match["condition"]
218
+ condition.sign = match["sign"]
219
+ condition.state = match["state"]
220
+ container.conditions.add(condition) if supports_and_conditions
185
221
  end
186
222
  end
187
223
  end
@@ -284,6 +320,7 @@ module OpenHAB
284
320
 
285
321
  @switch = switch
286
322
  @frequency = frequency
323
+ @switch_enabled = nil
287
324
  end
288
325
 
289
326
  # (see #switch=)
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of openHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.11.0"
7
+ VERSION = "5.12.0"
8
8
  end
9
9
  end
data/lib/openhab/dsl.rb CHANGED
@@ -77,7 +77,13 @@ module OpenHAB
77
77
  #
78
78
  # Defines a new profile that can be applied to item channel links.
79
79
  #
80
+ # To create a profile that can be used in the UI, provide a label and optionally a {config_description},
81
+ # otherwise the profile will not be visible in the UI.
82
+ #
80
83
  # @param [String, Symbol] id The id for the profile.
84
+ # @param [String, nil] label The label for the profile. When nil, the profile will not be visible in the UI.
85
+ # @param [org.openhab.core.config.core.ConfigDescription, nil] config_description
86
+ # The configuration description for the profile so that it can be configured in the UI.
81
87
  # @yield [event, command: nil, state: nil, callback:, link:, item:, channel_uid:, configuration:, context:]
82
88
  # All keyword params are optional. Any that aren't defined won't be passed.
83
89
  # @yieldparam [:command_from_item, :state_from_item, :command_from_handler, :state_from_handler] event
@@ -97,8 +103,8 @@ module OpenHAB
97
103
  # @yieldreturn [Boolean] Return true from the block in order to have default processing.
98
104
  # @return [void]
99
105
  #
100
- # @see org.openhab.thing.Profile
101
- # @see org.openhab.thing.StateProfile
106
+ # @see org.openhab.core.thing.profiles.Profile
107
+ # @see org.openhab.core.thing.profiles.StateProfile
102
108
  #
103
109
  # @example Vetoing a command
104
110
  # profile(:veto_closing_shades) do |event, item:, command:|
@@ -142,17 +148,54 @@ module OpenHAB
142
148
  # # can also be referenced from an `.items` file:
143
149
  # # Number:Temperature MyTempWithNonUnitValueFromBinding "I prefer Celsius [%d °C]" { channel="something_that_returns_F"[profile="ruby:set_uom", unit="°F"] }
144
150
  #
145
- def profile(id, &block)
151
+ # @example Create a profile that is usable in the UI
152
+ # config_description = config_description do
153
+ # parameter :min, :decimal, label: "Minimum", description: "Minimum value"
154
+ # parameter :max, :decimal, label: "Maximum", description: "Maximum value"
155
+ # end
156
+ #
157
+ # profile(:range_filter, label: "Range Filter", config_description: config_description) do |event, state:, configuration:|
158
+ # return true unless event == :state_from_handler
159
+ #
160
+ # (configuration["min"]..configuration["max"]).cover?(state)
161
+ # end
162
+ #
163
+ def profile(id, label: nil, config_description: nil, &block)
146
164
  raise ArgumentError, "Block is required" unless block
147
165
 
148
166
  id = id.to_s
149
- uid = org.openhab.core.thing.profiles.ProfileTypeUID.new("ruby", id)
150
167
 
151
168
  ThreadLocal.thread_local(openhab_rule_type: "profile", openhab_rule_uid: id) do
152
- Core::ProfileFactory.instance.register(uid, block)
169
+ Core::ProfileFactory.instance.register(id, block, label: label, config_description: config_description)
153
170
  end
154
171
  end
155
172
 
173
+ #
174
+ # Create a {org.openhab.core.config.core.ConfigDescription ConfigDescription} object.
175
+ #
176
+ # @param [String, java.net.URI] uri The URI for the ConfigDescription. When nil, a dummy URI is used which will
177
+ # be replaced by the profile with the correct URI for that profile.
178
+ # @yield Block that consists of {ConfigDescription::Builder#parameter} and {ConfigDescription::Builder#group} calls.
179
+ #
180
+ # @return [org.openhab.core.config.core.ConfigDescription]
181
+ # The created {org.openhab.core.config.core.ConfigDescription ConfigDescription} object
182
+ #
183
+ # @example
184
+ # config_description = config_description do
185
+ # parameter :ungrouped_parameter, :decimal, label: "Ungrouped Parameter", min: 1, max: 5
186
+ #
187
+ # group "Config Group", label: "Grouped parameters", advanced: true do
188
+ # parameter :my_parameter, :string, label: "My Parameter", description: "My Parameter Description"
189
+ # parameter :other_parameter, :integer, label: "Other Parameter", description: "Other Parameter Description"
190
+ # end
191
+ # end
192
+ #
193
+ def config_description(uri = nil, &block)
194
+ raise ArgumentError, "Block is required" unless block
195
+
196
+ ConfigDescription::Builder.new.build(uri, &block)
197
+ end
198
+
156
199
  # rubocop:enable Layout/LineLength
157
200
 
158
201
  # @!group Object Access
@@ -9,7 +9,9 @@ module YARD
9
9
  # Which might be a class, an enum, or an interface
10
10
  module Base
11
11
  module ClassMethods
12
- def new(name)
12
+ def new(name, _suffix = nil)
13
+ # _suffix is given when it encounters a class with ::, e.g. org.openhab.core.OpenHAB::DEFAULT_CONFIG_FOLDER
14
+
13
15
  super(:root, name)
14
16
  end
15
17
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YARD
4
+ module CodeObjects
5
+ module Java
6
+ class MethodObject < CodeObjects::MethodObject
7
+ include Base
8
+
9
+ def type
10
+ :method
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -5,27 +5,76 @@ module YARD
5
5
  module JRuby
6
6
  module Base
7
7
  class << self
8
+ #
9
+ # Creates an external link to java documentation for a java class.
10
+ #
11
+ # The supported classes are defined in the `javadocs` configuration option.
12
+ #
13
+ # Supported syntaxes:
14
+ # Package:
15
+ # - org.openhab.core => href_base/org/openhab/core/package-summary.html
16
+ #
17
+ # Class:
18
+ # - org.openhab.core.OpenHAB => href_base/org/openhab/core/OpenHAB.html
19
+ # This doesn't get mistaken as a constant:
20
+ # - java.net.URI => href_base/java/net/URI.html
21
+ #
22
+ # Constant: (To specify a constant, use Ruby's `::` syntax)
23
+ # - org.openhab.core.OpenHAB::DEFAULT_CONFIG_FOLDER =>
24
+ # href_base/org/openhab/core/OpenHAB.html#DEFAULT_CONFIG_FOLDER
25
+ #
26
+ # Method:
27
+ # - org.openhab.core.OpenHAB#getVersion() => href_base/org/openhab/core/OpenHAB.html#getVersion()
28
+ # But can also work with constants, albeit not a valid Ruby syntax:
29
+ # - org.openhab.core.OpenHAB#version => href_base/org/openhab/core/OpenHAB.html#version
30
+ # - org.openhab.core.OpenHAB#DEFAULT_CONFIG_FOLDER =>
31
+ # href_base/org/openhab/core/OpenHAB.html#DEFAULT_CONFIG_FOLDER
32
+ #
33
+ # Inner class:
34
+ # - org.openhab.core.config.core.ConfigDescriptionParameter::Type =>
35
+ # href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html
36
+ # - org.openhab.core.config.core.ConfigDescriptionParameter.Type =>
37
+ # href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html
38
+ #
39
+ # Constant in inner class:
40
+ # - org.openhab.core.config.core.ConfigDescriptionParameter::Type::TEXT =>
41
+ # href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html#TEXT
42
+ # - org.openhab.core.config.core.ConfigDescriptionParameter.Type::TEXT =>
43
+ # href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html#TEXT
44
+ #
8
45
  def infer_java_class(klass, inferred_type = nil, comments = nil, statement = nil)
9
- components = klass.split(".")
10
- components.pop if components.last == "freeze"
11
-
12
- class_first_char = components.last[0]
13
- is_field = components.last == components.last.upcase
14
- container_first_char = components[-2]&.[](0)
15
- is_method = container_first_char &&
16
- class_first_char != class_first_char.upcase &&
17
- container_first_char == container_first_char.upcase
18
- is_package = !is_method && !is_field && class_first_char != class_first_char.upcase
19
-
20
- # methods aren't supported right now
21
- return if is_method
22
-
23
46
  javadocs = YARD::Config.options.dig(:jruby, "javadocs") || {}
24
47
 
25
48
  href_base = javadocs.find { |package, _href| klass == package || klass.start_with?("#{package}.") }&.last
26
49
  return unless href_base
27
50
 
51
+ components = klass.split(/\.(?=[A-Z])/, 2)
52
+ components.unshift(*components.shift.split("."))
53
+ components.push(components.pop.delete_suffix(".freeze"))
54
+
55
+ class_first_char = components.last[0]
56
+ if /#|::/.match?(components.last)
57
+ parts = components.pop.rpartition(/#|::/)
58
+ is_field = parts.last == parts.last.upcase
59
+ # explicit method is fine, e.g. `org.openhab.core.OpenHAB#getVersion()`
60
+ is_method = !is_field
61
+ components.push(parts.first.gsub("::", "."), parts.last)
62
+ else
63
+ is_field = is_method = false
64
+ if components.last.include?(".")
65
+ parts = components.last.split(".")
66
+ if (is_method = parts.last[0] == parts.last[0].downcase)
67
+ # implicit method is not supported, e.g. `org.openhab.core.OpenHAB.version`
68
+ # because we're not sure whether it should be #version() or #getVersion()
69
+ return
70
+ end
71
+ end
72
+ end
73
+
74
+ is_package = !is_method && !is_field && class_first_char != class_first_char.upcase
75
+
28
76
  inferred_type = CodeObjects::Java::FieldObject if is_field
77
+ inferred_type = CodeObjects::Java::MethodObject if is_method
29
78
  inferred_type = CodeObjects::Java::PackageObject if is_package
30
79
  if inferred_type.nil?
31
80
  docstring = Docstring.parser.parse(comments || statement&.comments).to_docstring
@@ -36,12 +85,18 @@ module YARD
36
85
  end
37
86
  end
38
87
 
88
+ orig_klass = klass.dup
89
+
90
+ # purposely calling gsub! to modify the caller's string
91
+ # YARD doesn't handle java inner classes well, so we convert them to ruby
92
+ klass.gsub!("::", ".")
93
+
39
94
  inferred_type.new(klass) do |o|
40
95
  o.source = statement if statement
41
96
  suffix = "/package-summary" if is_package
42
- field = "##{components.pop}" if is_field
97
+ field = "##{components.pop}" if is_field || is_method
43
98
  link = "#{href_base}#{components.join("/")}#{suffix}.html#{field}"
44
- o.docstring.add_tag(Tags::Tag.new(:see, klass, nil, link)) unless o.docstring.has_tag?(:see)
99
+ o.docstring.add_tag(Tags::Tag.new(:see, orig_klass, nil, link)) unless o.docstring.has_tag?(:see)
45
100
  end
46
101
  end
47
102
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.11.0
4
+ version: 5.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian O'Connell
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-10-29 00:00:00.000000000 Z
13
+ date: 2023-12-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -124,20 +124,6 @@ dependencies:
124
124
  - - "~>"
125
125
  - !ruby/object:Gem::Version
126
126
  version: '2.2'
127
- - !ruby/object:Gem::Dependency
128
- name: github_changelog_generator
129
- requirement: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - "~>"
132
- - !ruby/object:Gem::Version
133
- version: '1.16'
134
- type: :development
135
- prerelease: false
136
- version_requirements: !ruby/object:Gem::Requirement
137
- requirements:
138
- - - "~>"
139
- - !ruby/object:Gem::Version
140
- version: '1.16'
141
127
  - !ruby/object:Gem::Dependency
142
128
  name: guard-rubocop
143
129
  requirement: !ruby/object:Gem::Requirement
@@ -391,6 +377,7 @@ files:
391
377
  - lib/openhab/core/events/abstract_event.rb
392
378
  - lib/openhab/core/events/abstract_item_registry_event.rb
393
379
  - lib/openhab/core/events/abstract_thing_registry_event.rb
380
+ - lib/openhab/core/events/channel_triggered_event.rb
394
381
  - lib/openhab/core/events/item_command_event.rb
395
382
  - lib/openhab/core/events/item_event.rb
396
383
  - lib/openhab/core/events/item_state_changed_event.rb
@@ -505,6 +492,7 @@ files:
505
492
  - lib/openhab/core_ext/ruby/symbol.rb
506
493
  - lib/openhab/core_ext/ruby/time.rb
507
494
  - lib/openhab/dsl.rb
495
+ - lib/openhab/dsl/config_description/builder.rb
508
496
  - lib/openhab/dsl/debouncer.rb
509
497
  - lib/openhab/dsl/events.rb
510
498
  - lib/openhab/dsl/events/watch_event.rb
@@ -569,6 +557,7 @@ files:
569
557
  - lib/openhab/yard/code_objects/java/class_object.rb
570
558
  - lib/openhab/yard/code_objects/java/field_object.rb
571
559
  - lib/openhab/yard/code_objects/java/interface_object.rb
560
+ - lib/openhab/yard/code_objects/java/method_object.rb
572
561
  - lib/openhab/yard/code_objects/java/package_object.rb
573
562
  - lib/openhab/yard/code_objects/java/proxy.rb
574
563
  - lib/openhab/yard/coderay.rb