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
@@ -1,44 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'openhab/log/logger'
4
- require_relative 'trigger'
3
+ require_relative "trigger"
5
4
 
6
5
  module OpenHAB
7
6
  module DSL
8
7
  module Rules
9
- #
10
- # Module holds rule triggers
11
- #
12
8
  module Triggers
13
- include OpenHAB::Log
14
-
15
- #
16
- # Create a trigger when item, group or thing is updated
17
- #
18
- # @param [Array] items array to trigger on updated
19
- # @param [State] to to match for tigger
20
- # @param [Object] attach object to be attached to the trigger
21
- #
22
- # @return [Trigger] Trigger for updated entity
23
- #
24
- def updated(*items, to: nil, attach: nil)
25
- updated = Updated.new(rule_triggers: @rule_triggers)
26
- flattened_items = Updated.flatten_items(items)
27
- @ruby_triggers << [:updated, flattened_items, { to: to }]
28
- flattened_items.map do |item|
29
- logger.trace("Creating updated trigger for item(#{item}) to(#{to})")
30
- [to].flatten.map do |to_state|
31
- updated.trigger(item: item, to: to_state, attach: attach)
32
- end
33
- end.flatten
34
- end
35
-
9
+ # @!visibility private
36
10
  #
37
11
  # Creates updated triggers
38
12
  #
39
13
  class Updated < Trigger
40
- include OpenHAB::Log
41
-
42
14
  #
43
15
  # Create the trigger
44
16
  #
@@ -46,7 +18,7 @@ module OpenHAB
46
18
  # @param [Item State] to state to restrict trigger to
47
19
  # @param [Object] attach object to be attached to the trigger
48
20
  #
49
- # @return [Trigger] OpenHAB triggers
21
+ # @return [org.openhab.core.automation.Trigger]
50
22
  #
51
23
  def trigger(item:, to:, attach:)
52
24
  case to
@@ -59,20 +31,20 @@ module OpenHAB
59
31
  private
60
32
 
61
33
  # @return [String] A thing status update trigger
62
- THING_UPDATE = 'core.ThingStatusUpdateTrigger'
34
+ THING_UPDATE = "core.ThingStatusUpdateTrigger"
63
35
 
64
36
  # @return [String] An item state update trigger
65
- ITEM_STATE_UPDATE = 'core.ItemStateUpdateTrigger'
37
+ ITEM_STATE_UPDATE = "core.ItemStateUpdateTrigger"
66
38
 
67
39
  # @return [String] A group state update trigger for items in the group
68
- GROUP_STATE_UPDATE = 'core.GroupStateUpdateTrigger'
40
+ GROUP_STATE_UPDATE = "core.GroupStateUpdateTrigger"
69
41
 
70
42
  #
71
43
  # Creates a trigger with a range condition on the 'to' field
72
44
  # @param [Object] item to create changed trigger on
73
45
  # @param [Object] to state restrict trigger to
74
46
  # @param [Object] attach object to be attached to the trigger
75
- # @return [Trigger] OpenHAB trigger
47
+ # @return [org.openhab.core.automation.Trigger]
76
48
  #
77
49
  def range_trigger(item:, to:, attach:)
78
50
  to, * = Conditions::Proc.range_procs(to)
@@ -84,7 +56,7 @@ module OpenHAB
84
56
  # @param [Object] item to create changed trigger on
85
57
  # @param [Object] to state restrict trigger to
86
58
  # @param [Object] attach object to be attached to the trigger
87
- # @return [Trigger] OpenHAB trigger
59
+ # @return [org.openhab.core.automation.Trigger]
88
60
  #
89
61
  def proc_trigger(item:, to:, attach:)
90
62
  conditions = Conditions::Proc.new(to: to)
@@ -98,13 +70,17 @@ module OpenHAB
98
70
  # @param [State] to state restriction on trigger
99
71
  # @param [Object] attach object to be attached to the trigger
100
72
  #
101
- # @return [Trigger] OpenHAB triggers
73
+ # @return [org.openhab.core.automation.Trigger]
102
74
  #
103
75
  def update_trigger(item:, to:, attach: nil, conditions: nil)
104
76
  type, config = case item
105
- when OpenHAB::DSL::Items::GroupItem::GroupMembers then group_update(item: item, to: to)
106
- when Thing then thing_update(thing: item, to: to)
107
- else item_update(item: item, to: to)
77
+ when GroupItem::Members
78
+ group_update(item: item, to: to)
79
+ when Core::Things::Thing,
80
+ Core::Things::ThingUID
81
+ thing_update(thing: item, to: to)
82
+ else
83
+ item_update(item: item, to: to)
108
84
  end
109
85
  append_trigger(type: type, config: config, attach: attach, conditions: conditions)
110
86
  end
@@ -119,23 +95,23 @@ module OpenHAB
119
95
  # second element is a Hash configuring trigger
120
96
  #
121
97
  def item_update(item:, to:)
122
- config = { 'itemName' => item.name }
123
- config['state'] = to.to_s unless to.nil?
98
+ config = { "itemName" => item.name }
99
+ config["state"] = to.to_s unless to.nil?
124
100
  [ITEM_STATE_UPDATE, config]
125
101
  end
126
102
 
127
103
  #
128
104
  # Create an update trigger for a group
129
105
  #
130
- # @param [Item] item to create trigger for
106
+ # @param [GroupItem::Members] item to create trigger for
131
107
  # @param [State] to optional state restriction for target
132
108
  #
133
109
  # @return [Array<Hash,String>] first element is a String specifying trigger type
134
110
  # second element is a Hash configuring trigger
135
111
  #
136
112
  def group_update(item:, to:)
137
- config = { 'groupName' => item.group.name }
138
- config['state'] = to.to_s unless to.nil?
113
+ config = { "groupName" => item.group.name }
114
+ config["state"] = to.to_s unless to.nil?
139
115
  [GROUP_STATE_UPDATE, config]
140
116
  end
141
117
 
@@ -1,126 +1,278 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'java'
4
- require 'openhab/log/logger'
5
- require 'openhab/core/services'
3
+ require "singleton"
4
+ require "pathname"
5
+ require "securerandom"
6
6
 
7
7
  module OpenHAB
8
8
  module DSL
9
9
  module Rules
10
- #
11
- # Module holds rule triggers
12
- #
13
10
  module Triggers
11
+ # @!visibility private
14
12
  #
15
13
  # Module for watching directories/files
16
14
  #
17
15
  module WatchHandler
18
- include OpenHAB::Log
19
-
20
- #
21
- # Creates trigger types and trigger type factories for OpenHAB
22
- #
23
- private_class_method def self.watch_trigger_type
24
- TriggerType.new(
25
- WATCH_TRIGGER_MODULE_ID,
26
- nil,
27
- 'A path change event is detected',
28
- 'Triggers when a path change event is detected',
29
- nil,
30
- org.openhab.core.automation.Visibility::VISIBLE,
31
- nil
32
- )
16
+ # Trigger ID for Watch Triggers
17
+ WATCH_TRIGGER_MODULE_ID = "jsr223.jruby.WatchTrigger"
18
+
19
+ # WatchService is only available in openHAB4
20
+ def self.factory
21
+ @factory ||= OSGi.service("org.openhab.core.service.WatchServiceFactory")
33
22
  end
34
23
 
35
- # Struct for Watch Events
36
- WatchEvent = Struct.new(:type, :path, :attachment)
24
+ # Due to the refactoring in OH4, we need a different watcher implementation
25
+ if WatchHandler.factory
26
+ # A class that implements openHAB4's WatchEventListener
27
+ # and also creates and removes a unique WatchService for each instance
28
+ class Watcher
29
+ # Use full java class name here to satisfy YARD linter
30
+ include org.openhab.core.service.WatchService::WatchEventListener
31
+ java_import org.openhab.core.service.WatchService
37
32
 
38
- # Trigger ID for Watch Triggers
39
- WATCH_TRIGGER_MODULE_ID = 'jsr223.jruby.WatchTrigger'
40
-
41
- # Extends the OpenHAB watch service to watch directories
42
- #
43
- # Must match java method name style
44
- # rubocop:disable Naming/MethodName
45
- class Watcher < org.openhab.core.service.AbstractWatchService
46
- java_import java.nio.file.StandardWatchEventKinds
47
-
48
- # Hash of event symbols as strings to map to NIO events
49
- STRING_TO_EVENT = {
50
- created: StandardWatchEventKinds::ENTRY_CREATE,
51
- deleted: StandardWatchEventKinds::ENTRY_DELETE,
52
- modified: StandardWatchEventKinds::ENTRY_MODIFY
53
- }.transform_keys(&:to_s).freeze
54
-
55
- # Hash of NIO event kinds to ruby symbols
56
- EVENT_TO_SYMBOL = STRING_TO_EVENT.invert.transform_values(&:to_sym).freeze
57
-
58
- # Creates a new Watch Service
59
- def initialize(path, types, &block)
60
- super(path)
61
- @types = types.map { |type| STRING_TO_EVENT[type] }
62
- @block = block
63
- end
33
+ # Hash of event symbols as strings to map to WatchService events
34
+ STRING_TO_EVENT = {
35
+ created: WatchService::Kind::CREATE,
36
+ deleted: WatchService::Kind::DELETE,
37
+ modified: WatchService::Kind::MODIFY
38
+ }.transform_keys(&:to_s).freeze
64
39
 
65
- # Invoked by java super class to get type of events to watch for
66
- # @param [String] _path ignored
67
- #
68
- # @return [Array] array of NIO event kinds
69
- def getWatchEventKinds(_path)
70
- @types
71
- end
40
+ # Hash of WatchService event kinds to ruby symbols
41
+ EVENT_TO_SYMBOL = STRING_TO_EVENT.invert.transform_values(&:to_sym).freeze
72
42
 
73
- # Invoked by java super class to check if sub directories should be watched
74
- # @return [false] false
75
- def watchSubDirectories
76
- false
43
+ # constructor
44
+ def initialize(path, subdirs, types, &block)
45
+ @types = types.map { |type| STRING_TO_EVENT[type] }
46
+ @block = block
47
+ @subdirs = subdirs
48
+ @path = Pathname.new(path)
49
+ return if path.to_s.start_with?(OpenHAB::Core.config_folder.to_s)
50
+
51
+ @custom_watcher = "jrubyscripting-#{SecureRandom.uuid}"
52
+ end
53
+
54
+ # Creates a new Watch Service and registers ourself as a listener
55
+ # This isn't an OSGi service, but it's called by {WatchTriggerHandler} below.
56
+ def activate
57
+ java_path = java.nio.file.Path.of(@path.to_s)
58
+
59
+ service_name = WatchService::SERVICE_PID
60
+ filter = if @custom_watcher
61
+ WatchHandler.factory.create_watch_service(@custom_watcher, java_path)
62
+ logger.trace { "Created a watch service #{@custom_watcher} for #{@path}" }
63
+ "(name=#{@custom_watcher})"
64
+ else
65
+ logger.trace { "Using configWatcher service for #{@path}" }
66
+ WatchService::CONFIG_WATCHER_FILTER
67
+ end
68
+
69
+ start = Time.now
70
+ sleep 0.1 until (@watch_service = OSGi.service(service_name, filter: filter)) || Time.now - start > 2
71
+
72
+ unless @watch_service
73
+ logger.warn("Watch service is not ready in time. #{@path} will not be monitored!")
74
+ return
75
+ end
76
+
77
+ @watch_service.register_listener(self, java_path, @subdirs)
78
+ logger.trace { "Registered watch service listener for #{@path} including subdirs: #{@subdirs}" }
79
+ end
80
+
81
+ # Unregister ourself as a listener and remove the watch service
82
+ def deactivate
83
+ @watch_service&.unregister_listener(self)
84
+ return unless @custom_watcher
85
+
86
+ WatchHandler.factory.remove_watch_service(@custom_watcher)
87
+ logger.trace { "Removed watch service #{@custom_watcher} for #{@path}" }
88
+ end
89
+
90
+ # Invoked by the WatchService when a watch event occurs
91
+ # @param [org.openhab.core.service.WatchService.Kind] kind WatchService event kind
92
+ # @param [java.nio.file.Path] path The path that had an event
93
+ def processWatchEvent(kind, path) # rubocop:disable Naming/MethodName
94
+ logger.trace { "processWatchEvent triggered #{path} #{kind} #{@types}" }
95
+ return unless @types.include?(kind)
96
+
97
+ # OH4 WatchService feeds us a relative path,
98
+ # but just in case its implementation changes in the future
99
+ path = path.absolute? ? Pathname.new(path.to_s) : @path + path.to_s
100
+ @block.call(Events::WatchEvent.new(EVENT_TO_SYMBOL[kind], path))
101
+ end
77
102
  end
103
+ else
104
+ # @deprecated OH3.4
105
+ #
106
+ # Extends the openHAB3 watch service to watch directories
107
+ #
108
+ # Must match java method name style
109
+ # rubocop:disable Naming/MethodName
110
+ class Watcher < org.openhab.core.service.AbstractWatchService
111
+ java_import java.nio.file.StandardWatchEventKinds
112
+
113
+ # Hash of event symbols as strings to map to NIO events
114
+ STRING_TO_EVENT = {
115
+ created: StandardWatchEventKinds::ENTRY_CREATE,
116
+ deleted: StandardWatchEventKinds::ENTRY_DELETE,
117
+ modified: StandardWatchEventKinds::ENTRY_MODIFY
118
+ }.transform_keys(&:to_s).freeze
119
+
120
+ # Hash of NIO event kinds to ruby symbols
121
+ EVENT_TO_SYMBOL = STRING_TO_EVENT.invert.transform_values(&:to_sym).freeze
122
+
123
+ # Creates a new Watch Service
124
+ def initialize(path, subdirs, types, &block)
125
+ super(path)
126
+ @types = types.map { |type| STRING_TO_EVENT[type] }
127
+ @block = block
128
+ @subdirs = subdirs
129
+ end
78
130
 
79
- # Invoked by java super class when an watch event occurs
80
- # @param [String] _event ignored
81
- # @param [StandardWatchEventKind] kind NIO watch event kind
82
- # @param [java.nio.Path] path that had an event
83
- def processWatchEvent(_event, kind, path)
84
- @block.call(WatchEvent.new(EVENT_TO_SYMBOL[kind], Pathname.new(path.to_s)))
131
+ # Invoked by java super class to get type of events to watch for
132
+ # @param [String] _path ignored
133
+ #
134
+ # @return [Array] array of NIO event kinds
135
+ def getWatchEventKinds(_path)
136
+ @types
137
+ end
138
+
139
+ # Invoked by java super class to check if sub directories should be watched
140
+ # @return [false] false
141
+ def watchSubDirectories
142
+ logger.trace("watchSubDirectories returning #{@subdirs}")
143
+ @subdirs
144
+ end
145
+
146
+ # Invoked by java super class when a watch event occurs
147
+ # @param [String] _event ignored
148
+ # @param [StandardWatchEventKind] kind NIO watch event kind
149
+ # @param [java.nio.file.Path] path that had an event
150
+ def processWatchEvent(_event, kind, path)
151
+ @block.call(Events::WatchEvent.new(EVENT_TO_SYMBOL[kind], Pathname.new(path.to_s)))
152
+ end
85
153
  end
154
+ # rubocop:enable Naming/MethodName
86
155
  end
87
- # rubocop:enable Naming/MethodName
88
156
 
89
- # Implements the OpenHAB TriggerHandler interface to process Watch Triggers
157
+ # Implements the openHAB TriggerHandler interface to process Watch Triggers
90
158
  class WatchTriggerHandler
91
- include OpenHAB::Log
92
159
  include org.openhab.core.automation.handler.TriggerHandler
93
160
 
161
+ class << self
162
+ #
163
+ # Returns the directory to watch, subdir flag, and glob pattern to use
164
+ #
165
+ # @param [String] path The path provided to the watch trigger which may include glob patterns
166
+ # @param [String] glob The glob pattern provided by the user
167
+ #
168
+ # @return [Array<String,Boolean,String>,nil] An array of directory to watch,
169
+ # whether to watch in subdirectories, and the glob pattern to use.
170
+ # Returns nil if the given path doesn't exist all the way to root, e.g. /nonexistent
171
+ #
172
+ def dir_subdir_glob(path, glob)
173
+ pathname = Pathname.new(path)
174
+ return [pathname.dirname.to_s, false, path] if pathname.file?
175
+
176
+ dir = find_parent(pathname)
177
+ return unless dir
178
+
179
+ # we were given the exact existing directory to watch
180
+ if dir == pathname
181
+ glob_pathname = Pathname.new(glob)
182
+ subdirs = recursive_glob?(glob)
183
+ unless glob_pathname.absolute? || glob.start_with?("**")
184
+ glob = subdirs ? "**/#{glob}" : "#{path}/#{glob}"
185
+ end
186
+ return [path, subdirs, glob]
187
+ end
188
+
189
+ if glob != "*" # if it isn't the default glob
190
+ logger.warn("The provided glob '#{glob}' is ignored because " \
191
+ "the given path (#{path}) isn't an existing directory, " \
192
+ "so it is used as the glob pattern")
193
+ end
194
+
195
+ relative_glob = pathname.relative_path_from(dir).to_s
196
+ subdir_flag = dir != pathname.dirname || recursive_glob?(relative_glob)
197
+ [dir.to_s, subdir_flag, path]
198
+ end
199
+
200
+ # Returns true if string contains glob characters
201
+ def glob?(string)
202
+ unless @regexp
203
+ # (?<!X) is a negative lookbehind pattern: only match the pattern if it wasn't
204
+ # preceded with X. In this case we want to match only non escaped glob chars
205
+ glob_pattern = %w[** * ? [ ] { }].map { |char| Regexp.escape(char) }
206
+ .join("|")
207
+ .then { |pattern| "(?<!\\\\)(#{pattern})" }
208
+
209
+ @regexp = Regexp.new(glob_pattern)
210
+ end
211
+ @regexp.match?(string)
212
+ end
213
+
214
+ # Returns true if string contains a recursive glob pattern (** or x/y)
215
+ def recursive_glob?(string)
216
+ /(?<!\\\\)\*\*/.match?(string) || Pathname.new(string).each_filename.to_a.size > 1
217
+ end
218
+
219
+ #
220
+ # Find the part of the path that exists on disk.
221
+ #
222
+ # /a/b/c/*/d/*.e -> /a/b/c if it exists
223
+ # /a/b/c/d/e/f -> /a/b/c if /a/b/c directory exists, but /a/b/c/d doesn't exist
224
+ # /a/b/c -> nil if /a doesn't exist
225
+ # / -> /
226
+ #
227
+ # @param [Pathname] pathname The pathname to check
228
+ # @return [Pathname,nil] The leading part of the path name that corresponds to
229
+ # an existing directory. nil if none was found up until the root directory
230
+ #
231
+ def find_parent(pathname)
232
+ return pathname if pathname.root?
233
+
234
+ pathname.ascend { |part| return part if part.directory? && !part.root? }
235
+ end
236
+ end
237
+
94
238
  # Creates a new WatchTriggerHandler
95
- # @param [Trigger] trigger OpenHAB trigger associated with handler
239
+ # @param [org.openhab.core.automation.Trigger] trigger
96
240
  #
97
241
  def initialize(trigger)
98
242
  @trigger = trigger
99
243
  config = trigger.configuration.properties.to_hash.transform_keys(&:to_sym)
100
- @path = config[:path]
101
- @watcher = Watcher.new(@path, config[:types], &watch_event_handler(config[:glob]))
244
+ @path, subdirs, glob = self.class.dir_subdir_glob(config[:path], config[:glob])
245
+ logger.trace { "WatchTriggerHandler#initialize path: #{@path}, subdirs: #{subdirs}, glob: #{glob}" }
246
+ unless @path
247
+ logger.warn("Watch error: the given path doesn't exist: '#{@path}'")
248
+ return
249
+ end
250
+ @watcher = Watcher.new(@path, subdirs, config[:types], &watch_event_handler(glob))
102
251
  @watcher.activate
103
- logger.trace("Created watcher for #{@path}")
252
+ logger.trace { "Created watcher for #{@path} subdirs: #{subdirs}" }
104
253
  end
105
254
 
106
255
  # Create a lambda to use to invoke rule engine when file watch notification happens
107
256
  # @param [String] glob to match for notification events
108
257
  #
109
- # @return [Lambda] lambda to execute on notification events
258
+ # @return [Proc] lambda to execute on notification events
110
259
  #
111
260
  def watch_event_handler(glob)
112
- lambda { |watch_event|
113
- logger.trace("Received event(#{watch_event})")
114
- if watch_event.path.fnmatch?(glob)
115
- @rule_engine_callback&.triggered(@trigger, { 'event' => watch_event })
261
+ default_fs = java.nio.file.FileSystems.default
262
+ path_matcher = default_fs.get_path_matcher("glob:#{glob}")
263
+ lambda do |watch_event|
264
+ if path_matcher.matches(default_fs.get_path(watch_event.path.to_s))
265
+ logger.trace do
266
+ "Received event(#{watch_event}) glob: #{glob}, rule_engine_callback = #{@rule_engine_callback}"
267
+ end
268
+ @rule_engine_callback&.triggered(@trigger, { "event" => watch_event })
116
269
  else
117
- logger.trace("Event #{watch_event} did not match glob(#{glob})")
270
+ logger.trace { "Event #{watch_event} did not match glob(#{glob})" }
118
271
  end
119
- }
272
+ end
120
273
  end
121
274
 
122
- # Called by OpenHAB to set the rule engine to invoke when triggered
123
- # Must match java method name style
275
+ # Called by openHAB to set the rule engine to invoke when triggered
124
276
  def setCallback(callback) # rubocop:disable Naming/MethodName
125
277
  @rule_engine_callback = callback
126
278
  end
@@ -129,41 +281,44 @@ module OpenHAB
129
281
  # Dispose of handler which deactivates watcher
130
282
  #
131
283
  def dispose
132
- logger.trace("Deactivating watcher for #{@path}")
133
- @watcher&.deactivate
284
+ logger.trace { "Deactivating watcher for #{@path}" }
285
+ @watcher.deactivate
134
286
  end
135
287
  end
136
288
 
137
289
  # Implements the ScriptedTriggerHandlerFactory interface to create a new Trigger Handler
138
290
  class WatchTriggerHandlerFactory
291
+ include Singleton
139
292
  include org.openhab.core.automation.module.script.rulesupport.shared.factories.ScriptedTriggerHandlerFactory
140
293
 
141
- # Invoked by the OpenHAB core to get a trigger handler for the supllied trigger
142
- # @param [Trigger] trigger OpenHAB trigger
294
+ def initialize
295
+ Core.automation_manager.add_trigger_handler(
296
+ WATCH_TRIGGER_MODULE_ID,
297
+ self
298
+ )
299
+
300
+ Core.automation_manager.add_trigger_type(org.openhab.core.automation.type.TriggerType.new(
301
+ WATCH_TRIGGER_MODULE_ID,
302
+ nil,
303
+ "A path change event is detected",
304
+ "Triggers when a path change event is detected",
305
+ nil,
306
+ org.openhab.core.automation.Visibility::VISIBLE,
307
+ nil
308
+ ))
309
+ logger.trace("Added watch trigger handler")
310
+ end
311
+
312
+ # Invoked by openHAB core to get a trigger handler for the supllied trigger
313
+ # @param [org.openhab.core.automation.Trigger] trigger
143
314
  #
144
315
  # @return [WatchTriggerHandler] trigger handler for supplied trigger
145
316
  def get(trigger)
146
317
  WatchTriggerHandler.new(trigger)
147
318
  end
148
319
  end
149
-
150
- #
151
- # Creates trigger types and trigger type factories for OpenHAB
152
- #
153
- def self.add_watch_handler
154
- java_import org.openhab.core.automation.type.TriggerType
155
- OpenHAB::Core.automation_manager.add_trigger_handler(
156
- WATCH_TRIGGER_MODULE_ID,
157
- WatchTriggerHandlerFactory.new
158
- )
159
-
160
- OpenHAB::Core.automation_manager.add_trigger_type(watch_trigger_type)
161
- OpenHAB::Log.logger(self).trace('Added watch trigger handler')
162
- end
163
320
  end
164
321
  end
165
322
  end
166
323
  end
167
324
  end
168
- # Add the watch handler to OpenHAB
169
- OpenHAB::DSL::Rules::Triggers::WatchHandler.add_watch_handler
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Rules
6
+ # Contains helper classes for implementing triggers.
7
+ # @!visibility private
8
+ module Triggers
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Rules
6
+ end
7
+ end
8
+ end