openhab-scripting 5.6.1 → 5.7.1
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/http.rb +24 -8
- data/lib/openhab/core/items/registry.rb +1 -1
- data/lib/openhab/core/items/semantics.rb +11 -20
- data/lib/openhab/core/provider.rb +1 -1
- data/lib/openhab/core/sitemaps/provider.rb +132 -0
- data/lib/openhab/core/timer.rb +2 -1
- data/lib/openhab/core/types/quantity_type.rb +45 -35
- data/lib/openhab/dsl/rules/builder.rb +7 -4
- data/lib/openhab/dsl/sitemaps/builder.rb +942 -0
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +5 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 951ad54507dbf4b297d59534c124c21bbf6f6b7a02e4c3fa967a5290aac9968e
|
4
|
+
data.tar.gz: d4b33c4b8cdf237c6bdc1c2b99b87459f913f2d787423f261677d469d9629df3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f26471513aca95dcb0266ffca7176ee57980cbea404c8290c095642c4851954e4d870232507cbea34c6b6c4a940da84d6681944ee039199c3fcc766bdd64a598
|
7
|
+
data.tar.gz: 0c6e9e9cf72ee4a1935c399c235256144b0c6fbbb7bc0eb3f07a81405f3e52cc0193a1856ec910212f963c37208cb29191bbe90d143bf822bfc2c987828de47d
|
@@ -3,6 +3,17 @@
|
|
3
3
|
module OpenHAB
|
4
4
|
module Core
|
5
5
|
module Actions
|
6
|
+
#
|
7
|
+
# The HTTP actions allow you to send HTTP requests and receive the response.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # Send a GET request
|
11
|
+
# headers = {
|
12
|
+
# "User-Agent": "JRuby/1.2.3", # enclose in quotes if the key contains dashes
|
13
|
+
# Accept: "application/json",
|
14
|
+
# }
|
15
|
+
# response = HTTP.send_http_get_request("http://example.com/list", headers: headers)
|
16
|
+
#
|
6
17
|
# @see https://www.openhab.org/docs/configuration/actions.html#http-actions HTTP Actions
|
7
18
|
class HTTP
|
8
19
|
class << self
|
@@ -10,7 +21,8 @@ module OpenHAB
|
|
10
21
|
# Sends an HTTP GET request and returns the result as a String.
|
11
22
|
#
|
12
23
|
# @param [String] url
|
13
|
-
# @param [Hash<String, String>] headers
|
24
|
+
# @param [Hash<String, String>, Hash<Symbol, String>] headers
|
25
|
+
# A hash of headers to send with the request. Symbolic keys will be converted to strings.
|
14
26
|
# @param [Duration, int, nil] timeout Timeout (in milliseconds, if given as an Integer)
|
15
27
|
# @return [String] the response body
|
16
28
|
# @return [nil] if an error occurred
|
@@ -19,7 +31,7 @@ module OpenHAB
|
|
19
31
|
timeout ||= 5_000
|
20
32
|
timeout = timeout.to_millis if timeout.is_a?(Duration)
|
21
33
|
|
22
|
-
sendHttpGetRequest(url, headers, timeout)
|
34
|
+
sendHttpGetRequest(url, headers.transform_keys(&:to_s), timeout)
|
23
35
|
end
|
24
36
|
|
25
37
|
#
|
@@ -28,7 +40,8 @@ module OpenHAB
|
|
28
40
|
# @param [String] url
|
29
41
|
# @param [String] content_type
|
30
42
|
# @param [String] content
|
31
|
-
# @param [Hash<String, String>] headers
|
43
|
+
# @param [Hash<String, String>, Hash<Symbol, String>] headers
|
44
|
+
# A hash of headers to send with the request. Symbolic keys will be converted to strings.
|
32
45
|
# @param [Duration, int, nil] timeout Timeout (in milliseconds, if given as an Integer)
|
33
46
|
# @return [String] the response body
|
34
47
|
# @return [nil] if an error occurred
|
@@ -37,7 +50,7 @@ module OpenHAB
|
|
37
50
|
timeout ||= 1_000
|
38
51
|
timeout = timeout.to_millis if timeout.is_a?(Duration)
|
39
52
|
|
40
|
-
sendHttpPutRequest(url, content_type, content, headers, timeout)
|
53
|
+
sendHttpPutRequest(url, content_type, content, headers.transform_keys(&:to_s), timeout)
|
41
54
|
end
|
42
55
|
|
43
56
|
#
|
@@ -46,7 +59,8 @@ module OpenHAB
|
|
46
59
|
# @param [String] url
|
47
60
|
# @param [String] content_type
|
48
61
|
# @param [String] content
|
49
|
-
# @param [Hash<String, String>] headers
|
62
|
+
# @param [Hash<String, String>, Hash<Symbol, String>] headers
|
63
|
+
# A hash of headers to send with the request. Symbolic keys will be converted to strings.
|
50
64
|
# @param [Duration, int, nil] timeout Timeout (in milliseconds, if given as an Integer)
|
51
65
|
# @return [String] the response body
|
52
66
|
# @return [nil] if an error occurred
|
@@ -55,14 +69,16 @@ module OpenHAB
|
|
55
69
|
timeout ||= 1_000
|
56
70
|
timeout = timeout.to_millis if timeout.is_a?(Duration)
|
57
71
|
|
58
|
-
sendHttpPostRequest(url, content_type, content, headers, timeout)
|
72
|
+
sendHttpPostRequest(url, content_type, content, headers.transform_keys(&:to_s), timeout)
|
59
73
|
end
|
60
74
|
|
61
75
|
#
|
62
76
|
# Sends an HTTP DELETE request and returns the result as a String.
|
63
77
|
#
|
64
78
|
# @param [String] url
|
65
|
-
# @param [Hash<String, String>] headers
|
79
|
+
# @param [Hash<String, String>, Hash<Symbol, String>] headers
|
80
|
+
# A hash of headers to send with the request. Keys are strings or symbols, values are strings.
|
81
|
+
# Underscores in symbolic keys are replaced with dashes.
|
66
82
|
# @param [Duration, int, nil] timeout Timeout (in milliseconds, if given as an Integer)
|
67
83
|
# @return [String] the response body
|
68
84
|
# @return [nil] if an error occurred
|
@@ -71,7 +87,7 @@ module OpenHAB
|
|
71
87
|
timeout ||= 1_000
|
72
88
|
timeout = timeout.to_millis if timeout.is_a?(Duration)
|
73
89
|
|
74
|
-
sendHttpDeleteRequest(url, headers, timeout)
|
90
|
+
sendHttpDeleteRequest(url, headers.transform_keys(&:to_s), timeout)
|
75
91
|
end
|
76
92
|
end
|
77
93
|
end
|
@@ -48,7 +48,7 @@ module OpenHAB
|
|
48
48
|
# @yield Block executed in the context of a {DSL::Items::Builder}
|
49
49
|
# @return [Object] The return value of the block.
|
50
50
|
#
|
51
|
-
#
|
51
|
+
# @see DSL::Items::Builder
|
52
52
|
#
|
53
53
|
def build(preferred_provider = nil, &block)
|
54
54
|
DSL::Items::BaseBuilderDSL.new(preferred_provider).instance_eval_with_dummy_items(&block)
|
@@ -262,7 +262,7 @@ module OpenHAB
|
|
262
262
|
# @deprecated OH3.4 cannot add a tag
|
263
263
|
# this not in the class << self block above because YARD doesn't figure out
|
264
264
|
# it's a class method with the conditional
|
265
|
-
if Provider.registry
|
265
|
+
if Provider.registry
|
266
266
|
class << self
|
267
267
|
#
|
268
268
|
# Adds custom semantic tags.
|
@@ -311,25 +311,16 @@ module OpenHAB
|
|
311
311
|
synonyms = Array.wrap(synonyms).map { |s| s.to_s.strip }
|
312
312
|
|
313
313
|
tags.map do |name, parent|
|
314
|
-
|
315
|
-
if
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
Provider.instance.add(new_tag)
|
325
|
-
lookup(name)
|
326
|
-
else
|
327
|
-
parent_is_tag = parent.respond_to?(:java_class) && parent.java_class < Tag.java_class
|
328
|
-
parent = parent_is_tag ? parent.java_class : parent.to_s
|
329
|
-
org.openhab.core.semantics.SemanticTags
|
330
|
-
.add(name.to_s, parent, label, synonyms.join(","), description)
|
331
|
-
&.then { lookup(name) }
|
332
|
-
end
|
314
|
+
parent = lookup(parent) unless parent.is_a?(SemanticTag)
|
315
|
+
next if lookup(name)
|
316
|
+
next unless parent
|
317
|
+
|
318
|
+
new_tag = org.openhab.core.semantics.SemanticTagImpl.new("#{parent.uid}_#{name}",
|
319
|
+
label,
|
320
|
+
description,
|
321
|
+
synonyms)
|
322
|
+
Provider.instance.add(new_tag)
|
323
|
+
lookup(name)
|
333
324
|
end.compact
|
334
325
|
end
|
335
326
|
end
|
@@ -44,6 +44,7 @@ module OpenHAB
|
|
44
44
|
|
45
45
|
# Known supported provider types
|
46
46
|
# @return [Array<Symbol>]
|
47
|
+
# @!visibility private
|
47
48
|
KNOWN_TYPES = %i[items metadata things links].freeze
|
48
49
|
|
49
50
|
class << self
|
@@ -223,7 +224,6 @@ module OpenHAB
|
|
223
224
|
def initialize(unload_priority: nil)
|
224
225
|
super()
|
225
226
|
@elements = java.util.concurrent.ConcurrentHashMap.new
|
226
|
-
# @deprecated OH3.4 safe navigation only required for missing Semantics registry
|
227
227
|
self.class.registry&.add_provider(self)
|
228
228
|
ScriptHandling.script_unloaded(priority: unload_priority) { unregister }
|
229
229
|
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module OpenHAB
|
6
|
+
module Core
|
7
|
+
#
|
8
|
+
# Contains sitemap related classes.
|
9
|
+
#
|
10
|
+
module Sitemaps
|
11
|
+
#
|
12
|
+
# Provides sitemaps created in Ruby to openHAB
|
13
|
+
#
|
14
|
+
class Provider < Core::Provider
|
15
|
+
PREFIX = "jruby_"
|
16
|
+
SUFFIX = ".sitemap"
|
17
|
+
private_constant :PREFIX, :SUFFIX
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# @!visibility private
|
21
|
+
def registry
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
include org.openhab.core.model.sitemap.SitemapProvider
|
27
|
+
|
28
|
+
# @!visibility private
|
29
|
+
alias_method :getSitemap, :get
|
30
|
+
|
31
|
+
# rubocop:disable Naming/MethodName
|
32
|
+
|
33
|
+
# @!visibility private
|
34
|
+
def getSitemapNames
|
35
|
+
@elements.key_set
|
36
|
+
end
|
37
|
+
|
38
|
+
# @!visibility private
|
39
|
+
def addModelChangeListener(listener)
|
40
|
+
@listeners.add(listener)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @!visibility private
|
44
|
+
def removeModelChangeListener(listener)
|
45
|
+
@listeners.remove(listener)
|
46
|
+
end
|
47
|
+
|
48
|
+
# rubocop:enable Naming/MethodName
|
49
|
+
|
50
|
+
# @!visibility private
|
51
|
+
def unregister
|
52
|
+
@registration.unregister
|
53
|
+
end
|
54
|
+
|
55
|
+
# rubocop:disable Layout/LineLength
|
56
|
+
|
57
|
+
#
|
58
|
+
# Enter the Sitemap Builder DSL.
|
59
|
+
#
|
60
|
+
# @yield Block executed in the context of a {DSL::Sitemaps::Builder}
|
61
|
+
# @return [void]
|
62
|
+
#
|
63
|
+
# @see DSL::Sitemaps::Builder
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# sitemaps.build do
|
67
|
+
# sitemap "default", "My Residence" do
|
68
|
+
# frame label: "Control" do
|
69
|
+
# text label: "Climate", icon: "if:mdi:home-thermometer-outline" do
|
70
|
+
# frame label: "Main Floor" do
|
71
|
+
# text item: MainFloor_AmbTemp
|
72
|
+
# switch item: MainFloorThermostat_TargetMode, label: "Mode", mappings: %w[off auto cool heat]
|
73
|
+
# setpoint item: MainFloorThermostat_SetPoint, label: "Set Point", visibility: "MainFloorThermostat_TargetMode!=off"
|
74
|
+
# end
|
75
|
+
# frame label: "Basement" do
|
76
|
+
# text item: Basement_AmbTemp
|
77
|
+
# switch item: BasementThermostat_TargetMode, label: "Mode", mappings: { OFF: "off", COOL: "cool", HEAT: "heat" }
|
78
|
+
# setpoint item: BasementThermostat_SetPoint, label: "Set Point", visibility: "BasementThermostat_TargetMode!=off"
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
def build(&block)
|
86
|
+
DSL::Sitemaps::Builder.new(self).instance_eval(&block)
|
87
|
+
end
|
88
|
+
# rubocop:enable Layout/LineLength
|
89
|
+
|
90
|
+
# For use in specs
|
91
|
+
# @!visibility private
|
92
|
+
def clear
|
93
|
+
elements = @elements
|
94
|
+
@elements = java.util.concurrent.ConcurrentHashMap.new
|
95
|
+
elements.each_value do |v|
|
96
|
+
notify_listeners_about_removed_element(v)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Remove a sitemap.
|
102
|
+
#
|
103
|
+
# @param [String] sitemap_name
|
104
|
+
# @return [Boolean] If a sitemap was removed
|
105
|
+
def remove(sitemap_name)
|
106
|
+
super("#{PREFIX}#{sitemap_name}#{SUFFIX}")
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def initialize
|
112
|
+
super
|
113
|
+
@listeners = java.util.concurrent.CopyOnWriteArraySet.new
|
114
|
+
|
115
|
+
@registration = OSGi.register_service(self, org.openhab.core.model.sitemap.SitemapProvider)
|
116
|
+
end
|
117
|
+
|
118
|
+
def notify_listeners_about_added_element(element)
|
119
|
+
@listeners.each { |l| l.model_changed(element.name, org.openhab.core.model.core.EventType::ADDED) }
|
120
|
+
end
|
121
|
+
|
122
|
+
def notify_listeners_about_removed_element(element)
|
123
|
+
@listeners.each { |l| l.model_changed(element.name, org.openhab.core.model.core.EventType::REMOVED) }
|
124
|
+
end
|
125
|
+
|
126
|
+
def notify_listeners_about_updated_element(element)
|
127
|
+
@listeners.each { |l| l.model_changed(element.name, org.openhab.core.model.core.EventType::MODIFIED) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/openhab/core/timer.rb
CHANGED
@@ -49,7 +49,8 @@ module OpenHAB
|
|
49
49
|
@id = id
|
50
50
|
@thread_locals = thread_locals
|
51
51
|
@block = block
|
52
|
-
|
52
|
+
timer_identifier = block.source_location.join(":")
|
53
|
+
@timer = ScriptExecution.create_timer(timer_identifier, 1.minute.from_now) { execute }
|
53
54
|
reschedule!(@time)
|
54
55
|
end
|
55
56
|
|
@@ -174,25 +174,30 @@ module OpenHAB
|
|
174
174
|
add: :+,
|
175
175
|
subtract: :-
|
176
176
|
}.each do |java_op, ruby_op|
|
177
|
-
convert = "self.class.new(other,
|
177
|
+
convert = "self.class.new(other, thread_unit)"
|
178
178
|
|
179
179
|
class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition https://github.com/rubocop/rubocop/issues/10179
|
180
180
|
# def +(other)
|
181
181
|
# logger.trace("#{self} + #{other} (#{other.class})")
|
182
182
|
# if other.is_a?(QuantityType)
|
183
183
|
# add_quantity(other)
|
184
|
-
# elsif
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
192
|
-
#
|
193
|
-
# lhs
|
184
|
+
# elsif (thread_unit = DSL.unit(dimension))
|
185
|
+
# if other.is_a?(DecimalType)
|
186
|
+
# other = other.to_big_decimal
|
187
|
+
# add_quantity(self.class.new(other, thread_unit))
|
188
|
+
# elsif other.is_a?(java.math.BigDecimal)
|
189
|
+
# add_quantity(self.class.new(other, thread_unit))
|
190
|
+
# elsif other.respond_to?(:to_d)
|
191
|
+
# other = other.to_d.to_java
|
192
|
+
# add_quantity(self.class.new(other, thread_unit))
|
193
|
+
# elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(to_d))
|
194
|
+
# lhs + rhs
|
195
|
+
# else
|
196
|
+
# raise TypeError, "#{other.class} can't be coerced into #{self.class}"
|
197
|
+
# end
|
194
198
|
# else
|
195
|
-
# raise TypeError,
|
199
|
+
# raise TypeError,
|
200
|
+
# "#{self.class} can only be added with another #{self.class} outside a unit block"
|
196
201
|
# end
|
197
202
|
# end
|
198
203
|
<<~RUBY, __FILE__, __LINE__ + 1
|
@@ -200,18 +205,23 @@ module OpenHAB
|
|
200
205
|
logger.trace("\#{self} #{ruby_op} \#{other} (\#{other.class})")
|
201
206
|
if other.is_a?(QuantityType)
|
202
207
|
#{java_op}_quantity(other)
|
203
|
-
elsif
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
lhs
|
208
|
+
elsif (thread_unit = DSL.unit(dimension))
|
209
|
+
if other.is_a?(DecimalType)
|
210
|
+
other = other.to_big_decimal
|
211
|
+
#{java_op}_quantity(#{convert})
|
212
|
+
elsif other.is_a?(java.math.BigDecimal)
|
213
|
+
#{java_op}_quantity(#{convert})
|
214
|
+
elsif other.respond_to?(:to_d)
|
215
|
+
other = other.to_d.to_java
|
216
|
+
#{java_op}_quantity(#{convert})
|
217
|
+
elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(to_d))
|
218
|
+
lhs #{ruby_op} rhs
|
219
|
+
else
|
220
|
+
raise TypeError, "\#{other.class} can't be coerced into \#{self.class}"
|
221
|
+
end
|
213
222
|
else
|
214
|
-
raise TypeError,
|
223
|
+
raise TypeError,
|
224
|
+
"\#{self.class} can only be #{java_op}ed with another \#{self.class} outside a unit block"
|
215
225
|
end
|
216
226
|
end
|
217
227
|
RUBY
|
@@ -243,13 +253,13 @@ module OpenHAB
|
|
243
253
|
def #{ruby_op}(other)
|
244
254
|
logger.trace("\#{self} #{ruby_op} \#{other} (\#{other.class})")
|
245
255
|
if other.is_a?(QuantityType)
|
246
|
-
#{java_op}_quantity(other)
|
256
|
+
#{java_op}_quantity(other).unitize
|
247
257
|
elsif other.is_a?(DecimalType)
|
248
|
-
#{java_op}(other.to_big_decimal)
|
258
|
+
#{java_op}(other.to_big_decimal).unitize
|
249
259
|
elsif other.is_a?(java.math.BigDecimal)
|
250
|
-
#{java_op}(other)
|
260
|
+
#{java_op}(other).unitize
|
251
261
|
elsif other.respond_to?(:to_d)
|
252
|
-
#{java_op}(other.to_d.to_java)
|
262
|
+
#{java_op}(other.to_d.to_java).unitize
|
253
263
|
elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(to_d))
|
254
264
|
lhs #{ruby_op} rhs
|
255
265
|
else
|
@@ -262,7 +272,7 @@ module OpenHAB
|
|
262
272
|
|
263
273
|
# if it's a dimensionless quantity, change the unit to match other_unit
|
264
274
|
# @!visibility private
|
265
|
-
def unitize(other_unit = unit)
|
275
|
+
def unitize(other_unit = unit, relative: false)
|
266
276
|
# prefer converting to the thread-specified unit if there is one
|
267
277
|
other_unit = DSL.unit(dimension) || other_unit
|
268
278
|
logger.trace("Converting #{self} to #{other_unit}")
|
@@ -273,7 +283,7 @@ module OpenHAB
|
|
273
283
|
when other_unit
|
274
284
|
self
|
275
285
|
else
|
276
|
-
to_unit(other_unit)
|
286
|
+
relative ? to_unit_relative(other_unit) : to_unit(other_unit)
|
277
287
|
end
|
278
288
|
end
|
279
289
|
|
@@ -288,16 +298,16 @@ module OpenHAB
|
|
288
298
|
|
289
299
|
private
|
290
300
|
|
291
|
-
# do addition directly against a QuantityType while ensuring we unitize
|
292
|
-
# both sides
|
301
|
+
# do addition directly against a QuantityType while ensuring we unitize both sides
|
293
302
|
def add_quantity(other)
|
294
|
-
|
303
|
+
self_unit = (unit == Units::ONE && DSL.unit(other.dimension)) || unit
|
304
|
+
unitize(self_unit).add(other.unitize(relative: true))
|
295
305
|
end
|
296
306
|
|
297
|
-
# do subtraction directly against a QuantityType while ensuring we
|
298
|
-
# unitize both sides
|
307
|
+
# do subtraction directly against a QuantityType while ensuring we unitize both sides
|
299
308
|
def subtract_quantity(other)
|
300
|
-
|
309
|
+
self_unit = (unit == Units::ONE && DSL.unit(other.dimension)) || unit
|
310
|
+
unitize(self_unit).subtract(other.unitize(relative: true))
|
301
311
|
end
|
302
312
|
|
303
313
|
# do multiplication directly against a QuantityType while ensuring
|
@@ -1592,12 +1592,15 @@ module OpenHAB
|
|
1592
1592
|
end
|
1593
1593
|
|
1594
1594
|
#
|
1595
|
-
# Creates a trigger based on the time stored in a {DateTimeItem}
|
1595
|
+
# Creates a trigger based on the date and time stored in a {DateTimeItem}
|
1596
1596
|
#
|
1597
|
-
# The trigger will dynamically update
|
1598
|
-
#
|
1597
|
+
# The trigger will dynamically update whenever the state of the item changes.
|
1598
|
+
# If the item is {NULL} or {UNDEF}, the trigger will not run.
|
1599
1599
|
#
|
1600
|
-
#
|
1600
|
+
# To trigger just on the time portion of the item, use {every} instead, e.g.
|
1601
|
+
# `every :day, at: MyDateTimeItem`.
|
1602
|
+
#
|
1603
|
+
# @param [Item, String, Symbol] item The item (or its name)
|
1601
1604
|
# @return [void]
|
1602
1605
|
#
|
1603
1606
|
# @example
|