openhab-scripting 5.22.1 → 5.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/openhab/core/actions/notification.rb +7 -2
- data/lib/openhab/core/items/group_item.rb +1 -1
- data/lib/openhab/core/types/time_series.rb +57 -16
- data/lib/openhab/dsl/items/timed_command.rb +51 -8
- data/lib/openhab/dsl/rules/builder.rb +32 -6
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +41 -13
- data/lib/openhab/dsl/sitemaps/builder.rb +304 -72
- data/lib/openhab/dsl/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55ff8734004f7befde1f1d3bb27560cfc8c5dbb7287f8dbb5e19a50fadec0d23
|
4
|
+
data.tar.gz: dba9276e8b4845e1b265973440aa0e036da3137176ba44c5c256ddfcd5dad227
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c4692d9a8ce6104b511e1475e01fcae49f0fda6bdf04f498c26b023237f8332e87166cbdc5e2754f1375b4e2cbf31f70c706e68beda3657d6f09b28d37b59bf
|
7
|
+
data.tar.gz: 133e78f26b440c5ffbb628ee323d56d2e4b4e74c1a65762cec75818f7ebfe5eeda4275e7cd6157fb68d90d551c5e2b4c984016c149abf222dc1917428f4c7e49
|
@@ -29,8 +29,11 @@ module OpenHAB
|
|
29
29
|
# @param on_click [String, nil] The action to be performed when the user clicks on the notification.
|
30
30
|
# Specified using the {https://next.openhab.org/addons/integrations/openhabcloud/#action-syntax
|
31
31
|
# action syntax}.
|
32
|
-
# @param attachment [String, nil] The URL of the media attachment to be displayed with the notification.
|
33
|
-
# This
|
32
|
+
# @param attachment [String, Item, nil] The URL of the media attachment to be displayed with the notification.
|
33
|
+
# This can either be a fully qualified URL, prefixed with
|
34
|
+
# `http://` or `https://` and reachable by the client device,
|
35
|
+
# a relative path on the user's openHAB instance starting with `/`,
|
36
|
+
# or an image item.
|
34
37
|
# @param buttons [Array<String>, Hash<String, String>, nil] Buttons to include in the notification.
|
35
38
|
# - In array form, each element is specified as `Title=$action`, where `$action` follows the
|
36
39
|
# {https://next.openhab.org/addons/integrations/openhabcloud/#action-syntax action syntax}.
|
@@ -94,6 +97,8 @@ module OpenHAB
|
|
94
97
|
buttons = buttons.map { |title, action| "#{title}=#{action}" } if buttons.is_a?(Hash)
|
95
98
|
raise ArgumentError, "buttons must contain (0..3) elements." unless (0..3).cover?(buttons.size)
|
96
99
|
|
100
|
+
attachment = "item:#{attachment.name}" if attachment.is_a?(Item) && attachment.image_item?
|
101
|
+
|
97
102
|
args.push(title&.to_s,
|
98
103
|
id&.to_s,
|
99
104
|
on_click&.to_s,
|
@@ -146,7 +146,7 @@ module OpenHAB
|
|
146
146
|
base_item.format_type(command)
|
147
147
|
end
|
148
148
|
|
149
|
-
%w[color contact date_time dimmer image location number player rollershutter string switch].each do |type|
|
149
|
+
%w[call color contact date_time dimmer image location number player rollershutter string switch].each do |type|
|
150
150
|
type_class = type.gsub(/(^[a-z]|_[a-z])/) { |letter| letter[-1].upcase }
|
151
151
|
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
152
152
|
def #{type}_item? # def date_time_item?
|
@@ -4,6 +4,7 @@
|
|
4
4
|
return unless OpenHAB::Core.version >= OpenHAB::Core::V4_1
|
5
5
|
|
6
6
|
require "forwardable"
|
7
|
+
require "openhab/core/lazy_array"
|
7
8
|
|
8
9
|
module OpenHAB
|
9
10
|
module Core
|
@@ -30,7 +31,7 @@ module OpenHAB
|
|
30
31
|
# @see DSL::Rules::BuilderDSL#time_series_updated #time_series_updated rule trigger
|
31
32
|
#
|
32
33
|
class TimeSeries
|
33
|
-
|
34
|
+
include LazyArray
|
34
35
|
|
35
36
|
# @!attribute [r] policy
|
36
37
|
# Returns the persistence policy of this series.
|
@@ -81,12 +82,19 @@ module OpenHAB
|
|
81
82
|
"size=#{size}>"
|
82
83
|
end
|
83
84
|
|
85
|
+
# Explicit conversion to Array
|
86
|
+
#
|
87
|
+
# @return [Array]
|
88
|
+
def to_a
|
89
|
+
get_states.to_array.to_a.freeze
|
90
|
+
end
|
91
|
+
|
84
92
|
#
|
85
93
|
# Returns the content of this series.
|
86
94
|
# @return [Array<org.openhab.core.types.TimeSeries.Entry>]
|
87
95
|
#
|
88
96
|
def states
|
89
|
-
|
97
|
+
to_a
|
90
98
|
end
|
91
99
|
|
92
100
|
# rename raw methods so we can overwrite them
|
@@ -100,29 +108,62 @@ module OpenHAB
|
|
100
108
|
#
|
101
109
|
# @note This method returns self so it can be chained, unlike the Java version.
|
102
110
|
#
|
103
|
-
# @param [Instant, #to_zoned_date_time, #to_instant]
|
111
|
+
# @param [Instant, #to_zoned_date_time, #to_instant] timestamp An instant for the given state.
|
104
112
|
# @param [State, String, Numeric] state The State at the given timestamp.
|
105
113
|
# If a String is given, it will be converted to {StringType}.
|
106
114
|
# If a {Numeric} is given, it will be converted to {DecimalType}.
|
107
115
|
# @return [self]
|
108
116
|
# @raise [ArgumentError] if state is not a {State}, String or {Numeric}
|
109
117
|
#
|
110
|
-
def add(
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
when State then state
|
115
|
-
when String then StringType.new(state)
|
116
|
-
when Numeric then DecimalType.new(state)
|
117
|
-
else
|
118
|
-
raise ArgumentError, "state must be a State, String or Numeric, but was #{state.class}"
|
119
|
-
end
|
120
|
-
add_instant(instant, state)
|
118
|
+
def add(timestamp, state)
|
119
|
+
timestamp = to_instant(timestamp)
|
120
|
+
state = format_state(state)
|
121
|
+
add_instant(timestamp, state)
|
121
122
|
self
|
122
123
|
end
|
123
124
|
|
124
|
-
#
|
125
|
-
|
125
|
+
#
|
126
|
+
# Appends an entry to self, returns self
|
127
|
+
#
|
128
|
+
# @param [Array<Instant, State>] entry a two-element array with the timestamp and state.
|
129
|
+
# The timestamp can be an {Instant} or any object that responds to #to_zoned_date_time.
|
130
|
+
# @return [self]
|
131
|
+
#
|
132
|
+
# @example Append an entry
|
133
|
+
# time_series << [Time.at(2), 2]
|
134
|
+
#
|
135
|
+
def <<(entry)
|
136
|
+
raise ArgumentError, "entry must be an Array, but was #{entry.class}" unless entry.respond_to?(:to_ary)
|
137
|
+
|
138
|
+
entry = entry.to_ary
|
139
|
+
raise ArgumentError, "entry must be an Array of size 2, but was #{entry.size}" unless entry.size == 2
|
140
|
+
|
141
|
+
add(entry[0], entry[1])
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def to_instant(timestamp)
|
147
|
+
if timestamp.is_a?(Instant)
|
148
|
+
timestamp
|
149
|
+
elsif timestamp.respond_to?(:to_instant)
|
150
|
+
timestamp.to_instant
|
151
|
+
elsif timestamp.respond_to?(:to_zoned_date_time)
|
152
|
+
timestamp.to_zoned_date_time.to_instant
|
153
|
+
else
|
154
|
+
raise ArgumentError, "timestamp must be an Instant, or convertible to one, but was #{timestamp.class}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def format_state(state)
|
159
|
+
case state
|
160
|
+
when State then state
|
161
|
+
when String then StringType.new(state)
|
162
|
+
when Numeric then DecimalType.new(state)
|
163
|
+
else
|
164
|
+
raise ArgumentError, "state must be a State, String or Numeric, but was #{state.class}"
|
165
|
+
end
|
166
|
+
end
|
126
167
|
end
|
127
168
|
end
|
128
169
|
end
|
@@ -64,6 +64,29 @@ module OpenHAB
|
|
64
64
|
def cancelled?
|
65
65
|
resolution == :cancelled
|
66
66
|
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Reschedule the timed command.
|
70
|
+
#
|
71
|
+
# If the timed command was cancelled, this will also resume it.
|
72
|
+
#
|
73
|
+
# @param [java.time.temporal.TemporalAmount, #to_zoned_date_time, Proc, nil] time
|
74
|
+
# When to reschedule the timer for. If unspecified, the original time is used.
|
75
|
+
# @return [void]
|
76
|
+
#
|
77
|
+
def reschedule(time = nil)
|
78
|
+
self.resolution = nil
|
79
|
+
timer.reschedule(time)
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Resume a cancelled timed command to its original expiration time.
|
84
|
+
#
|
85
|
+
# @return [void]
|
86
|
+
#
|
87
|
+
def resume
|
88
|
+
self.resolution = nil
|
89
|
+
end
|
67
90
|
end
|
68
91
|
|
69
92
|
@timed_commands = java.util.concurrent.ConcurrentHashMap.new
|
@@ -82,7 +105,13 @@ module OpenHAB
|
|
82
105
|
#
|
83
106
|
# @note If a block is provided, and the timer is canceled because the
|
84
107
|
# item changed state while it was waiting, the block will still be
|
85
|
-
# executed.
|
108
|
+
# executed. The timed command can be reinstated by calling {TimedCommandDetails#resume #resume} or
|
109
|
+
# {TimedCommandDetails#reschedule #reschedule}.
|
110
|
+
#
|
111
|
+
# If the timer expired, the timed command can be rescheduled from inside the block by calling
|
112
|
+
# {TimedCommandDetails#reschedule #reschedule}.
|
113
|
+
#
|
114
|
+
# Be sure to check {TimedCommandDetails#expired? #expired?}
|
86
115
|
# and/or {TimedCommandDetails#cancelled? #cancelled?} to determine why
|
87
116
|
# the block was called.
|
88
117
|
#
|
@@ -181,25 +210,30 @@ module OpenHAB
|
|
181
210
|
end
|
182
211
|
|
183
212
|
# Creates the timer to handle changing the item state when timer expires or invoking user supplied block
|
184
|
-
# @param [
|
213
|
+
# @param [TimedCommandDetails] timed_command_details details about the timed command
|
185
214
|
# @return [Timer] Timer
|
186
215
|
def timed_command_timer(timed_command_details, duration)
|
187
216
|
DSL.after(duration) do
|
188
217
|
timed_command_details.mutex.synchronize do
|
189
218
|
logger.trace "Timed command expired - #{timed_command_details}"
|
190
|
-
DSL.rules.remove(timed_command_details.rule_uid)
|
191
219
|
timed_command_details.resolution = :expired
|
192
220
|
case timed_command_details.on_expire
|
193
221
|
when Proc
|
194
222
|
logger.trace "Invoking block #{timed_command_details.on_expire} after timed command for #{name} expired"
|
195
223
|
timed_command_details.on_expire.call(timed_command_details)
|
224
|
+
if timed_command_details.resolution.nil?
|
225
|
+
logger.trace { "Block rescheduled the timer to #{timed_command_details.timer.execution_time}" }
|
226
|
+
end
|
196
227
|
when Core::Types::UnDefType
|
197
228
|
update(timed_command_details.on_expire)
|
198
229
|
else
|
199
230
|
command(timed_command_details.on_expire)
|
200
231
|
end
|
232
|
+
if timed_command_details.resolution
|
233
|
+
DSL.rules.remove(timed_command_details.rule_uid)
|
234
|
+
TimedCommand.timed_commands.delete(timed_command_details.item)
|
235
|
+
end
|
201
236
|
end
|
202
|
-
TimedCommand.timed_commands.delete(timed_command_details.item)
|
203
237
|
end
|
204
238
|
end
|
205
239
|
|
@@ -250,17 +284,26 @@ module OpenHAB
|
|
250
284
|
def execute(_mod = nil, inputs = nil)
|
251
285
|
ThreadLocal.thread_local(**@thread_locals) do
|
252
286
|
@timed_command_details.mutex.synchronize do
|
253
|
-
logger.trace
|
254
|
-
|
287
|
+
logger.trace do
|
288
|
+
"Canceling implicit timer #{@timed_command_details.timer} for " \
|
289
|
+
"#{@timed_command_details.item.name} because of received event #{inputs}"
|
290
|
+
end
|
291
|
+
original_execution_time = @timed_command_details.timer.execution_time
|
255
292
|
@timed_command_details.timer.cancel
|
256
|
-
DSL.rules
|
293
|
+
DSL.rules[@timed_command_details.rule_uid].disable
|
257
294
|
@timed_command_details.resolution = :cancelled
|
258
295
|
if @timed_command_details.on_expire.is_a?(Proc)
|
259
296
|
logger.trace "Executing user supplied block on timed command cancelation"
|
260
297
|
@timed_command_details.on_expire.call(@timed_command_details)
|
261
298
|
end
|
299
|
+
if @timed_command_details.resolution
|
300
|
+
DSL.rules.remove(@timed_command_details.rule_uid)
|
301
|
+
TimedCommand.timed_commands.delete(@timed_command_details.item)
|
302
|
+
else
|
303
|
+
DSL.rules[@timed_command_details.rule_uid].enable
|
304
|
+
@timed_command_details.timer.reschedule(original_execution_time)
|
305
|
+
end
|
262
306
|
end
|
263
|
-
TimedCommand.timed_commands.delete(@timed_command_details.item)
|
264
307
|
rescue Exception => e
|
265
308
|
raise if defined?(::RSpec)
|
266
309
|
|
@@ -1278,6 +1278,8 @@ module OpenHAB
|
|
1278
1278
|
#
|
1279
1279
|
# The `event` passed to run blocks will be a {Core::Events::TimerEvent}.
|
1280
1280
|
#
|
1281
|
+
# For a more complex schedule, use {cron}.
|
1282
|
+
#
|
1281
1283
|
# @param [String,
|
1282
1284
|
# Duration,
|
1283
1285
|
# java.time.MonthDay,
|
@@ -1294,8 +1296,8 @@ module OpenHAB
|
|
1294
1296
|
# :thursday,
|
1295
1297
|
# :friday,
|
1296
1298
|
# :saturday,
|
1297
|
-
# :sunday]
|
1298
|
-
# When to execute rule.
|
1299
|
+
# :sunday] values
|
1300
|
+
# When to execute rule. Multiple day-of-week can be specified. Otherwise, only one value is allowed.
|
1299
1301
|
# @param [LocalTime, String, Core::Items::DateTimeItem, nil] at What time of day to execute rule
|
1300
1302
|
# If `value` is `:day`, `at` can be a {Core::Items::DateTimeItem DateTimeItem}, and
|
1301
1303
|
# the trigger will run every day at the (time only portion of) current state of the
|
@@ -1304,6 +1306,7 @@ module OpenHAB
|
|
1304
1306
|
# @return [void]
|
1305
1307
|
#
|
1306
1308
|
# @see at
|
1309
|
+
# @see cron
|
1307
1310
|
#
|
1308
1311
|
# @example
|
1309
1312
|
# rule "Daily" do
|
@@ -1363,15 +1366,38 @@ module OpenHAB
|
|
1363
1366
|
# run { logger.info "Happy Valentine's Day!" }
|
1364
1367
|
# end
|
1365
1368
|
#
|
1366
|
-
|
1367
|
-
|
1369
|
+
# @example Multiple day-of-week
|
1370
|
+
# rule "Weekend" do
|
1371
|
+
# every :saturday, :sunday, at: "10:00"
|
1372
|
+
# run { logger.info "It's the weekend!" }
|
1373
|
+
# end
|
1374
|
+
#
|
1375
|
+
def every(*values, at: nil, attach: nil)
|
1376
|
+
raise ArgumentError, "Missing values" if values.empty?
|
1377
|
+
|
1378
|
+
if Cron.all_dow_symbols?(values)
|
1379
|
+
@ruby_triggers << [:every, values.join(", "), { at: at }]
|
1380
|
+
return cron(Cron.from_dow_symbols(values, at), attach: attach)
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
if values.size != 1
|
1384
|
+
raise ArgumentError,
|
1385
|
+
"Multiple values are only allowed for day-of-week. " \
|
1386
|
+
"Otherwise only one value is allowed, given: #{values.size}"
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
value = values.first
|
1390
|
+
value = java.time.MonthDay.parse(value.to_str) if value.respond_to?(:to_str)
|
1368
1391
|
|
1369
1392
|
@ruby_triggers << [:every, value, { at: at }]
|
1370
1393
|
|
1371
1394
|
if value == :day && at.is_a?(Item)
|
1372
|
-
|
1395
|
+
# @!deprecated OH 3.4 - attachments are supported in OH 4.0+
|
1396
|
+
if Core.version <= Core::V4_0 && !attach.nil?
|
1397
|
+
raise ArgumentError, "Attachments are not supported with dynamic datetime triggers in openHAB 3.x"
|
1398
|
+
end
|
1373
1399
|
|
1374
|
-
return trigger("timer.DateTimeTrigger", itemName: at.name, timeOnly: true)
|
1400
|
+
return trigger("timer.DateTimeTrigger", itemName: at.name, timeOnly: true, attach: attach)
|
1375
1401
|
end
|
1376
1402
|
|
1377
1403
|
cron_expression = case value
|
@@ -50,8 +50,13 @@ module OpenHAB
|
|
50
50
|
}.freeze
|
51
51
|
private_constant :DAY_OF_WEEK_MAP
|
52
52
|
|
53
|
+
DAY_OF_WEEK = DAY_OF_WEEK_MAP.keys.freeze
|
54
|
+
private_constant :DAY_OF_WEEK
|
55
|
+
|
53
56
|
# @return [Hash] Converts the DAY_OF_WEEK_MAP to map used by Cron Expression
|
54
|
-
DAY_OF_WEEK_EXPRESSION_MAP = DAY_OF_WEEK_MAP.transform_values
|
57
|
+
DAY_OF_WEEK_EXPRESSION_MAP = DAY_OF_WEEK_MAP.transform_values do |v|
|
58
|
+
CRON_EXPRESSION_MAP.merge(second: 0, minute: 0, hour: 0, dow: v)
|
59
|
+
end.freeze
|
55
60
|
private_constant :DAY_OF_WEEK_EXPRESSION_MAP
|
56
61
|
|
57
62
|
# @return [Hash] Create a set of cron expressions based on different time intervals
|
@@ -76,7 +81,7 @@ module OpenHAB
|
|
76
81
|
# @param [Duration] duration
|
77
82
|
# @param [Object] at LocalTime or String representing time of day
|
78
83
|
#
|
79
|
-
# @return [
|
84
|
+
# @return [String] cron expression
|
80
85
|
#
|
81
86
|
def self.from_duration(duration, at)
|
82
87
|
raise ArgumentError, '"at" cannot be used with duration' if at
|
@@ -90,7 +95,7 @@ module OpenHAB
|
|
90
95
|
# @param [MonthDay] monthday a {MonthDay} object
|
91
96
|
# @param [Object] at LocalTime or String representing time of day
|
92
97
|
#
|
93
|
-
# @return [
|
98
|
+
# @return [String] cron expression
|
94
99
|
#
|
95
100
|
def self.from_monthday(monthday, at)
|
96
101
|
expression_map = EXPRESSION_MAP[:day].merge(month: monthday.month_value, dom: monthday.day_of_month)
|
@@ -104,7 +109,7 @@ module OpenHAB
|
|
104
109
|
# @param [Symbol] symbol
|
105
110
|
# @param [Object] at LocalTime or String representing time of day
|
106
111
|
#
|
107
|
-
# @return [
|
112
|
+
# @return [String] cron expression created from symbol
|
108
113
|
#
|
109
114
|
def self.from_symbol(symbol, at)
|
110
115
|
expression_map = EXPRESSION_MAP[symbol]
|
@@ -112,12 +117,38 @@ module OpenHAB
|
|
112
117
|
map_to_cron(expression_map)
|
113
118
|
end
|
114
119
|
|
120
|
+
#
|
121
|
+
# Checks if all symbols are day-of-week symbols
|
122
|
+
#
|
123
|
+
# @param [Array<Symbol>] symbols
|
124
|
+
#
|
125
|
+
# @return [Boolean] true if all symbols are day-of-week symbols
|
126
|
+
#
|
127
|
+
def self.all_dow_symbols?(symbols)
|
128
|
+
(symbols & DAY_OF_WEEK) == symbols
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Create a cron map from a list of day-of-week symbols
|
133
|
+
#
|
134
|
+
# @param [Symbol] symbols
|
135
|
+
# @param [Object] at LocalTime or String representing time of day
|
136
|
+
#
|
137
|
+
# @return [String] cron expression created from symbols
|
138
|
+
#
|
139
|
+
def self.from_dow_symbols(symbols, at)
|
140
|
+
dow = DAY_OF_WEEK_MAP.fetch_values(*symbols).join(",")
|
141
|
+
expression_map = CRON_EXPRESSION_MAP.merge(dow: dow, hour: 0, minute: 0, second: 0)
|
142
|
+
expression_map = at_condition(expression_map, at) if at
|
143
|
+
map_to_cron(expression_map)
|
144
|
+
end
|
145
|
+
|
115
146
|
#
|
116
147
|
# Create a cron map from cron elements
|
117
148
|
#
|
118
149
|
# @param [Hash] fields Cron fields (second, minute, hour, dom, month, dow, year)
|
119
150
|
#
|
120
|
-
# @return [
|
151
|
+
# @return [String] cron expression
|
121
152
|
#
|
122
153
|
def self.from_fields(fields)
|
123
154
|
extra_fields = fields.keys - CRON_EXPRESSION_MAP.keys
|
@@ -190,17 +221,14 @@ module OpenHAB
|
|
190
221
|
#
|
191
222
|
# If an at time is provided, parse that and merge the new fields into the expression.
|
192
223
|
#
|
193
|
-
# @param [
|
194
|
-
# @param [
|
224
|
+
# @param [Hash] expression_map
|
225
|
+
# @param [LocalTime,String] at_time
|
195
226
|
#
|
196
|
-
# @return [
|
227
|
+
# @return [Hash] expression map with at time merged in
|
197
228
|
#
|
198
229
|
def self.at_condition(expression_map, at_time)
|
199
|
-
|
200
|
-
|
201
|
-
expression_map = expression_map.merge(hour: tod.hour, minute: tod.minute, second: tod.second)
|
202
|
-
end
|
203
|
-
expression_map
|
230
|
+
tod = at_time.is_a?(LocalTime) ? at_time : LocalTime.parse(at_time)
|
231
|
+
expression_map.merge(hour: tod.hour, minute: tod.minute, second: tod.second)
|
204
232
|
end
|
205
233
|
|
206
234
|
#
|
@@ -9,7 +9,32 @@ module OpenHAB
|
|
9
9
|
# @!visibility private
|
10
10
|
org.openhab.core.model.sitemap.sitemap.impl.SitemapImpl.alias_method :uid, :name
|
11
11
|
|
12
|
-
#
|
12
|
+
#
|
13
|
+
# A sitemap builder allows you to dynamically create openHAB sitemaps at runtime.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# sitemaps.build do
|
17
|
+
# sitemap "demo", label: "My home automation" do
|
18
|
+
# frame label: "Date" do
|
19
|
+
# text item: Date
|
20
|
+
# end
|
21
|
+
# frame label: "Demo" do
|
22
|
+
# switch item: Lights, icon: "light"
|
23
|
+
# text item: LR_Temperature, label: "Livingroom [%.1f °C]"
|
24
|
+
# group item: Heating
|
25
|
+
# text item: LR_Multimedia_Summary, label: "Multimedia [%s]", static_icon: "video" do
|
26
|
+
# selection item: LR_TV_Channel,
|
27
|
+
# mappings: { 0 => "off", 1 => "DasErste", 2 => "BBC One", 3 => "Cartoon Network" }
|
28
|
+
# slider item: LR_TV_Volume
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @see https://www.openhab.org/docs/ui/sitemaps.html
|
35
|
+
# @see OpenHAB::DSL.sitemaps
|
36
|
+
# @see OpenHAB::Core::Sitemaps::Provider#build sitemaps.build
|
37
|
+
#
|
13
38
|
class Builder
|
14
39
|
# @!visibility private
|
15
40
|
def initialize(provider, builder_proxy, update:)
|
@@ -698,88 +723,92 @@ module OpenHAB
|
|
698
723
|
end
|
699
724
|
end
|
700
725
|
|
701
|
-
# Builds a `
|
702
|
-
#
|
703
|
-
#
|
704
|
-
#
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
726
|
+
# Builds a `Button` element
|
727
|
+
#
|
728
|
+
# This element can only exist within a `Buttongrid` element.
|
729
|
+
#
|
730
|
+
# @since openHAB 4.2
|
731
|
+
# @see https://www.openhab.org/docs/ui/sitemaps.html#element-type-button
|
732
|
+
# @see org.openhab.core.model.sitemap.sitemap.Button
|
733
|
+
class ButtonBuilder < WidgetBuilder
|
734
|
+
# The row in which the button is placed
|
735
|
+
# @return [Integer]
|
736
|
+
attr_accessor :row
|
737
|
+
|
738
|
+
# The column in which the button is placed
|
739
|
+
# @return [Integer]
|
740
|
+
attr_accessor :column
|
741
|
+
|
742
|
+
# The command to send when the button is pressed
|
743
|
+
# @return [String, Command]
|
744
|
+
attr_accessor :click
|
745
|
+
|
746
|
+
# The command to send when the button is released
|
747
|
+
# @return [String, Command, nil]
|
748
|
+
attr_accessor :release
|
749
|
+
|
750
|
+
# Whether the button is stateless
|
751
|
+
# @return [true, false, nil]
|
752
|
+
attr_writer :stateless
|
709
753
|
|
710
754
|
# (see WidgetBuilder#initialize)
|
711
|
-
# @!method initialize(item: nil, label: nil, icon: nil, static_icon: nil,
|
712
|
-
# @param [
|
713
|
-
#
|
714
|
-
#
|
715
|
-
#
|
716
|
-
#
|
717
|
-
#
|
718
|
-
#
|
719
|
-
#
|
720
|
-
# @
|
721
|
-
#
|
722
|
-
# sitemaps.build do
|
723
|
-
# sitemap "remote", label: "TV Remote Control" do
|
724
|
-
# buttongrid item: LivingRoom_TV_RCButton, buttons: [
|
725
|
-
# [1, 1, "BACK", "Back", "f7:return"],
|
726
|
-
# [1, 2, "HOME", "Menu", "material:apps"],
|
727
|
-
# [1, 3, "YELLOW", "Search", "f7:search"],
|
728
|
-
# [2, 2, "UP", "Up", "f7:arrowtriangle_up"],
|
729
|
-
# [4, 2, "DOWN", "Down", "f7:arrowtriangle_down"],
|
730
|
-
# [3, 1, "LEFT", "Left", "f7:arrowtriangle_left"],
|
731
|
-
# [3, 3, "RIGHT", "Right", "f7:arrowtriangle_right"],
|
732
|
-
# [3, 2, "ENTER", "Enter", "material:adjust"]
|
733
|
-
# ]
|
734
|
-
# end
|
735
|
-
# end
|
755
|
+
# @!method initialize(item: nil, label: nil, icon: nil, static_icon: nil, row:, column:, click:, release: nil, stateless: nil, label_color: nil, value_color: nil, icon_color: nil, visibility: nil)
|
756
|
+
# @param [Integer] row
|
757
|
+
# The row in which the button is placed (see {ButtonBuilder#row})
|
758
|
+
# @param [Integer] column
|
759
|
+
# The column in which the button is placed (see {ButtonBuilder#column})
|
760
|
+
# @param [String, Command] click
|
761
|
+
# The command to send when the button is pressed (see {ButtonBuilder#click})
|
762
|
+
# @param [String, Command, nil] release
|
763
|
+
# The command to send when the button is released (see {ButtonBuilder#release})
|
764
|
+
# @param [true, false, nil] stateless
|
765
|
+
# Whether the button is stateless (see {ButtonBuilder#stateless=})
|
736
766
|
#
|
737
|
-
# @see https://www.openhab.org/docs/ui/sitemaps.html#element-type-buttongrid
|
738
767
|
# @!visibility private
|
739
|
-
def initialize(
|
740
|
-
|
741
|
-
|
742
|
-
|
768
|
+
def initialize(builder_proxy,
|
769
|
+
row:,
|
770
|
+
column:,
|
771
|
+
click:,
|
772
|
+
release: nil,
|
773
|
+
stateless: nil,
|
774
|
+
**kwargs,
|
775
|
+
&block)
|
776
|
+
|
777
|
+
super(:button, builder_proxy, **kwargs, &block)
|
778
|
+
|
779
|
+
@row = row
|
780
|
+
@column = column
|
781
|
+
@click = click
|
782
|
+
@release = release
|
783
|
+
@stateless = stateless
|
743
784
|
end
|
744
785
|
|
745
|
-
#
|
746
|
-
|
747
|
-
|
748
|
-
# @param [Array<int, int, Command, String, String>] button the button to add
|
749
|
-
# @return [Array<Array<int, int, Command, String, String>>] the current buttons
|
750
|
-
#
|
751
|
-
def button(button)
|
752
|
-
validate_button(button)
|
753
|
-
@buttons << button
|
786
|
+
# (see #stateless=)
|
787
|
+
def stateless?
|
788
|
+
@stateless
|
754
789
|
end
|
755
790
|
|
756
791
|
# @!visibility private
|
757
792
|
def build
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
793
|
+
if Core.version >= Core::V4_2
|
794
|
+
super.tap do |widget|
|
795
|
+
widget.row = row
|
796
|
+
widget.column = column
|
797
|
+
widget.cmd = click.to_s
|
798
|
+
widget.release_cmd = release.to_s unless release.nil?
|
799
|
+
widget.stateless = stateless? unless @stateless.nil?
|
800
|
+
end
|
801
|
+
else
|
802
|
+
# @deprecated OH 4.1
|
803
|
+
# in OH 4.1, the button is a property of the Buttongrid, not a widget
|
804
|
+
SitemapBuilder.factory.create_button.tap do |button|
|
805
|
+
button.row = row
|
806
|
+
button.column = column
|
807
|
+
button.cmd = click.to_s
|
808
|
+
button.label = label
|
809
|
+
button.icon = icon if icon
|
810
|
+
end
|
772
811
|
end
|
773
|
-
|
774
|
-
widget
|
775
|
-
end
|
776
|
-
|
777
|
-
private
|
778
|
-
|
779
|
-
def validate_button(button)
|
780
|
-
return if (4..5).cover?(button.size)
|
781
|
-
|
782
|
-
raise ArgumentError, "Invalid button: '#{button.inspect}'. It must be an array with (4..5) elements"
|
783
812
|
end
|
784
813
|
end
|
785
814
|
|
@@ -1169,6 +1198,209 @@ module OpenHAB
|
|
1169
1198
|
class FrameBuilder < LinkableWidgetBuilder
|
1170
1199
|
end
|
1171
1200
|
|
1201
|
+
# Builds a `Buttongrid` element
|
1202
|
+
# @since openHAB 4.1
|
1203
|
+
# @see https://www.openhab.org/docs/ui/sitemaps.html#element-type-buttongrid
|
1204
|
+
# @see org.openhab.core.model.sitemap.sitemap.Buttongrid
|
1205
|
+
class ButtongridBuilder < LinkableWidgetBuilder
|
1206
|
+
REQUIRED_BUTTON_ARGS = %i[row column click].freeze
|
1207
|
+
private_constant :REQUIRED_BUTTON_ARGS
|
1208
|
+
|
1209
|
+
# @!deprecated OH 4.1 in OH 4.1, Buttongrid is not a LinkableWidget.
|
1210
|
+
# Pretend that the buttons property is its children so we can add to it in LinkableWidgetBuilder#build
|
1211
|
+
if (Core::V4_1...Core::V4_2).cover?(Core.version)
|
1212
|
+
java_import org.openhab.core.model.sitemap.sitemap.Buttongrid
|
1213
|
+
module Buttongrid
|
1214
|
+
def children
|
1215
|
+
buttons
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
# (see WidgetBuilder#initialize)
|
1221
|
+
# @!method initialize(item: nil, label: nil, icon: nil, static_icon: nil, buttons: nil, label_color: nil, value_color: nil, icon_color: nil, visibility: nil)
|
1222
|
+
# @param [Array<Array<int, int, Command, String, String>>] buttons An array of buttons to display.
|
1223
|
+
# Each element can be a hash with keyword arguments (see {Sitemaps::ButtongridBuilder#button}),
|
1224
|
+
# or an array with the following elements:
|
1225
|
+
# - row: 1-12
|
1226
|
+
# - column: 1-12
|
1227
|
+
# - click: The command to send when the button is pressed
|
1228
|
+
# - label: The label to display on the button (optional)
|
1229
|
+
# - icon: The icon to display on the button (optional)
|
1230
|
+
#
|
1231
|
+
# @example Create a buttongrid with buttons as an argument
|
1232
|
+
# # This creates a buttongrid to emulate a TV remote control
|
1233
|
+
# sitemaps.build do
|
1234
|
+
# sitemap "remote", label: "TV Remote Control" do
|
1235
|
+
# buttongrid item: LivingRoom_TV_RCButton, buttons: [
|
1236
|
+
# [1, 1, "BACK", "Back", "f7:return"],
|
1237
|
+
# [1, 2, "HOME", "Menu", "material:apps"],
|
1238
|
+
# [1, 3, "YELLOW", "Search", "f7:search"],
|
1239
|
+
# [2, 2, "UP", "Up", "f7:arrowtriangle_up"],
|
1240
|
+
# [4, 2, "DOWN", "Down", "f7:arrowtriangle_down"],
|
1241
|
+
# [3, 1, "LEFT", "Left", "f7:arrowtriangle_left"],
|
1242
|
+
# [3, 3, "RIGHT", "Right", "f7:arrowtriangle_right"],
|
1243
|
+
#
|
1244
|
+
# # Using keyword arguments:
|
1245
|
+
# {row: 3, column: 2, click: "ENTER", label: "Enter", icon: "material:adjust" }
|
1246
|
+
# ]
|
1247
|
+
# end
|
1248
|
+
# end
|
1249
|
+
#
|
1250
|
+
# @example Create a buttongrid with button widgets
|
1251
|
+
# sitemaps.build do
|
1252
|
+
# sitemap "remote", label: "TV Remote Control" do
|
1253
|
+
# buttongrid item: LivingRoom_TV_RCButton do
|
1254
|
+
# button 1, 1, click: "BACK", icon: "f7:return"
|
1255
|
+
# button 1, 2, click: "HOME", icon: "material:apps"
|
1256
|
+
# button 1, 3, click: "YELLOW", icon: "f7:search"
|
1257
|
+
# button 2, 2, click: "UP", icon: "f7:arrowtriangle_up"
|
1258
|
+
# button 4, 2, click: "DOWN", icon: "f7:arrowtriangle_down"
|
1259
|
+
# button 3, 1, click: "LEFT", icon: "f7:arrowtriangle_left"
|
1260
|
+
# button 3, 3, click: "RIGHT", icon: "f7:arrowtriangle_right"
|
1261
|
+
# button 3, 2, click: "ENTER", icon: "material:adjust"
|
1262
|
+
# end
|
1263
|
+
#
|
1264
|
+
# # The following buttons use widget features introduced in openHAB 4.2+
|
1265
|
+
# buttongrid item: LivingRoom_Curtain do
|
1266
|
+
# button 1, 1, click: "up", release: "stop", icon: "f7:arrowtriangle_up"
|
1267
|
+
# button 2, 1, click: "down", release: "stop", icon: "f7:arrowtriangle_up"
|
1268
|
+
# end
|
1269
|
+
# end
|
1270
|
+
# end
|
1271
|
+
#
|
1272
|
+
# @see https://www.openhab.org/docs/ui/sitemaps.html#element-type-buttongrid
|
1273
|
+
# @!visibility private
|
1274
|
+
def initialize(type, builder_proxy, buttons: [], **kwargs, &block)
|
1275
|
+
super(type, builder_proxy, **kwargs, &block)
|
1276
|
+
|
1277
|
+
# Put the buttons given in the constructor before those added in the block
|
1278
|
+
# We can't do this before calling the super constructor because `children` is initialized there
|
1279
|
+
children.slice!(0..).then do |buttons_from_block|
|
1280
|
+
buttons.each do |b|
|
1281
|
+
if b.is_a?(Array)
|
1282
|
+
button(*b)
|
1283
|
+
else
|
1284
|
+
button(**b)
|
1285
|
+
end
|
1286
|
+
end
|
1287
|
+
children.concat(buttons_from_block)
|
1288
|
+
end
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
#
|
1292
|
+
# @!method button(row = nil, column = nil, click = nil, label = nil, icon = nil, item: nil, label: nil, icon: nil, static_icon: nil, row:, column:, click:, release: nil, stateless: nil, label_color: nil, value_color: nil, icon_color: nil, visibility: nil)
|
1293
|
+
# Adds a button inside the buttongrid
|
1294
|
+
#
|
1295
|
+
# - In openHAB 4.1, buttons are direct properties of the buttongrid.
|
1296
|
+
# Only `row`, `column`, `click`, `label` (optional), and `icon` (optional) are used.
|
1297
|
+
# All the other parameters are ignored.
|
1298
|
+
# All the buttons will send commands to the same item assigned to the buttongrid.
|
1299
|
+
#
|
1300
|
+
# - In openHAB 4.2+, buttons are widgets within the containing buttongrid, and they
|
1301
|
+
# support all the parameters listed in the method signature such as
|
1302
|
+
# `release`, `label_color`, `visibility`, etc.
|
1303
|
+
# Each Button element has an item associated with that button.
|
1304
|
+
# When an item is not specified for the button, it will default to the containing buttongrid's item.
|
1305
|
+
#
|
1306
|
+
# This method supports positional arguments and/or keyword arguments.
|
1307
|
+
# Their use can be mixed, however, the keyword arguments will override the positional arguments
|
1308
|
+
# when both are specified.
|
1309
|
+
#
|
1310
|
+
# @param (see ButtonBuilder#initialize)
|
1311
|
+
# @return [ButtonBuilder]
|
1312
|
+
#
|
1313
|
+
# @example Adding buttons to a buttongrid with positional arguments
|
1314
|
+
# sitemaps.build do
|
1315
|
+
# sitemap "remote" do
|
1316
|
+
# buttongrid item: RCButton do
|
1317
|
+
# button 1, 1, "BACK", "Back", "f7:return"
|
1318
|
+
# button 1, 2, "HOME", "Menu", "material:apps"
|
1319
|
+
# button 1, 3, "YELLOW", "Search", "f7:search"
|
1320
|
+
# button 2, 2, "UP", "Up", "f7:arrowtriangle_up"
|
1321
|
+
# button 4, 2, "DOWN", "Down", "f7:arrowtriangle_down"
|
1322
|
+
# button 3, 1, "LEFT", "Left", "f7:arrowtriangle_left"
|
1323
|
+
# button 3, 3, "RIGHT", "Right", "f7:arrowtriangle_right"
|
1324
|
+
# button 3, 2, "ENTER", "Enter", "material:adjust"
|
1325
|
+
# end
|
1326
|
+
# end
|
1327
|
+
# end
|
1328
|
+
#
|
1329
|
+
# @example Adding buttons to a buttongrid with keyword arguments
|
1330
|
+
# sitemaps.build do
|
1331
|
+
# sitemap "remote" do
|
1332
|
+
# buttongrid item: RCButton do
|
1333
|
+
# # These buttons will use the default item assigned to the buttongrid (RCButton)
|
1334
|
+
# button row: 1, column: 1, click: "BACK", icon: "f7:return"
|
1335
|
+
# button row: 1, column: 2, click: "HOME", icon: "material:apps"
|
1336
|
+
# button row: 1, column: 3, click: "YELLOW", icon: "f7:search"
|
1337
|
+
# button row: 2, column: 2, click: "UP", icon: "f7:arrowtriangle_up"
|
1338
|
+
# button row: 4, column: 2, click: "DOWN", icon: "f7:arrowtriangle_down"
|
1339
|
+
# button row: 3, column: 1, click: "LEFT", icon: "f7:arrowtriangle_left"
|
1340
|
+
# button row: 3, column: 3, click: "RIGHT", icon: "f7:arrowtriangle_right"
|
1341
|
+
# button row: 3, column: 2, click: "ENTER", icon: "material:adjust"
|
1342
|
+
# end
|
1343
|
+
# end
|
1344
|
+
# end
|
1345
|
+
#
|
1346
|
+
# @example Mixing positional and keyword arguments
|
1347
|
+
# sitemaps.build do
|
1348
|
+
# sitemap "remote" do
|
1349
|
+
# buttongrid item: RCButton do
|
1350
|
+
# button 1, 1, click: "BACK", icon: "f7:return"
|
1351
|
+
# button 1, 2, click: "HOME", icon: "material:apps"
|
1352
|
+
# button 1, 3, click: "YELLOW", icon: "f7:search"
|
1353
|
+
# button 2, 2, click: "UP", icon: "f7:arrowtriangle_up"
|
1354
|
+
# button 4, 2, click: "DOWN", icon: "f7:arrowtriangle_down"
|
1355
|
+
# button 3, 1, click: "LEFT", icon: "f7:arrowtriangle_left"
|
1356
|
+
# button 3, 3, click: "RIGHT", icon: "f7:arrowtriangle_right"
|
1357
|
+
# button 3, 2, click: "ENTER", icon: "material:adjust"
|
1358
|
+
# end
|
1359
|
+
# end
|
1360
|
+
# end
|
1361
|
+
#
|
1362
|
+
# @example openHAB 4.2+ supports assigning different items to buttons, along with additional features
|
1363
|
+
# sitemaps.build do
|
1364
|
+
# sitemap "remote" do
|
1365
|
+
# buttongrid item: RCButton do
|
1366
|
+
# button 1, 1, click: "BACK", icon: "f7:return"
|
1367
|
+
# button 1, 2, click: "HOME", icon: "material:apps"
|
1368
|
+
# button 1, 3, click: "YELLOW", icon: "f7:search", icon_color: "yellow"
|
1369
|
+
# button 2, 2, click: "UP", icon: "f7:arrowtriangle_up"
|
1370
|
+
# button 4, 2, click: "DOWN", icon: "f7:arrowtriangle_down"
|
1371
|
+
# button 3, 1, click: "LEFT", icon: "f7:arrowtriangle_left"
|
1372
|
+
# button 3, 3, click: "RIGHT", icon: "f7:arrowtriangle_right"
|
1373
|
+
# button 3, 2, click: "ENTER", icon: "material:adjust", icon_color: "red"
|
1374
|
+
#
|
1375
|
+
# # These buttons will use the specified item, only supported in openHAB 4.2+
|
1376
|
+
# button 4, 3, click: ON, static_icon: "switch-off", visibility: "TVPower!=ON", item: TVPower
|
1377
|
+
# button 4, 3, click: OFF, static_icon: "switch-on", visibility: "TVPower==ON", item: TVPower
|
1378
|
+
# end
|
1379
|
+
# end
|
1380
|
+
# end
|
1381
|
+
#
|
1382
|
+
def button(row = nil, column = nil, click = nil, label = nil, icon = nil, **kwargs, &block)
|
1383
|
+
args = [row, column, click, label, icon].compact
|
1384
|
+
|
1385
|
+
args = args.first if args.first.is_a?(Array)
|
1386
|
+
kwargs = %i[row column click label icon].zip(args).to_h.compact.merge(kwargs)
|
1387
|
+
|
1388
|
+
missing_args = (REQUIRED_BUTTON_ARGS - kwargs.keys).compact
|
1389
|
+
unless missing_args.empty?
|
1390
|
+
args = kwargs.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
|
1391
|
+
missing_args = missing_args.map(&:to_s).join(", ")
|
1392
|
+
raise ArgumentError, "button(#{args}) missing required parameters: #{missing_args}"
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
kwargs[:item] ||= item if item # default to the buttongrid's item
|
1396
|
+
kwargs[:label] ||= kwargs[:click].to_s
|
1397
|
+
|
1398
|
+
ButtonBuilder.new(@builder_proxy, **kwargs, &block).tap do |b|
|
1399
|
+
children << b
|
1400
|
+
end
|
1401
|
+
end
|
1402
|
+
end
|
1403
|
+
|
1172
1404
|
# Builds a `Sitemap`
|
1173
1405
|
# @see https://www.openhab.org/docs/ui/sitemaps.html
|
1174
1406
|
# @see org.openhab.core.model.sitemap.sitemap.Sitemap
|
data/lib/openhab/dsl/version.rb
CHANGED
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.
|
4
|
+
version: 5.23.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: 2024-07-
|
13
|
+
date: 2024-07-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -490,7 +490,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
490
490
|
- !ruby/object:Gem::Version
|
491
491
|
version: '0'
|
492
492
|
requirements: []
|
493
|
-
rubygems_version: 3.5.
|
493
|
+
rubygems_version: 3.5.16
|
494
494
|
signing_key:
|
495
495
|
specification_version: 4
|
496
496
|
summary: JRuby Helper Libraries for openHAB Scripting
|