diff --git a/configuration/jsr223.md b/configuration/jsr223.md index 549711e592..d87709ebb1 100644 --- a/configuration/jsr223.md +++ b/configuration/jsr223.md @@ -236,23 +236,27 @@ Note that prior to openHAB 3, script ordering was performed alphanumerically bas To facilitate JSR223 scripting, several openHAB-related variables are automatically predefined within `ScriptExtension` presets. They can be loaded into the script context using `scriptExtension.importPreset(String preset)`, e.g. `scriptExtension.importPreset("RuleSimple")`. -The `default` preset is preloaded, so it does not require importing. +The `default`, `lifecycle` and `media` presets are preloaded, so they do not require importing. With `scriptExtension.get("automationManager")` the `automationManager` can be made available without loading a preset. - [Overview](#overview) - [Example rules for a first impression](#example-rules-for-a-first-impression) - [Script Locations](#script-locations) - [`ScriptExtension` Objects (all JSR223 languages)](#scriptextension-objects-all-jsr223-languages) - - [Default Preset (`importPreset` not required)](#default-preset-importpreset-not-required) + - [`default` Preset (`importPreset` not required)](#default-preset-importpreset-not-required) - [`events` operations](#events-operations) + - [`lifecycle` Preset (`importPreset` not required)](#lifecycle-preset-importpreset-not-required) + - [`media` Preset (`importPreset` not required)](#media-preset-importpreset-not-required) - [`RuleSimple` Preset](#rulesimple-preset) - [`RuleSupport` Preset](#rulesupport-preset) - [`RuleFactories` Preset](#rulefactories-preset) - [`ScriptAction` Preset](#scriptaction-preset) - [`cache` Preset](#cache-preset) + - [`provider` Preset](#provider-preset) - [`TriggerType` Objects (all JSR223 languages)](#triggertype-objects-all-jsr223-languages) + - [The `scriptLoaded` and `scriptUnloaded` functions](#the-scriptloaded-and-scriptunloaded-functions) -#### Default Preset (`importPreset` not required) +#### `default` Preset (`importPreset` not required) | Variable | Description | |-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -335,6 +339,24 @@ With `scriptExtension.get("automationManager")` the `automationManager` can be m - `events.storeStates(Item...)` - `events.restoreStates(Map)` +#### `lifecycle` Preset (`importPreset` not required) + +It provides a mechanism to execute code, when the script is deleted. +Modifying a script deletes it and creates it again. + +| Variable | Description | +|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `lifecycleTracker` | [`org.openhab.core.automation.module.script.LifecycleScriptExtensionProvider.LifecycleTracker`](https://www.openhab.org/javadoc/latest/org/openhab/core/automation/module/script/lifecyclescriptextensionprovider.lifecycletracker) | + +This is demonstrated in [The `scriptLoaded` and `scriptUnloaded` functions](#the-scriptloaded-and-scriptunloaded-functions) section. + +#### `media` Preset (`importPreset` not required) + +| Variable | Description | +|----------|---------------------------------------------------------------------------------------------------------------------| +| `audio` | [`org.openhab.core.audio.AudioManager`](https://www.openhab.org/javadoc/latest/org/openhab/core/audio/audiomanager) | +| `voice` | [`org.openhab.core.voice.VoiceManager`](https://www.openhab.org/javadoc/latest/org/openhab/core/voice/voicemanager) | + #### `RuleSimple` Preset These variables and classes are loaded using: @@ -532,6 +554,25 @@ Both caches implement the `org.openhab.core.automation.module.script.rulesupport - `Object get(String key)`: Get the value for the given key from the cache. Non-existent keys return `null`. - `Object get(String key, Supplier supplier`: Get the value for the given key. If no value is present, add the value that is return from the `supplier`. +#### `provider` Preset + +The preset is available since openHAB 5.0. + +| Variable | Description | +|---------------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `itemRegistry` | [`org.openhab.core.automation.module.script.providersupport.shared.ProviderItemRegistryDelegate`](https://www.openhab.org/javadoc/latest/org/openhab/core/automation/module/script/providersupport/shared/provideritemregistrydelegate) | +| `metadataRegistry` | [`org.openhab.core.automation.module.script.providersupport.shared.ProviderMetadataRegistryDelegate`](https://www.openhab.org/javadoc/latest/org/openhab/core/automation/module/script/providersupport/shared/providermetadataregistrydelegate) | +| `thingRegistry` | [`org.openhab.core.automation.module.script.providersupport.shared.ProviderThingRegistryDelegate`](https://www.openhab.org/javadoc/latest/org/openhab/core/automation/module/script/providersupport/shared/providerthingregistrydelegate) | +| `itemChannelLinkRegistry` | [`org.openhab.core.automation.module.script.providersupport.shared.ProviderItemChannelLinkRegistry`](https://www.openhab.org/javadoc/latest/org/openhab/core/automation/module/script/providersupport/shared/provideritemchannellinkregistry) | + +The above instances provide implementations of the interfaces [`org.openhab.core.items.ItemRegistry`](https://www.openhab.org/javadoc/latest/org/openhab/core/items/itemregistry), [`org.openhab.core.items.MetadataRegistry`](https://www.openhab.org/javadoc/latest/org/openhab/core/items/metadataregistry) and [`org.openhab.core.thing.ThingRegistry`](https://www.openhab.org/javadoc/latest/org/openhab/core/thing/thingregistry) respectively. +The `itemChannelLinkRegistry` does not provide the same methods as the [`org.openhab.core.thing.link.ItemChannelLinkRegistry`](https://www.openhab.org/javadoc/latest/org/openhab/core/thing/link/itemchannellinkregistry) interface. + +All instances from this preset have an `addPermanent(…)` method, in addition to `add(…)`. +With the `add(…)` method, elements added over the above instances are removed, when the script, which inserted the elements, is deleted or changed. +When `addPermanent(…)` is used, the inserted elements are … not removed. +`itemRegistry.addPermanent(…)`/`thingRegistry.addPermanent(…)` from this preset offer the same functionality as `itemRegistry.add(…)`/`things.add(…)` from the `default` preset. + ### `TriggerType` Objects (all JSR223 languages) The following trigger types are defined by openHAB (custom triggers can also be defined) and take the specified configuration parameters. @@ -666,3 +707,131 @@ Read the JSR223 language specific documentation for examples of using these `Tri | `startlevel` | The system `StartLevel` | ::: + +### The `scriptLoaded` and `scriptUnloaded` functions + +When a JSR223 script is created or changed and it contains the `scriptLoaded(String)` function, OpenHAB executes it, and passes as parameter the path of the loaded script. +Similarly, when a script is changed or deleted, and the script contained the `scriptUnloaded()` function, it is invoked. +`scriptLoaded(String)` is only executed when a script from the automation add-on directory, like `${OPENHAB_CONF}/automation/jsr223/`, is loaded. +It is not executed in transformations, UI rules with Inline Script action, UI scripts. +The [`lifecycleTracker`](#lifecycle-preset-importpreset-not-required) object and the `scriptUnloaded()` function serve similar purposes. +When a script is executed several times, on each execution it adds a Disposable, and then the script is changed, its `scriptUnloaded()` is executed once and each added Disposable is also `dispose()`d. + +:::: tabs + +::: tab Groovy + +```groovy +static @groovy.transform.Field logger = org.slf4j.LoggerFactory.getLogger("org.openhab.automation.example") + +lifecycleTracker.addDisposeHook(new org.openhab.core.automation.module.script.LifecycleScriptExtensionProvider.Disposable() { + public void dispose() { + logger.error("I am logged fourth.") + } +}) + +lifecycleTracker.addDisposeHook{ logger.error("I am logged fifth. Bye!") } + +void scriptLoaded(String filename) { // can be static + logger.error("I am logged second and I am from ${filename}.") +} + +static void scriptUnloaded() { // can be non-static + logger.error("I am logged third.") +} +logger.error("I am logged first.") +``` + +::: + +::: tab JS Nashorn + +```js +var logger = Java.type('org.slf4j.LoggerFactory').getLogger("org.openhab.core.automation.examples") +lifecycleTracker.addDisposeHook(function() { + logger.error("I am logged fourth. Bye!") +}) +function scriptLoaded(filename) { + logger.error("I am logged second and I am from " + filename + ".") +} +function scriptUnloaded() { + logger.error("I am logged third.") +} +logger.error("I am logged first.") +``` + +::: + +::: tab JS Scripting + +```js +require('@runtime').lifecycleTracker.addDisposeHook( () => console.log("I am logged fourth. Bye!") ) + +const scriptUnloaded = () => console.log("I am logged third.") + +function scriptLoaded(filename) { + console.log(`I am logged second and I am from ${filename}.`) +} + +console.log("I am logged first.") +``` + +::: + +::: tab Jython + +```python +from org.slf4j import LoggerFactory + +logger = LoggerFactory.getLogger("org.openhab.core.automation.examples") + +def scriptUnloaded(): + logger.error("I am logged third.") + +def scriptLoaded(filename): + logger.error("I am logged second and I am from " + filename + ".") + +lifecycleTracker.addDisposeHook(lambda : logger.error("I am logged fourth. Bye!")) +logger.error("I am logged first.") +``` + +::: + +::: tab Python + +When the setting “Use scope and import wrapper” is on, the `scope` module is enabled: + +```python +import sys +import scope + +def scriptUnloaded(): + print("I am logged third.") + +def scriptLoaded(filename): + print("I am logged second and I am from " + filename + ".") + +scope.lifecycleTracker.addDisposeHook(lambda : print("I am logged fourth. Bye!")) + +print("I am logged first.") +``` + +When the `scope` module is disabled: + +```python +import sys + +def scriptUnloaded(): + print("I am logged third.") + +def scriptLoaded(filename): + print("I am logged second and I am from " + filename + ".") + +lifecycleTracker.addDisposeHook(lambda : print("I am logged fourth. Bye!")) + +print("I am logged first.") +``` + +::: + +::::