openhab-jrubyscripting 5.0.0.rc1

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 (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,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Additions to Enumerable to allow easily filtering and commanding groups of items.
5
+ #
6
+ # @example Turn on all members of a group
7
+ # gOutsideLights.members.on
8
+ #
9
+ # @example Turn on all lights that are tagged `NightLights`
10
+ # items.tagged("NightLights").on
11
+ #
12
+ # @example Close all blinds in the same room when the TV is turned on
13
+ # rule "Close Blinds" do
14
+ # changed gTVPower.members, to: ON
15
+ # triggered do |item|
16
+ # item.location
17
+ # .equipments(Semantics::Blinds)
18
+ # .points(Semantics::OpenLevel)
19
+ # .down
20
+ # end
21
+ # end
22
+ #
23
+ # @example {OpenHAB::DSL::Items::Ensure::Ensurable Ensure} works on Enumerable
24
+ # gLights.members.ensure.on
25
+ # # or
26
+ # gLights.members.ensure << ON
27
+ #
28
+ # @example Send a command to a list of items
29
+ # [Light1, Light2, Light3].on
30
+ # # or
31
+ # [Light1, Light2, Light3].command(ON) # can't use <<, because that's already defined on Array
32
+ #
33
+ # @see OpenHAB::Core::Items::Semantics Semantics
34
+ #
35
+
36
+ module Enumerable
37
+ #
38
+ # @!group Filtering Methods
39
+ # Methods to help filter the members of the Enumerable
40
+ #
41
+
42
+ # Returns a new array of items that have at least one of the given tags
43
+ # @return [Array<GenericItem>]
44
+ def tagged(*tags)
45
+ reject { |i| (tags & i.tags.to_a).empty? }
46
+ end
47
+
48
+ # Returns a new array of items that do not have any of the given tags
49
+ # @return [Array<GenericItem>]
50
+ def not_tagged(*tags)
51
+ select { |i| (tags & i.tags.to_a).empty? }
52
+ end
53
+
54
+ # Returns a new array of items that are a member of at least one of the given groups
55
+ # @return [Array<GenericItem>]
56
+ def member_of(*groups)
57
+ reject { |i| (groups.map(&:name) & i.group_names).empty? }
58
+ end
59
+
60
+ # Returns a new array of items that are not a member of any of the given groups
61
+ # @return [Array<GenericItem>]
62
+ def not_member_of(*groups)
63
+ select { |i| (groups.map(&:name) & i.group_names).empty? }
64
+ end
65
+
66
+ # Returns the group members the elements
67
+ # @return [Array<GenericItem>]
68
+ def members
69
+ grep(OpenHAB::Core::Items::GroupItem).flat_map(&:members)
70
+ end
71
+
72
+ # @!group Items State and Command Methods
73
+
74
+ # Send a command to every item in the collection
75
+ # @return [self]
76
+ def command(command)
77
+ each { |i| i.command(command) }
78
+ end
79
+
80
+ # Update the state of every item in the collection
81
+ # @return [self]
82
+ def update(state)
83
+ each { |i| i.update(state) }
84
+ end
85
+
86
+ # @!method refresh
87
+ # Send the {REFRESH} command to every item in the collection
88
+ # @return [self]
89
+
90
+ # @!method on
91
+ # Send the {ON} command to every item in the collection
92
+ # @return [self]
93
+
94
+ # @!method off
95
+ # Send the {OFF} command to every item in the collection
96
+ # @return [self]
97
+
98
+ # @!method up
99
+ # Send the {UP} command to every item in the collection
100
+ # @return [self]
101
+
102
+ # @!method down
103
+ # Send the {DOWN} command to every item in the collection
104
+ # @return [self]
105
+
106
+ # @!method stop
107
+ # Send the {STOP} command to every item in the collection
108
+ # @return [self]
109
+
110
+ # @!method move
111
+ # Send the {MOVE} command to every item in the collection
112
+ # @return [self]
113
+
114
+ # @!method increase
115
+ # Send the {INCREASE} command to every item in the collection
116
+ # @return [self]
117
+
118
+ # @!method decrease
119
+ # Send the {DECREASE} command to every item in the collection
120
+ # @return [self]
121
+
122
+ # @!method play
123
+ # Send the {PLAY} command to every item in the collection
124
+ # @return [self]
125
+
126
+ # @!method pause
127
+ # Send the {PAUSE} command to every item in the collection
128
+ # @return [self]
129
+
130
+ # @!method rewind
131
+ # Send the {REWIND} command to every item in the collection
132
+ # @return [self]
133
+
134
+ # @!method fast_forward
135
+ # Send the {FASTFORWARD} command to every item in the collection
136
+ # @return [self]
137
+
138
+ # @!method next
139
+ # Send the {NEXT} command to every item in the collection
140
+ # @return [self]
141
+
142
+ # @!method previous
143
+ # Send the {PREVIOUS} command to every item in the collection
144
+ # @return [self]
145
+
146
+ # @!visibility private
147
+ # can't use `include`, because Enumerable has already been included
148
+ # in other classes
149
+ def ensure
150
+ OpenHAB::DSL::Items::Ensure::GenericItemDelegate.new(self)
151
+ end
152
+ end
@@ -0,0 +1,476 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ require_relative "generic_item"
6
+ require_relative "group_item"
7
+ require_relative "semantics/enumerable"
8
+
9
+ module OpenHAB
10
+ module Core
11
+ module Items
12
+ # Module for implementing semantics helper methods on {GenericItem} in order to easily navigate
13
+ # the {https://www.openhab.org/docs/tutorial/model.html Semantic Model} in your scripts.
14
+ # This can be extremely useful to find related items in rules that are executed for any member of a group.
15
+ #
16
+ # Wraps {org.openhab.core.model.script.actions.Semantics} as well as adding a few additional convenience methods.
17
+ # Also includes classes for each semantic tag.
18
+ #
19
+ # Be warned that the Semantic model is stricter than can actually be
20
+ # described by tags and groups on an Item. It makes assumptions that any
21
+ # given item only belongs to one semantic type ({Location}, {Equipment}, {Point}).
22
+ #
23
+ # ## Enumerable helper methods
24
+ #
25
+ # {Enumerable Enumerable helper methods} are also provided to complement the semantic model. These methods can be
26
+ # chained together to find specific item(s) based on custom tags or group memberships that are outside
27
+ # the semantic model.
28
+ #
29
+ # The Enumerable helper methods apply to:
30
+ #
31
+ # * {GroupItem#members} and {GroupItem#all_members}. This includes semantic
32
+ # {#location} and {#equipment} because they are also group items.
33
+ # An exception is for Equipments that are an item (not a group)
34
+ # * Array of items, such as the return value of {Enumerable#equipments}, {Enumerable#locations},
35
+ # {Enumerable#points}, {Enumerable#tagged}, {Enumerable#not_tagged}, {Enumerable#member_of},
36
+ # {Enumerable#not_member_of}, {Enumerable#members} methods, etc.
37
+ # * {OpenHAB::DSL.items items[]} hash which contains all items in the system.
38
+ #
39
+ # ## Semantic Classes
40
+ #
41
+ # Each [Semantic
42
+ # Tag](https://github.com/openhab/openhab-core/blob/main/bundles/org.openhab.core.semantics/model/SemanticTags.csv)
43
+ # has a corresponding class within the {org.openhab.core.semantics} class hierarchy.
44
+ # These "semantic classes" are available as constants in the {Semantics} module with the corresponding name.
45
+ # The following table illustrates the semantic constants:
46
+ #
47
+ # | Semantic Constant | openHAB's Semantic Class |
48
+ # | ----------------------- | ------------------------------------------------------ |
49
+ # | `Semantics::LivingRoom` | `org.openhab.core.semantics.model.location.LivingRoom` |
50
+ # | `Semantics::Lightbulb` | `org.openhab.core.semantics.model.equipment.Lightbulb` |
51
+ # | `Semantics::Control` | `org.openhab.core.semantics.model.point.Control` |
52
+ # | `Semantics::Switch` | `org.openhab.core.semantics.model.point.Switch` |
53
+ # | `Semantics::Power` | `org.openhab.core.semantics.model.property.Power` |
54
+ # | ... | ... |
55
+ #
56
+ # These constants can be used as arguments to the {#points},
57
+ # {Enumerable#locations} and {Enumerable#equipments} methods to filter
58
+ # their results. They can also be compared against the return value of
59
+ # {#semantic_type}, {#location_type}, {#equipment_type}, {#point_type},
60
+ # and {#property_type}. They can even be used with
61
+ # {DSL::Items::ItemBuilder#tag}.
62
+ #
63
+ # @see https://github.com/openhab/openhab-core/blob/main/bundles/org.openhab.core.semantics/model/SemanticTags.csv Semantic Tags Table
64
+ #
65
+ # @example Working with tags
66
+ # # Return an array of sibling points with a "Switch" tag
67
+ # Light_Color.points(Semantics::Switch)
68
+ #
69
+ # # check semantic type
70
+ # LoungeRoom_Light.equipment_type == Semantics::Lightbulb
71
+ # Light_Color.property_type == Semantics::Light
72
+ #
73
+ # @example switches.items
74
+ # Group gFullOn
75
+ # Group gRoomOff
76
+ #
77
+ # Group eGarageLights "Garage Lights" (lGarage) [ "Lightbulb" ]
78
+ # Dimmer GarageLights_Dimmer "Garage Lights" <light> (eGarageLights) [ "Switch" ]
79
+ # Number GarageLights_Scene "Scene" (eGarageLights, gFullOn, gRoomOff)
80
+ #
81
+ # Group eMudLights "Mud Room Lights" (lMud) [ "Lightbulb" ]
82
+ # Dimmer MudLights_Dimmer "Garage Lights" <light> (eMudLights) [ "Switch" ]
83
+ # Number MudLights_Scene "Scene" (eMudLights, gFullOn, gRoomOff)
84
+ #
85
+ # @example Find the switch item for a scene channel on a zwave dimmer
86
+ # rule "turn dimmer to full on when switch double-tapped up" do
87
+ # changed gFullOn.members, to: 1.3
88
+ # run do |event|
89
+ # dimmer_item = event.item.points(Semantics::Switch).first
90
+ # dimmer_item.ensure << 100
91
+ # end
92
+ # end
93
+ #
94
+ # @example Turn off all the lights in a room
95
+ # rule "turn off all lights in the room when switch double-tapped down" do
96
+ # changed gRoomOff.members, to: 2.3
97
+ # run do |event|
98
+ # event
99
+ # .item
100
+ # .location
101
+ # .equipments(Semantics::Lightbulb)
102
+ # .members
103
+ # .points(Semantics::Switch)
104
+ # .ensure.off
105
+ # end
106
+ # end
107
+ #
108
+ # @example Finding a related item that doesn't fit in the semantic model
109
+ # # We can use custom tags to identify certain items that don't quite fit in the semantic model.
110
+ # # The extensions to the Enumerable mentioned above can help in this scenario.
111
+ #
112
+ # # In the following example, the TV `Equipment` has three `Points`. However, we are using custom tags
113
+ # # `Application` and `Channel` to identify the corresponding points, since the semantic model
114
+ # # doesn't have a specific property for them.
115
+ #
116
+ # # Here, we use Enumerable#tagged
117
+ # # to find the point with the custom tag that we want.
118
+ #
119
+ # # Item model:
120
+ # Group gTVPower
121
+ # Group lLivingRoom [ "LivingRoom" ]
122
+ #
123
+ # Group eTV "TV" (lLivingRoom) [ "Television" ]
124
+ # Switch TV_Power "Power" (eTV, gTVPower) [ "Switch", "Power" ]
125
+ # String TV_Application "App" (eTV) [ "Control", "Application" ]
126
+ # String TV_Channel "Channel" (eTV) [ "Control", "Channel" ]
127
+ #
128
+ # # Rule:
129
+ # rule 'Switch TV to Netflix on startup' do
130
+ # changed gTVPower.members, to: ON
131
+ # run do |event|
132
+ # application = event.item.points.tagged('Application').first
133
+ # application << 'netflix'
134
+ # end
135
+ # end
136
+ #
137
+ # @example Find all semantic entities regardless of hierarchy
138
+ # # All locations
139
+ # items.locations
140
+ #
141
+ # # All rooms
142
+ # items.locations(Semantics::Room)
143
+ #
144
+ # # All equipments
145
+ # items.equipments
146
+ #
147
+ # # All lightbulbs
148
+ # items.equipments(Semantics::Lightbulb)
149
+ #
150
+ # # All blinds
151
+ # items.equipments(Semantics::Blinds)
152
+ #
153
+ # # Turn off all "Power control"
154
+ # items.points(Semantics::Control, Semantics::Power).off
155
+ #
156
+ # # All items tagged "SmartLightControl"
157
+ # items.tagged("SmartLightControl")
158
+ #
159
+ #
160
+ module Semantics
161
+ GenericItem.include(self)
162
+ GroupItem.extend(Forwardable)
163
+ GroupItem.def_delegators :members, :equipments, :locations
164
+ # @!parse
165
+ # class Items::GroupItem
166
+ # #
167
+ # # @!attribute [r] equipments
168
+ # #
169
+ # # Calls {Enumerable#equipments members.equipments}.
170
+ # #
171
+ # # @return (see Enumerable#equipments)
172
+ # #
173
+ # # @see Enumerable#equipments
174
+ # #
175
+ # def equipments; end
176
+ #
177
+ # #
178
+ # # @!attribute [r] locations
179
+ # #
180
+ # # Calls {Enumerable#locations members.locations}.
181
+ # #
182
+ # # @return (see Enumerable#locations)
183
+ # #
184
+ # # @see Enumerable#locations
185
+ # #
186
+ # def locations; end
187
+ # end
188
+ #
189
+
190
+ # @!visibility private
191
+ # import the actual semantics action
192
+ SemanticsAction = org.openhab.core.model.script.actions.Semantics
193
+ private_constant :SemanticsAction
194
+
195
+ # import all the semantics constants
196
+ [org.openhab.core.semantics.model.point.Points,
197
+ org.openhab.core.semantics.model.property.Properties,
198
+ org.openhab.core.semantics.model.equipment.Equipments,
199
+ org.openhab.core.semantics.model.location.Locations].each do |parent_tag|
200
+ parent_tag.stream.for_each do |tag|
201
+ const_set(tag.simple_name.to_sym, tag.ruby_class)
202
+ end
203
+ end
204
+ # This is a marker interface for all semantic tag classes.
205
+ # @interface
206
+ Tag = org.openhab.core.semantics.Tag
207
+
208
+ # @!parse
209
+ # # This is the super interface for all types that represent a Location.
210
+ # # @interface
211
+ # Location = org.openhab.core.semantics.Location
212
+ #
213
+ # # This is the super interface for all types that represent an Equipment.
214
+ # # @interface
215
+ # Equipment = org.openhab.core.semantics.Equipment
216
+ #
217
+ # # This is the super interface for all types that represent a Point.
218
+ # # @interface
219
+ # Point = org.openhab.core.semantics.Point
220
+ #
221
+ # # This is the super interface for all property tags.
222
+ # # @interface
223
+ # Property = org.openhab.core.semantics.Property
224
+
225
+ # put ourself into the global namespace, replacing the action
226
+ ::Semantics = self # rubocop:disable Naming/ConstantName
227
+
228
+ #
229
+ # Checks if this Item is a {Location}
230
+ #
231
+ # This is implemented as checking if the item's {#semantic_type}
232
+ # is a {Location}. I.e. an Item has a single {#semantic_type}.
233
+ #
234
+ # @return [true, false]
235
+ #
236
+ def location?
237
+ SemanticsAction.location?(self)
238
+ end
239
+
240
+ #
241
+ # Checks if this Item is an {Equipment}
242
+ #
243
+ # This is implemented as checking if the item's {#semantic_type}
244
+ # is an {Equipment}. I.e. an Item has a single {#semantic_type}.
245
+ #
246
+ # @return [true, false]
247
+ #
248
+ def equipment?
249
+ SemanticsAction.equipment?(self)
250
+ end
251
+
252
+ # Checks if this Item is a {Point}
253
+ #
254
+ # This is implemented as checking if the item's {#semantic_type}
255
+ # is a {Point}. I.e. an Item has a single {#semantic_type}.
256
+ #
257
+ # @return [true, false]
258
+ #
259
+ def point?
260
+ SemanticsAction.point?(self)
261
+ end
262
+
263
+ #
264
+ # Checks if this Item has any semantic tags
265
+ #
266
+ # @return [true, false]
267
+ #
268
+ def semantic?
269
+ !!semantic_type
270
+ end
271
+
272
+ #
273
+ # @!attribute [r] location
274
+ #
275
+ # Gets the related {Location} Item of this Item.
276
+ #
277
+ # Checks ancestor groups one level at a time, returning the first
278
+ # {Location} Item found.
279
+ #
280
+ # @return [GenericItem, nil]
281
+ #
282
+ def location
283
+ SemanticsAction.get_location(self)&.then(&Proxy.method(:new))
284
+ end
285
+
286
+ #
287
+ # @!attribute [r] location_type
288
+ #
289
+ # Returns the sub-class of {Location} related to this Item.
290
+ #
291
+ # In other words, the {#semantic_type} of this Item's {Location}.
292
+ #
293
+ # @return [Class, nil]
294
+ #
295
+ def location_type
296
+ SemanticsAction.get_location_type(self)&.ruby_class
297
+ end
298
+
299
+ #
300
+ # @!attribute [r] equipment
301
+ #
302
+ # Gets the related {Equipment} Item of this Item.
303
+ #
304
+ # Checks ancestor groups one level at a time, returning the first {Equipment} Item found.
305
+ #
306
+ # @return [GenericItem, nil]
307
+ #
308
+ def equipment
309
+ SemanticsAction.get_equipment(self)&.then(&Proxy.method(:new))
310
+ end
311
+
312
+ #
313
+ # @!attribute [r] equipment_type
314
+ #
315
+ # Returns the sub-class of {Equipment} related to this Item.
316
+ #
317
+ # In other words, the {#semantic_type} of this Item's {Equipment}.
318
+ #
319
+ # @return [Class, nil]
320
+ #
321
+ def equipment_type
322
+ SemanticsAction.get_equipment_type(self)&.ruby_class
323
+ end
324
+
325
+ #
326
+ # @!attribute [r] point_type
327
+ #
328
+ # Returns the sub-class of {Point} this Item is tagged with.
329
+ #
330
+ # @return [Class, nil]
331
+ #
332
+ def point_type
333
+ SemanticsAction.get_point_type(self)&.ruby_class
334
+ end
335
+
336
+ #
337
+ # @!attribute [r] property_type
338
+ #
339
+ # Returns the sub-class of {Property} this Item is tagged with.
340
+ #
341
+ # @return [Class, nil]
342
+ #
343
+ def property_type
344
+ SemanticsAction.get_property_type(self)&.ruby_class
345
+ end
346
+
347
+ # @!attribute [r] semantic_type
348
+ #
349
+ # Returns the sub-class of {Tag} this Item is tagged with.
350
+ #
351
+ # It will only return the first applicable Tag, preferring
352
+ # a sub-class of {Location}, {Equipment}, or {Point} first,
353
+ # and if none of those are found, looks for a {Property}.
354
+ #
355
+ # @return [Class, nil]
356
+ #
357
+ def semantic_type
358
+ SemanticsAction.get_semantic_type(self)&.ruby_class
359
+ end
360
+
361
+ #
362
+ # Return the related Point Items.
363
+ #
364
+ # Searches this Equipment Item for Points that are tagged appropriately.
365
+ #
366
+ # If called on a Point Item, it will automatically search for sibling Points
367
+ # (and remove itself if found).
368
+ #
369
+ # @example Get all points for a TV
370
+ # eGreatTV.points
371
+ # @example Search an Equipment item for its switch
372
+ # eGuestFan.points(Semantics::Switch) # => [GuestFan_Dimmer]
373
+ # @example Search a Thermostat item for its current temperature item
374
+ # eFamilyThermostat.points(Semantics::Status, Semantics::Temperature)
375
+ # # => [FamilyThermostat_AmbTemp]
376
+ # @example Search a Thermostat item for is setpoints
377
+ # eFamilyThermostat.points(Semantics::Control, Semantics::Temperature)
378
+ # # => [FamilyThermostat_HeatingSetpoint, FamilyThermostat_CoolingSetpoint]
379
+ # @example Given a A/V receiver's input item, search for its power item
380
+ # FamilyReceiver_Input.points(Semantics::Switch) # => [FamilyReceiver_Switch]
381
+ #
382
+ # @param [Class] point_or_property_types
383
+ # Pass 1 or 2 classes that are sub-classes of {Point} or {Property}.
384
+ # Note that when comparing against semantic tags, it does a sub-class check.
385
+ # So if you search for [Control], you'll get items tagged with [Switch].
386
+ # @return [Array<GenericItem>]
387
+ #
388
+ def points(*point_or_property_types)
389
+ return members.points(*point_or_property_types) if equipment? || location?
390
+
391
+ # automatically search the parent equipment (or location?!) for sibling points
392
+ result = (equipment || location)&.points(*point_or_property_types) || []
393
+ result.delete(self)
394
+ result
395
+ end
396
+ end
397
+ end
398
+ end
399
+ end
400
+
401
+ # @!parse Semantics = OpenHAB::Core::Items::Semantics
402
+
403
+ # Additions to Enumerable to allow easily filtering groups of items based on the semantic model
404
+ module Enumerable
405
+ #
406
+ # @!group Filtering Methods
407
+ #
408
+
409
+ # Returns a new array of items that are a semantics Location (optionally of the given type)
410
+ # @return [Array<GenericItem>]
411
+ def locations(type = nil)
412
+ if type && (!type.is_a?(Module) || !(type < OpenHAB::Core::Items::Semantics::Location))
413
+ raise ArgumentError, "type must be a subclass of Location"
414
+ end
415
+
416
+ result = select(&:location?)
417
+ result.select! { |i| i.location_type <= type } if type
418
+
419
+ result
420
+ end
421
+
422
+ # Returns a new array of items that are a semantics equipment (optionally of the given type)
423
+ #
424
+ # @note As {Semantics::Equipment equipments} are usually
425
+ # {GroupItem GroupItems}, this method therefore returns an array of
426
+ # {GroupItem GroupItems}. In order to get the {Semantics::Point points}
427
+ # that belong to the {Semantics::Equipment equipments}, use {#members}
428
+ # before calling {#points}. See the example with {#points}.
429
+ #
430
+ # @return [Array<GenericItem>]
431
+ #
432
+ # @example Get all TVs in a room
433
+ # lGreatRoom.equipments(Semantics::Screen)
434
+ def equipments(type = nil)
435
+ if type && (!type.is_a?(Module) || !(type < OpenHAB::Core::Items::Semantics::Equipment))
436
+ raise ArgumentError, "type must be a subclass of Equipment"
437
+ end
438
+
439
+ result = select(&:equipment?)
440
+ result.select! { |i| i.equipment_type <= type } if type
441
+
442
+ result
443
+ end
444
+
445
+ # Returns a new array of items that are semantics points (optionally of a given type)
446
+ #
447
+ # @return [Array<GenericItem>]
448
+ #
449
+ # @example Get all the power switch items for every equipment in a room
450
+ # lGreatRoom.equipments.members.points(Semantics::Switch)
451
+ #
452
+ # @see #members
453
+ #
454
+ def points(*point_or_property_types)
455
+ unless (0..2).cover?(point_or_property_types.length)
456
+ raise ArgumentError, "wrong number of arguments (given #{point_or_property_types.length}, expected 0..2)"
457
+ end
458
+ unless point_or_property_types.all? do |tag|
459
+ tag.is_a?(Module) &&
460
+ (tag < OpenHAB::Core::Items::Semantics::Point || tag < OpenHAB::Core::Items::Semantics::Property)
461
+ end
462
+ raise ArgumentError, "point_or_property_types must all be a subclass of Point or Property"
463
+ end
464
+ if point_or_property_types.count { |tag| tag < OpenHAB::Core::Items::Semantics::Point } > 1 ||
465
+ point_or_property_types.count { |tag| tag < OpenHAB::Core::Items::Semantics::Property } > 1
466
+ raise ArgumentError, "point_or_property_types cannot both be a subclass of Point or Property"
467
+ end
468
+
469
+ select do |point|
470
+ point.point? && point_or_property_types.all? do |tag|
471
+ (tag < OpenHAB::Core::Items::Semantics::Point && point.point_type <= tag) ||
472
+ (tag < OpenHAB::Core::Items::Semantics::Property && point.property_type&.<=(tag))
473
+ end
474
+ end
475
+ end
476
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module Items
8
+ #
9
+ # Delegates state storage to a Hash providing methods to operate with states
10
+ #
11
+ class StateStorage < SimpleDelegator
12
+ #
13
+ # Create a StateStorage object that stores the states of the given items
14
+ #
15
+ # @param [Array<Item>] items A list of items
16
+ #
17
+ # @return [StateStorage] A state storage object
18
+ #
19
+ # @!visibility private
20
+ def self.from_items(*items)
21
+ StateStorage.new(org.openhab.core.model.script.actions.BusEvent.store_states(*items).to_h)
22
+ end
23
+
24
+ #
25
+ # Restore the stored states of all items
26
+ #
27
+ # @return [void]
28
+ #
29
+ def restore
30
+ org.openhab.core.model.script.actions.BusEvent.restore_states(to_h)
31
+ end
32
+
33
+ #
34
+ # Restore states for items that have changed
35
+ #
36
+ # @return [void]
37
+ #
38
+ def restore_changes
39
+ org.openhab.core.model.script.actions.BusEvent.restore_states(select { |item, value| item.state != value })
40
+ end
41
+
42
+ #
43
+ # Detect if any items have changed states since being stored
44
+ #
45
+ # @return [true,false] True if any items have changed states, false otherwise
46
+ #
47
+ def changed?
48
+ any? { |item, value| item.state != value }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end