openhab-jrubyscripting 5.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/lib/openhab/core/actions.rb +163 -0
  3. data/lib/openhab/core/entity_lookup.rb +144 -0
  4. data/lib/openhab/core/events/abstract_event.rb +17 -0
  5. data/lib/openhab/core/events/item_channel_link.rb +36 -0
  6. data/lib/openhab/core/events/item_command_event.rb +78 -0
  7. data/lib/openhab/core/events/item_event.rb +22 -0
  8. data/lib/openhab/core/events/item_state_changed_event.rb +52 -0
  9. data/lib/openhab/core/events/item_state_event.rb +51 -0
  10. data/lib/openhab/core/events/thing.rb +29 -0
  11. data/lib/openhab/core/events/thing_status_info_event.rb +53 -0
  12. data/lib/openhab/core/events.rb +10 -0
  13. data/lib/openhab/core/items/accepted_data_types.rb +29 -0
  14. data/lib/openhab/core/items/color_item.rb +52 -0
  15. data/lib/openhab/core/items/contact_item.rb +52 -0
  16. data/lib/openhab/core/items/date_time_item.rb +58 -0
  17. data/lib/openhab/core/items/dimmer_item.rb +148 -0
  18. data/lib/openhab/core/items/generic_item.rb +344 -0
  19. data/lib/openhab/core/items/group_item.rb +174 -0
  20. data/lib/openhab/core/items/image_item.rb +109 -0
  21. data/lib/openhab/core/items/location_item.rb +34 -0
  22. data/lib/openhab/core/items/metadata/hash.rb +390 -0
  23. data/lib/openhab/core/items/metadata/namespace_hash.rb +469 -0
  24. data/lib/openhab/core/items/metadata.rb +11 -0
  25. data/lib/openhab/core/items/number_item.rb +62 -0
  26. data/lib/openhab/core/items/numeric_item.rb +22 -0
  27. data/lib/openhab/core/items/persistence.rb +327 -0
  28. data/lib/openhab/core/items/player_item.rb +66 -0
  29. data/lib/openhab/core/items/proxy.rb +59 -0
  30. data/lib/openhab/core/items/registry.rb +66 -0
  31. data/lib/openhab/core/items/rollershutter_item.rb +68 -0
  32. data/lib/openhab/core/items/semantics/enumerable.rb +152 -0
  33. data/lib/openhab/core/items/semantics.rb +476 -0
  34. data/lib/openhab/core/items/state_storage.rb +53 -0
  35. data/lib/openhab/core/items/string_item.rb +28 -0
  36. data/lib/openhab/core/items/switch_item.rb +78 -0
  37. data/lib/openhab/core/items.rb +114 -0
  38. data/lib/openhab/core/lazy_array.rb +52 -0
  39. data/lib/openhab/core/profile_factory.rb +118 -0
  40. data/lib/openhab/core/script_handling.rb +55 -0
  41. data/lib/openhab/core/things/channel.rb +48 -0
  42. data/lib/openhab/core/things/channel_uid.rb +51 -0
  43. data/lib/openhab/core/things/item_channel_link.rb +33 -0
  44. data/lib/openhab/core/things/profile_callback.rb +52 -0
  45. data/lib/openhab/core/things/proxy.rb +69 -0
  46. data/lib/openhab/core/things/registry.rb +46 -0
  47. data/lib/openhab/core/things/thing.rb +194 -0
  48. data/lib/openhab/core/things.rb +22 -0
  49. data/lib/openhab/core/timer.rb +128 -0
  50. data/lib/openhab/core/types/comparable_type.rb +23 -0
  51. data/lib/openhab/core/types/date_time_type.rb +259 -0
  52. data/lib/openhab/core/types/decimal_type.rb +192 -0
  53. data/lib/openhab/core/types/hsb_type.rb +183 -0
  54. data/lib/openhab/core/types/increase_decrease_type.rb +34 -0
  55. data/lib/openhab/core/types/next_previous_type.rb +34 -0
  56. data/lib/openhab/core/types/numeric_type.rb +52 -0
  57. data/lib/openhab/core/types/on_off_type.rb +46 -0
  58. data/lib/openhab/core/types/open_closed_type.rb +41 -0
  59. data/lib/openhab/core/types/percent_type.rb +95 -0
  60. data/lib/openhab/core/types/play_pause_type.rb +38 -0
  61. data/lib/openhab/core/types/point_type.rb +117 -0
  62. data/lib/openhab/core/types/quantity_type.rb +327 -0
  63. data/lib/openhab/core/types/raw_type.rb +26 -0
  64. data/lib/openhab/core/types/refresh_type.rb +27 -0
  65. data/lib/openhab/core/types/rewind_fastforward_type.rb +38 -0
  66. data/lib/openhab/core/types/stop_move_type.rb +34 -0
  67. data/lib/openhab/core/types/string_type.rb +76 -0
  68. data/lib/openhab/core/types/type.rb +117 -0
  69. data/lib/openhab/core/types/un_def_type.rb +38 -0
  70. data/lib/openhab/core/types/up_down_type.rb +50 -0
  71. data/lib/openhab/core/types.rb +69 -0
  72. data/lib/openhab/core/uid.rb +36 -0
  73. data/lib/openhab/core.rb +85 -0
  74. data/lib/openhab/core_ext/java/duration.rb +115 -0
  75. data/lib/openhab/core_ext/java/local_date.rb +93 -0
  76. data/lib/openhab/core_ext/java/local_time.rb +106 -0
  77. data/lib/openhab/core_ext/java/month.rb +59 -0
  78. data/lib/openhab/core_ext/java/month_day.rb +105 -0
  79. data/lib/openhab/core_ext/java/period.rb +103 -0
  80. data/lib/openhab/core_ext/java/temporal_amount.rb +34 -0
  81. data/lib/openhab/core_ext/java/time.rb +58 -0
  82. data/lib/openhab/core_ext/java/unit.rb +15 -0
  83. data/lib/openhab/core_ext/java/zoned_date_time.rb +116 -0
  84. data/lib/openhab/core_ext/ruby/array.rb +21 -0
  85. data/lib/openhab/core_ext/ruby/class.rb +15 -0
  86. data/lib/openhab/core_ext/ruby/date.rb +89 -0
  87. data/lib/openhab/core_ext/ruby/numeric.rb +190 -0
  88. data/lib/openhab/core_ext/ruby/range.rb +70 -0
  89. data/lib/openhab/core_ext/ruby/time.rb +104 -0
  90. data/lib/openhab/core_ext.rb +18 -0
  91. data/lib/openhab/dsl/events/watch_event.rb +18 -0
  92. data/lib/openhab/dsl/events.rb +9 -0
  93. data/lib/openhab/dsl/gems.rb +3 -0
  94. data/lib/openhab/dsl/items/builder.rb +618 -0
  95. data/lib/openhab/dsl/items/ensure.rb +93 -0
  96. data/lib/openhab/dsl/items/timed_command.rb +236 -0
  97. data/lib/openhab/dsl/rules/automation_rule.rb +308 -0
  98. data/lib/openhab/dsl/rules/builder.rb +1373 -0
  99. data/lib/openhab/dsl/rules/guard.rb +115 -0
  100. data/lib/openhab/dsl/rules/name_inference.rb +160 -0
  101. data/lib/openhab/dsl/rules/property.rb +76 -0
  102. data/lib/openhab/dsl/rules/rule_triggers.rb +96 -0
  103. data/lib/openhab/dsl/rules/terse.rb +63 -0
  104. data/lib/openhab/dsl/rules/triggers/changed.rb +169 -0
  105. data/lib/openhab/dsl/rules/triggers/channel.rb +57 -0
  106. data/lib/openhab/dsl/rules/triggers/command.rb +107 -0
  107. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +161 -0
  108. data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +164 -0
  109. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +195 -0
  110. data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +127 -0
  111. data/lib/openhab/dsl/rules/triggers/trigger.rb +56 -0
  112. data/lib/openhab/dsl/rules/triggers/updated.rb +130 -0
  113. data/lib/openhab/dsl/rules/triggers/watch/watch.rb +55 -0
  114. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +155 -0
  115. data/lib/openhab/dsl/rules/triggers.rb +12 -0
  116. data/lib/openhab/dsl/rules.rb +29 -0
  117. data/lib/openhab/dsl/script_handling.rb +55 -0
  118. data/lib/openhab/dsl/things/builder.rb +263 -0
  119. data/lib/openhab/dsl/thread_local.rb +48 -0
  120. data/lib/openhab/dsl/timer_manager.rb +191 -0
  121. data/lib/openhab/dsl/version.rb +9 -0
  122. data/lib/openhab/dsl.rb +686 -0
  123. data/lib/openhab/log.rb +348 -0
  124. data/lib/openhab/osgi.rb +70 -0
  125. data/lib/openhab/rspec/configuration.rb +56 -0
  126. data/lib/openhab/rspec/example_group.rb +90 -0
  127. data/lib/openhab/rspec/helpers.rb +439 -0
  128. data/lib/openhab/rspec/hooks.rb +93 -0
  129. data/lib/openhab/rspec/jruby.rb +46 -0
  130. data/lib/openhab/rspec/karaf.rb +811 -0
  131. data/lib/openhab/rspec/mocks/bundle_install_support.rb +25 -0
  132. data/lib/openhab/rspec/mocks/bundle_resolver.rb +30 -0
  133. data/lib/openhab/rspec/mocks/event_admin.rb +146 -0
  134. data/lib/openhab/rspec/mocks/metadata_provider.rb +75 -0
  135. data/lib/openhab/rspec/mocks/persistence_service.rb +140 -0
  136. data/lib/openhab/rspec/mocks/safe_caller.rb +40 -0
  137. data/lib/openhab/rspec/mocks/synchronous_executor.rb +56 -0
  138. data/lib/openhab/rspec/mocks/thing_handler.rb +76 -0
  139. data/lib/openhab/rspec/mocks/timer.rb +95 -0
  140. data/lib/openhab/rspec/openhab/core/actions.rb +26 -0
  141. data/lib/openhab/rspec/openhab/core/items/proxy.rb +27 -0
  142. data/lib/openhab/rspec/openhab/core/things/proxy.rb +27 -0
  143. data/lib/openhab/rspec/shell.rb +31 -0
  144. data/lib/openhab/rspec/suspend_rules.rb +60 -0
  145. data/lib/openhab/rspec.rb +17 -0
  146. data/lib/openhab/yard/cli/stats.rb +23 -0
  147. data/lib/openhab/yard/code_objects/group_object.rb +17 -0
  148. data/lib/openhab/yard/code_objects/java/base.rb +31 -0
  149. data/lib/openhab/yard/code_objects/java/class_object.rb +11 -0
  150. data/lib/openhab/yard/code_objects/java/field_object.rb +15 -0
  151. data/lib/openhab/yard/code_objects/java/interface_object.rb +15 -0
  152. data/lib/openhab/yard/code_objects/java/package_object.rb +11 -0
  153. data/lib/openhab/yard/code_objects/java/proxy.rb +23 -0
  154. data/lib/openhab/yard/handlers/jruby/base.rb +49 -0
  155. data/lib/openhab/yard/handlers/jruby/class_handler.rb +18 -0
  156. data/lib/openhab/yard/handlers/jruby/constant_handler.rb +18 -0
  157. data/lib/openhab/yard/handlers/jruby/java_import_handler.rb +27 -0
  158. data/lib/openhab/yard/handlers/jruby/mixin_handler.rb +23 -0
  159. data/lib/openhab/yard/html_helper.rb +44 -0
  160. data/lib/openhab/yard/tags/constant_directive.rb +20 -0
  161. data/lib/openhab/yard/tags/group_directive.rb +24 -0
  162. data/lib/openhab/yard/tags/library.rb +3 -0
  163. data/lib/openhab/yard.rb +32 -0
  164. metadata +504 -0
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dimmer_item"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module Items
8
+ java_import org.openhab.core.library.items.ColorItem
9
+
10
+ #
11
+ # {ColorItem} represents a color values, e.g. for LED lights.
12
+ #
13
+ # Note that it inherits from {DimmerItem}, so you can call {#on}, {#off},
14
+ # {#on?}, {#off?}, etc. on it. Its state type is an {HSBType},
15
+ # which is stored as Hue, Saturation, and Brightness, but has easy
16
+ # helpers for working with RGB values of various forms.
17
+ #
18
+ # @example Sending commands
19
+ # HueBulb << "#ff0000" # send 'red' as a command
20
+ # HueBulb.on
21
+ # HueBulb.dim
22
+ #
23
+ # @example Inspect state
24
+ # HueBulb.on? # => true
25
+ # HueBulb.state.red # => 100%
26
+ # HueBulb.state.hue # => 0 °
27
+ # HueBulb.state.brightness # => 100%
28
+ # HueBulb.state.to_rgb # => [100%, 0%, 0%]
29
+ # HueBulb.state.rgb # => 16711680
30
+ # HueBulb.state.to_hex # => "0xff0000"
31
+ # HueBulb.state.on? # => true
32
+ # HueBulb.state.red.to_byte # => 255
33
+ # HueBulb.state.blue.to_byte # => 0
34
+ #
35
+ # @!attribute [r] state
36
+ # @return [HSBType, nil]
37
+ #
38
+ class ColorItem < DimmerItem
39
+ # Make sure to do the String => HSBType conversion in Ruby,
40
+ # where we add support for hex
41
+ # @!visibility private
42
+ def format_type(type)
43
+ return Types::HSBType.new(type) if type.respond_to?(:to_str)
44
+
45
+ super
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # @!parse ColorItem = OpenHAB::Core::Items::ColorItem
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "generic_item"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module Items
8
+ java_import org.openhab.core.library.items.ContactItem
9
+
10
+ #
11
+ # A {ContactItem} can be used for sensors that return an "open" or
12
+ # "closed" as a state.
13
+ #
14
+ # This is useful for doors, windows, etc.
15
+ #
16
+ # @!attribute [r] state
17
+ # @return [OpenClosedType, nil]
18
+ #
19
+ # @example
20
+ # rule 'Log state of all doors on system startup' do
21
+ # on_start
22
+ # run do
23
+ # Doors.each do |door|
24
+ # case door.state
25
+ # when OPEN then logger.info("#{door.name} is Open")
26
+ # when CLOSED then logger.info("#{door.name} is Open")
27
+ # else logger.info("#{door.name} is not initialized")
28
+ # end
29
+ # end
30
+ # end
31
+ # end
32
+ #
33
+ class ContactItem < GenericItem
34
+ # @!method open?
35
+ # Check if the item state == {OPEN}
36
+ # @return [true,false]
37
+ #
38
+ # @example Log open contacts
39
+ # Contacts.select(&:open?).each { |contact| logger.info("Contact #{contact.name} is open")}
40
+
41
+ # @!method closed?
42
+ # Check if the item state == {CLOSED}
43
+ # @return [true,false]
44
+ #
45
+ # @example Log closed contacts
46
+ # Contacts.select(&:closed?).each { |contact| logger.info("Contact #{contact.name} is closed")}
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # @!parse ContactItem = OpenHAB::Core::Items::ContactItem
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "generic_item"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module Items
8
+ java_import org.openhab.core.library.items.DateTimeItem
9
+
10
+ #
11
+ # A DateTimeItem stores a timestamp including a valid time zone.
12
+ #
13
+ # @!attribute [r] state
14
+ # @return [DateTimeType, nil]
15
+ #
16
+ # @example DateTime items can be updated and commanded with Ruby Time objects or Java ZonedDateTime objects
17
+ # Example_DateTimeItem << Time.now
18
+ # Example_DateTimeItem << ZonedDateTime.now
19
+ #
20
+ # @example Math operations (+ and -) are available to make calculations with time in a few different ways
21
+ # Example_DateTimeItem.state + 600 # Number of seconds
22
+ # Example_DateTimeItem.state - '01:15' # Subtracts 1h 15 min
23
+ # Example_DateTimeItem.state + 2.hours # Use the helper library's duration methods
24
+ #
25
+ # Example_DateTimeItem.state - Example_DateTimeItem2.state # Calculate the time difference, in seconds
26
+ # Example_DateTimeItem.state - '2021-01-01 15:40' # Calculates time difference
27
+ #
28
+ # @example Comparisons between different time objects can be performed
29
+ # Example_DateTimeItem.state == Example_DateTimeItem2.state # Equality, works across time zones
30
+ # Example_DateTimeItem.state > Date.parse('2021-01-31') # After midnight jan 31st 2021
31
+ # Example_DateTimeItem.state <= Time.now # Before or equal to now
32
+ # Example_DateTimeItem.state < LocalTime::NOON # Before noon
33
+ #
34
+ # @example LocalTime ranges created also work
35
+ # case Example_DateTimeItem.state
36
+ # when LocalTime.parse('00:00')...LocalTime.parse('08:00')
37
+ # logger.info('Example_DateTimeItem is between 00:00..08:00')
38
+ # when LocalTime.parse('08:00')...LocalTime.parse('16:00')
39
+ # logger.info('Example_DateTimeItem is between 08:00..16:00')
40
+ # when LocalTime.parse('16:00')..LocalTime.parse'23:59')
41
+ # logger.info('Example_DateTimeItem is between 16:00...23:59')
42
+ # end
43
+ #
44
+ class DateTimeItem < GenericItem
45
+ # Time types need formatted as ISO8601
46
+ # @!visibility private
47
+ def format_type(command)
48
+ return Types::DateTimeType.new(command) if command.is_a?(java.time.ZonedDateTime)
49
+
50
+ command = command.iso8601 if command.respond_to?(:iso8601)
51
+ super
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ # @!parse DateTimeItem = OpenHAB::Core::Items::DateTimeItem
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "numeric_item"
4
+ require_relative "switch_item"
5
+
6
+ module OpenHAB
7
+ module Core
8
+ module Items
9
+ java_import org.openhab.core.library.items.DimmerItem
10
+
11
+ #
12
+ # A DimmerItem can be used as a switch (ON/OFF), but it also accepts
13
+ # percent values to reflect the dimmed state.
14
+ #
15
+ # @!attribute [r] state
16
+ # @return [PercentType, nil]
17
+ #
18
+ # @example
19
+ # DimmerOne << DimmerOne.state - 5
20
+ # DimmerOne << 100 - DimmerOne.state
21
+ #
22
+ # @example Turn on all dimmers in group
23
+ # Dimmers.members.each(&:on)
24
+ #
25
+ # @example Turn off all dimmers in group
26
+ # Dimmers.members.each(&:off)
27
+ #
28
+ # @example Turn on switches that are off
29
+ # Dimmers.select(&:off?).each(&:on)
30
+ #
31
+ # @example Turn off switches that are on
32
+ # Dimmers.select(&:on?).each(&:off)
33
+ #
34
+ # @example Dimmers can be selected in an enumerable with grep.
35
+ # items.grep(DimmerItem)
36
+ # .each { |dimmer| logger.info("#{dimmer.name} is a Dimmer") }
37
+ #
38
+ # @example Dimmers can also be used in case statements with ranges.
39
+ # items.grep(DimmerItem)
40
+ # .each do |dimmer|
41
+ # case dimmer.state
42
+ # when (0..50)
43
+ # logger.info("#{dimmer.name} is less than 50%")
44
+ # when (51..100)
45
+ # logger.info("#{dimmer.name} is greater than 50%")
46
+ # end
47
+ # end
48
+ #
49
+ # @example
50
+ # rule 'Dim a switch on system startup over 100 seconds' do
51
+ # on_start
52
+ # 100.times do
53
+ # run { DimmerSwitch.dim }
54
+ # delay 1.second
55
+ # end
56
+ # end
57
+ #
58
+ # @example
59
+ # rule 'Dim a switch on system startup by 5, pausing every second' do
60
+ # on_start
61
+ # 100.step(-5, 0) do |level|
62
+ # run { DimmerSwitch << level }
63
+ # delay 1.second
64
+ # end
65
+ # end
66
+ #
67
+ # @example
68
+ # rule 'Turn off any dimmers curently on at midnight' do
69
+ # every :day
70
+ # run do
71
+ # items.grep(DimmerItem)
72
+ # .select(&:on?)
73
+ # .each(&:off)
74
+ # end
75
+ # end
76
+ #
77
+ # @example
78
+ # rule 'Turn off any dimmers set to less than 50 at midnight' do
79
+ # every :day
80
+ # run do
81
+ # items.grep(DimmerItem)
82
+ # .select { |i| (1...50).cover?(i.state) }
83
+ # .each(&:off)
84
+ # end
85
+ # end
86
+ #
87
+ class DimmerItem < SwitchItem
88
+ include NumericItem
89
+
90
+ #
91
+ # Dim the dimmer
92
+ #
93
+ # @param [Integer] amount to dim by
94
+ # If 1 is the amount, the DECREASE command is sent, otherwise the
95
+ # current state - amount is sent as a command.
96
+ #
97
+ # @return [Integer] level target for dimmer
98
+ #
99
+ # @example
100
+ # DimmerOne.dim
101
+ # DimmerOne.dim(2)
102
+ #
103
+ def dim(amount = 1)
104
+ target = [state&.-(amount), 0].compact.max
105
+ command(target)
106
+ target
107
+ end
108
+
109
+ #
110
+ # Brighten the dimmer
111
+ #
112
+ # @param [Integer] amount to brighten by
113
+ # If 1 is the amount, the INCREASE command is sent, otherwise the
114
+ # current state + amount is sent as a command.
115
+ #
116
+ # @return [Integer] level target for dimmer
117
+ #
118
+ # @example
119
+ # DimmerOne.brighten
120
+ # DimmerOne.brighten(2)
121
+ #
122
+ def brighten(amount = 1)
123
+ target = [state&.+(amount), 100].compact.min
124
+ command(target)
125
+ target
126
+ end
127
+
128
+ # @!method increase
129
+ # Send the {INCREASE} command to the item
130
+ # @return [DimmerItem] `self`
131
+
132
+ # @!method decrease
133
+ # Send the {DECREASE} command to the item
134
+ # @return [DimmerItem] `self`
135
+
136
+ # raw numbers translate directly to PercentType, not a DecimalType
137
+ # @!visibility private
138
+ def format_type(command)
139
+ return Types::PercentType.new(command) if command.is_a?(Numeric)
140
+
141
+ super
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ # @!parse DimmerItem = OpenHAB::Core::Items::DimmerItem
@@ -0,0 +1,344 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module Items
6
+ java_import org.openhab.core.items.GenericItem
7
+
8
+ #
9
+ # The abstract base class for all items.
10
+ #
11
+ # @see https://www.openhab.org/javadoc/latest/org/openhab/core/items/genericitem
12
+ #
13
+ # @!attribute [r] name
14
+ # The item's name.
15
+ # @return [String]
16
+ #
17
+ # @!attribute [r] label
18
+ # The item's descriptive label.
19
+ # @return [String, nil]
20
+ #
21
+ class GenericItem
22
+ # rubocop:disable Naming/MethodName these mimic Java fields, which are
23
+ # actually methods
24
+ class << self
25
+ # manually define this, since the Java side doesn't
26
+ # @!visibility private
27
+ def ACCEPTED_COMMAND_TYPES
28
+ [org.openhab.core.types.RefreshType.java_class].freeze
29
+ end
30
+
31
+ # manually define this, since the Java side doesn't
32
+ # @!visibility private
33
+ def ACCEPTED_DATA_TYPES
34
+ [org.openhab.core.types.UnDefType.java_class].freeze
35
+ end
36
+
37
+ # @!visibility private
38
+ #
39
+ # Override to support Proxy
40
+ #
41
+ def ===(other)
42
+ other.is_a?(self)
43
+ end
44
+ end
45
+ # rubocop:enable Naming/MethodName
46
+
47
+ # @!attribute [r] accepted_command_types
48
+ # @return [Array<Class>] An array of {Command}s that can be sent as commands to this item
49
+
50
+ # @!attribute [r] accepted_data_types
51
+ # @return [Array<Class>] An array of {State}s that can be sent as commands to this item
52
+
53
+ alias_method :hash, :hash_code
54
+
55
+ # @!attribute [r] raw_state
56
+ #
57
+ # Get the raw item state.
58
+ #
59
+ # The state of the item, including possibly {NULL} or {UNDEF}
60
+ #
61
+ # @return [State]
62
+ #
63
+ alias_method :raw_state, :state
64
+
65
+ #
66
+ # Send a command to this item
67
+ #
68
+ # @param [Command] command command to send to the item
69
+ # @return [self]
70
+ #
71
+ # @see DSL::Items::TimedCommand#command
72
+ #
73
+ def command(command)
74
+ command = format_command(command)
75
+ logger.trace "Sending Command #{command} to #{name}"
76
+ org.openhab.core.model.script.actions.BusEvent.sendCommand(self, command)
77
+ self
78
+ end
79
+
80
+ # not an alias to allow easier stubbing and overriding
81
+ def <<(command)
82
+ command(command)
83
+ end
84
+
85
+ # @!parse alias_method :<<, :command
86
+
87
+ #
88
+ # Send an update to this item
89
+ #
90
+ # @param [State] state
91
+ # @return [self]
92
+ #
93
+ def update(state)
94
+ state = format_update(state)
95
+ logger.trace "Sending Update #{state} to #{name}"
96
+ org.openhab.core.model.script.actions.BusEvent.postUpdate(self, state)
97
+ self
98
+ end
99
+
100
+ #
101
+ # Check if the item has a state (not {UNDEF} or {NULL})
102
+ #
103
+ # @return [true, false]
104
+ #
105
+ def state?
106
+ !raw_state.is_a?(Types::UnDefType)
107
+ end
108
+
109
+ #
110
+ # @!attribute [r] state
111
+ # @return [State, nil]
112
+ # OpenHAB item state if state is not {UNDEF} or {NULL}, nil otherwise.
113
+ # This makes it easy to use with the
114
+ # [Ruby safe navigation operator `&.`](https://ruby-doc.org/core-2.6/doc/syntax/calling_methods_rdoc.html)
115
+ # Use {#undef?} or {#null?} to check for those states.
116
+ #
117
+ def state
118
+ raw_state if state?
119
+ end
120
+
121
+ #
122
+ # The item's {#label} if one is defined, otherwise it's {#name}.
123
+ #
124
+ # @return [String]
125
+ #
126
+ def to_s
127
+ label || name
128
+ end
129
+
130
+ #
131
+ # @!attribute [r] groups
132
+ #
133
+ # Return all groups that this item is part of
134
+ #
135
+ # @return [Array<Group>] All groups that this item is part of
136
+ #
137
+ def groups
138
+ group_names.map { |name| EntityLookup.lookup_item(name) }.compact
139
+ end
140
+
141
+ # rubocop:disable Layout/LineLength
142
+
143
+ # @!attribute [r] metadata
144
+ # @return [Metadata::NamespaceHash]
145
+ #
146
+ # Access to the item's metadata.
147
+ #
148
+ # Both the return value of this method as well as the individual
149
+ # namespaces can be treated as Hashes.
150
+ #
151
+ # Examples assume the following items:
152
+ #
153
+ # ```xtend
154
+ # Switch Item1 { namespace1="value" [ config1="foo", config2="bar" ] }
155
+ # String StringItem1
156
+ # ```
157
+ #
158
+ # @example Check namespace's existence
159
+ # Item1.metadata["namespace"].nil?
160
+ # Item1.metadata.key?("namespace")
161
+ #
162
+ # @example Access item's metadata value
163
+ # Item1.metadata["namespace1"].value
164
+ #
165
+ # @example Access namespace1's configuration
166
+ # Item1.metadata["namespace1"]["config1"]
167
+ #
168
+ # @example Safely search for the specified value - no errors are raised, only nil returned if a key in the chain doesn"t exist
169
+ # Item1.metadata.dig("namespace1", "config1") # => "foo"
170
+ # Item1.metadata.dig("namespace2", "config1") # => nil
171
+ #
172
+ # @example Set item's metadata value, preserving its config
173
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
174
+ # Item1.metadata["namespace1"].value = "new value"
175
+ # # Item1's metadata after: {"namespace1"=>["new value", {"config1"=>"foo", "config2"=>"bar"]}}
176
+ #
177
+ # @example Set item's metadata config, preserving its value
178
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
179
+ # Item1.metadata["namespace1"].replace({ "scooby"=>"doo" })
180
+ # # Item1's metadata after: {"namespace1"=>["value", {scooby="doo"}]}
181
+ #
182
+ # @example Set a namespace to a new value and config in one line
183
+ # # Item1's metadata before: {"namespace1"=>"value", {"config1"=>"foo", "config2"=>"bar"}}
184
+ # Item1.metadata["namespace1"] = "new value", { "scooby"=>"doo" }
185
+ # # Item1's metadata after: {"namespace1"=>["new value", {scooby="doo"}]}
186
+ #
187
+ # @example Set item's metadata value and clear its previous config
188
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
189
+ # Item1.metadata["namespace1"] = "new value"
190
+ # # Item1's metadata after: {"namespace1"=>"value" }
191
+ #
192
+ # @example Set item's metadata config, set its value to nil, and wiping out previous config
193
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
194
+ # Item1.metadata["namespace1"] = { "newconfig"=>"value" }
195
+ # # Item1's metadata after: {"namespace1"=>{"config1"=>"foo", "config2"=>"bar"}}
196
+ #
197
+ # @example Update namespace1's specific configuration, preserving its value and other config
198
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
199
+ # Item1.metadata["namespace1"]["config1"] = "doo"
200
+ # # Item1's metadata will be: {"namespace1"=>["value", {"config1"=>"doo", "config2"=>"bar"}]}
201
+ #
202
+ # @example Add a new configuration to namespace1
203
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
204
+ # Item1.metadata["namespace1"]["config3"] = "boo"
205
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar", config3="boo"}]}
206
+ #
207
+ # @example Delete a config
208
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
209
+ # Item1.metadata["namespace1"].delete("config2")
210
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo"}]}
211
+ #
212
+ # @example Add a namespace and set it to a value
213
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
214
+ # Item1.metadata["namespace2"] = "qx"
215
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace2"=>"qx"}
216
+ #
217
+ # @example Add a namespace and set it to a value and config
218
+ # # Item1's metadata before: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
219
+ # Item1.metadata["namespace2"] = "qx", { "config1"=>"doo" }
220
+ # # Item1's metadata after: {"namespace1"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace2"=>["qx", {"config1"=>"doo"}]}
221
+ #
222
+ # @example Enumerate Item1's namespaces
223
+ # Item1.metadata.each { |namespace, metadata| logger.info("Item1's namespace: #{namespace}=#{metadata}") }
224
+ #
225
+ # @example Add metadata from a hash
226
+ # Item1.metadata.merge!({"namespace1"=>{"foo", {"config1"=>"baz"} ], "namespace2"=>{"qux", {"config"=>"quu"} ]})
227
+ #
228
+ # @example Merge Item2's metadata into Item1's metadata
229
+ # Item1.metadata.merge!(Item2.metadata)
230
+ #
231
+ # @example Delete a namespace
232
+ # Item1.metadata.delete("namespace1")
233
+ #
234
+ # @example Delete all metadata of the item
235
+ # Item1.metadata.clear
236
+ #
237
+ # @example Does this item have any metadata?
238
+ # Item1.metadata.any?
239
+ #
240
+ # @example Store another item's state
241
+ # StringItem1.update "TEST"
242
+ # Item1.metadata["other_state"] = StringItem1.state
243
+ #
244
+ # @example Store event's state
245
+ # rule "save event state" do
246
+ # changed StringItem1
247
+ # run { |event| Item1.metadata["last_event"] = event.was }
248
+ # end
249
+ #
250
+ # @example If the namespace already exists: Update the value of a namespace but preserve its config; otherwise create a new namespace with the given value and nil config.
251
+ # Item1.metadata["namespace"] = "value", Item1.metadata["namespace"]
252
+ #
253
+ # @example Copy another namespace
254
+ # # Item1's metadata before: {"namespace2"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
255
+ # Item1.metadata["namespace"] = Item1.metadata["namespace2"]
256
+ # # Item1's metadata after: {"namespace2"=>["value", {"config1"=>"foo", "config2"=>"bar"}], "namespace"=>["value", {"config1"=>"foo", "config2"=>"bar"}]}
257
+ #
258
+ def metadata
259
+ @metadata ||= Metadata::NamespaceHash.new(name)
260
+ end
261
+ # rubocop:enable Layout/LineLength
262
+
263
+ # Return the item's thing if this item is linked with a thing. If an item is linked to more than one thing,
264
+ # this method only returns the first thing.
265
+ #
266
+ # @return [Thing] The thing associated with this item or nil
267
+ def thing
268
+ all_linked_things.first
269
+ end
270
+ alias_method :linked_thing, :thing
271
+
272
+ # Returns all of the item's linked things.
273
+ #
274
+ # @return [Array<Thing>] An array of things or an empty array
275
+ def things
276
+ registry = OSGi.service("org.openhab.core.thing.link.ItemChannelLinkRegistry")
277
+ channels = registry.get_bound_channels(name).to_a
278
+ channels.map(&:thing_uid).uniq.map { |tuid| EntityLookup.lookup_thing(tuid) }.compact
279
+ end
280
+ alias_method :all_linked_things, :things
281
+
282
+ # @!method null?
283
+ # Check if the item state == {NULL}
284
+ # @return [true,false]
285
+
286
+ # @!method undef?
287
+ # Check if the item state == {UNDEF}
288
+ # @return [true,false]
289
+
290
+ # @!method refresh
291
+ # Send the {REFRESH} command to the item
292
+ # @return [GenericItem] `self`
293
+
294
+ # @!visibility private
295
+ def format_command(command)
296
+ command = format_type(command)
297
+ return command if command.is_a?(Types::Command)
298
+
299
+ command = command.to_s
300
+ org.openhab.core.types.TypeParser.parse_command(getAcceptedCommandTypes, command) || command
301
+ end
302
+
303
+ # @!visibility private
304
+ def format_update(state)
305
+ state = format_type(state)
306
+ return state if state.is_a?(Types::State)
307
+
308
+ state = state.to_s
309
+ org.openhab.core.types.TypeParser.parse_state(getAcceptedDataTypes, state) || state
310
+ end
311
+
312
+ # formats a {Types::Type} to send to the event bus
313
+ # @!visibility private
314
+ def format_type(type)
315
+ # actual Type types can be sent directly without conversion
316
+ # make sure to use Type, because this method is used for both
317
+ # #update and #command
318
+ return type if type.is_a?(Types::Type)
319
+
320
+ type.to_s
321
+ end
322
+
323
+ # @return [String]
324
+ def inspect
325
+ s = "#<OpenHAB::Core::Items::#{type}Item#{type_details} #{name} #{label.inspect} state=#{raw_state.inspect}"
326
+ s += " category=#{category.inspect}" if category
327
+ s += " tags=#{tags.to_a.inspect}" unless tags.empty?
328
+ s += " groups=#{group_names}" unless group_names.empty?
329
+ meta = metadata.to_h
330
+ s += " metadata=#{meta.inspect}" unless meta.empty?
331
+ "#{s}>"
332
+ end
333
+
334
+ private
335
+
336
+ # Allows sub-classes to append additional details to the type in an inspect string
337
+ # @return [String]
338
+ def type_details; end
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ # @!parse GenericItem = OpenHAB::Core::Items::GenericItem