openhab-scripting 2.9.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.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/workflow.yml +327 -0
  3. data/.gitignore +17 -0
  4. data/.java-version +1 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +113 -0
  8. data/Gemfile +28 -0
  9. data/Gemfile.lock +245 -0
  10. data/Guardfile +35 -0
  11. data/LICENSE +277 -0
  12. data/README.md +23 -0
  13. data/Rakefile +406 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/config/userdata/config/org/openhab/restauth.config +3 -0
  17. data/cucumber.yml +1 -0
  18. data/docs/_config.yml +135 -0
  19. data/docs/contributing/index.md +47 -0
  20. data/docs/examples/conversions.md +123 -0
  21. data/docs/examples/index.md +61 -0
  22. data/docs/index.md +19 -0
  23. data/docs/installation/index.md +26 -0
  24. data/docs/motivation/index.md +27 -0
  25. data/docs/usage/execution.md +9 -0
  26. data/docs/usage/execution/delay.md +48 -0
  27. data/docs/usage/execution/otherwise.md +30 -0
  28. data/docs/usage/execution/run.md +70 -0
  29. data/docs/usage/execution/triggered.md +48 -0
  30. data/docs/usage/guards.md +51 -0
  31. data/docs/usage/guards/between.md +30 -0
  32. data/docs/usage/guards/not_if.md +41 -0
  33. data/docs/usage/guards/only_if.md +40 -0
  34. data/docs/usage/index.md +11 -0
  35. data/docs/usage/items.md +66 -0
  36. data/docs/usage/items/contact.md +84 -0
  37. data/docs/usage/items/dimmer.md +147 -0
  38. data/docs/usage/items/groups.md +76 -0
  39. data/docs/usage/items/number.md +225 -0
  40. data/docs/usage/items/string.md +49 -0
  41. data/docs/usage/items/switch.md +85 -0
  42. data/docs/usage/misc.md +7 -0
  43. data/docs/usage/misc/actions.md +108 -0
  44. data/docs/usage/misc/duration.md +21 -0
  45. data/docs/usage/misc/gems.md +25 -0
  46. data/docs/usage/misc/logging.md +21 -0
  47. data/docs/usage/misc/metadata.md +128 -0
  48. data/docs/usage/misc/store_states.md +42 -0
  49. data/docs/usage/misc/time_of_day.md +69 -0
  50. data/docs/usage/misc/timers.md +67 -0
  51. data/docs/usage/rule.md +43 -0
  52. data/docs/usage/things.md +29 -0
  53. data/docs/usage/triggers.md +8 -0
  54. data/docs/usage/triggers/changed.md +57 -0
  55. data/docs/usage/triggers/channel.md +54 -0
  56. data/docs/usage/triggers/command.md +69 -0
  57. data/docs/usage/triggers/cron.md +19 -0
  58. data/docs/usage/triggers/every.md +76 -0
  59. data/docs/usage/triggers/updated.md +78 -0
  60. data/lib/openhab.rb +39 -0
  61. data/lib/openhab/configuration.rb +16 -0
  62. data/lib/openhab/core/cron.rb +27 -0
  63. data/lib/openhab/core/debug.rb +34 -0
  64. data/lib/openhab/core/dsl.rb +47 -0
  65. data/lib/openhab/core/dsl/actions.rb +107 -0
  66. data/lib/openhab/core/dsl/entities.rb +103 -0
  67. data/lib/openhab/core/dsl/gems.rb +29 -0
  68. data/lib/openhab/core/dsl/group.rb +91 -0
  69. data/lib/openhab/core/dsl/items/items.rb +39 -0
  70. data/lib/openhab/core/dsl/items/number_item.rb +217 -0
  71. data/lib/openhab/core/dsl/items/string_item.rb +102 -0
  72. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +4 -0
  73. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +22 -0
  74. data/lib/openhab/core/dsl/monkey_patch/events.rb +5 -0
  75. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +13 -0
  76. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +25 -0
  77. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +26 -0
  78. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +54 -0
  79. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +125 -0
  80. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +27 -0
  81. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +130 -0
  82. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +259 -0
  83. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +86 -0
  84. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +69 -0
  85. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +46 -0
  86. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +5 -0
  87. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +24 -0
  88. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +41 -0
  89. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +25 -0
  90. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +23 -0
  91. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +7 -0
  92. data/lib/openhab/core/dsl/property.rb +85 -0
  93. data/lib/openhab/core/dsl/rule/channel.rb +41 -0
  94. data/lib/openhab/core/dsl/rule/cron.rb +115 -0
  95. data/lib/openhab/core/dsl/rule/guard.rb +99 -0
  96. data/lib/openhab/core/dsl/rule/item.rb +207 -0
  97. data/lib/openhab/core/dsl/rule/rule.rb +374 -0
  98. data/lib/openhab/core/dsl/rule/triggers.rb +77 -0
  99. data/lib/openhab/core/dsl/states.rb +63 -0
  100. data/lib/openhab/core/dsl/things.rb +93 -0
  101. data/lib/openhab/core/dsl/time_of_day.rb +203 -0
  102. data/lib/openhab/core/dsl/timers.rb +85 -0
  103. data/lib/openhab/core/dsl/types/quantity.rb +255 -0
  104. data/lib/openhab/core/dsl/units.rb +41 -0
  105. data/lib/openhab/core/duration.rb +69 -0
  106. data/lib/openhab/core/log.rb +175 -0
  107. data/lib/openhab/core/patch_load_path.rb +7 -0
  108. data/lib/openhab/core/startup_delay.rb +22 -0
  109. data/lib/openhab/osgi.rb +52 -0
  110. data/lib/openhab/version.rb +9 -0
  111. data/openhab-scripting.gemspec +30 -0
  112. data/openhab_rules/warmup.rb +5 -0
  113. metadata +157 -0
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'delegate'
5
+ require 'pp'
6
+ require 'forwardable'
7
+ require 'openhab/osgi'
8
+ require 'openhab/core/log'
9
+
10
+ module OpenHAB
11
+ module Core
12
+ module DSL
13
+ module MonkeyPatch
14
+ module Items
15
+ #
16
+ # Metadata extension for Items
17
+ #
18
+ module Metadata
19
+ include Logging
20
+
21
+ java_import org.openhab.core.items.Metadata
22
+ java_import org.openhab.core.items.MetadataKey
23
+
24
+ #
25
+ # Provide the interface to access namespace's value and configuration
26
+ #
27
+ class MetadataItem < SimpleDelegator
28
+ extend Forwardable
29
+
30
+ def_delegator :@metadata, :value
31
+
32
+ def initialize(metadata: nil, key: nil, value: nil, config: nil)
33
+ @metadata = metadata || Metadata.new(key || MetadataKey.new('', ''), value, config)
34
+ super(@metadata&.configuration)
35
+ end
36
+
37
+ #
38
+ # Updates the metadata configuration associated with the key
39
+ #
40
+ def []=(key, value)
41
+ configuration = {}.merge(@metadata&.configuration || {}).merge({ key => value })
42
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, configuration)
43
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
44
+ end
45
+
46
+ #
47
+ # Delete the configuration with the given key
48
+ #
49
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
50
+ #
51
+ def delete(key)
52
+ configuration = {}.merge(@metadata&.configuration || {})
53
+ configuration.delete(key)
54
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, configuration)
55
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
56
+ end
57
+
58
+ #
59
+ # Set the metadata value
60
+ #
61
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
62
+ #
63
+ def value=(value)
64
+ raise ArgumentError, 'Value must be a string' unless value.is_a? String
65
+
66
+ metadata = Metadata.new(@metadata&.uID, value, @metadata&.configuration)
67
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
68
+ end
69
+
70
+ #
71
+ # Set the entire configuration to a hash
72
+ #
73
+ # @return [Java::Org::openhab::core::items::Metadata] the old metadata
74
+ #
75
+ def config=(config)
76
+ raise ArgumentError, 'Configuration must be a hash' unless config.is_a? Hash
77
+
78
+ metadata = Metadata.new(@metadata&.uID, @metadata&.value, config)
79
+ NamespaceAccessor.registry.update(metadata) if @metadata&.uID
80
+ end
81
+ alias configuration= config=
82
+
83
+ #
84
+ # Convert the metadata to an array
85
+ #
86
+ # @return [Array[2]] An array of [value, configuration]
87
+ #
88
+ def to_a
89
+ [@metadata&.value, @metadata&.configuration || {}]
90
+ end
91
+ end
92
+
93
+ #
94
+ # Provide the interface to access item metadata
95
+ #
96
+ class NamespaceAccessor
97
+ include Enumerable
98
+
99
+ def initialize(item_name:)
100
+ @item_name = item_name
101
+ end
102
+
103
+ #
104
+ # Return the metadata namespace
105
+ #
106
+ # @return [OpenHAB::Core::DSL::MonkeyPatch::Items::MetadataItem], or nil if the namespace doesn't exist
107
+ #
108
+ def [](namespace)
109
+ logger.trace("Namespaces (#{NamespaceAccessor.registry.getAll})")
110
+ logger.trace("Namespace (#{NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))})")
111
+ metadata = NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name))
112
+ MetadataItem.new(metadata: metadata) if metadata
113
+ end
114
+
115
+ #
116
+ # Set the metadata namespace. If the namespace does not exist, it will be created
117
+ #
118
+ # @param value [Object] The assigned value can be a OpenHAB::Core::DSL::MonkeyPatch::Items::MetadataItem,
119
+ # Java::Org::openhab::core::items::Metadata, Array[2] of [value, configuration],
120
+ # A String to set the value and clear the configuration,
121
+ # or a Hash to set the configuration and set the value to nil
122
+ #
123
+ # @return [OpenHAB::Core::DSL::MonkeyPatch::Items::MetadataItem]
124
+ #
125
+ def []=(namespace, value)
126
+ case value
127
+ when MetadataItem
128
+ meta_value = value.value
129
+ configuration = value.__getobj__
130
+ when Metadata
131
+ meta_value = value.value
132
+ configuration = value.configuration
133
+ when Array
134
+ raise ArgumentError, 'Array must contain 2 elements: value, config' if value.length < 2
135
+
136
+ meta_value = value[0]
137
+ configuration = value[1]
138
+ when Hash
139
+ meta_value = nil
140
+ configuration = value
141
+ else
142
+ meta_value = value
143
+ configuration = nil
144
+ end
145
+
146
+ key = MetadataKey.new(namespace, @item_name)
147
+ metadata = Metadata.new(key, meta_value, configuration)
148
+ # registry.get can be omitted, but registry.update will log a warning for nonexistent metadata
149
+ if NamespaceAccessor.registry.get(key)
150
+ NamespaceAccessor.registry.update(metadata)
151
+ else
152
+ NamespaceAccessor.registry.add(metadata)
153
+ end
154
+ end
155
+
156
+ #
157
+ # Enumerates through all the namespaces
158
+ #
159
+ def each
160
+ return unless block_given?
161
+
162
+ NamespaceAccessor.registry.getAll.each do |meta|
163
+ yield meta.uID.namespace, meta.value, meta.configuration if meta.uID.itemName == @item_name
164
+ end
165
+ end
166
+
167
+ #
168
+ # Remove all the namespaces
169
+ #
170
+ def clear
171
+ NamespaceAccessor.registry.removeItemMetadata @item_name
172
+ end
173
+
174
+ #
175
+ # Delete a specific namespace
176
+ #
177
+ # @param namespace [String] The namespace to delete
178
+ #
179
+ def delete(namespace)
180
+ NamespaceAccessor.registry.remove(MetadataKey.new(namespace, @item_name))
181
+ end
182
+
183
+ alias delete_all clear
184
+
185
+ #
186
+ # @return [Boolean] True if the given namespace exists, false otherwise
187
+ #
188
+ def has_key?(namespace)
189
+ !NamespaceAccessor.registry.get(MetadataKey.new(namespace, @item_name)).nil?
190
+ end
191
+
192
+ alias key? has_key?
193
+ alias include? has_key?
194
+
195
+ #
196
+ # Merge the given hash with the current metadata. Existing namespace that matches the name
197
+ # of the new namespace will be overwritten. Others will be added.
198
+ #
199
+ def merge!(*others)
200
+ return self if others.empty?
201
+
202
+ others.each do |other|
203
+ case other
204
+ when Hash
205
+ other.each do |key, new_meta|
206
+ if block_given?
207
+ current_meta = self[key]&.to_a
208
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
209
+ end
210
+ self[key] = new_meta
211
+ end
212
+ when self.class
213
+ other.each do |key, new_value, new_config|
214
+ new_meta = new_value, new_config
215
+ if block_given?
216
+ current_meta = self[key]&.to_a
217
+ new_meta = yield key, current_meta, new_meta unless current_meta.nil?
218
+ end
219
+ self[key] = new_meta
220
+ end
221
+ else
222
+ raise ArgumentError, "merge only supports Hash, or another item's metadata"
223
+ end
224
+ end
225
+ self
226
+ end
227
+
228
+ #
229
+ # @return [String] the string representation of all the namespaces with their value and config
230
+ #
231
+ def to_s
232
+ namespaces = []
233
+ each { |ns, value, config| namespaces << "\"#{ns}\"=>[\"#{value}\",#{config}]" }
234
+ "{#{namespaces.join(',')}}"
235
+ end
236
+
237
+ #
238
+ # @return [Java::org::openhab::core::items::MetadataRegistry]
239
+ #
240
+ def self.registry
241
+ @@registry ||= OpenHAB::OSGI.service('org.openhab.core.items.MetadataRegistry')
242
+ end
243
+ end
244
+
245
+ #
246
+ # Accessor to the item's metadata
247
+ #
248
+ # @return [NamespaceAccessor] an Enumerable object to access item's namespaces
249
+ #
250
+ def meta
251
+ @meta ||= NamespaceAccessor.new(item_name: name)
252
+ end
253
+ alias metadata meta
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ java_import org.openhab.core.library.items.SwitchItem
4
+
5
+ # Alias class names for easy is_a? comparisons
6
+ Switch = SwitchItem
7
+
8
+ #
9
+ # Monkeypatching SwitchItem to add Ruby Support methods
10
+ #
11
+ # rubocop:disable Style/ClassAndModuleChildren
12
+ class Java::OrgOpenhabCoreLibraryItems::SwitchItem
13
+ java_import org.openhab.core.library.types.OnOffType
14
+ # rubocop:enable Style/ClassAndModuleChildren
15
+
16
+ #
17
+ # Send the OFF command to the switch
18
+ #
19
+ #
20
+ def off
21
+ command(OnOffType::OFF)
22
+ end
23
+
24
+ #
25
+ # Send the OFF command to the switch
26
+ #
27
+ #
28
+ def on
29
+ command(OnOffType::ON)
30
+ end
31
+
32
+ #
33
+ # Check if a switch is on
34
+ #
35
+ # @return [Boolean] True if the switch is on, false otherwise
36
+ #
37
+ def on?
38
+ state? && state == OnOffType::ON
39
+ end
40
+
41
+ alias truthy? on?
42
+
43
+ #
44
+ # Check if a switch is off
45
+ #
46
+ # @return [Boolean] True if the switch is off, false otherwise
47
+ #
48
+ def off?
49
+ state? && state == OnOffType::OFF
50
+ end
51
+
52
+ #
53
+ # Send a command to invert the state of the switch
54
+ #
55
+ # @return [OnOffType] Inverted state
56
+ #
57
+ def toggle
58
+ self << !self
59
+ end
60
+
61
+ #
62
+ # Return the inverted state of the switch: ON if the switch is OFF, UNDEF or NULL; OFF if the switch is ON
63
+ #
64
+ # @return [OnOffType] Inverted state
65
+ #
66
+ def !
67
+ return !state if state?
68
+
69
+ OnOffType::ON
70
+ end
71
+
72
+ #
73
+ # Check for equality against supplied object
74
+ #
75
+ # @param [Object] other object to compare to
76
+ #
77
+ # @return [Boolean] True if other is a OnOffType and other equals state for this switch item, otherwise result from super
78
+ #
79
+ def ==(other)
80
+ if other.is_a? OnOffType
81
+ state? && state == other
82
+ else
83
+ super
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core/duration'
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module DSL
8
+ module MonkeyPatch
9
+ module Ruby
10
+ #
11
+ # Extend integer to create duration object
12
+ #
13
+ module IntegerExtensions
14
+ include OpenHAB::Core
15
+
16
+ #
17
+ # Create Duration with unit of seconds
18
+ #
19
+ # @return [OpenHAB::Core::Duration] Duration with number of seconds from self
20
+ #
21
+ def seconds
22
+ Duration.new(temporal_unit: :SECONDS, amount: self)
23
+ end
24
+
25
+ #
26
+ # Create Duration with unit of milliseconds
27
+ #
28
+ # @return [OpenHAB::Core::Duration] Duration with number of milliseconds from self
29
+ #
30
+ def milliseconds
31
+ Duration.new(temporal_unit: :MILLISECONDS, amount: self)
32
+ end
33
+
34
+ #
35
+ # Create Duration with unit of minutes
36
+ #
37
+ # @return [OpenHAB::Core::Duration] Duration with number of minutes from self
38
+ #
39
+ def minutes
40
+ Duration.new(temporal_unit: :MINUTES, amount: self)
41
+ end
42
+
43
+ #
44
+ # Create Duration with unit of hours
45
+ #
46
+ # @return [OpenHAB::Core::Duration] Duration with number of hours from self
47
+ #
48
+ def hours
49
+ Duration.new(temporal_unit: :HOURS, amount: self)
50
+ end
51
+
52
+ alias second seconds
53
+ alias millisecond milliseconds
54
+ alias ms milliseconds
55
+ alias minute minutes
56
+ alias hour hours
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ #
65
+ # Prepend Integer class with duration extensions
66
+ #
67
+ class Integer
68
+ prepend OpenHAB::Core::DSL::MonkeyPatch::Ruby::IntegerExtensions
69
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+
5
+ # Monkey patch range to support case equality of OpenHab "Numeric" Objects
6
+
7
+ module OpenHAB
8
+ module Core
9
+ module DSL
10
+ #
11
+ # MonkeyPatch both Ruby and OpenHAB Objects to support DSL
12
+ #
13
+ module MonkeyPatch
14
+ #
15
+ # MonkeyPatch ruby object to support DSL
16
+ #
17
+ module Ruby
18
+ #
19
+ # Extensions for Range Class to support DimmerItems
20
+ #
21
+ module RangeExtensions
22
+ #
23
+ # Override range === method to support DimmerItems
24
+ #
25
+ # @param [Object] other object to compare for case equals
26
+ #
27
+ # @return [Boolean] if other is DimmerItem and state is covered by range, result from parent Range class if not DimmerItem
28
+ #
29
+ def ===(other)
30
+ return super unless other.is_a? DimmerItem
31
+
32
+ cover? other.state.to_i
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ #
42
+ # Prepend Range class with RangeExtensions
43
+ #
44
+ class Range
45
+ prepend OpenHAB::Core::DSL::MonkeyPatch::Ruby::RangeExtensions
46
+ end