[jrubyscripting] Update README.md (#15624)

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
jimtng 2023-10-02 00:01:13 +10:00 committed by GitHub
parent cbf4411034
commit 5a39985420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -38,6 +38,7 @@ If you're new to Ruby, you may want to check out [Ruby Basics](https://openhab.g
- [Shared Code](#shared-code)
- [Transformations](#transformations)
- [Profile](#profile)
- [Sitemaps](#sitemaps)
- [File Based Rules](#file-based-rules)
- [Basic Rule Structure](#basic-rule-structure)
- [Rule Triggers](#rule-triggers)
@ -61,6 +62,7 @@ If you're new to Ruby, you may want to check out [Ruby Basics](https://openhab.g
- [Dynamic Generation of Rules](#dynamic-generation-of-rules)
- [Hooks](#hooks)
- [Calling Java From JRuby](#calling-java-from-jruby)
- [Full Documentation](#full-documentation)
Additional [example rules are available](https://openhab.github.io/openhab-jruby/main/file.examples.html), as well as examples of [conversions from DSL and Python rules](https://openhab.github.io/openhab-jruby/main/file.conversions.html).
@ -79,7 +81,7 @@ Additional [example rules are available](https://openhab.github.io/openhab-jruby
- Abstract away complexities of openHAB
- Enable all the power of Ruby and openHAB
- Create a Frictionless experience for building automation
- The common, yet tricky tasks are abstracted and made easy. e.g. creating a timer that automatically reschedules itself.
- The common, yet tricky tasks are abstracted and made easy, e.g. creating a timer that automatically reschedules itself.
- Tested
- Designed and tested using [Test-Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) with [RSpec](https://rspec.info/)
- Extensible.
@ -95,8 +97,7 @@ Additional [example rules are available](https://openhab.github.io/openhab-jruby
### From the User Interface
1. Go to `Settings -> Add-ons -> Automation` and install the jrubyscripting automation addon
following the [openHAB instructions](https://www.openhab.org/docs/configuration/addons.html).
1. Go to `Settings -> Add-ons -> Automation` and install the jrubyscripting automation addon following the [openHAB instructions](https://www.openhab.org/docs/configuration/addons.html).
In openHAB 4.0+ the defaults are set so the next step can be skipped.
1. Go to `Settings -> Other Services -> JRuby Scripting`:
- **Ruby Gems**: `openhab-scripting=~>5.0`
@ -104,8 +105,7 @@ Additional [example rules are available](https://openhab.github.io/openhab-jruby
### Using Files
1. Edit `<OPENHAB_CONF>/services/addons.cfg` and ensure that `jrubyscripting` is included in
an uncommented `automation=` list of automations to install.
1. Edit `<OPENHAB_CONF>/services/addons.cfg` and ensure that `jrubyscripting` is included in an uncommented `automation=` list of automations to install.
In openHAB 4.0+ the defaults are set so the next step can be skipped.
1. Configure JRuby openHAB services
@ -146,20 +146,18 @@ org.openhab.automation.jrubyscripting:require=openhab/dsl
### gem_home
Path to where Ruby Gems will be installed to and loaded from. The directory will be created if necessary.
You can use `RUBY_ENGINE_VERSION`, `RUBY_ENGINE` and/or `RUBY_VERSION` replacements in this value
to automatically point to a new directory when the addon is updated with a new version of JRuby.
Path to where Ruby Gems will be installed to and loaded from.
The directory will be created if necessary.
You can use `RUBY_ENGINE_VERSION`, `RUBY_ENGINE` and/or `RUBY_VERSION` replacements in this value to automatically point to a new directory when the addon is updated with a new version of JRuby.
### gems
A comma separated list of [Ruby Gems](https://rubygems.org/) to install.
The default installs the version of the helper for this version of openHAB.
When overriding the default, be sure to still include the `openhab-scripting` gem in the
list of gems to install.
When overriding the default, be sure to still include the `openhab-scripting` gem in the list of gems to install.
Each gem can have version specifiers which uses
[pessimistic versioning](https://thoughtbot.com/blog/rubys-pessimistic-operator).
Each gem can have version specifiers which uses [pessimistic versioning](https://thoughtbot.com/blog/rubys-pessimistic-operator).
Multiple version specifiers can be added by separating them with a semicolon.
Examples:
@ -175,8 +173,7 @@ Examples:
### check_update
Check RubyGems for updates to the above gems when openHAB starts or JRuby settings are changed.
Otherwise it will try to fulfil the requirements with locally installed gems, and you can manage them yourself
with an external Ruby by setting the same GEM_HOME.
Otherwise it will try to fulfil the requirements with locally installed gems, and you can manage them yourself with an external Ruby by setting the same GEM_HOME.
### require
@ -185,13 +182,13 @@ The default is to require the helper library.
### rubylib
Search path for user libraries. Separate each path with a colon (semicolon in Windows).
Search path for user libraries.
Separate each path with a colon (semicolon in Windows).
### dependency_tracking
Dependency tracking allows your scripts to automatically reload when one of its dependencies is updated.
You may want to disable dependency tracking if you plan on editing or updating a shared library,
but don't want all your scripts to reload until you can test it.
You may want to disable dependency tracking if you plan on editing or updating a shared library, but don't want all your scripts to reload until you can test it.
### local_context
@ -201,7 +198,8 @@ See [this](https://github.com/jruby/jruby/wiki/RedBridge#context-instance-type)
### local_variables
Defines how variables are shared between Ruby and Java. Valid values are: `transient`, `persistent`, or `global`.
Defines how variables are shared between Ruby and Java.
Valid values are: `transient`, `persistent`, or `global`.
See the [JRuby documentation](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details.
## Usage
@ -210,8 +208,7 @@ See the [JRuby documentation](https://github.com/jruby/jruby/wiki/RedBridge#loca
The quickest way to add rules is through the openHAB Web UI.
Advanced users, or users migrating scripts from existing systems may want to use
[File Based Scripts](#file-based-scripts) for managing rules using files in the user configuration directory.
Advanced users, or users migrating scripts from existing systems may want to use [File Based Scripts](#file-based-scripts) for managing rules using files in the user configuration directory.
#### Adding Triggers
@ -262,7 +259,8 @@ See [File Based Rules](#file-based-rules) for examples of creating rules within
When you use "Item event" as trigger (i.e. "[item] received a command", "[item] was updated", "[item] changed"), there is additional context available for the action in a variable called `event`.
This tables gives an overview of the `event` object for most common trigger types. For full details, explore [OpenHAB::Core::Events](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Events.html).
This tables gives an overview of the `event` object for most common trigger types.
For full details, explore [OpenHAB::Core::Events](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Events.html).
| Property Name | Type | Trigger Types | Description | Rules DSL Equivalent |
| ------------- | -------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------- | ---------------------- |
@ -542,9 +540,7 @@ See [unit block](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL.html#u
##### Range checking
Types that are comparable, such as [StringType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/StringType.html), [DateTimeType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/DateTimeType.html), [DecimalType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/DecimalType.html), [PercentType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/PercentType.html),
include Ruby's [Comparable](https://docs.ruby-lang.org/en/master/Comparable.html) module which provides
the handy [between?](https://docs.ruby-lang.org/en/master/Comparable.html#method-i-between-3F) method.
Types that are comparable, such as [StringType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/StringType.html), [DateTimeType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/DateTimeType.html), [DecimalType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/DecimalType.html), [PercentType](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Types/PercentType.html), include Ruby's [Comparable](https://docs.ruby-lang.org/en/master/Comparable.html) module which provides the handy [between?](https://docs.ruby-lang.org/en/master/Comparable.html#method-i-between-3F) method.
```ruby
String_Item.update("Freddy")
@ -559,8 +555,8 @@ Temperature_Item.update(16 | "°C")
Temperature_Item.state.between?(20 | "°C", 24 | "°C") # => false
```
Alternatively, a Ruby [range](https://docs.ruby-lang.org/en/master/Range.html) can be used. This can be
handy for excluding the end of the range with the `...` operator.
Alternatively, a Ruby [range](https://docs.ruby-lang.org/en/master/Range.html) can be used.
This can be handy for excluding the end of the range with the `...` operator.
```ruby
if (5..10).cover?(Number_Item.state)
@ -708,6 +704,23 @@ thing.enable
logger.info "TV enabled: #{thing.enabled?}"
```
Get Thing's configurations:
```ruby
server = things["smtp:mail:local"].configuration["hostname"]
logger.info "Configured SMTP Server: #{server}"
frontporch_cam_ip = things["ipcamera:dahua:frontporch"].configuration["ipAddress"]
logger.info "Front Porch Camera's IP Address: #{frontporch_cam_ip}"
```
Get Thing's property:
```ruby
model_id = things["fronius:meter:mybridge:mymeter"].properties["modelId"]
logger.info "Fronius Smart Meter model: #{model_id}"
```
### Actions
[openHAB built-in actions](https://www.openhab.org/docs/configuration/actions.html) are available as children of the [Actions](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Actions.html) module.
@ -740,14 +753,15 @@ Exec.execute_command_line('/path/to/program')
### Logging
The JRuby Scripting addon has a global `logger` object for logging. To log a message on `INFO` log level:
The JRuby Scripting addon has a global `logger` object for logging.
To log a message on `INFO` log level:
```ruby
logger.info("The current time is #{Time.now}")
```
The default logger name for UI rules is `org.openhab.automation.jrubyscripting.script`.
For file-based rules, it's based on the rule's ID, such as `org.openhab.automation.jrubyscripting.rule.myrule.rb:15`
For file-based rules, it's based on the rule's ID, such as `org.openhab.automation.jrubyscripting.rule.myrule.rb:15`.
To use a custom logger name:
@ -780,7 +794,9 @@ sleep 1.5 # sleep for 1.5 seconds
See Ruby docs on [sleep](https://docs.ruby-lang.org/en/master/Kernel.html#method-i-sleep).
`sleep` should be avoided if possible. A [delay](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL/Rules/BuilderDSL.html#delay-instance_method) can be inserted in between two execution blocks to achieve the same result. This delay is implemented with a timer.
`sleep` should be avoided if possible.
A [delay](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL/Rules/BuilderDSL.html#delay-instance_method) can be inserted in between two execution blocks to achieve the same result.
This delay is implemented with a timer.
This is available only on file-based rules.
```ruby
@ -850,7 +866,7 @@ It can be rescheduled to a different duration
```ruby
after(3.minutes) do |timer|
My_Light.on
my_timer.reschedule(1.minute)
timer.reschedule(1.minute)
end
```
@ -922,22 +938,22 @@ Just be wary of Ruby-only data types (such as Symbols) that won't be accessible
Get a previously set object with a default value:
```ruby
counter_object = shared_cache.compute_if_absent(:counter) { { "times" => 0 } }
logger.info("Count: #{counter_object["times"] += 1}")"
shared_cache.compute_if_absent(:counter) { 0 } # Initialize with 0 if it didn't exist
logger.info("Count: #{shared_cache[:counter] += 1}")
```
Get a previously set object, or assign it (this version is subject to race conditions with other scripts):
```ruby
counter_object = shared_cache[:counter] ||= { "times" => 0 }
logger.info("Count: #{counter_object["times"] += 1}")"
shared_cache[:counter] ||= 0
logger.info("Count: #{shared_cache[:counter] += 1}")
```
Get a previously set object with a default value, without assigning it (this version has an even longer amount of time between fetchig the value and assigning it):
Get a previously set object with a default value, without assigning it (this version has an even longer amount of time between fetching the value and assigning it):
```ruby
count = shared_count.fetch(:counter) { 0 }
shared_count[:counter] = count + 1
count = shared_cache.fetch(:counter) { 0 }
shared_cache[:counter] = count + 1
```
### Time
@ -1140,20 +1156,19 @@ Date.today.in_dayset?(:school) # => false
### Rules, Scripts, and Scenes
[Rules](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Rule.html), Scenes and Scripts can be accessed using the
[rules](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Registry.html) object. For example, to execute/trigger a rule:
[Rules](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Rule.html), Scenes and Scripts can be accessed using the [rules](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Registry.html) object.
For example, to execute/trigger a rule:
```ruby
rules[rule_uid].trigger
```
Scenes are rules with a `Scene` tag, and Scripts are rules with a `Script` tag. They can be found
using their uid just like normal rules, i.e. `rules[uid]`. For convenience, a list of all Scenes are
available through the enumerable [rules.scenes](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Registry.html#scenes-instance_method),
and a list of all Scripts through [rules.scripts](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Registry.html#scripts-instance_method).
Scenes are rules with a `Scene` tag, and Scripts are rules with a `Script` tag.
They can be found using their uid just like normal rules, i.e. `rules[uid]`.
For convenience, a list of all Scenes are available through the enumerable [rules.scenes](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Registry.html#scenes-instance_method), and a list of all Scripts through [rules.scripts](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Rules/Registry.html#scripts-instance_method).
Example: All scenes tagged `sunrise` will be triggered at sunrise, and all scenes tagged
`sunset` will be triggered at sunset. Note: these use the [Terse Rule](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL/Rules/Terse.html) syntax.
Example: All scenes tagged `sunrise` will be triggered at sunrise, and all scenes tagged `sunset` will be triggered at sunset.
Note: these use the [Terse Rule](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL/Rules/Terse.html) syntax.
```ruby
channel("astro:sun:home:rise#event") { rules.scenes.tagged("sunrise").each(&:trigger) }
@ -1210,9 +1225,32 @@ rules[rule_uid].enable
rules[rule_uid].disable
```
#### Passing Values to Rules
A rule/script may be given additional context/data by the caller.
This additional data is available within the rule by referring to the names of the context variable.
This is applicable to both UI rules and file-based rules.
Within the script/rule body (either UI or file rule)
```ruby
script id: "check_temp" do
if CPU_Temperature.state > maxTemperature
logger.warn "The CPU is overheating!"
end
end
```
The above script can be executed, passing it the `maxTemperature` argument from any supported scripting language, e.g.:
```ruby
rules["check_temp"].trigger(maxTemperature: 80 | "°C")
```
### Gems
[Bundler](https://bundler.io/) is integrated, enabling any [Ruby gem](https://rubygems.org/) compatible with JRuby to be used within rules. This permits easy access to the vast ecosystem of libraries within the Ruby community.
[Bundler](https://bundler.io/) is integrated, enabling any [Ruby gem](https://rubygems.org/) compatible with JRuby to be used within rules.
This permits easy access to the vast ecosystem of libraries within the Ruby community.
Gems are available using the [inline bundler syntax](https://bundler.io/guides/bundler_in_a_single_file_ruby_script.html).
The require statement can be omitted.
@ -1250,14 +1288,26 @@ end
### Transformations
#### Using openHAB Transformations
Existing openHAB transformations can also be used by calling the [transform](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL.html#transform-class_method) method.
This enables the use of any transformations from the `/transform` folder or managed through the UI, such as MAP, JSONPATH, Jinja Transformation, etc.
```ruby
# Convert OPEN/CLOSED to Online/Offline using availability.map
# OPEN=Online
# CLOSED=OFFLINE
logger.info transform(:map, "availability.map", LivingRoom_Switch_Availability.state)
```
#### Writing Custom Transformations in Ruby
This add-on also provides the necessary infrastructure to use Ruby for writing [transformations](https://www.openhab.org/docs/configuration/transformations.html).
The main value to be transformed is given to the script in a variable called `input`.
Note that the values are passed to the transformation as Strings even for numeric items and data types.
**Note**: In openHAB 3.4, due to an [issue](https://github.com/jruby/jruby/issues/5876) in the current version of JRuby,
you will need to begin your script with `input ||= nil` (and `a ||= nil` etc. for additional query variables) so that
JRuby will recognize the variables as variables--rather than method calls--when it's parsing the script.
**Note**: In openHAB 3.4, due to an [issue](https://github.com/jruby/jruby/issues/5876) in the current version of JRuby, you will need to begin your script with `input ||= nil` (and `a ||= nil` etc. for additional query variables) so that JRuby will recognize the variables as variables--rather than method calls--when it's parsing the script.
Otherwise you will get errors like `(NameError) undefined local variable or method 'input' for main:Object`.
This is not necessary in openHAB 4.0+.
@ -1266,8 +1316,7 @@ This is not necessary in openHAB 4.0+.
Once the addon is installed, you can create a Ruby file in the `$OPENHAB_CONF/transform` directory, with the extension `.rb`.
When referencing the file, you need to specify the `RB` transform: `RB(mytransform.rb):%s`.
You can also specify additional variables to be set in the script using a URI-like query syntax: `RB(mytransform.rb?a=1&b=c):%s`
in order to share a single script with slightly different parameters for different items.
You can also specify additional variables to be set in the script using a URI-like query syntax: `RB(mytransform.rb?a=1&b=c):%s` in order to share a single script with slightly different parameters for different items.
##### Example: Display the wind direction in degrees and cardinal direction
@ -1309,7 +1358,8 @@ When 3 lights out of 10 lights are on, this will produce a formatted state of `3
#### Inline Transformations
Inline transformations are supported too. For example, to display the temperature in both °C and °F:
Inline transformations are supported too.
For example, to display the temperature in both °C and °F:
```Xtend
Number:Temperature Outside_Temperature "Outside Temperature [RB(| input.to_f.|('°C').then { |t| %(#{t.format('%d °C')} / #{t.to_unit('°F').format('%d °F')}) } ):%s]"
@ -1322,6 +1372,31 @@ When the item contains `0 °C`, this will produce a formatted state of `0 °C /
You can create an openHAB profile in JRuby that can be applied to item channel links.
For more details, see [#profile](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL.html#profile-class_method).
### Sitemaps
Sitemaps can be created via [sitemaps.build](https://openhab.github.io/openhab-jruby/main/OpenHAB/Core/Sitemaps/Provider.html#build-instance_method).
```ruby
sitemaps.build do
sitemap "default", "My Residence" do
frame label: "Control" do
text label: "Climate", icon: "if:mdi:home-thermometer-outline" do
frame label: "Main Floor" do
text item: MainFloor_AmbTemp
switch item: MainFloorThermostat_TargetMode, label: "Mode", mappings: %w[off auto cool heat]
setpoint item: MainFloorThermostat_SetPoint, label: "Set Point", visibility: "MainFloorThermostat_TargetMode!=off"
end
frame label: "Basement" do
text item: Basement_AmbTemp
switch item: BasementThermostat_TargetMode, label: "Mode", mappings: { OFF: "off", COOL: "cool", HEAT: "heat" }
setpoint item: BasementThermostat_SetPoint, label: "Set Point", visibility: "BasementThermostat_TargetMode!=off"
end
end
end
end
end
```
## File Based Rules
### Basic Rule Structure
@ -1360,8 +1435,8 @@ See [#changed](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL/Rules/Bu
##### Detecting Change Duration
Only execute a rule when an item state changed and stayed the same for a period of time. This method
can only be done using a file-based rule.
Only execute a rule when an item state changed and stayed the same for a period of time.
This method can only be done using a file-based rule.
```ruby
rule "Garage Door Alert" do
@ -1540,13 +1615,13 @@ See [Rule Guards](https://openhab.github.io/openhab-jruby/main/OpenHAB/DSL/Rules
### Rule Executions
Execution blocks are executed when a rule is triggered and all the rule conditions are met.
Multiple execution blocks can be specified. This can be useful especially when using a delay execution
block inbetween two run or triggered blocks.
Multiple execution blocks can be specified.
This can be useful especially when using a delay execution block inbetween two run or triggered blocks.
#### Run Execution Block
A run execution block is the most commonly used execution block. It provides the full [event object](#event-object)
to the block.
A run execution block is the most commonly used execution block.
It provides the full [event object](#event-object) to the block.
```ruby
rule "Rule with a run block" do
@ -1559,8 +1634,8 @@ end
#### Triggered Execution Block
A triggered execution block passes the `TriggeringItem` object directly to the block. It is handy when combined with
Ruby's pretzel-colon operator to act directly on the object.
A triggered execution block passes the `TriggeringItem` object directly to the block.
It is handy when combined with Ruby's pretzel-colon operator to act directly on the object.
```ruby
rule "Limit the duration of TV watching" do
@ -1571,9 +1646,9 @@ end
#### Delay Execution Block
A delay exection block is useful for adding a delay inbetween rule executions or even at the beginning of the
trigger event without having to manually create a timer. Unlike `sleep`, a delay block does not block
the current executing thread. It actually sets a timer for you behind the scenes.
A delay exection block is useful for adding a delay inbetween rule executions or even at the beginning of the trigger event without having to manually create a timer.
Unlike `sleep`, a delay block does not block the current executing thread.
It actually sets a timer for you behind the scenes.
```ruby
rule "Check for offline things 15 minutes after openHAB had started" do
@ -1686,7 +1761,7 @@ end
## Calling Java From JRuby
JRuby can access almost any Java object that's available in the current JVM.
JRuby can [access almost any Java object](https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby) that's available in the current JVM.
This is how the library is implemented internally.
```ruby
@ -1699,4 +1774,6 @@ formatter = DateTimeFormatter.of_pattern("yyyy MM dd")
formatter = java.time.format.DateTimeFormatter.of_pattern("yyyy MM dd")
```
See [full documentation from JRuby](https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby)
## Full Documentation
Visit <https://openhab.github.io/openhab-jruby/> for the full documentation of the **openHAB JRuby Helper Library**.