openhab-scripting 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/workflow.yml +327 -0
  3. data/.gitignore +17 -0
  4. data/.java-version +1 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +113 -0
  8. data/Gemfile +28 -0
  9. data/Gemfile.lock +245 -0
  10. data/Guardfile +35 -0
  11. data/LICENSE +277 -0
  12. data/README.md +23 -0
  13. data/Rakefile +406 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/config/userdata/config/org/openhab/restauth.config +3 -0
  17. data/cucumber.yml +1 -0
  18. data/docs/_config.yml +135 -0
  19. data/docs/contributing/index.md +47 -0
  20. data/docs/examples/conversions.md +123 -0
  21. data/docs/examples/index.md +61 -0
  22. data/docs/index.md +19 -0
  23. data/docs/installation/index.md +26 -0
  24. data/docs/motivation/index.md +27 -0
  25. data/docs/usage/execution.md +9 -0
  26. data/docs/usage/execution/delay.md +48 -0
  27. data/docs/usage/execution/otherwise.md +30 -0
  28. data/docs/usage/execution/run.md +70 -0
  29. data/docs/usage/execution/triggered.md +48 -0
  30. data/docs/usage/guards.md +51 -0
  31. data/docs/usage/guards/between.md +30 -0
  32. data/docs/usage/guards/not_if.md +41 -0
  33. data/docs/usage/guards/only_if.md +40 -0
  34. data/docs/usage/index.md +11 -0
  35. data/docs/usage/items.md +66 -0
  36. data/docs/usage/items/contact.md +84 -0
  37. data/docs/usage/items/dimmer.md +147 -0
  38. data/docs/usage/items/groups.md +76 -0
  39. data/docs/usage/items/number.md +225 -0
  40. data/docs/usage/items/string.md +49 -0
  41. data/docs/usage/items/switch.md +85 -0
  42. data/docs/usage/misc.md +7 -0
  43. data/docs/usage/misc/actions.md +108 -0
  44. data/docs/usage/misc/duration.md +21 -0
  45. data/docs/usage/misc/gems.md +25 -0
  46. data/docs/usage/misc/logging.md +21 -0
  47. data/docs/usage/misc/metadata.md +128 -0
  48. data/docs/usage/misc/store_states.md +42 -0
  49. data/docs/usage/misc/time_of_day.md +69 -0
  50. data/docs/usage/misc/timers.md +67 -0
  51. data/docs/usage/rule.md +43 -0
  52. data/docs/usage/things.md +29 -0
  53. data/docs/usage/triggers.md +8 -0
  54. data/docs/usage/triggers/changed.md +57 -0
  55. data/docs/usage/triggers/channel.md +54 -0
  56. data/docs/usage/triggers/command.md +69 -0
  57. data/docs/usage/triggers/cron.md +19 -0
  58. data/docs/usage/triggers/every.md +76 -0
  59. data/docs/usage/triggers/updated.md +78 -0
  60. data/lib/openhab.rb +39 -0
  61. data/lib/openhab/configuration.rb +16 -0
  62. data/lib/openhab/core/cron.rb +27 -0
  63. data/lib/openhab/core/debug.rb +34 -0
  64. data/lib/openhab/core/dsl.rb +47 -0
  65. data/lib/openhab/core/dsl/actions.rb +107 -0
  66. data/lib/openhab/core/dsl/entities.rb +103 -0
  67. data/lib/openhab/core/dsl/gems.rb +29 -0
  68. data/lib/openhab/core/dsl/group.rb +91 -0
  69. data/lib/openhab/core/dsl/items/items.rb +39 -0
  70. data/lib/openhab/core/dsl/items/number_item.rb +217 -0
  71. data/lib/openhab/core/dsl/items/string_item.rb +102 -0
  72. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +4 -0
  73. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +22 -0
  74. data/lib/openhab/core/dsl/monkey_patch/events.rb +5 -0
  75. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +13 -0
  76. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +25 -0
  77. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +26 -0
  78. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +54 -0
  79. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +125 -0
  80. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +27 -0
  81. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +130 -0
  82. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +259 -0
  83. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +86 -0
  84. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +69 -0
  85. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +46 -0
  86. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +5 -0
  87. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +24 -0
  88. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +41 -0
  89. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +25 -0
  90. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +23 -0
  91. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +7 -0
  92. data/lib/openhab/core/dsl/property.rb +85 -0
  93. data/lib/openhab/core/dsl/rule/channel.rb +41 -0
  94. data/lib/openhab/core/dsl/rule/cron.rb +115 -0
  95. data/lib/openhab/core/dsl/rule/guard.rb +99 -0
  96. data/lib/openhab/core/dsl/rule/item.rb +207 -0
  97. data/lib/openhab/core/dsl/rule/rule.rb +374 -0
  98. data/lib/openhab/core/dsl/rule/triggers.rb +77 -0
  99. data/lib/openhab/core/dsl/states.rb +63 -0
  100. data/lib/openhab/core/dsl/things.rb +93 -0
  101. data/lib/openhab/core/dsl/time_of_day.rb +203 -0
  102. data/lib/openhab/core/dsl/timers.rb +85 -0
  103. data/lib/openhab/core/dsl/types/quantity.rb +255 -0
  104. data/lib/openhab/core/dsl/units.rb +41 -0
  105. data/lib/openhab/core/duration.rb +69 -0
  106. data/lib/openhab/core/log.rb +175 -0
  107. data/lib/openhab/core/patch_load_path.rb +7 -0
  108. data/lib/openhab/core/startup_delay.rb +22 -0
  109. data/lib/openhab/osgi.rb +52 -0
  110. data/lib/openhab/version.rb +9 -0
  111. data/openhab-scripting.gemspec +30 -0
  112. data/openhab_rules/warmup.rb +5 -0
  113. metadata +157 -0
@@ -0,0 +1,9 @@
1
+ ---
2
+ layout: default
3
+ title: Execution Blocks
4
+ nav_order: 2
5
+ has_children: true
6
+ parent: Usage
7
+ ---
8
+
9
+
@@ -0,0 +1,48 @@
1
+ ---
2
+ layout: default
3
+ title: Delay
4
+ nav_order: 3
5
+ has_children: false
6
+ parent: Execution Blocks
7
+ grand_parent: Usage
8
+ ---
9
+
10
+
11
+ # Delay
12
+ The delay property is a non thread-blocking element that is executed after, before, or between run blocks.
13
+
14
+ ```ruby
15
+ rule 'Delay sleeps between execution elements' do
16
+ on_start
17
+ run { logger.info("Sleeping") }
18
+ delay 5.seconds
19
+ run { logger.info("Awake") }
20
+ end
21
+ ```
22
+
23
+ Like other execution blocks, multiple can exist in a single rule.
24
+
25
+ ```ruby
26
+ rule 'Multiple delays can exist in a rule' do
27
+ on_start
28
+ run { logger.info("Sleeping") }
29
+ delay 5.seconds
30
+ run { logger.info("Sleeping Again") }
31
+ delay 5.seconds
32
+ run { logger.info("Awake") }
33
+ end
34
+ ```
35
+
36
+
37
+ You can use ruby code in your rule across multiple execution blocks like a run and a delay.
38
+ ```ruby
39
+ rule 'Dim a switch on system startup over 100 seconds' do
40
+ on_start
41
+ 100.times do
42
+ run { DimmerSwitch.dim }
43
+ delay 1.second
44
+ end
45
+ end
46
+
47
+ ```
48
+
@@ -0,0 +1,30 @@
1
+ ---
2
+ layout: default
3
+ title: Otherwise
4
+ nav_order: 4
5
+ has_children: false
6
+ parent: Execution Blocks
7
+ grand_parent: Usage
8
+ ---
9
+
10
+
11
+ # Otherwise
12
+ The otherwise property is the automation code that is executed when a rule is triggered and guards are not satisfied. This property accepts a block of code and executes it. The block is automatically passed an event object which can be used to access multiple properties about the triggering event.
13
+
14
+ ## Event Properties
15
+
16
+ | Property | Description |
17
+ | -------- | -------------------------------- |
18
+ | item | Triggering item |
19
+ | state | Changed state of triggering item |
20
+ | last | Last state of triggering item |
21
+
22
+ ```ruby
23
+ rule 'Turn switch ON or OFF based on value of another switch' do
24
+ on_start
25
+ run { TestSwitch << ON }
26
+ otherwise { TestSwitch << OFF }
27
+ only_if { OtherSwitch == ON }
28
+ end
29
+ ```
30
+
@@ -0,0 +1,70 @@
1
+ ---
2
+ layout: default
3
+ title: Run
4
+ nav_order: 1
5
+ has_children: false
6
+ parent: Execution Blocks
7
+ grand_parent: Usage
8
+ ---
9
+
10
+
11
+ # Run
12
+ The run property is the automation code that is executed when a rule is triggered. This property accepts a block of code and executes it. The block is automatically passed an event object which can be used to access multiple properties about the triggering event. The code for the automation can be entirely within the run block can call methods defined in the ruby script.
13
+
14
+ ## State/Update Event Properties
15
+ The following properties exist when a run block is triggered from an [updated](#updated) or [changed](#changed) trigger.
16
+
17
+ | Property | Description |
18
+ | -------- | -------------------------------- |
19
+ | item | Triggering item |
20
+ | state | Changed state of triggering item |
21
+ | last | Last state of triggering item |
22
+
23
+ ## Command Event Properties
24
+ The following properties exist when a run block is triggered from a [received_command](#received_command) trigger.
25
+
26
+ | Property | Description |
27
+ | -------- | -------------------- |
28
+ | command | Command sent to item |
29
+
30
+ ## Thing Event Properties
31
+ The following properties exist when a run block is triggered from an [updated](#updated) or [changed](#changed) trigger on a Thing.
32
+
33
+ | Property | Description |
34
+ | -------- | ----------------------------------------------------------------- |
35
+ | uid | UID of the triggered Thing |
36
+ | last | Status before Change for thing (only valid on Change, not update) |
37
+ | status | Current status of the triggered Thing |
38
+
39
+
40
+
41
+ `{}` Style used for single line blocks
42
+ ```ruby
43
+ rule 'Access Event Properties' do
44
+ changed TestSwitch
45
+ run { |event| logger.info("#{event.item.id} triggered from #{event.last} to #{event.state}") }
46
+ end
47
+ ```
48
+
49
+ `do/end` style used for multi-line blocks
50
+ ```ruby
51
+ rule 'Multi Line Run Block' do
52
+ changed TestSwitch
53
+ run do |event|
54
+ logger.info("#{event.item.id} triggered")
55
+ logger.info("from #{event.last}") if event.last
56
+ logger.info("to #{event.state}") if event.state
57
+ end
58
+ end
59
+ ```
60
+
61
+ Rules can have multiple run blocks and they are executed in order, Useful when used in combination with delay
62
+ ```ruby
63
+ rule 'Multiple Run Blocks' do
64
+ changed TestSwitch
65
+ run { |event| logger.info("#{event.item.id} triggered") }
66
+ run { |event| logger.info("from #{event.last}") if event.last }
67
+ run { |event| logger.info("to #{event.state}") if event.state }
68
+ end
69
+
70
+ ```
@@ -0,0 +1,48 @@
1
+ ---
2
+ layout: default
3
+ title: Triggered
4
+ nav_order: 2
5
+ has_children: false
6
+ parent: Execution Blocks
7
+ grand_parent: Usage
8
+ ---
9
+
10
+ # Triggered
11
+ This property is the same as the run property except rather than passing an event object to the automation block the triggered item is passed. This enables optimizations for simple cases and supports ruby's [pretzel colon `&:` operator.](https://medium.com/@dcjones/the-pretzel-colon-75df46dde0c7)
12
+
13
+ ## Examples
14
+ ```ruby
15
+ rule 'Triggered has access directly to item triggered' do
16
+ changed TestSwitch
17
+ triggered { |item| logger.info("#{item.id} triggered") }
18
+ end
19
+
20
+ ```
21
+
22
+ Triggered items are highly useful when working with groups
23
+ ```ruby
24
+ #Switches is a group of Switch items
25
+
26
+ rule 'Triggered item is item changed when a group item is changed.' do
27
+ changed Switches.items
28
+ triggered { |item| logger.info("Switch #{item.id} changed to #{item}")}
29
+ end
30
+
31
+
32
+ rule 'Turn off any switch that changes' do
33
+ changed Switches.items
34
+ triggered(&:off)
35
+ end
36
+
37
+ ```
38
+
39
+ Like other execution blocks, multiple triggered blocks are supported in a single rule
40
+ ```ruby
41
+ rule 'Turn a switch off and log it, 5 seconds after turning it on' do
42
+ changed Switches.items, to: ON
43
+ delay 5.seconds
44
+ triggered(&:off)
45
+ triggered {|item| logger.info("#{item.label} turned off") }
46
+ end
47
+ ```
48
+
@@ -0,0 +1,51 @@
1
+ ---
2
+ layout: default
3
+ title: Guards
4
+ nav_order: 3
5
+ has_children: true
6
+ parent: Usage
7
+ ---
8
+
9
+ # Guards
10
+
11
+ Guards exist to only permit rules to run if certain conditions are satisfied. Think of these as declarative if statements that keep the run block free of conditional logic, although you can of course still use conditional logic in run blocks if you prefer.
12
+
13
+ only_if and not_if guards that are provided objects rather than blocks automatically check for the 'truthyness' of the supplied object.
14
+
15
+ Truthyness for Item types:
16
+
17
+ | Item | Truthy when |
18
+ | ------- | ----------- |
19
+ | Switch | state == ON |
20
+ | Dimmer | state != 0 |
21
+ | Contact | Not Defined |
22
+ | String | Not Blank |
23
+ | Number | state != 0 |
24
+
25
+
26
+
27
+ ## Guard Combination
28
+
29
+ only_if and not_if can be used on the same rule, both be satisfied for a rule to execute.
30
+
31
+ ```ruby
32
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is OFF and Door is CLOSED' do
33
+ changed LightSwitch, to: ON
34
+ run { OutsideDimmer << 50 }
35
+ only_if { Door == CLOSED }
36
+ not_if OtherSwitch
37
+ end
38
+ ```
39
+
40
+
41
+ #### Guard Event Access
42
+ Guards have access to event information.
43
+
44
+ ```ruby
45
+ rule 'Set OutsideDimmer to 50% if any switch in group Switches starting with Outside is switched On' do
46
+ changed Switches.items, to: ON
47
+ run { OutsideDimmer << 50 }
48
+ only_if { |event| event.item.name.start_with? 'Outside' }
49
+ end
50
+ ```
51
+
@@ -0,0 +1,30 @@
1
+ ---
2
+ layout: default
3
+ title: Between
4
+ nav_order: 3
5
+ has_children: false
6
+ parent: Guards
7
+ grand_parent: Usage
8
+ ---
9
+
10
+ # between
11
+ Only runs the rule if the current time is in the provided range
12
+
13
+ ```ruby
14
+ rule 'Log an entry if started between 3:30:04 and midnight using strings' do
15
+ on_start
16
+ run { logger.info ("Started at #{TimeOfDay.now}")}
17
+ between '3:30:04'..MIDNIGHT
18
+ end
19
+ ```
20
+
21
+ or
22
+
23
+ ```ruby
24
+ rule 'Log an entry if started between 3:30:04 and midnight using TimeOfDay objects' do
25
+ on_start
26
+ run { logger.info ("Started at #{TimeOfDay.now}")}
27
+ between TimeOfDay.new(h: 3, m: 30, s: 4)..MIDNIGHT
28
+ end
29
+ ```
30
+
@@ -0,0 +1,41 @@
1
+ ---
2
+ layout: default
3
+ title: Not If
4
+ nav_order: 2
5
+ has_children: false
6
+ parent: Guards
7
+ grand_parent: Usage
8
+ ---
9
+
10
+ #### not_if
11
+
12
+ not_if allows prevents execution of rules when result is false and prevents when true
13
+
14
+ ```
15
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is OFF' do
16
+ changed LightSwitch, to: ON
17
+ run { OutsideDimmer << 50 }
18
+ not_if { OtherSwitch == ON }
19
+ end
20
+ ```
21
+
22
+ Because not_if uses 'truthy?' on non-block objects the above rule can also be written like this:
23
+
24
+ ```ruby
25
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is OFF' do
26
+ changed LightSwitch, to: ON
27
+ run { OutsideDimmer << 50 }
28
+ not_if OtherSwitch
29
+ end
30
+ ```
31
+
32
+ Multiple not_if statements can be used and if **any** of them are not satisfied the rule will not run.
33
+
34
+ ```ruby
35
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is OFF and Door is not CLOSED' do
36
+ changed LightSwitch, to: ON
37
+ run { OutsideDimmer << 50 }
38
+ not_if OtherSwitch
39
+ not_if { Door == CLOSED }
40
+ end
41
+ ```
@@ -0,0 +1,40 @@
1
+ ---
2
+ layout: default
3
+ title: Only If
4
+ nav_order: 1
5
+ has_children: false
6
+ parent: Guards
7
+ grand_parent: Usage
8
+ ---
9
+
10
+ # only_if
11
+ only_if allows rule execution when result is true and prevents when false.
12
+
13
+ ```ruby
14
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is also ON' do
15
+ changed LightSwitch, to: ON
16
+ run { OutsideDimmer << 50 }
17
+ only_if { OtherSwitch == ON }
18
+ end
19
+ ```
20
+
21
+ Because only_if uses 'truthy?' on non-block objects the above rule can also be written like this:
22
+
23
+ ```ruby
24
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is also ON' do
25
+ changed LightSwitch, to: ON
26
+ run { OutsideDimmer << 50 }
27
+ only_if OtherSwitch
28
+ end
29
+ ```
30
+
31
+ multiple only_if statements can be used and **all** must be true for the rule to run.
32
+
33
+ ```ruby
34
+ rule 'Set OutsideDimmer to 50% if LightSwtich turned on and OtherSwitch is also ON and Door is closed' do
35
+ changed LightSwitch, to: ON
36
+ run { OutsideDimmer << 50 }
37
+ only_if OtherSwitch
38
+ only_if { Door == CLOSED }
39
+ end
40
+ ```
@@ -0,0 +1,11 @@
1
+ ---
2
+ layout: default
3
+ title: Usage
4
+ nav_order: 4
5
+ has_children: true
6
+ ---
7
+
8
+
9
+ ## Rules Requirements
10
+ 1. Place Ruby rules files in `ruby/personal/` subdirectory for OpenHAB scripted automation. See [OpenHAB documentation](https://www.openhab.org/docs/configuration/jsr223.html#script-locations) for parent directory location.
11
+ 2. Put `require 'openhab'` at the top of any Ruby based rules file.
@@ -0,0 +1,66 @@
1
+ ---
2
+ layout: default
3
+ title: Items
4
+ nav_order: 4
5
+ has_children: true
6
+ parent: Usage
7
+ ---
8
+
9
+
10
+ # Items
11
+ Items can be directly accessed, compared, etc, without any special accessors. You may use the item name anywhere within the code and it will automatically be loaded.
12
+
13
+ All items can be accessed as an enumerable the `items` method.
14
+
15
+ | Method | Description |
16
+ | ------------------ | ------------------------------------------------------------------------------ |
17
+ | [] | Get a specific item by name, this syntax can be used to dynamically load items |
18
+ | enumerable methods | All methods [here](https://ruby-doc.org/core-2.5.0/Enumerable.html) |
19
+
20
+ ## Examples
21
+
22
+ Item Definition
23
+ ```
24
+ Dimmer DimmerTest "Test Dimmer"
25
+ Switch SwitchTest "Test Switch"
26
+
27
+ ```
28
+
29
+ ```ruby
30
+ logger.info("Item Count: #{items.count}") # Item Count: 2
31
+ logger.info("Items: #{items.sort_by(&:label).map(&:label).join(', ')}") #Items: Test Dimmer, Test Switch'
32
+ ```
33
+
34
+ ```ruby
35
+ rule 'Use dynamic item lookup to increase related dimmer brightness when switch is turned on' do
36
+ changed SwitchTest, to: ON
37
+ triggered { |item| items[item.name.gsub('Switch','Dimmer')].brighten(10) }
38
+ end
39
+ ```
40
+
41
+ ## All Items
42
+ Item types have methods added to them to make it flow naturally within the a ruby context. All methods of the OpenHAB item are available plus the additional methods described below.
43
+
44
+
45
+ | Method | Description | Example |
46
+ | ------- | ------------------------------------------------- | ------------------------------------------------------------ |
47
+ | << | Sends command to item | `VirtualSwich << ON` |
48
+ | command | alias for shovel operator (<<) | `VirtualSwich.command(ON)` |
49
+ | update | Sends update to an item | `VirtualSwitch.update(ON)` |
50
+ | id | Returns label or item name if no label | `logger.info(#{item.id})` |
51
+ | undef? | Returns true if the state of the item is UNDEF | `logger.info("SwitchTest is UNDEF") if SwitchTest.undef?` |
52
+ | null? | Returns true if the state of the item is NULL | `logger.info("SwitchTest is NULL") if SwitchTest.null?` |
53
+ | state? | Returns true if the state is not UNDEF or NULL | `logger.info("SwitchTest has a state") if SwitchTest.state?` |
54
+ | state | Returns state of the item or nil if UNDEF or NULL | `logger.info("SwitchTest state #{SwitchTest.state}")` |
55
+ | to_s | Returns state in string format | `logger.info(#{item.id}: #{item})` |
56
+
57
+ State returns nil instead of UNDEF or NULL so that it can be used with with [Ruby safe navigation operator](https://ruby-doc.org/core-2.6/doc/syntax/calling_methods_rdoc.html) `&.` Use `undef?` or `null?` to check for those states.
58
+
59
+ To operate across an arbitrary collection of items you can place them in an [array](https://ruby-doc.org/core-2.5.0/Array.html) and execute methods against the array.
60
+
61
+ ```ruby
62
+ number_items = [Livingroom_Temp, Bedroom_Temp]
63
+ logger.info("Max is #{number_items.max}")
64
+ logger.info("Min is #{number_items.min}")
65
+ ```
66
+