openhab-scripting 2.14.1 → 2.14.2

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab.rb +3 -0
  3. data/lib/openhab/core/dsl/actions.rb +1 -1
  4. data/lib/openhab/core/dsl/entities.rb +41 -4
  5. data/lib/openhab/core/dsl/gems.rb +1 -1
  6. data/lib/openhab/core/dsl/group.rb +3 -1
  7. data/lib/openhab/core/dsl/items/items.rb +3 -1
  8. data/lib/openhab/core/dsl/items/number_item.rb +151 -50
  9. data/lib/openhab/core/dsl/items/string_item.rb +21 -3
  10. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +66 -42
  11. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +2 -1
  12. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +2 -1
  13. data/lib/openhab/core/dsl/property.rb +15 -4
  14. data/lib/openhab/core/dsl/rule/automation_rule.rb +348 -0
  15. data/lib/openhab/core/dsl/rule/guard.rb +43 -6
  16. data/lib/openhab/core/dsl/rule/rule.rb +80 -367
  17. data/lib/openhab/core/dsl/rule/rule_config.rb +153 -0
  18. data/lib/openhab/core/dsl/rule/triggers/changed.rb +145 -0
  19. data/lib/openhab/core/dsl/rule/{channel.rb → triggers/channel.rb} +22 -8
  20. data/lib/openhab/core/dsl/rule/triggers/command.rb +106 -0
  21. data/lib/openhab/core/dsl/rule/{cron.rb → triggers/cron.rb} +36 -14
  22. data/lib/openhab/core/dsl/rule/triggers/trigger.rb +126 -0
  23. data/lib/openhab/core/dsl/rule/triggers/updated.rb +100 -0
  24. data/lib/openhab/core/dsl/time_of_day.rb +50 -24
  25. data/lib/openhab/core/dsl/timers.rb +2 -6
  26. data/lib/openhab/core/dsl/types/quantity.rb +106 -69
  27. data/lib/openhab/core/log.rb +3 -8
  28. data/lib/openhab/core/startup_delay.rb +1 -0
  29. data/lib/openhab/osgi.rb +7 -0
  30. data/lib/openhab/version.rb +1 -1
  31. metadata +10 -6
  32. data/lib/openhab/core/dsl/rule/item.rb +0 -203
  33. data/lib/openhab/core/dsl/rule/triggers.rb +0 -77
@@ -11,7 +11,7 @@ module OpenHAB
11
11
  #
12
12
  # Cron type rules
13
13
  #
14
- module Cron
14
+ module Triggers
15
15
  java_import org.openhab.core.automation.util.TriggerBuilder
16
16
  java_import org.openhab.core.config.core.Configuration
17
17
 
@@ -58,18 +58,12 @@ module OpenHAB
58
58
  #
59
59
  #
60
60
  def every(value, at: nil)
61
- case value
62
- when Symbol
63
- expression_map = EXPRESSION_MAP[value]
64
- expression_map = at_condition(expression_map, at) if at
65
- cron(map_to_cron(expression_map))
66
- when Java::JavaTime::Duration
67
- raise ArgumentError, '"at" cannot be used with duration' if at
68
-
69
- cron(map_to_cron(duration_to_map(value)))
70
- else
71
- raise ArgumentExpression, 'Unknown interval' unless expression_map
72
- end
61
+ cron_expression = case value
62
+ when Symbol then cron_from_symbol(value, at)
63
+ when Java::JavaTime::Duration then cron_from_duration(value, at)
64
+ else raise ArgumentExpression, 'Unknown interval'
65
+ end
66
+ cron(cron_expression)
73
67
  end
74
68
 
75
69
  #
@@ -83,6 +77,34 @@ module OpenHAB
83
77
 
84
78
  private
85
79
 
80
+ #
81
+ # Create a cron map from a duration
82
+ #
83
+ # @param [java::time::Duration] duration
84
+ # @param [Object] at TimeOfDay or String representing time of day
85
+ #
86
+ # @return [Hash] map describing cron expression
87
+ #
88
+ def cron_from_duration(duration, at)
89
+ raise ArgumentError, '"at" cannot be used with duration' if at
90
+
91
+ map_to_cron(duration_to_map(duration))
92
+ end
93
+
94
+ #
95
+ # Create a cron map from a symbol
96
+ #
97
+ # @param [Symbol] symbol
98
+ # @param [Object] at TimeOfDay or String representing time of day
99
+ #
100
+ # @return [Hash] map describing cron expression created from symbol
101
+ #
102
+ def cron_from_symbol(symbol, at)
103
+ expression_map = EXPRESSION_MAP[symbol]
104
+ expression_map = at_condition(expression_map, at) if at
105
+ map_to_cron(expression_map)
106
+ end
107
+
86
108
  #
87
109
  # Map cron expression to to cron string
88
110
  #
@@ -126,7 +148,7 @@ module OpenHAB
126
148
  #
127
149
  def at_condition(expression_map, at_time)
128
150
  if at_time
129
- tod = (at_time.is_a? TimeOfDay) ? at_time : TimeOfDay.parse(at_time)
151
+ tod = at_time.is_a?(TimeOfDay) ? at_time : TimeOfDay.parse(at_time)
130
152
  expression_map = expression_map.merge(hour: tod.hour, minute: tod.minute, second: tod.second)
131
153
  end
132
154
  expression_map
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'java'
5
+
6
+ module OpenHAB
7
+ module Core
8
+ module DSL
9
+ module Rule
10
+ #
11
+ # Module holds rule triggers
12
+ #
13
+ module Triggers
14
+ #
15
+ # Create a trigger for a thing
16
+ #
17
+ # @param [Thing] thing to create trigger for
18
+ # @param [Trigger] trigger to map with thing
19
+ # @param [State] to for thing
20
+ # @param [State] from state of thing
21
+ #
22
+ # @return [Array] Trigger and config for thing
23
+ #
24
+ def trigger_for_thing(thing, trigger, to = nil, from = nil)
25
+ config = { 'thingUID' => thing.uid.to_s }
26
+ config['status'] = trigger_state_from_symbol(to).to_s if to
27
+ config['previousStatus'] = trigger_state_from_symbol(from).to_s if from
28
+ [trigger, config]
29
+ end
30
+
31
+ #
32
+ # converts object to upcase string if its a symbol
33
+ #
34
+ # @param [sym] sym potential symbol to convert
35
+ #
36
+ # @return [String] Upcased symbol as string
37
+ #
38
+ def trigger_state_from_symbol(sym)
39
+ sym.to_s.upcase if (sym.is_a? Symbol) || sym
40
+ end
41
+
42
+ #
43
+ # Append a trigger to the list of triggeres
44
+ #
45
+ # @param [String] type of trigger to create
46
+ # @param [Map] config map describing trigger configuration
47
+ #
48
+ # @return [Trigger] OpenHAB trigger
49
+ #
50
+ def append_trigger(type, config)
51
+ logger.trace("Creating trigger of type #{type} for #{config}")
52
+ trigger = Trigger.trigger(type: type, config: config)
53
+ @triggers << trigger
54
+ trigger
55
+ end
56
+
57
+ #
58
+ # Class for creating and managing triggers
59
+ #
60
+ class Trigger
61
+ java_import org.openhab.core.automation.util.TriggerBuilder
62
+ java_import org.openhab.core.config.core.Configuration
63
+
64
+ # @return [String] A channel event trigger
65
+ CHANNEL_EVENT = 'core.ChannelEventTrigger'
66
+
67
+ # @return [String] A thing status Change trigger
68
+ THING_CHANGE = 'core.ThingStatusChangeTrigger'
69
+
70
+ # @return [String] A thing status update trigger
71
+ THING_UPDATE = 'core.ThingStatusUpdateTrigger'
72
+
73
+ # @return [String] An item command trigger
74
+ ITEM_COMMAND = 'core.ItemCommandTrigger'
75
+
76
+ # @return [String] An item state update trigger
77
+ ITEM_STATE_UPDATE = 'core.ItemStateUpdateTrigger'
78
+
79
+ # @return [String] An item state change trigger
80
+ ITEM_STATE_CHANGE = 'core.ItemStateChangeTrigger'
81
+
82
+ # @return [String] A group state change trigger for items in the group
83
+ GROUP_STATE_CHANGE = 'core.GroupStateChangeTrigger'
84
+
85
+ # @return [String] A group state update trigger for items in the group
86
+ GROUP_STATE_UPDATE = 'core.GroupStateUpdateTrigger'
87
+
88
+ # @return [String] A group command trigger for items in the group
89
+ GROUP_COMMAND = 'core.GroupCommandTrigger'
90
+
91
+ # @return [String] A time of day trigger
92
+ TIME_OF_DAY = 'timer.TimeOfDayTrigger'
93
+
94
+ # @return [String] A cron trigger
95
+ CRON = 'timer.GenericCronTrigger'
96
+
97
+ #
98
+ # Create a trigger
99
+ #
100
+ # @param [String] type of trigger
101
+ # @param [Map] config map
102
+ #
103
+ # @return [OpenHAB Trigger] configured by type and supplied config
104
+ #
105
+ def self.trigger(type:, config:)
106
+ TriggerBuilder.create
107
+ .with_id(uuid)
108
+ .with_type_uid(type)
109
+ .with_configuration(Configuration.new(config))
110
+ .build
111
+ end
112
+
113
+ #
114
+ # Generate a UUID for triggers
115
+ #
116
+ # @return [String] UUID
117
+ #
118
+ def self.uuid
119
+ SecureRandom.uuid
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'core/log'
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module DSL
8
+ module Rule
9
+ #
10
+ # Module holds rule triggers
11
+ #
12
+ module Triggers
13
+ include Logging
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
+ #
21
+ # @return [Trigger] Trigger for updated entity
22
+ #
23
+ def updated(*items, to: nil)
24
+ items.flatten.each do |item|
25
+ logger.trace("Creating updated trigger for item(#{item}) to(#{to})")
26
+ [to].flatten.each do |to_state|
27
+ trigger, config = create_update_trigger(item, to_state)
28
+ append_trigger(trigger, config)
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ #
36
+ # Create a trigger for updates
37
+ #
38
+ # @param [Object] item Type of item [Group,Thing,Item] to create update trigger for
39
+ # @param [State] to_state state restriction on trigger
40
+ #
41
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
42
+ # second element is a Hash configuring trigger
43
+ #
44
+ def create_update_trigger(item, to_state)
45
+ case item
46
+ when GroupItems then group_update(item, to_state)
47
+ when Thing then thing_update(item, to_state)
48
+ else item_update(item, to_state)
49
+ end
50
+ end
51
+
52
+ #
53
+ # Create an update trigger for an item
54
+ #
55
+ # @param [Item] item to create trigger for
56
+ # @param [State] to_state optional state restriction for target
57
+ #
58
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
59
+ # second element is a Hash configuring trigger
60
+ #
61
+ def item_update(item, to_state)
62
+ config = { 'itemName' => item.name }
63
+ config['state'] = to_state.to_s unless to_state.nil?
64
+ trigger = Trigger::ITEM_STATE_UPDATE
65
+ [trigger, config]
66
+ end
67
+
68
+ #
69
+ # Create an update trigger for a group
70
+ #
71
+ # @param [Item] item to create trigger for
72
+ # @param [State] to_state optional state restriction for target
73
+ #
74
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
75
+ # second element is a Hash configuring trigger
76
+ #
77
+ def group_update(item, to_state)
78
+ config = { 'groupName' => item.group.name }
79
+ config['state'] = to_state.to_s unless to_state.nil?
80
+ trigger = Trigger::GROUP_STATE_UPDATE
81
+ [trigger, config]
82
+ end
83
+
84
+ #
85
+ # Create an update trigger for a thing
86
+ #
87
+ # @param [Thing] thing to create trigger for
88
+ # @param [State] to_state optional state restriction for target
89
+ #
90
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
91
+ # second element is a Hash configuring trigger
92
+ #
93
+ def thing_update(thing, to_state)
94
+ trigger_for_thing(thing, Trigger::THING_UPDATE, to_state)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -50,7 +50,8 @@ module OpenHAB
50
50
 
51
51
  # Constructs a TimeOfDay representing the time when called
52
52
  # @since 0.0.1
53
- # @param [String] string representation of TimeOfDay. Valid formats include "HH:MM:SS", "HH:MM", "H:MM", "HH", "H", "H:MM am"
53
+ # @param [String] string representation of TimeOfDay. Valid formats include "HH:MM:SS", "HH:MM",
54
+ # "H:MM", "HH", "H", "H:MM am"
54
55
  # @return [TimeOfDay] object created by parsing supplied string
55
56
  def self.parse(string)
56
57
  format = /(am|pm)$/i.match?(string) ? 'h[:mm[:ss]][ ]a' : 'H[:mm[:ss]]'
@@ -67,10 +68,13 @@ module OpenHAB
67
68
  # @option opts [Number] :m Minute of the day, defaults to 0
68
69
  # @option opts [Number] :s Second of the day, defaults to 0
69
70
  # @return [TimeOfDay] representing time when method was invoked
71
+ # rubocop: disable Naming/MethodParameterName
72
+ # This method has a better feel with short parameter names
70
73
  def initialize(h: 0, m: 0, s: 0)
71
74
  @local_time = LocalTime.of(h, m, s)
72
75
  freeze
73
76
  end
77
+ # rubocop: enable Naming/MethodParameterName
74
78
 
75
79
  # Returns true if the time falls within a range
76
80
  def between?(range)
@@ -100,14 +104,16 @@ module OpenHAB
100
104
 
101
105
  # Returns the string representation of the TimeOfDay
102
106
  # @since 0.0.1
103
- # @return [String] in any of the following formats depending on time representation HH:mm, HH:mm:ss, HH:mm:ss.SSS, HH:mm:ss.SSSSSS, HH:mm:ss.SSSSSSSSS
107
+ # @return [String] in any of the following formats depending on time representation HH:mm, HH:mm:ss,
108
+ # HH:mm:ss.SSS, HH:mm:ss.SSSSSS, HH:mm:ss.SSSSSSSSS
104
109
  def to_s
105
110
  @local_time.to_s
106
111
  end
107
112
 
108
113
  # Compares one TimeOfDay to another
109
114
  # @since 0.0.1
110
- # @return [Number, nil] -1,0,1 if other TimeOfDay is less than, equal to, or greater than this TimeOfDay or nil if an object other than TimeOfDay is provided
115
+ # @return [Number, nil] -1,0,1 if other TimeOfDay is less than, equal to, or greater than this TimeOfDay
116
+ # or nil if an object other than TimeOfDay is provided
111
117
  def <=>(other)
112
118
  case other
113
119
  when TimeOfDay
@@ -143,28 +149,36 @@ module OpenHAB
143
149
  # @since 2.4.0
144
150
  # @return [Number, nil] -1,0,1 if other is less than, equal to, or greater than this TimeOfDay
145
151
  def <=>(other)
146
- other_second_of_day = case other
147
- when TimeOfDay
148
- adjust_second_of_day(other.local_time.to_second_of_day)
149
- when String
150
- adjust_second_of_day(TimeOfDay.parse(other).local_time.to_second_of_day)
151
- when Time
152
- adjust_second_of_day(TimeOfDay.new(h: other.hour, m: other.min,
153
- s: other.sec).local_time.to_second_of_day)
154
- when TimeOfDayRangeElement
155
- other.sod
156
- else
157
- raise ArgumentError, 'Supplied argument cannot be converted into Time Of Day Object'
158
- end
159
-
152
+ other_second_of_day = to_second_of_day(other)
160
153
  logger.trace do
161
- "SOD(#{sod}) other SOD(#{other_second_of_day}) Other Class (#{other.class}) Result (#{sod <=> other_second_of_day})"
154
+ "SOD(#{sod}) "\
155
+ "other SOD(#{other_second_of_day}) "\
156
+ "Other Class (#{other.class}) "\
157
+ "Result (#{sod <=> other_second_of_day})"
162
158
  end
163
159
  sod <=> other_second_of_day
164
160
  end
165
161
 
166
162
  private
167
163
 
164
+ #
165
+ # Convert object to the seconds of a day they reprsent
166
+ #
167
+ # @param [Object] object TimeofDay,String,Time, or TimeOfDayRangeElement to convert
168
+ #
169
+ # @return [Integer] seconds of day represented by supplied object
170
+ #
171
+ def to_second_of_day(object)
172
+ case object
173
+ when TimeOfDay then adjust_second_of_day(object.local_time.to_second_of_day)
174
+ when String then adjust_second_of_day(TimeOfDay.parse(object).local_time.to_second_of_day)
175
+ when Time then adjust_second_of_day(TimeOfDay.new(h: object.hour, m: object.min,
176
+ s: object.sec).local_time.to_second_of_day)
177
+ when TimeOfDayRangeElement then object.sod
178
+ else raise ArgumentError, 'Supplied argument cannot be converted into Time Of Day Object'
179
+ end
180
+ end
181
+
168
182
  def adjust_second_of_day(second_of_day)
169
183
  second_of_day += NUM_SECONDS_IN_DAY if second_of_day < @range_begin
170
184
  second_of_day
@@ -175,14 +189,13 @@ module OpenHAB
175
189
  # to see if they are within the range
176
190
  # @since 2.4.0
177
191
  # @return Range object representing a TimeOfDay Range
192
+ module_function
193
+
178
194
  def between(range)
179
195
  raise ArgumentError, 'Supplied object must be a range' unless range.is_a? Range
180
196
 
181
- start = range.begin
182
- ending = range.end
183
-
184
- start = TimeOfDay.parse(start) if start.is_a? String
185
- ending = TimeOfDay.parse(ending) if ending.is_a? String
197
+ start = to_time_of_day(range.begin)
198
+ ending = to_time_of_day(range.end)
186
199
 
187
200
  start_sod = start.local_time.to_second_of_day
188
201
  ending_sod = ending.local_time.to_second_of_day
@@ -192,7 +205,20 @@ module OpenHAB
192
205
  ending_range = TimeOfDayRangeElement.new(sod: ending_sod, range_begin: start_sod)
193
206
  range.exclude_end? ? (start_range...ending_range) : (start_range..ending_range)
194
207
  end
195
- module_function :between
208
+
209
+ #
210
+ # Convert object to TimeOfDay object
211
+ #
212
+ # @param [Object] object TimeOfDay or String to be converted
213
+ #
214
+ # @return [TimeOfDay] TimeOfDay created from supplied object
215
+ #
216
+ private_class_method def to_time_of_day(object)
217
+ case object
218
+ when String then TimeOfDay.parse(object)
219
+ else object
220
+ end
221
+ end
196
222
 
197
223
  MIDNIGHT = TimeOfDay.midnight
198
224
  NOON = TimeOfDay.noon
@@ -39,15 +39,11 @@ module OpenHAB
39
39
  # occurs before the @timer variable can be set resulting in @timer being nil
40
40
  semaphore = Mutex.new
41
41
 
42
- @block = proc do
43
- semaphore.synchronize do
44
- block.call(self)
45
- end
46
- end
42
+ timer_block = proc { semaphore.synchronize { block.call(self) } }
47
43
 
48
44
  semaphore.synchronize do
49
45
  @timer = ScriptExecution.createTimer(
50
- ZonedDateTime.now.plus(@duration), @block
46
+ ZonedDateTime.now.plus(@duration), timer_block
51
47
  )
52
48
  super(@timer)
53
49
  end