openhab-scripting 2.16.2 → 2.16.3

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab.rb +12 -16
  3. data/lib/openhab/core/entity_lookup.rb +162 -0
  4. data/lib/openhab/core/openhab_setup.rb +31 -0
  5. data/lib/openhab/core/osgi.rb +61 -0
  6. data/lib/openhab/dsl/actions.rb +105 -0
  7. data/lib/openhab/dsl/dsl.rb +47 -0
  8. data/lib/openhab/{core/dsl → dsl}/gems.rb +0 -1
  9. data/lib/openhab/dsl/group.rb +100 -0
  10. data/lib/openhab/dsl/items/items.rb +46 -0
  11. data/lib/openhab/dsl/items/number_item.rb +352 -0
  12. data/lib/openhab/dsl/items/string_item.rb +120 -0
  13. data/lib/openhab/dsl/monkey_patch/actions/actions.rb +4 -0
  14. data/lib/openhab/dsl/monkey_patch/actions/script_thing_actions.rb +32 -0
  15. data/lib/openhab/dsl/monkey_patch/events/events.rb +5 -0
  16. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +23 -0
  17. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +35 -0
  18. data/lib/openhab/dsl/monkey_patch/events/thing_status_info.rb +33 -0
  19. data/lib/openhab/dsl/monkey_patch/items/contact_item.rb +61 -0
  20. data/lib/openhab/dsl/monkey_patch/items/dimmer_item.rb +193 -0
  21. data/lib/openhab/dsl/monkey_patch/items/group_item.rb +37 -0
  22. data/lib/openhab/dsl/monkey_patch/items/items.rb +133 -0
  23. data/lib/openhab/dsl/monkey_patch/items/metadata.rb +281 -0
  24. data/lib/openhab/dsl/monkey_patch/items/persistence.rb +70 -0
  25. data/lib/openhab/dsl/monkey_patch/items/switch_item.rb +95 -0
  26. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +39 -0
  27. data/lib/openhab/dsl/monkey_patch/ruby/range.rb +47 -0
  28. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +7 -0
  29. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +41 -0
  30. data/lib/openhab/dsl/monkey_patch/types/decimal_type.rb +70 -0
  31. data/lib/openhab/dsl/monkey_patch/types/on_off_type.rb +51 -0
  32. data/lib/openhab/dsl/monkey_patch/types/open_closed_type.rb +36 -0
  33. data/lib/openhab/dsl/monkey_patch/types/percent_type.rb +32 -0
  34. data/lib/openhab/dsl/monkey_patch/types/quantity_type.rb +69 -0
  35. data/lib/openhab/dsl/monkey_patch/types/types.rb +8 -0
  36. data/lib/openhab/dsl/persistence.rb +25 -0
  37. data/lib/openhab/dsl/rules/automation_rule.rb +342 -0
  38. data/lib/openhab/dsl/rules/guard.rb +134 -0
  39. data/lib/openhab/dsl/rules/property.rb +102 -0
  40. data/lib/openhab/dsl/rules/rule.rb +116 -0
  41. data/lib/openhab/dsl/rules/rule_config.rb +151 -0
  42. data/lib/openhab/dsl/rules/triggers/changed.rb +143 -0
  43. data/lib/openhab/dsl/rules/triggers/channel.rb +53 -0
  44. data/lib/openhab/dsl/rules/triggers/command.rb +104 -0
  45. data/lib/openhab/dsl/rules/triggers/cron.rb +177 -0
  46. data/lib/openhab/dsl/rules/triggers/trigger.rb +124 -0
  47. data/lib/openhab/dsl/rules/triggers/updated.rb +98 -0
  48. data/lib/openhab/dsl/states.rb +61 -0
  49. data/lib/openhab/dsl/things.rb +91 -0
  50. data/lib/openhab/dsl/time_of_day.rb +228 -0
  51. data/lib/openhab/dsl/timers.rb +77 -0
  52. data/lib/openhab/dsl/types/quantity.rb +290 -0
  53. data/lib/openhab/dsl/units.rb +39 -0
  54. data/lib/openhab/log/configuration.rb +21 -0
  55. data/lib/openhab/log/logger.rb +172 -0
  56. data/lib/openhab/version.rb +1 -1
  57. metadata +55 -58
  58. data/lib/openhab/configuration.rb +0 -16
  59. data/lib/openhab/core/cron.rb +0 -27
  60. data/lib/openhab/core/debug.rb +0 -34
  61. data/lib/openhab/core/dsl.rb +0 -51
  62. data/lib/openhab/core/dsl/actions.rb +0 -107
  63. data/lib/openhab/core/dsl/entities.rb +0 -147
  64. data/lib/openhab/core/dsl/group.rb +0 -102
  65. data/lib/openhab/core/dsl/items/items.rb +0 -51
  66. data/lib/openhab/core/dsl/items/number_item.rb +0 -323
  67. data/lib/openhab/core/dsl/items/string_item.rb +0 -122
  68. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +0 -4
  69. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +0 -22
  70. data/lib/openhab/core/dsl/monkey_patch/events.rb +0 -5
  71. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +0 -13
  72. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +0 -25
  73. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +0 -26
  74. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +0 -54
  75. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +0 -182
  76. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +0 -27
  77. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +0 -132
  78. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +0 -283
  79. data/lib/openhab/core/dsl/monkey_patch/items/persistence.rb +0 -72
  80. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +0 -87
  81. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +0 -41
  82. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +0 -47
  83. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +0 -7
  84. data/lib/openhab/core/dsl/monkey_patch/ruby/string.rb +0 -43
  85. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +0 -60
  86. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +0 -41
  87. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +0 -25
  88. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +0 -23
  89. data/lib/openhab/core/dsl/monkey_patch/types/quantity_type.rb +0 -58
  90. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +0 -8
  91. data/lib/openhab/core/dsl/persistence.rb +0 -27
  92. data/lib/openhab/core/dsl/property.rb +0 -96
  93. data/lib/openhab/core/dsl/rule/automation_rule.rb +0 -345
  94. data/lib/openhab/core/dsl/rule/guard.rb +0 -136
  95. data/lib/openhab/core/dsl/rule/rule.rb +0 -117
  96. data/lib/openhab/core/dsl/rule/rule_config.rb +0 -153
  97. data/lib/openhab/core/dsl/rule/triggers/changed.rb +0 -145
  98. data/lib/openhab/core/dsl/rule/triggers/channel.rb +0 -55
  99. data/lib/openhab/core/dsl/rule/triggers/command.rb +0 -106
  100. data/lib/openhab/core/dsl/rule/triggers/cron.rb +0 -160
  101. data/lib/openhab/core/dsl/rule/triggers/trigger.rb +0 -126
  102. data/lib/openhab/core/dsl/rule/triggers/updated.rb +0 -100
  103. data/lib/openhab/core/dsl/states.rb +0 -63
  104. data/lib/openhab/core/dsl/things.rb +0 -93
  105. data/lib/openhab/core/dsl/time_of_day.rb +0 -231
  106. data/lib/openhab/core/dsl/timers.rb +0 -79
  107. data/lib/openhab/core/dsl/types/quantity.rb +0 -292
  108. data/lib/openhab/core/dsl/units.rb +0 -41
  109. data/lib/openhab/core/log.rb +0 -170
  110. data/lib/openhab/core/patch_load_path.rb +0 -7
  111. data/lib/openhab/core/startup_delay.rb +0 -23
  112. data/lib/openhab/osgi.rb +0 -59
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/log/logger'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module Rules
8
+ #
9
+ # Module holds rule triggers
10
+ #
11
+ module Triggers
12
+ include OpenHAB::Log
13
+
14
+ #
15
+ # Struct capturing data necessary for a conditional trigger
16
+ #
17
+ TriggerDelay = Struct.new(:to, :from, :duration, :timer, :tracking_to, keyword_init: true) do
18
+ def timer_active?
19
+ timer&.is_active
20
+ end
21
+ end
22
+
23
+ #
24
+ # Creates a trigger item, group and thing changed
25
+ #
26
+ # @param [Object] items array of objects to create trigger for
27
+ # @param [to] to state for object to change for
28
+ # @param [from] from <description>
29
+ # @param [OpenHAB::Core::Duration] for Duration to delay trigger until to state is met
30
+ #
31
+ # @return [Trigger] OpenHAB trigger
32
+ #
33
+ def changed(*items, to: nil, from: nil, for: nil)
34
+ items.flatten.each do |item|
35
+ logger.trace("Creating changed trigger for entity(#{item}), to(#{to}), from(#{from})")
36
+ # for is a reserved word in ruby, so use local_variable_get :for
37
+ if (wait_duration = binding.local_variable_get(:for))
38
+ changed_wait(item, to: to, from: from, duration: wait_duration)
39
+ else
40
+ # Place in array and flatten to support multiple to elements or single or nil
41
+ [to].flatten.each do |to_state|
42
+ create_changed_trigger(item, from, to_state)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ #
51
+ # Create a TriggerDelay for for an item or group that is changed for a specific duration
52
+ #
53
+ # @param [Object] item to create trigger delay for
54
+ # @param [OpenHAB::Core::Duration] duration to delay trigger for until condition is met
55
+ # @param [Item State] to OpenHAB Item State item or group needs to change to
56
+ # @param [Item State] from OpenHAB Item State item or group needs to be coming from
57
+ #
58
+ # @return [Array] Array of current TriggerDelay objects
59
+ #
60
+ def changed_wait(item, duration:, to: nil, from: nil)
61
+ # If GroupItems specified, use the group state trigger instead
62
+ if item.is_a? GroupItems
63
+ config = { 'groupName' => item.group.name }
64
+ trigger = Trigger::GROUP_STATE_CHANGE
65
+ else
66
+ config = { 'itemName' => item.name }
67
+ trigger = Trigger::ITEM_STATE_CHANGE
68
+ end
69
+ logger.trace("Creating Changed Wait Change Trigger for #{config}")
70
+ trigger = append_trigger(trigger, config)
71
+ @trigger_delays[trigger.id] = TriggerDelay.new(to: to, from: from, duration: duration)
72
+ end
73
+
74
+ #
75
+ # Create a changed trigger
76
+ #
77
+ # @param [Object] item to create changed trigger on
78
+ # @param [String] from state to restrict trigger to
79
+ # @param [String] to state restrict trigger to
80
+ #
81
+ #
82
+ def create_changed_trigger(item, from, to)
83
+ trigger, config = case item
84
+ when GroupItems then create_group_changed_trigger(item, from, to)
85
+ when Thing then create_thing_changed_trigger(item, from, to)
86
+ else create_item_changed_trigger(item, from, to)
87
+ end
88
+ append_trigger(trigger, config)
89
+ end
90
+
91
+ #
92
+ # Create a changed trigger for a thing
93
+ #
94
+ # @param [Thing] thing to detected changed states on
95
+ # @param [String] from state to restrict trigger to
96
+ # @param [String] to state to restrict trigger to
97
+ #
98
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
99
+ # second element is a Hash configuring trigger
100
+ #
101
+ def create_thing_changed_trigger(thing, from, to)
102
+ trigger_for_thing(thing, Trigger::THING_CHANGE, to, from)
103
+ end
104
+
105
+ #
106
+ # Create a changed trigger for an item
107
+ #
108
+ # @param [Item] item to detected changed states on
109
+ # @param [String] from state to restrict trigger to
110
+ # @param [String] to to restrict trigger to
111
+ #
112
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
113
+ # second element is a Hash configuring trigger
114
+ #
115
+ def create_item_changed_trigger(item, from, to)
116
+ config = { 'itemName' => item.name }
117
+ config['state'] = to.to_s if to
118
+ config['previousState'] = from.to_s if from
119
+ trigger = Trigger::ITEM_STATE_CHANGE
120
+ [trigger, config]
121
+ end
122
+
123
+ #
124
+ # Create a changed trigger for group items
125
+ #
126
+ # @param [Group] group to detected changed states on
127
+ # @param [String] from state to restrict trigger to
128
+ # @param [String] to to restrict trigger to
129
+ #
130
+ # @return [Array<Hash,String>] first element is a String specifying trigger type
131
+ # second element is a Hash configuring trigger
132
+ #
133
+ def create_group_changed_trigger(group, from, to)
134
+ config = { 'groupName' => group.group.name }
135
+ config['state'] = to.to_s if to
136
+ config['previousState'] = from.to_s if from
137
+ trigger = Trigger::GROUP_STATE_CHANGE
138
+ [trigger, config]
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/log/logger'
4
+ require 'openhab/dsl/rules/triggers/trigger'
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ module Rules
9
+ #
10
+ # Channel triggers
11
+ #
12
+ module Triggers
13
+ include OpenHAB::Log
14
+
15
+ #
16
+ # Creates a channel trigger
17
+ #
18
+ # @param [Array] channels array to create triggers for on form of 'binding_id:type_id:thing_id#channel_id'
19
+ # or 'channel_id' if thing is provided
20
+ # @param [thing] thing to create trigger for if not specified with the channel
21
+ # @param [String] triggered specific triggering condition to match for trigger
22
+ #
23
+ #
24
+ def channel(*channels, thing: nil, triggered: nil)
25
+ channels.flatten.each do |channel|
26
+ channel = [thing, channel].join(':') if thing
27
+ logger.trace("Creating channel trigger for channel(#{channel}), thing(#{thing}), trigger(#{triggered})")
28
+ [triggered].flatten.each do |trigger|
29
+ create_channel_trigger(channel, trigger)
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ #
37
+ # Create a trigger for a channel
38
+ #
39
+ # @param [Channel] channel to look for triggers
40
+ # @param [Trigger] trigger specific channel trigger to match
41
+ #
42
+ #
43
+ def create_channel_trigger(channel, trigger)
44
+ config = { 'channelUID' => channel }
45
+ config['event'] = trigger.to_s unless trigger.nil?
46
+ config['channelUID'] = channel
47
+ logger.trace("Creating Change Trigger for #{config}")
48
+ @triggers << Trigger.trigger(type: Trigger::CHANNEL_EVENT, config: config)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/log/logger'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module Rules
8
+ #
9
+ # Module holds rule triggers
10
+ #
11
+ module Triggers
12
+ include OpenHAB::Log
13
+
14
+ #
15
+ # Create a trigger for when an item or group receives a command
16
+ #
17
+ # The commands/commands parameters are replicated for DSL fluency
18
+ #
19
+ # @param [Array] items Array of items to create trigger for
20
+ # @param [Array] command commands to match for trigger
21
+ # @param [Array] commands commands to match for trigger
22
+ #
23
+ #
24
+ def received_command(*items, command: nil, commands: nil)
25
+ items.flatten.each do |item|
26
+ logger.trace("Creating received command trigger for item(#{item})"\
27
+ "command(#{command}) commands(#{commands})")
28
+
29
+ # Combine command and commands, doing union so only a single nil will be in the combined array.
30
+ combined_commands = combine_commands(command, commands)
31
+ create_received_trigger(combined_commands, item)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ #
38
+ # Create a received trigger based on item type
39
+ #
40
+ # @param [Array] commands to create trigger for
41
+ # @param [Object] item to create trigger for
42
+ #
43
+ #
44
+ def create_received_trigger(commands, item)
45
+ commands.each do |command|
46
+ if item.is_a? GroupItems
47
+ config, trigger = create_group_command_trigger(item)
48
+ else
49
+ config, trigger = create_item_command_trigger(item)
50
+ end
51
+ config['command'] = command.to_s unless command.nil?
52
+ append_trigger(trigger, config)
53
+ end
54
+ end
55
+
56
+ #
57
+ # Create trigger for item commands
58
+ #
59
+ # @param [Item] item to create trigger for
60
+ #
61
+ # @return [Array<Hash,Trigger>] first element is hash of trigger config properties
62
+ # second element is trigger type
63
+ #
64
+ def create_item_command_trigger(item)
65
+ config = { 'itemName' => item.name }
66
+ trigger = Trigger::ITEM_COMMAND
67
+ [config, trigger]
68
+ end
69
+
70
+ #
71
+ # Create trigger for group items
72
+ #
73
+ # @param [Group] group to create trigger for
74
+ #
75
+ # @return [Array<Hash,Trigger>] first element is hash of trigger config properties
76
+ # second element is trigger type
77
+ #
78
+ def create_group_command_trigger(group)
79
+ config = { 'groupName' => group.group.name }
80
+ trigger = Trigger::GROUP_COMMAND
81
+ [config, trigger]
82
+ end
83
+
84
+ #
85
+ # Combine command and commands into a single array
86
+ #
87
+ # @param [Array] command list of commands to trigger on
88
+ # @param [Array] commands list of commands to trigger on
89
+ #
90
+ # @return [Array] Combined flattened and compacted list of commands
91
+ #
92
+ def combine_commands(command, commands)
93
+ combined_commands = ([command] | [commands]).flatten
94
+
95
+ # If either command or commands has a value and one is nil, we need to remove nil from the array.
96
+ # If it is only now a single nil value, we leave the nil in place, so that we create a trigger
97
+ # That isn't looking for a specific command.
98
+ combined_commands = combined_commands.compact unless combined_commands.all?(&:nil?)
99
+ combined_commands
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'openhab/dsl/time_of_day'
5
+
6
+ module OpenHAB
7
+ module DSL
8
+ module Rules
9
+ #
10
+ # Cron type rules
11
+ #
12
+ module Triggers
13
+ java_import org.openhab.core.automation.util.TriggerBuilder
14
+ java_import org.openhab.core.config.core.Configuration
15
+
16
+ #
17
+ # Returns a default map for cron expressions that fires every second
18
+ # This map is usually updated via merge by other methods to refine cron type triggers.
19
+ #
20
+ # @return [Hash] Map with symbols for :seconds, :minute, :hour, :dom, :month, :dow
21
+ # configured to fire every second
22
+ #
23
+ def cron_expression_map
24
+ {
25
+ second: '*',
26
+ minute: '*',
27
+ hour: '*',
28
+ dom: '?',
29
+ month: '*',
30
+ dow: '?'
31
+ }
32
+ end
33
+ # Rubocop check is disabled because YARD cannot process the method if placed in front of
34
+ # the method definition
35
+ # rubocop:disable Style/AccessModifierDeclarations
36
+ module_function :cron_expression_map
37
+ # rubocop:enable Style/AccessModifierDeclarations
38
+
39
+ # @return [Hash] Map of days of the week from symbols to to OpenHAB cron strings
40
+ DAY_OF_WEEK_MAP = {
41
+ monday: 'MON',
42
+ tuesday: 'TUE',
43
+ wednesday: 'WED',
44
+ thursday: 'THU',
45
+ friday: 'FRI',
46
+ saturday: 'SAT',
47
+ sunday: 'SUN'
48
+ }.freeze
49
+
50
+ private_constant :DAY_OF_WEEK_MAP
51
+
52
+ # @return [Hash] Converts the DAY_OF_WEEK_MAP to map used by Cron Expression
53
+ DAY_OF_WEEK_EXPRESSION_MAP = DAY_OF_WEEK_MAP.transform_values { |v| cron_expression_map.merge(dow: v) }
54
+
55
+ private_constant :DAY_OF_WEEK_EXPRESSION_MAP
56
+
57
+ # @return [Hash] Create a set of cron expressions based on different time intervals
58
+ EXPRESSION_MAP = {
59
+ second: cron_expression_map,
60
+ minute: cron_expression_map.merge(second: '0'),
61
+ hour: cron_expression_map.merge(second: '0', minute: '0'),
62
+ day: cron_expression_map.merge(second: '0', minute: '0', hour: '0'),
63
+ week: cron_expression_map.merge(second: '0', minute: '0', hour: '0', dow: 'MON'),
64
+ month: cron_expression_map.merge(second: '0', minute: '0', hour: '0', dom: '1'),
65
+ year: cron_expression_map.merge(second: '0', minute: '0', hour: '0', dom: '1', month: '1')
66
+ }.merge(DAY_OF_WEEK_EXPRESSION_MAP)
67
+ .freeze
68
+
69
+ private_constant :EXPRESSION_MAP
70
+
71
+ #
72
+ # Create a rule that executes at the specified interval
73
+ #
74
+ # @param [Object] value Symbol or Duration to execute this rule
75
+ # @param [Object] at TimeOfDay or String representing TimeOfDay in which to execute rule
76
+ #
77
+ #
78
+ def every(value, at: nil)
79
+ cron_expression = case value
80
+ when Symbol then cron_from_symbol(value, at)
81
+ when Java::JavaTime::Duration then cron_from_duration(value, at)
82
+ else raise ArgumentExpression, 'Unknown interval'
83
+ end
84
+ cron(cron_expression)
85
+ end
86
+
87
+ #
88
+ # Create a OpenHAB Cron trigger
89
+ #
90
+ # @param [String] expression OpenHAB style cron expression
91
+ #
92
+ def cron(expression)
93
+ @triggers << Trigger.trigger(type: Trigger::CRON, config: { 'cronExpression' => expression })
94
+ end
95
+
96
+ private
97
+
98
+ #
99
+ # Create a cron map from a duration
100
+ #
101
+ # @param [java::time::Duration] duration
102
+ # @param [Object] at TimeOfDay or String representing time of day
103
+ #
104
+ # @return [Hash] map describing cron expression
105
+ #
106
+ def cron_from_duration(duration, at)
107
+ raise ArgumentError, '"at" cannot be used with duration' if at
108
+
109
+ map_to_cron(duration_to_map(duration))
110
+ end
111
+
112
+ #
113
+ # Create a cron map from a symbol
114
+ #
115
+ # @param [Symbol] symbol
116
+ # @param [Object] at TimeOfDay or String representing time of day
117
+ #
118
+ # @return [Hash] map describing cron expression created from symbol
119
+ #
120
+ def cron_from_symbol(symbol, at)
121
+ expression_map = EXPRESSION_MAP[symbol]
122
+ expression_map = at_condition(expression_map, at) if at
123
+ map_to_cron(expression_map)
124
+ end
125
+
126
+ #
127
+ # Map cron expression to to cron string
128
+ #
129
+ # @param [Map] map of cron expression
130
+ #
131
+ # @return [String] OpenHAB cron string
132
+ #
133
+ def map_to_cron(map)
134
+ %i[second minute hour dom month dow].map { |field| map.fetch(field) }.join(' ')
135
+ end
136
+
137
+ #
138
+ # Convert a Java Duration to a map for the map_to_cron method
139
+ #
140
+ # @param duration [Java::JavaTime::Duration] The duration object
141
+ #
142
+ # @return [Hash] a map suitable for map_to_cron
143
+ #
144
+ def duration_to_map(duration)
145
+ if duration.to_millis_part.zero? && duration.to_nanos_part.zero? && duration.to_days.zero?
146
+ %i[second minute hour].each do |unit|
147
+ to_unit_part = duration.public_send("to_#{unit}s_part")
148
+ next unless to_unit_part.positive?
149
+
150
+ to_unit = duration.public_send("to_#{unit}s")
151
+ break unless to_unit_part == to_unit
152
+
153
+ return EXPRESSION_MAP[unit].merge(unit => "*/#{to_unit}")
154
+ end
155
+ end
156
+ raise ArgumentError, "Cron Expression not supported for duration: #{duration}"
157
+ end
158
+
159
+ #
160
+ # If an at time is provided, parse that and merge the new fields into the expression.
161
+ #
162
+ # @param [<Type>] expression_map <description>
163
+ # @param [<Type>] at_time <description>
164
+ #
165
+ # @return [<Type>] <description>
166
+ #
167
+ def at_condition(expression_map, at_time)
168
+ if at_time
169
+ tod = at_time.is_a?(TimeOfDay::TimeOfDay) ? at_time : TimeOfDay::TimeOfDay.parse(at_time)
170
+ expression_map = expression_map.merge(hour: tod.hour, minute: tod.minute, second: tod.second)
171
+ end
172
+ expression_map
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end