openhab-scripting 4.46.2 → 5.0.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.
Files changed (281) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/actions/audio.rb +47 -0
  3. data/lib/openhab/core/actions/ephemeris.rb +39 -0
  4. data/lib/openhab/core/actions/exec.rb +51 -0
  5. data/lib/openhab/core/actions/http.rb +80 -0
  6. data/lib/openhab/core/actions/ping.rb +30 -0
  7. data/lib/openhab/core/actions/transformation.rb +32 -0
  8. data/lib/openhab/core/actions/voice.rb +36 -0
  9. data/lib/openhab/core/actions.rb +82 -0
  10. data/lib/openhab/core/dependency_tracking.rb +34 -0
  11. data/lib/openhab/core/dto/item_channel_link.rb +33 -0
  12. data/lib/openhab/core/dto/thing.rb +27 -0
  13. data/lib/openhab/core/dto.rb +11 -0
  14. data/lib/openhab/core/entity_lookup.rb +152 -70
  15. data/lib/openhab/core/events/abstract_event.rb +18 -0
  16. data/lib/openhab/core/events/abstract_item_registry_event.rb +36 -0
  17. data/lib/openhab/core/events/abstract_thing_registry_event.rb +40 -0
  18. data/lib/openhab/core/events/item_command_event.rb +78 -0
  19. data/lib/openhab/core/events/item_event.rb +22 -0
  20. data/lib/openhab/core/events/item_state_changed_event.rb +75 -0
  21. data/lib/openhab/core/events/item_state_event.rb +79 -0
  22. data/lib/openhab/core/events/thing_status_info_event.rb +55 -0
  23. data/lib/openhab/core/events.rb +10 -0
  24. data/lib/openhab/core/items/accepted_data_types.rb +29 -0
  25. data/lib/openhab/core/items/color_item.rb +52 -0
  26. data/lib/openhab/core/items/contact_item.rb +52 -0
  27. data/lib/openhab/core/items/date_time_item.rb +59 -0
  28. data/lib/openhab/core/items/dimmer_item.rb +148 -0
  29. data/lib/openhab/core/items/generic_item.rb +292 -0
  30. data/lib/openhab/core/items/group_item.rb +176 -0
  31. data/lib/openhab/{dsl → core}/items/image_item.rb +35 -29
  32. data/lib/openhab/core/items/item.rb +273 -0
  33. data/lib/openhab/core/items/location_item.rb +34 -0
  34. data/lib/openhab/core/items/metadata/hash.rb +433 -0
  35. data/lib/openhab/core/items/metadata/namespace_hash.rb +475 -0
  36. data/lib/openhab/core/items/metadata/provider.rb +48 -0
  37. data/lib/openhab/core/items/metadata.rb +11 -0
  38. data/lib/openhab/core/items/number_item.rb +62 -0
  39. data/lib/openhab/core/items/numeric_item.rb +22 -0
  40. data/lib/openhab/core/items/persistence.rb +416 -0
  41. data/lib/openhab/core/items/player_item.rb +66 -0
  42. data/lib/openhab/core/items/provider.rb +44 -0
  43. data/lib/openhab/core/items/proxy.rb +136 -0
  44. data/lib/openhab/core/items/registry.rb +86 -0
  45. data/lib/openhab/core/items/rollershutter_item.rb +68 -0
  46. data/lib/openhab/core/items/semantics/enumerable.rb +177 -0
  47. data/lib/openhab/core/items/semantics.rb +473 -0
  48. data/lib/openhab/core/items/state_storage.rb +53 -0
  49. data/lib/openhab/core/items/string_item.rb +28 -0
  50. data/lib/openhab/core/items/switch_item.rb +78 -0
  51. data/lib/openhab/core/items.rb +108 -0
  52. data/lib/openhab/{dsl → core}/lazy_array.rb +9 -3
  53. data/lib/openhab/core/profile_factory.rb +132 -0
  54. data/lib/openhab/core/provider.rb +230 -0
  55. data/lib/openhab/core/proxy.rb +130 -0
  56. data/lib/openhab/core/registry.rb +40 -0
  57. data/lib/openhab/core/rules/module.rb +26 -0
  58. data/lib/openhab/core/rules/provider.rb +25 -0
  59. data/lib/openhab/core/rules/registry.rb +76 -0
  60. data/lib/openhab/core/rules/rule.rb +150 -0
  61. data/lib/openhab/core/rules.rb +25 -0
  62. data/lib/openhab/core/script_handling.rb +78 -20
  63. data/lib/openhab/core/things/channel.rb +48 -0
  64. data/lib/openhab/core/things/channel_uid.rb +51 -0
  65. data/lib/openhab/core/things/item_channel_link.rb +33 -0
  66. data/lib/openhab/core/things/links/provider.rb +78 -0
  67. data/lib/openhab/core/things/profile_callback.rb +52 -0
  68. data/lib/openhab/core/things/provider.rb +29 -0
  69. data/lib/openhab/core/things/proxy.rb +87 -0
  70. data/lib/openhab/core/things/registry.rb +73 -0
  71. data/lib/openhab/core/things/thing.rb +194 -0
  72. data/lib/openhab/core/things.rb +22 -0
  73. data/lib/openhab/core/timer.rb +148 -0
  74. data/lib/openhab/{dsl → core}/types/comparable_type.rb +5 -3
  75. data/lib/openhab/{dsl → core}/types/date_time_type.rb +55 -127
  76. data/lib/openhab/{dsl → core}/types/decimal_type.rb +50 -48
  77. data/lib/openhab/{dsl → core}/types/hsb_type.rb +35 -83
  78. data/lib/openhab/core/types/increase_decrease_type.rb +34 -0
  79. data/lib/openhab/core/types/next_previous_type.rb +34 -0
  80. data/lib/openhab/{dsl → core}/types/numeric_type.rb +20 -7
  81. data/lib/openhab/core/types/on_off_type.rb +46 -0
  82. data/lib/openhab/core/types/open_closed_type.rb +41 -0
  83. data/lib/openhab/{dsl → core}/types/percent_type.rb +19 -20
  84. data/lib/openhab/core/types/play_pause_type.rb +38 -0
  85. data/lib/openhab/core/types/point_type.rb +117 -0
  86. data/lib/openhab/core/types/quantity_type.rb +325 -0
  87. data/lib/openhab/core/types/raw_type.rb +26 -0
  88. data/lib/openhab/core/types/refresh_type.rb +27 -0
  89. data/lib/openhab/core/types/rewind_fastforward_type.rb +38 -0
  90. data/lib/openhab/core/types/stop_move_type.rb +34 -0
  91. data/lib/openhab/{dsl → core}/types/string_type.rb +17 -28
  92. data/lib/openhab/{dsl → core}/types/type.rb +42 -40
  93. data/lib/openhab/core/types/un_def_type.rb +38 -0
  94. data/lib/openhab/core/types/up_down_type.rb +50 -0
  95. data/lib/openhab/core/types.rb +82 -0
  96. data/lib/openhab/{dsl → core}/uid.rb +4 -23
  97. data/lib/openhab/core/value_cache.rb +188 -0
  98. data/lib/openhab/core.rb +98 -0
  99. data/lib/openhab/core_ext/between.rb +32 -0
  100. data/lib/openhab/core_ext/ephemeris.rb +53 -0
  101. data/lib/openhab/core_ext/java/class.rb +34 -0
  102. data/lib/openhab/core_ext/java/duration.rb +142 -0
  103. data/lib/openhab/core_ext/java/list.rb +436 -0
  104. data/lib/openhab/core_ext/java/local_date.rb +104 -0
  105. data/lib/openhab/core_ext/java/local_time.rb +118 -0
  106. data/lib/openhab/core_ext/java/map.rb +66 -0
  107. data/lib/openhab/core_ext/java/month.rb +71 -0
  108. data/lib/openhab/core_ext/java/month_day.rb +119 -0
  109. data/lib/openhab/core_ext/java/period.rb +103 -0
  110. data/lib/openhab/core_ext/java/temporal_amount.rb +34 -0
  111. data/lib/openhab/core_ext/java/time.rb +62 -0
  112. data/lib/openhab/core_ext/java/unit.rb +15 -0
  113. data/lib/openhab/core_ext/java/zoned_date_time.rb +213 -0
  114. data/lib/openhab/core_ext/ruby/array.rb +21 -0
  115. data/lib/openhab/core_ext/ruby/date.rb +96 -0
  116. data/lib/openhab/core_ext/ruby/date_time.rb +55 -0
  117. data/lib/openhab/core_ext/ruby/module.rb +15 -0
  118. data/lib/openhab/core_ext/ruby/numeric.rb +195 -0
  119. data/lib/openhab/core_ext/ruby/range.rb +70 -0
  120. data/lib/openhab/core_ext/ruby/symbol.rb +7 -0
  121. data/lib/openhab/core_ext/ruby/time.rb +108 -0
  122. data/lib/openhab/core_ext.rb +18 -0
  123. data/lib/openhab/dsl/debouncer.rb +259 -0
  124. data/lib/openhab/dsl/events/watch_event.rb +18 -0
  125. data/lib/openhab/dsl/events.rb +9 -0
  126. data/lib/openhab/dsl/gems.rb +1 -1
  127. data/lib/openhab/dsl/items/builder.rb +578 -0
  128. data/lib/openhab/dsl/items/ensure.rb +73 -82
  129. data/lib/openhab/dsl/items/timed_command.rb +214 -159
  130. data/lib/openhab/dsl/rules/automation_rule.rb +126 -115
  131. data/lib/openhab/dsl/rules/builder.rb +1935 -0
  132. data/lib/openhab/dsl/rules/guard.rb +51 -114
  133. data/lib/openhab/dsl/rules/name_inference.rb +66 -25
  134. data/lib/openhab/dsl/rules/property.rb +48 -75
  135. data/lib/openhab/dsl/rules/rule_triggers.rb +22 -27
  136. data/lib/openhab/dsl/rules/terse.rb +58 -14
  137. data/lib/openhab/dsl/rules/triggers/changed.rb +48 -94
  138. data/lib/openhab/dsl/rules/triggers/channel.rb +9 -40
  139. data/lib/openhab/dsl/rules/triggers/command.rb +14 -63
  140. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +34 -69
  141. data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +6 -14
  142. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +48 -82
  143. data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +30 -47
  144. data/lib/openhab/dsl/rules/triggers/trigger.rb +7 -28
  145. data/lib/openhab/dsl/rules/triggers/updated.rb +21 -45
  146. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +257 -102
  147. data/lib/openhab/dsl/rules/triggers.rb +12 -0
  148. data/lib/openhab/dsl/rules.rb +8 -0
  149. data/lib/openhab/dsl/things/builder.rb +299 -0
  150. data/lib/openhab/{core → dsl}/thread_local.rb +27 -17
  151. data/lib/openhab/dsl/timer_manager.rb +204 -0
  152. data/lib/openhab/dsl/version.rb +9 -0
  153. data/lib/openhab/dsl.rb +979 -0
  154. data/lib/openhab/log.rb +355 -0
  155. data/lib/openhab/osgi.rb +68 -0
  156. data/lib/openhab/rspec/configuration.rb +56 -0
  157. data/lib/openhab/rspec/example_group.rb +132 -0
  158. data/lib/openhab/rspec/helpers.rb +458 -0
  159. data/lib/openhab/rspec/hooks.rb +113 -0
  160. data/lib/openhab/rspec/jruby.rb +46 -0
  161. data/lib/openhab/rspec/karaf.rb +851 -0
  162. data/lib/openhab/rspec/mocks/bundle_install_support.rb +25 -0
  163. data/lib/openhab/rspec/mocks/bundle_resolver.rb +30 -0
  164. data/lib/openhab/rspec/mocks/event_admin.rb +146 -0
  165. data/lib/openhab/rspec/mocks/instance_method_stasher.rb +22 -0
  166. data/lib/openhab/rspec/mocks/persistence_service.rb +155 -0
  167. data/lib/openhab/rspec/mocks/safe_caller.rb +40 -0
  168. data/lib/openhab/rspec/mocks/space.rb +23 -0
  169. data/lib/openhab/rspec/mocks/synchronous_executor.rb +63 -0
  170. data/lib/openhab/rspec/mocks/thing_handler.rb +76 -0
  171. data/lib/openhab/rspec/mocks/timer.rb +134 -0
  172. data/lib/openhab/rspec/openhab/core/actions.rb +38 -0
  173. data/lib/openhab/rspec/openhab/core/items/proxy.rb +15 -0
  174. data/lib/openhab/rspec/openhab/core/things/proxy.rb +27 -0
  175. data/lib/openhab/rspec/shell.rb +31 -0
  176. data/lib/openhab/rspec/suspend_rules.rb +50 -0
  177. data/lib/openhab/rspec.rb +26 -0
  178. data/lib/openhab/yard/base_helper.rb +19 -0
  179. data/lib/openhab/yard/cli/stats.rb +23 -0
  180. data/lib/openhab/yard/code_objects/group_object.rb +23 -0
  181. data/lib/openhab/yard/code_objects/java/base.rb +31 -0
  182. data/lib/openhab/yard/code_objects/java/class_object.rb +11 -0
  183. data/lib/openhab/yard/code_objects/java/field_object.rb +15 -0
  184. data/lib/openhab/yard/code_objects/java/interface_object.rb +15 -0
  185. data/lib/openhab/yard/code_objects/java/package_object.rb +11 -0
  186. data/lib/openhab/yard/code_objects/java/proxy.rb +23 -0
  187. data/lib/openhab/yard/coderay.rb +17 -0
  188. data/lib/openhab/yard/handlers/jruby/base.rb +58 -0
  189. data/lib/openhab/yard/handlers/jruby/class_handler.rb +18 -0
  190. data/lib/openhab/yard/handlers/jruby/constant_handler.rb +18 -0
  191. data/lib/openhab/yard/handlers/jruby/java_import_handler.rb +30 -0
  192. data/lib/openhab/yard/handlers/jruby/mixin_handler.rb +23 -0
  193. data/lib/openhab/yard/html_helper.rb +78 -0
  194. data/lib/openhab/yard/markdown_helper.rb +148 -0
  195. data/lib/openhab/yard/tags/constant_directive.rb +20 -0
  196. data/lib/openhab/yard/tags/group_directive.rb +24 -0
  197. data/lib/openhab/yard/tags/library.rb +3 -0
  198. data/lib/openhab/yard.rb +38 -0
  199. metadata +475 -106
  200. data/lib/openhab/core/item_proxy.rb +0 -29
  201. data/lib/openhab/core/load_path.rb +0 -19
  202. data/lib/openhab/core/openhab_setup.rb +0 -29
  203. data/lib/openhab/core/osgi.rb +0 -58
  204. data/lib/openhab/core/services.rb +0 -24
  205. data/lib/openhab/dsl/actions.rb +0 -114
  206. data/lib/openhab/dsl/between.rb +0 -25
  207. data/lib/openhab/dsl/channel.rb +0 -43
  208. data/lib/openhab/dsl/dsl.rb +0 -59
  209. data/lib/openhab/dsl/group.rb +0 -54
  210. data/lib/openhab/dsl/imports.rb +0 -21
  211. data/lib/openhab/dsl/items/color_item.rb +0 -76
  212. data/lib/openhab/dsl/items/comparable_item.rb +0 -62
  213. data/lib/openhab/dsl/items/contact_item.rb +0 -41
  214. data/lib/openhab/dsl/items/date_time_item.rb +0 -65
  215. data/lib/openhab/dsl/items/dimmer_item.rb +0 -65
  216. data/lib/openhab/dsl/items/generic_item.rb +0 -229
  217. data/lib/openhab/dsl/items/group_item.rb +0 -127
  218. data/lib/openhab/dsl/items/item_equality.rb +0 -59
  219. data/lib/openhab/dsl/items/item_registry.rb +0 -54
  220. data/lib/openhab/dsl/items/items.rb +0 -109
  221. data/lib/openhab/dsl/items/location_item.rb +0 -59
  222. data/lib/openhab/dsl/items/metadata.rb +0 -326
  223. data/lib/openhab/dsl/items/number_item.rb +0 -17
  224. data/lib/openhab/dsl/items/numeric_item.rb +0 -87
  225. data/lib/openhab/dsl/items/persistence.rb +0 -307
  226. data/lib/openhab/dsl/items/player_item.rb +0 -58
  227. data/lib/openhab/dsl/items/rollershutter_item.rb +0 -51
  228. data/lib/openhab/dsl/items/semantics/enumerable.rb +0 -91
  229. data/lib/openhab/dsl/items/semantics.rb +0 -227
  230. data/lib/openhab/dsl/items/string_item.rb +0 -51
  231. data/lib/openhab/dsl/items/switch_item.rb +0 -70
  232. data/lib/openhab/dsl/monkey_patch/actions/actions.rb +0 -4
  233. data/lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb +0 -39
  234. data/lib/openhab/dsl/monkey_patch/events/events.rb +0 -7
  235. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +0 -85
  236. data/lib/openhab/dsl/monkey_patch/events/item_event.rb +0 -28
  237. data/lib/openhab/dsl/monkey_patch/events/item_state.rb +0 -61
  238. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +0 -60
  239. data/lib/openhab/dsl/monkey_patch/events/thing_status_info.rb +0 -33
  240. data/lib/openhab/dsl/monkey_patch/java/java.rb +0 -4
  241. data/lib/openhab/dsl/monkey_patch/java/local_time.rb +0 -44
  242. data/lib/openhab/dsl/monkey_patch/java/time_extensions.rb +0 -50
  243. data/lib/openhab/dsl/monkey_patch/java/zoned_date_time.rb +0 -45
  244. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +0 -104
  245. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +0 -6
  246. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +0 -47
  247. data/lib/openhab/dsl/monkey_patch/ruby/time.rb +0 -61
  248. data/lib/openhab/dsl/openhab.rb +0 -30
  249. data/lib/openhab/dsl/persistence.rb +0 -27
  250. data/lib/openhab/dsl/rules/item_event.rb +0 -19
  251. data/lib/openhab/dsl/rules/rule.rb +0 -160
  252. data/lib/openhab/dsl/rules/rule_config.rb +0 -147
  253. data/lib/openhab/dsl/rules/triggers/generic.rb +0 -31
  254. data/lib/openhab/dsl/rules/triggers/triggers.rb +0 -11
  255. data/lib/openhab/dsl/rules/triggers/watch/watch.rb +0 -81
  256. data/lib/openhab/dsl/states.rb +0 -89
  257. data/lib/openhab/dsl/things.rb +0 -147
  258. data/lib/openhab/dsl/time/month_day.rb +0 -180
  259. data/lib/openhab/dsl/time/time_of_day.rb +0 -235
  260. data/lib/openhab/dsl/timers/manager.rb +0 -119
  261. data/lib/openhab/dsl/timers/reentrant_timer.rb +0 -38
  262. data/lib/openhab/dsl/timers/timer.rb +0 -132
  263. data/lib/openhab/dsl/timers.rb +0 -77
  264. data/lib/openhab/dsl/types/increase_decrease_type.rb +0 -23
  265. data/lib/openhab/dsl/types/next_previous_type.rb +0 -23
  266. data/lib/openhab/dsl/types/on_off_type.rb +0 -28
  267. data/lib/openhab/dsl/types/open_closed_type.rb +0 -29
  268. data/lib/openhab/dsl/types/play_pause_type.rb +0 -27
  269. data/lib/openhab/dsl/types/point_type.rb +0 -180
  270. data/lib/openhab/dsl/types/quantity_type.rb +0 -265
  271. data/lib/openhab/dsl/types/refresh_type.rb +0 -18
  272. data/lib/openhab/dsl/types/rewind_fastforward_type.rb +0 -33
  273. data/lib/openhab/dsl/types/stop_move_type.rb +0 -23
  274. data/lib/openhab/dsl/types/types.rb +0 -83
  275. data/lib/openhab/dsl/types/un_def_type.rb +0 -22
  276. data/lib/openhab/dsl/types/up_down_type.rb +0 -32
  277. data/lib/openhab/dsl/units.rb +0 -45
  278. data/lib/openhab/log/configuration.rb +0 -21
  279. data/lib/openhab/log/logger.rb +0 -282
  280. data/lib/openhab/version.rb +0 -9
  281. data/lib/openhab.rb +0 -36
@@ -0,0 +1,299 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ #
6
+ # Contains extensions to simplify working with {Core::Things::Thing Thing}s.
7
+ #
8
+ module Things
9
+ # A thing builder allows you to dynamically create openHAB things at runtime.
10
+ # This can be useful either to create things as soon as the script loads,
11
+ # or even later based on a rule executing.
12
+ #
13
+ # @example Create a Thing from the Astro Binding
14
+ # things.build do
15
+ # thing "astro:sun:home", "Astro Sun Data", config: { "geolocation" => "0,0" }
16
+ # end
17
+ #
18
+ # @example Create a Thing with Channels
19
+ # thing_config = {
20
+ # availabilityTopic: "my-switch/status",
21
+ # payloadAvailable: "online",
22
+ # payloadNotAvailable: "offline"
23
+ # }
24
+ # things.build do
25
+ # thing("mqtt:topic:my-switch", "My Switch", bridge: "mqtt:bridge:mosquitto", config: thing_config) do
26
+ # channel("switch1", "switch", config: {
27
+ # stateTopic: "stat/my-switch/switch1/state", commandTopic="cmnd/my-switch/switch1/command"
28
+ # })
29
+ # channel("button1", "string", config: {
30
+ # stateTopic: "stat/my-switch/button1/state", commandTopic="cmnd/my-switch/button1/command"
31
+ # })
32
+ # end
33
+ # end
34
+ #
35
+ # @see ThingBuilder#initialize ThingBuilder#initialize for #thing's parameters
36
+ # @see ChannelBuilder#initialize ChannelBuilder#initialize for #channel's parameters
37
+ # @see Items::Builder
38
+ #
39
+ class Builder
40
+ # @return [org.openhab.core.thing.ManagedThingProvider]
41
+ attr_reader :provider
42
+
43
+ def initialize(provider)
44
+ @provider = Core::Things::Provider.current(provider)
45
+ end
46
+
47
+ # Create a new Bridge
48
+ # @see BridgeBuilder#initialize
49
+ def bridge(*args, **kwargs, &block)
50
+ build(BridgeBuilder, *args, **kwargs, &block)
51
+ end
52
+
53
+ # Create a new Thing
54
+ # @see ThingBuilder#initialize
55
+ def thing(*args, **kwargs, &block)
56
+ build(ThingBuilder, *args, **kwargs, &block)
57
+ end
58
+
59
+ private
60
+
61
+ def build(klass, *args, **kwargs, &block)
62
+ builder = klass.new(*args, **kwargs)
63
+ builder.instance_eval(&block) if block
64
+ thing = provider.add(builder.build)
65
+ thing = Core::Things::Proxy.new(thing)
66
+ thing.enable(enabled: builder.enabled) unless builder.enabled.nil?
67
+ thing
68
+ end
69
+ end
70
+
71
+ # The ThingBuilder DSL allows you to customize a thing
72
+ class ThingBuilder
73
+ # The label for this thing
74
+ # @return [String, nil]
75
+ attr_accessor :label
76
+ # The location for this thing
77
+ # @return [String, nil]
78
+ attr_accessor :location
79
+ # The id for this thing
80
+ # @return [Core::Things::ThingUID]
81
+ attr_reader :uid
82
+ # The type of this thing
83
+ # @return [ThingTypeUID]
84
+ attr_reader :thing_type_uid
85
+ # The bridge of this thing
86
+ # @return [Core::Things::ThingUID, nil]
87
+ attr_reader :bridge_uid
88
+ # The config for this thing
89
+ # @return [Hash, nil]
90
+ attr_reader :config
91
+ # If the thing should be enabled after it is created
92
+ # @return [true, false, nil]
93
+ attr_reader :enabled
94
+ # Explicitly configured channels on this thing
95
+ # @return [Array<ChannelBuilder>]
96
+ attr_reader :channels
97
+
98
+ class << self
99
+ # @!visibility private
100
+ def thing_type_registry
101
+ @thing_type_registry ||= OSGi.service("org.openhab.core.thing.type.ThingTypeRegistry")
102
+ end
103
+
104
+ # @!visibility private
105
+ def config_description_registry
106
+ @config_description_registry ||=
107
+ OSGi.service("org.openhab.core.config.core.ConfigDescriptionRegistry")
108
+ end
109
+
110
+ # @!visibility private
111
+ def thing_factory_helper
112
+ @thing_factory_helper ||= begin
113
+ # this is an internal class, so OSGi doesn't put it on the main class path,
114
+ # so we have to go find it ourselves manually
115
+ bundle = org.osgi.framework.FrameworkUtil.get_bundle(org.openhab.core.thing.Thing.java_class)
116
+ bundle.load_class("org.openhab.core.thing.internal.ThingFactoryHelper").ruby_class
117
+ end
118
+ end
119
+ end
120
+
121
+ #
122
+ # Constructor for ThingBuilder
123
+ #
124
+ # @param [String] uid The ThingUID for the created Thing.
125
+ # This can consist one or more segments separated by a colon. When the uid contains:
126
+ # - One segment: When the uid contains one segment, `binding` or `bridge` id must be provided.
127
+ # - Two segments: `typeid:thingid` The `binding` or `bridge` id must be provided.
128
+ # - Three or more segments: `bindingid:typeid:[bridgeid...]:thingid`. The `type` and `bridge` can be omitted
129
+ # @param [String] label The Thing's label.
130
+ # @param [String] binding The binding id. When this argument is not provided,
131
+ # the binding id must be deducible from the `uid`, `type`, or `bridge`.
132
+ # @param [String] type The type id. When this argument is not provided,
133
+ # it will be deducible from the `uid` if it contains two or more segments.
134
+ # To create a Thing with a blank type id, use one segment for `uid` and provide the binding id.
135
+ # @param [String, BridgeBuilder] bridge The bridge uid, if the Thing should belong to a bridge.
136
+ # @param [String, Item] location The location of this Thing.
137
+ # When given an Item, use the item's label as the location.
138
+ # @param [Hash] config The Thing's configuration, as required by the binding. The key can be strings or symbols.
139
+ # @param [true,false] enabled Whether the Thing should be enabled or disabled.
140
+ #
141
+ def initialize(uid, label = nil, binding: nil, type: nil, bridge: nil, location: nil, config: {}, enabled: nil)
142
+ @channels = []
143
+ uid = uid.to_s
144
+ uid_segments = uid.split(org.openhab.core.common.AbstractUID::SEPARATOR)
145
+ @bridge_uid = nil
146
+ bridge = bridge.uid if bridge.is_a?(org.openhab.core.thing.Bridge) || bridge.is_a?(BridgeBuilder)
147
+ bridge = bridge&.to_s
148
+ bridge_segments = bridge&.split(org.openhab.core.common.AbstractUID::SEPARATOR) || []
149
+ type = type&.to_s
150
+
151
+ # infer missing components
152
+ type ||= uid_segments[0] if uid_segments.length == 2
153
+ type ||= uid_segments[1] if uid_segments.length > 2
154
+ binding ||= uid_segments[0] if uid_segments.length > 2
155
+ binding ||= bridge_segments[0] if bridge_segments && bridge_segments.length > 2
156
+
157
+ if bridge
158
+ bridge_segments.unshift(binding) if bridge_segments.length < 3
159
+ @bridge_uid = org.openhab.core.thing.ThingUID.new(*bridge_segments)
160
+ end
161
+
162
+ thinguid = if uid_segments.length > 2
163
+ [binding, type, uid_segments.last].compact
164
+ else
165
+ [binding, type, @bridge_uid&.id, uid_segments.last].compact
166
+ end
167
+
168
+ @uid = org.openhab.core.thing.ThingUID.new(*thinguid)
169
+ @thing_type_uid = org.openhab.core.thing.ThingTypeUID.new(*@uid.all_segments[0..1])
170
+ @label = label
171
+ @location = location
172
+ @location = location.label if location.is_a?(Item)
173
+ @config = config.transform_keys(&:to_s)
174
+ @enabled = enabled
175
+ end
176
+
177
+ # Add an explicitly configured channel to this item
178
+ # @see ChannelBuilder#initialize
179
+ def channel(*args, **kwargs, &block)
180
+ channel = ChannelBuilder.new(*args, thing: self, **kwargs)
181
+ channel.instance_eval(&block) if block
182
+ @channels << channel.build
183
+ end
184
+
185
+ # @!visibility private
186
+ def build
187
+ configuration = org.openhab.core.config.core.Configuration.new(config)
188
+ if thing_type
189
+ self.class.thing_factory_helper.apply_default_configuration(
190
+ configuration, thing_type,
191
+ self.class.config_description_registry
192
+ )
193
+ end
194
+ builder = org.openhab.core.thing.binding.builder.ThingBuilder
195
+ .create(thing_type_uid, uid)
196
+ .with_label(label)
197
+ .with_configuration(configuration)
198
+ .with_bridge(bridge_uid)
199
+ .with_channels(channels)
200
+
201
+ if thing_type
202
+ # can't use with_channels, or it will wipe out custom channels from above
203
+ self.class.thing_factory_helper.create_channels(thing_type, uid,
204
+ self.class.config_description_registry).each do |channel|
205
+ builder.with_channel(channel)
206
+ end
207
+ builder.with_properties(thing_type.properties)
208
+ end
209
+
210
+ thing = builder.build
211
+ Core::Things.manager.set_enabled(uid, enabled) unless enabled.nil?
212
+ thing
213
+ end
214
+
215
+ private
216
+
217
+ def thing_type
218
+ @thing_type ||= self.class.thing_type_registry.get_thing_type(thing_type_uid)
219
+ end
220
+ end
221
+
222
+ # The BridgeBuilder DSL allows you to customize a thing
223
+ class BridgeBuilder < ThingBuilder
224
+ # Create a new Bridge with this Bridge as its Bridge
225
+ # @see BridgeBuilder#initialize
226
+ def bridge(*args, **kwargs, &block)
227
+ super(*args, bridge: self, **kwargs, &block)
228
+ end
229
+
230
+ # Create a new Thing with this Bridge as its Bridge
231
+ # @see ThingBuilder#initialize
232
+ def thing(*args, **kwargs, &block)
233
+ super(*args, bridge: self, **kwargs, &block)
234
+ end
235
+ end
236
+
237
+ # The ChannelBuilder DSL allows you to customize a channel
238
+ class ChannelBuilder
239
+ attr_accessor :label
240
+ attr_reader :uid, :config, :type
241
+
242
+ #
243
+ # Constructor for ChannelBuilder
244
+ #
245
+ # This class is instantiated by the {ThingBuilder#channel #channel} method inside a {Builder#thing} block.
246
+ #
247
+ # @param [String] uid The channel's ID.
248
+ # @param [String, ChannelTypeUID, :trigger] type The concrete type of the channel.
249
+ # @param [String] label The channel label.
250
+ # @param [thing] thing The thing associated with this channel.
251
+ # This parameter is not needed for the {ThingBuilder#channel} method.
252
+ # @param [String] group The group name.
253
+ # @param [Hash] config Channel configuration. The keys can be strings or symbols.
254
+ #
255
+ def initialize(uid, type, label = nil, thing:, group: nil, config: {})
256
+ @thing = thing
257
+
258
+ uid = uid.to_s
259
+ uid_segments = uid.split(org.openhab.core.common.AbstractUID::SEPARATOR)
260
+ group_segments = uid_segments.last.split(org.openhab.core.thing.ChannelUID::CHANNEL_GROUP_SEPARATOR)
261
+ if group
262
+ if group_segments.length == 2
263
+ group_segments[0] = group
264
+ else
265
+ group_segments.unshift(group)
266
+ end
267
+ uid_segments[-1] = group_segments.join(org.openhab.core.thing.ChannelUID::CHANNEL_GROUP_SEPARATOR)
268
+ end
269
+ @uid = org.openhab.core.thing.ChannelUID.new(thing.uid, uid_segments.last)
270
+ unless type.is_a?(org.openhab.core.thing.type.ChannelTypeUID)
271
+ type = org.openhab.core.thing.type.ChannelTypeUID.new(thing.uid.binding_id, type)
272
+ end
273
+ @type = type
274
+ @label = label
275
+ @config = config.transform_keys(&:to_s)
276
+ end
277
+
278
+ # @!visibility private
279
+ def build
280
+ org.openhab.core.thing.binding.builder.ChannelBuilder.create(uid)
281
+ .with_kind(kind)
282
+ .with_type(type)
283
+ .with_configuration(org.openhab.core.config.core.Configuration.new(config))
284
+ .build
285
+ end
286
+
287
+ private
288
+
289
+ def kind
290
+ if @type == :trigger
291
+ org.openhab.core.thing.type.ChannelKind::TRIGGER
292
+ else
293
+ org.openhab.core.thing.type.ChannelKind::STATE
294
+ end
295
+ end
296
+ end
297
+ end
298
+ end
299
+ end
@@ -1,15 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'openhab/log/logger'
4
-
5
- # OpenHAB main module
6
3
  module OpenHAB
7
- module Core
4
+ module DSL
8
5
  #
9
- # Manages thread local varaibles for access inside of blocks
6
+ # Manages thread local variables for access inside of blocks
10
7
  #
8
+ # @!visibility private
11
9
  module ThreadLocal
12
- include OpenHAB::Log
10
+ module_function
11
+
12
+ # Keys to persist
13
+ KNOWN_KEYS = %i[
14
+ openhab_ensure_states
15
+ openhab_holiday_file
16
+ openhab_persistence_service
17
+ openhab_providers
18
+ openhab_rule_uid
19
+ openhab_rule_type
20
+ openhab_units
21
+ ].freeze
22
+
23
+ #
24
+ # Fetch all {KNOWN_KEYS} from thread local storage.
25
+ #
26
+ # @return [Hash<Symbol=>Object>]
27
+ #
28
+ def persist
29
+ KNOWN_KEYS.to_h do |key|
30
+ [key, Thread.current[key]]
31
+ end
32
+ end
13
33
 
14
34
  #
15
35
  # Execute the supplied block with the supplied values set for the currently running thread
@@ -17,7 +37,7 @@ module OpenHAB
17
37
  #
18
38
  # @param [Hash] values Keys and values to set for running thread, if hash is nil no values are set
19
39
  #
20
- def self.thread_local(**values)
40
+ def thread_local(**values)
21
41
  old_values = values.to_h { |key, _value| [key, Thread.current[key]] }
22
42
  values.each { |key, value| Thread.current[key] = value }
23
43
  logger.trace "Executing block with thread local context: #{values} - old context: #{old_values}"
@@ -25,16 +45,6 @@ module OpenHAB
25
45
  ensure
26
46
  old_values.each { |key, value| Thread.current[key] = value }
27
47
  end
28
-
29
- #
30
- # Execute the supplied block with the supplied values set for the currently running thread
31
- # The previous values for each key are restored after the block is executed
32
- #
33
- # @param [Hash] values Keys and values to set for running thread, if hash is nil no values are set
34
- #
35
- def thread_local(**values, &block)
36
- ThreadLocal.thread_local(**values, &block)
37
- end
38
48
  end
39
49
  end
40
50
  end
@@ -0,0 +1,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "singleton"
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ #
9
+ # Manages timers created by {OpenHAB::DSL.after after}, or {#schedule}.
10
+ #
11
+ class TimerManager
12
+ include Singleton
13
+
14
+ Core::ScriptHandling.script_unloaded(priority: 40) { instance.cancel_all }
15
+
16
+ # @!visibility private
17
+ def initialize
18
+ # Tracks active timers
19
+ @timers = java.util.concurrent.ConcurrentHashMap.new
20
+ @timers_by_id = java.util.concurrent.ConcurrentHashMap.new
21
+ end
22
+
23
+ #
24
+ # Create a new timer, managing ids if necessary
25
+ #
26
+ # @!visibility private
27
+ def create(duration, thread_locals:, block:, id:, reschedule:)
28
+ if id
29
+ return @timers_by_id.compute(id) do |_key, old_timer|
30
+ # return the existing timer if we're only supposed to create a new
31
+ # timer when one doesn't already exist
32
+ next old_timer if !reschedule && old_timer
33
+
34
+ if old_timer
35
+ old_timer.cancel!
36
+ @timers.remove(old_timer)
37
+ end
38
+ Core::Timer.new(duration, id: id, thread_locals: thread_locals, block: block)
39
+ end
40
+ end
41
+
42
+ Core::Timer.new(duration, id: id, thread_locals: thread_locals, block: block)
43
+ end
44
+
45
+ # Add a timer that is now active
46
+ # @!visibility private
47
+ def add(timer)
48
+ logger.trace("Adding #{timer} to timers")
49
+ @timers[timer] = 1
50
+ end
51
+
52
+ #
53
+ # Delete a timer that is no longer active
54
+ #
55
+ # @!visibility private
56
+ def delete(timer)
57
+ logger.trace("Removing #{timer} from timers")
58
+ return unless @timers.remove(timer) && timer.id
59
+
60
+ @timers_by_id.remove(timer.id)
61
+ end
62
+
63
+ #
64
+ # Cancel a single timer by id
65
+ #
66
+ # @param [Object] id
67
+ # @return [true, false] if the timer was able to be cancelled
68
+ #
69
+ def cancel(id)
70
+ result = false
71
+ @timers_by_id.compute_if_present(id) do |_key, timer|
72
+ result = timer.cancel!
73
+ @timers.remove(timer)
74
+
75
+ nil
76
+ end
77
+ result
78
+ end
79
+
80
+ #
81
+ # Reschedule a single timer by id.
82
+ #
83
+ # @note Only timers that are still active can be rescheduled by their id.
84
+ # Once a timer is finished executing or cancelled, it is no longer maintained by TimerManager,
85
+ # and calling this method will do nothing.
86
+ # To reschedule a possibly expired or cancelled timer, either call the {Core::Timer#reschedule}
87
+ # method of the timer object, or use {schedule}.
88
+ #
89
+ # @param [Object] id
90
+ # @param [java.time.temporal.TemporalAmount, #to_zoned_date_time, Proc, nil] duration
91
+ # When to reschedule the timer for. `nil` to retain its current interval.
92
+ # @return [Timer, nil] the timer if it was rescheduled, otherwise `nil`
93
+ #
94
+ def reschedule(id, duration = nil)
95
+ @timers_by_id.compute_if_present(id) do |_key, timer|
96
+ timer.reschedule(duration)
97
+ end
98
+ end
99
+
100
+ #
101
+ # Schedule a timer by id
102
+ #
103
+ # Schedules a timer by id, but passes the current timer -- if it exists --
104
+ # to the block so that you can decide how you want to proceed based on that
105
+ # state. The timer is created in a thread-safe manner.
106
+ #
107
+ # @param [Object] id
108
+ # @yieldparam [Timer, nil] timer The existing timer with this id, if one exists.
109
+ # @yieldreturn [Timer, nil] A new timer to associate with this id, the existing
110
+ # timer, or nil. If nil, any existing timer will be cancelled.
111
+ # @return [Timer, nil]
112
+ #
113
+ # @example Extend an existing timer, or schedule a new one
114
+ # # This is technically the same functionality as just calling `after()` with an `id`,
115
+ # # but allows you to performa extra steps if the timer is actually scheduled.
116
+ # timers.schedule(item) do |timer|
117
+ # next timer.tap(&:reschedule) if timer
118
+ #
119
+ # notify("The lights were turned on")
120
+ #
121
+ # after(30.seconds) { item.off }
122
+ # end
123
+ #
124
+ # @example Keep trying to turn something on, up to 5 times
125
+ # timers.schedule(item) do |timer|
126
+ # next if timer # don't interrupt a retry cycle if it already exists
127
+ #
128
+ # retries = 5
129
+ # after(2.seconds) do |inner_timer|
130
+ # next if (retries -= 1).zero?
131
+ # next inner_timer.reschedule unless item.on?
132
+ #
133
+ # item.on
134
+ # end
135
+ # end
136
+ #
137
+ def schedule(id)
138
+ @timers_by_id.compute(id) do |_key, timer|
139
+ new_timer = yield timer
140
+ raise ArgumentError, "Block must return a timer or nil" unless new_timer.is_a?(Core::Timer) || new_timer.nil?
141
+
142
+ if !new_timer.equal?(timer) && new_timer&.id
143
+ raise ArgumentError,
144
+ "Do not schedule a new timer with an ID inside a #schedule block"
145
+ end
146
+
147
+ if new_timer&.cancelled?
148
+ new_timer = nil
149
+ elsif new_timer.nil? && timer && !timer.cancelled?
150
+ timer.cancel!
151
+ @timers.remove(timer)
152
+ end
153
+ next unless new_timer
154
+
155
+ new_timer.id ||= id
156
+ if new_timer.id != id
157
+ raise ArgumentError,
158
+ "The new timer cannot have a different ID than what you're attempting to schedule"
159
+ end
160
+
161
+ new_timer
162
+ end
163
+ end
164
+
165
+ #
166
+ # Checks if a timer exists by id
167
+ #
168
+ # @note This method is not recommended for normal use in rules.
169
+ # Timers are prone to race conditions if accessed from multiple rules,
170
+ # or from timers themselves. Rescheduling, canceling, or scheduling
171
+ # a new timer based on the results of this method may cause problems,
172
+ # since the state may have changed in the meantime. Instead, use
173
+ # {OpenHAB::DSL.after after} with an `id`, {#cancel}, {#reschedule}, or
174
+ # {#schedule} to perform those actions atomically.
175
+ #
176
+ # @param [Object] id
177
+ # @return [true, false]
178
+ #
179
+ def include?(id)
180
+ @timers_by_id.key?(id)
181
+ end
182
+ alias_method :key?, :include?
183
+ alias_method :member?, :include?
184
+
185
+ #
186
+ # Cancels all active timers in the current script/UI rule
187
+ #
188
+ # Including timers with or without an id.
189
+ #
190
+ # @return [void]
191
+ #
192
+ def cancel_all
193
+ logged = false
194
+ # don't use #each, in case timers are scheduling more timers
195
+ until @timers.empty?
196
+ logger.trace("Canceling #{@timers.length} timers") unless logged
197
+ logged = true
198
+ timer = @timers.keys.first
199
+ timer.cancel
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ # Version of openHAB helper libraries
6
+ # @return [String]
7
+ VERSION = "5.0.0"
8
+ end
9
+ end