openhab
v5.17.0
Published
JavaScript Library for openHAB Automation
Maintainers
Readme
openHAB JavaScript Library
This library aims to be a fairly high-level ES6 library to support automation in openHAB. It provides convenient access to common openHAB functionality within rules including Items, Things, actions, logging, and more.
This library is included by default in the openHAB JavaScript Scripting add-on.
- Installation
- Compatibility
- Configuration
- Scripting Basics
JSTransformation- Standard Library
- Rules created from Script Files
- Advanced Scripting
Installation
Default Installation
When installing the openHAB JavaScript Scripting add-on, a version of this library will be automatically installed and - depending on the add-on configuration - available to ECMAScript 2024+ for all or some rules.
openHAB also provides the JavaScript Scripting (Nashorn) add-on, which is based on the older Nashorn JavaScript engine. This is referred to as ECMA - 262 Edition 5.1 or application/javascript;version=ECMAScript-5.1 in the Main UI.
This library is not compatible with this older runtime.
Custom Installation
If you want to install the openHAB JavaScript library manually, you need to disable the caching of the internal library in the add-on settings.
On openHABian:
- Open the openHABian config tool:
sudo openhabian-config. - Select
40 | openHAB Related. - Select
46 | Install openhab-js.
Manually:
- Go to the JavaScript user scripts directory:
cd $OPENHAB_CONF/automation/js. - You may need to install
npm. - Install the latest release: Run
npm i openhab. - Install the latest development version: Run
npm i git+https://github.com/openhab/openhab-js.git.
NPM will create a node_modules directory containing the latest version of this library.
This will be used instead of the binding-provided version.
Compatibility
| openHAB version | Minimum openhab-js version | Maximum openhab-js version |
|-----------------|------------------------------|------------------------------|
| 3.2.x | 1.0.0 | 4.7.0 |
| 3.3.x | 1.0.0 | 4.7.0 |
| 3.4.x | 3.1.0 | 4.7.0 |
| 4.0.x | 4.2.1 | 4.7.0 |
| 4.1.0 | 4.2.1 | 4.7.0 |
| 4.1.1 etc. | 4.7.2 | 4.9.0 |
| 4.2.x | 5.0.0 | 5.7.2 |
| 4.3.x | 5.0.0 | 5.9.0 |
| 5.0.x | 5.0.0 | 5.15.0 |
| 5.1.x | 5.0.0 | |
Configuration
Rules in Main UI
Formerly known as UI-Based Rules.
The quickest way to use JavaScript Scripting is to create a rule in Main UI and add a Script Action, see Adding Actions below. If you only want to execute code and don't need triggers, you can instead create a script in Main UI.
Advanced users, or users migrating scripts from Rules DSL may want to use Rules created from Script Files for managing rules using files in the user configuration directory.
Adding Triggers
Using Main UI, first create a new rule and set a trigger condition.

Adding Actions
Select "Add Action" and then select "Inline Script" with "ECMAScript 262 Edition 11". This will add a so-called Script Action to the rule. It's important this is "Edition 11" or higher. Earlier versions will not work. This will bring up an empty script editor where you can enter your JavaScript.

You can now write rules using standard ES6 JavaScript along with the included openHAB Standard Library.

For example, turning a light on:
items.KitchenLight.sendCommand('ON');
console.log('Kitchen Light State', items.KitchenLight.state);Sending a notification
actions.NotificationAction.sendNotification('[email protected]', 'Balcony door is open');Querying the status of a thing
var thingStatusInfo = actions.Things.getThingStatusInfo('zwave:serial_zstick:512');
console.log('Thing status', thingStatusInfo.getStatus());See Standard Library for a complete list of functionality.
Adding Conditions
If you want the rule to only execute if one or many predefined conditions, e.g. some Item has a given state are met, select "Add Condition". Next, select "Script Condition" and, again, "ECMAScript 262 Edition 11".
You can now write conditions for your rule using standard ES6 JavaScript along with the included openHAB Standard Library.
When writing script conditions, the script has to provide a boolean value (true or false) whether the condition is met. This can be done in two ways:
Explicitly using
return: If the script condition wrapper is enabled (see below), thereturnkeyword has to be used to return a boolean value (trueorfalse). Example:if (items.KitchenWindow.state === 'OPEN') { return items.OutsideTemperature.quantityState.lessThan('12 °C') } return falseWhen using Blockly, there is a
returnblock available from the "Run & Process" category.Implicitly: If the script condition wrapper is not enabled or not available (see below), the last executed statement needs to evaluate to a boolean value. Example:
if (items.KitchenWindow.state === 'OPEN') { items.OutsideTemperature.quantityState.lessThan('12 °C') } false
The preferred way is explicit, as it is way clearer what is returned, however return is only supported if the script condition wrapper is enabled.
The script condition wrapper has been available since openHAB 5.1.0, previous versions only support implicit return.
It is advised to enable the wrapper and use explicit returns for all new script conditions, and step-by-step migrate existing conditions.
The wrapper can be enabled (and disabled as well) per script condition using the use wrapper directive:
- Adding
'use wrapper'or'use wrapper=true'(semicolons can be added) as the first or second line enables the wrapper. - Adding
'use wrapper=false'instead disables the wrapper.
New users of openHAB, users that haven't used script conditions with JavaScript Scripting before, and users that have migrated (through the directive) all conditions to wrapper use can simply turn on the "Wrap Script Conditions in Self-Executing Function" option in the add-on settings.
Event Object
When a rule is triggered, the script is provided the event instance that triggered it.
The specific data depends on the event type.
The event object provides some information about that trigger.
This table gives an overview over the event object:
| Property Name | Trigger Types | Description | Rules DSL Equivalent | Raw Event Object Equivalent |
|-------------------|-----------------------------------------------------|--------------------------------------------------------------------------------------------------------|------------------------|-----------------------------|
| oldState | ItemStateChangeTrigger, GroupStateChangeTrigger | Previous state of Item or Group that triggered event | previousState | oldItemState |
| newState | ItemStateChangeTrigger, GroupStateChangeTrigger | New state of Item or Group that triggered event | N/A | itemState |
| receivedState | ItemStateUpdateTrigger, GroupStateUpdateTrigger | State of Item that triggered event | triggeringItem.state | itemState |
| receivedCommand | ItemCommandTrigger, GroupCommandTrigger | Command that triggered event | receivedCommand | itemCommand |
| itemName | Item****Trigger, Group****Trigger | Name of Item that triggered event | triggeringItem.name | |
| groupName | Group****Trigger | Name of the group whose member triggered event | N/A | |
| receivedEvent | ChannelEventTrigger | Channel event that triggered event | N/A | event |
| channelUID | ChannelEventTrigger | UID of channel that triggered event | N/A | channel |
| oldStatus | ThingStatusChangeTrigger | Previous state of Thing that triggered event | N/A | |
| newStatus | ThingStatusChangeTrigger | New state of Thing that triggered event | N/A | |
| status | ThingStatusUpdateTrigger | State of Thing that triggered event | N/A | |
| thingUID | Thing****Trigger | UID of Thing that triggered event | N/A | |
| cronExpression | GenericCronTrigger | Cron expression of the trigger | N/A | |
| time | TimeOfDayTrigger | Time of day value of the trigger | N/A | |
| timeOnly | DateTimeTrigger | Whether the trigger only considers the time part of the DateTime Item | N/A | |
| offset | DateTimeTrigger | Offset in seconds added to the time of the DateTime Item | N/A | |
| eventType | all except PWMTrigger, PIDTrigger | Type of event that triggered event (change, command, triggered, update, time) | N/A | |
| triggerType | all except PWMTrigger, PIDTrigger | Type of trigger that triggered event | N/A | |
| eventName | all | simple Java class name of the triggering event, e.g. ExecutionEvent | N/A | type |
| eventClass | all | full Java class name of the triggering event, e.g. org.openhab.core.automation.events.ExecutionEvent | N/A | |
| eventTopic | all | topic of the triggering event, e.g. openhab/execution/29d999f4c4/triggered | N/A | topic |
| eventSource | all | structured source identifier of the sender of the event, not all senders will set the source | N/A | |
| module | all | (user-defined or auto-generated) name of trigger | N/A | |
| raw | all | Original contents of the event including data passed from a calling rule | N/A | |
All properties are typeof string except for properties contained by raw which are unmodified from the original types.
To learn more about the structure of the event source, refer to the Event Bus documentation.
Please note that when using GenericEventTrigger, the available properties depend on the chosen event types.
It is not possible for the openhab-js library to provide type conversions for all properties of all openHAB events, as those are too many.
In case the event object does not provide type-conversed properties for your chosen event type, use the payload property to gain access to the event's (Java data type) payload.
NOTE:
Group****Triggers use the equivalent Item****Trigger as trigger for each member.
See openhab-js : EventObject for full API documentation.
When disabling the option Convert Event from Java to JavaScript type in Script Actions & Script Conditions, you will receive a raw Java event object instead of the event object described above in Script Actions & Script Conditions.
This is useful for advanced users, but not recommended for most users.
See the expandable section below for more details.
This table gives an overview over the raw Java event object of Script Actions & Script Conditions (well-known rules in Main UI) for most common trigger types:
| Property Name | Type | Trigger Types | Description | Rules DSL Equivalent |
|----------------|----------------------------------------------------------------------------------------------------------------------|----------------------------------------|---------------------------------------------------------------------------------------------------------------|------------------------|
| itemState | sub-class of org.openhab.core.types.State | [item] changed, [item] was updated | State that triggered event | triggeringItem.state |
| oldItemState | sub-class of org.openhab.core.types.State | [item] changed | Previous state of Item or Group that triggered event | previousState |
| itemCommand | sub-class of org.openhab.core.types.Command | [item] received a command | Command that triggered event | receivedCommand |
| itemName | string | all | Name of Item that triggered event | triggeringItem.name |
| type | string | all | Type of event that triggered event ("ItemStateEvent", "ItemStateChangedEvent", "ItemCommandEvent", ...) | N/A |
| event | string | channel based triggers | Event data published by the triggering channel. | receivedEvent |
| payload | JSON formatted string | all | Any additional information provided by the trigger not already exposed. "{}" there is none. | N/A |
event, and therefore everything carried by event are Java types (not JavaScript).
Care must be taken when comparing these with JavaScript types:
var { ON } = require("@runtime")
console.log(event.itemState == "ON") // WRONG. Java type does not equal with string, not even with "relaxed" equals (==) comparison
console.log(event.itemState.toString() == "ON") // OK. Comparing strings
console.log(event.itemState == ON) // OK. Comparing Java typesNOTE: Even with String items, simple comparison with == is not working as one would expect! See below example:
// Example assumes String item trigger
console.log(event.itemState == "test") // WRONG. Will always log "false"
console.log(event.itemState.toString() == "test") // OKScripting Basics
The openHAB JavaScript Scripting runtime attempts to provide a familiar environment to JavaScript developers.
require
Scripts may include standard NPM libraries by using CommonJS require.
The library search will look in the path automation/js/node_modules in the user configuration directory.
See libraries for more information.
console
The JS Scripting binding supports the standard console object for logging.
Script logging is enabled by default at the INFO level (messages from console.debug and console.trace won't be displayed), but can be configured using the openHAB console:
log:set DEBUG org.openhab.automation.jsscripting
log:set TRACE org.openhab.automation.jsscripting
log:set DEFAULT org.openhab.automation.jsscriptingThe default logger name consists of the prefix org.openhab.automation.jsscripting and the script’s individual part .file.<filename>, .rule.<ruleUID>, or .transformation.<transformationUID>.
This logger name can be changed by assigning a new string to the loggerName property of the console:
console.loggerName = 'org.openhab.custom';Please be aware that messages do not appear in the logs if the logger name does not start with org.openhab.
This behaviour is due to log4j2 requiring a setting for each logger prefix in $OPENHAB_USERDATA/etc/log4j2.xml (on openHABian: /srv/openhab-userdata/etc/log4j2.xml).
Supported logging functions include:
console.log(obj1 [, obj2, ..., objN])console.info(obj1 [, obj2, ..., objN])console.warn(obj1 [, obj2, ..., objN])console.error(obj1 [, obj2, ..., objN])console.debug(obj1 [, obj2, ..., objN])console.trace(obj1 [, obj2, ..., objN])
Where obj1 ... objN is a list of JavaScript objects to output.
The string representations of each of these objects are appended together in the order listed and output.
See https://developer.mozilla.org/en-US/docs/Web/API/console for more information about console logging.
Note: openhab-js is logging to org.openhab.automation.openhab-js.
Timers
JS Scripting provides access to the global setTimeout, setInterval, clearTimeout and clearInterval methods specified in the Web APIs.
When a script is unloaded, all created timeouts and intervals are automatically cancelled.
setTimeout
The global setTimeout() method sets a timer which executes a function once the timer expires.
setTimeout() returns a timeoutId (a positive integer value) which identifies the timer created.
var timeoutId = setTimeout(callbackFunction, delay, param1, /* ... */ paramN);delay is an integer value that represents the number of milliseconds to wait before the timer expires.
param1 ... paramN are optional, additional arguments which are passed through to the callbackFunction.
The global clearTimeout(timeoutId) method cancels a timeout previously established by calling setTimeout().
If you need a more verbose way of creating timers, consider to use createTimer instead.
setInterval
The global setInterval() method repeatedly calls a function, with a fixed time delay between each call.
setInterval() returns an intervalId (a positive integer value) which identifies the interval created.
var intervalId = setInterval(callbackFunction, delay, param1, /* ... */ paramN);delay is an integer value that represents the number of milliseconds to wait before the timer expires.
param1 ... paramN are optional, additional arguments which are passed through to the callbackFunction.
The global clearInterval(intervalId) method cancels a timed, repeating action which was previously established by a call to setInterval().
Accessing Variables
You can access all variables of the current context in the created timers.
Note: Variables can be mutated (changed) after the timer has been created. Be aware that this can lead to unattended side effects, e.g. when you change the variable after timer creation, which can make debugging quite difficult!
var myVar = 'Hello world!';
// Schedule a timer that expires in ten seconds
setTimeout(() => {
console.info(`Timer expired with variable value = "${myVar}"`);
}, 10000);
myVar = 'Hello mutation!'; // When the timer runs, it will log "Hello mutation!" instead of "Hello world!"If you need to pass some variables to the timer but avoid that they can get mutated, pass those variables as parameters to setTimeout/setInterval or createTimer:
var myVar = 'Hello world!';
// Schedule a timer that expires in ten seconds
setTimeout((myVariable) => {
console.info(`Timer expired with variable value = "${myVariable}"`);
}, 10000, myVar); // Pass one or more variables as parameters here. They are passed through to the callback function.
myVar = 'Hello mutation!'; // When the timer runs, it will log "Hello world!"This also works for timers created with actions.ScriptExecution.createTimer.
Paths
For Rules created from Script Files, scripts will be loaded from automation/js in the user configuration directory.
NPM libraries will be loaded from automation/js/node_modules in the user configuration directory.
Deinitialization Hook
It is possible to hook into unloading of a script and register a function that is called when the script is unloaded.
require('@runtime').lifecycleTracker.addDisposeHook(() => functionToCall());
// Example
require('@runtime').lifecycleTracker.addDisposeHook(() => {
console.log("Deinitialization hook runs...")
});JS Transformation
openHAB provides several data transformation services as well as the script transformations, that are available from the framework and need no additional installation. It allows transforming values using any of the available scripting languages, which means JavaScript Scripting is supported as well. See the transformation docs for more general information on the usage of script transformations.
Use JavaScript Scripting as script transformation by:
Creating a script in the
$OPENHAB_CONF/transformfolder with the.jsextension. The script should take one argumentinputand return a value that supportstoString()ornull:(function(data) { // Do some data transformation here, e.g. return "String has" + data.length + "characters"; })(input);Using
JS(<scriptname>.js):%sas Item state transformation.Passing parameters is also possible by using a URL like syntax:
JS(<scriptname>.js?arg=value). Parameters are injected into the script and can be referenced like variables.
Simple transformations can aso be given as an inline script: JS(|...), e.g. JS(|"String has " + input.length + "characters").
It should start with the | character, quotes within the script may need to be escaped with a backslash \ when used with another quoted string as in text configurations.
Standard Library
Full documentation for the openHAB JavaScript library can be found at openhab-js.
The standard library is automatically injected into all scripts by default. However, it's recommended to enable auto-injection only for Script Actions & Script Conditions. To import the standard library namespaces manually, add the following at the beginning of your script:
// remove namespaces that are not needed by your code
const { actions, cache, items, things, time, triggers, utils, Quantity } = require('openhab');The openHAB JavaScript library provides type definitions for most of its APIs to enable code completion is IDEs like VS Code.
To use the type definitions, install the openhab npm package (read the installation guide for more information), and manually import the used namespaces (see above).
If an API does not provide type definitions and therefore autocompletion won't work, the documentation will include a note.
Items
The items namespace allows interactions with openHAB Items.
Anywhere a native openHAB Item is required, the runtime will automatically convert the JS-Item to its Java counterpart.
See openhab-js : items for full API documentation.
- items :
object- .NAME ⇒
Item - .existsItem(name) ⇒
boolean - .getItem(name, nullIfMissing) ⇒
Item - .getItems() ⇒
Array[Item] - .getItemsByTag(...tagNames) ⇒
Array[Item] - .addItem(itemConfig, persist) ⇒
Item - .removeItem(itemOrItemName) ⇒
Item|null - .replaceItem(itemConfig) ⇒
Item|null - .safeItemName(s) ⇒
string - .metadata ⇒
items.metadatanamespace: Manage metadata directly without the need of going "through" the Item - .itemChannelLink ⇒
items.itemChannelLinknamespace: Manage Item -> channel links
- .NAME ⇒
var item = items.KitchenLight;
console.log("Kitchen Light State", item.state);getItem(name, nullIfMissing)
Calling getItem(...) or ... returns an Item object with the following properties:
- Item :
object- .rawItem ⇒
HostItem - .persistence ⇒
ItemPersistence - .semantics ⇒
ItemSemantics - .type ⇒
string - .groupType ⇒
string|null - .name ⇒
string - .label ⇒
string - .state ⇒
string - .numericState ⇒
number|null: State as number, if state can be represented as number, ornullif that's not the case - .quantityState ⇒
Quantity|null: Item state as Quantity ornullif state is not Quantity-compatible or without unit - .boolState ⇒
boolean|null: Item state as boolean ornullif not boolean-compatible or is NULL or UNDEF, see below for mapping of state to boolean - .rawState ⇒
HostState - .previousState ⇒
string|null: Previous state as string, ornullif not available - .previousNumericState ⇒
number|null: Previous state as number, if state can be represented as number, ornullif that's not the case or not available - .previousQuantityState ⇒
Quantity|null: Previous item state as Quantity ornullif state is not Quantity-compatible, without unit, or not available - .previousRawState ⇒
HostState - .lastStateUpdateTimestamp ⇒
time.ZonedDateTime: The time the state was last updated as ZonedDateTime ornullif not available - .lastStateUpdateInstant ⇒
time.Instant: The time the state was last updated as Instant ornullif not available - .lastStateChangeTimestamp ⇒
time.ZonedDateTime: The time the state was last changed as ZonedDateTime ornullif not available - .lastStateChangeInstant ⇒
time.Instant: The time the state was last changed as Instant ornullif not available - .members ⇒
Array[Item] - .descendents ⇒
Array[Item] - .isInitialized ⇒
boolean - ~~.isUninitialized ⇒
boolean~~ use.isInitializedinstead - .groupNames ⇒
Array[string] - .tags ⇒
Array[string] - .getMetadata(namespace) ⇒
object|null - .replaceMetadata(namespace, value, configuration) ⇒
object - .removeMetadata(namespace) ⇒
object|null - .sendCommand(value):
valuecan be a string, a number, atime.ZonedDateTime, atime.Instant, or aQuantity - .sendCommand(value, expire):
expireis atime.Duration, this will return the Item to its previous state after the givenexpireduration - .sendCommand(value, expire, onExpire):
onExpirecan be the same type asvalue, this will return the Item to the givenonExpirevalue after the givenexpireduration - .sendCommandIfDifferent(value) ⇒
boolean:valuecan be a string, a number, atime.ZonedDateTime, atime.Instant, or aQuantity - .sendIncreaseCommand(value) ⇒
boolean:valuecan be a number, or aQuantity - .sendDecreaseCommand(value) ⇒
boolean:valuecan be a number, or aQuantity - .sendToggleCommand(): Sends a command to flip the Item's state (e.g. if it is
ON, anOFFcommand is sent). - .postUpdate(value):
valuecan be a string, atime.ZonedDateTime, or aQuantity - .addGroups(...groupNamesOrItems)
- .removeGroups(...groupNamesOrItems)
- .addTags(...tagNames)
- .removeTags(...tagNames)
- .rawItem ⇒
// Equivalent to items.KitchenLight
var item = items.getItem("KitchenLight");
// Send an ON command
item.sendCommand("ON");
// Post an update
item.postUpdate("OFF");
// Get state
console.log("KitchenLight state", item.state);The boolState property is mapped according to the following table:
| Item Type | .boolState |
|--------------------|----------------------------------------------------|
| Call | null |
| Color | brightness > 0 |
| Contact | state === OPEN |
| DateTime | null |
| Dimmer | state > 0 |
| Group | null if no group type, else use the group state |
| Image | null |
| Location | null |
| Number | state !== 0 |
| Number: | state !== 0 |
| Player | state === PLAY |
| Rollershutter | state > 0 |
| String | null |
| Switch | state === ON |
See openhab-js : Item for full API documentation.
itemConfig
Calling addItem(itemConfig) or replaceItem(itemConfig) requires the itemConfig object with the following properties:
- itemConfig :
object- .type ⇒
string: required, e.g.SwitchorGroup - .name ⇒
string: required - .label ⇒
string: optional - .category (icon) ⇒
string: optional - .groups ⇒
Array[string]: optional names of groups to be a member of - .tags ⇒
Array[string]: optional - .group ⇒
object: optional additional config if Item is group Item- .type ⇒
string: optional type of the group, e.g.Switch - .function ⇒
string: optional aggregation function, e.g.AND - .parameters ⇒
Array[string]: parameters possibly required by aggregation function, e.g.ONandOFF
- .type ⇒
- .channels ⇒
string | Object { channeluid: { config } } - .metadata ⇒
Object { namespace: 'value' } | Object { namespace: { value: '' , configuration: { ... } } }
- .type ⇒
There are a few short forms for common metadata available:
- itemConfig :
object- .format ⇒
string: short form forstateDescriptionmetadata's pattern configuration - .unit ⇒
string: short form for theunitmetadata - .autoupdate ⇒
boolean: short form for theautoupdatemetadata
- .format ⇒
Note: .type and .name are required.
Basic UI and the mobile apps need metadata.stateDescription.configuration.pattern to render the state of an Item.
Example:
items.replaceItem({
type: 'Switch',
name: 'MySwitch',
label: 'My Switch'
});
items.replaceItem({
type: 'String',
name: 'Hallway_Light',
label: 'Hallway Light',
category: 'light',
groups: ['Hallway', 'Light'],
tags: ['Lightbulb'],
channels: {
'binding:thing:device:hallway#light': {},
'binding:thing:device:livingroom#light': {
profile: 'system:follow'
}
},
metadata: {
expire: '10m,command=1',
stateDescription: {
config: {
pattern: '%d%%',
options: '1=Red, 2=Green, 3=Blue'
}
}
}
});
items.replaceItem({
type: 'Group',
name: 'gLights',
label: 'Lights',
group: {
type: 'Switch',
function: 'AND',
parameters: ['ON', 'OFF']
}
});See openhab-js : ItemConfig for full API documentation.
Providing Items (& metadata & channel links) from Scripts
The addItem method can be used to provide Items from scripts in a configuration-as-code manner.
It also allows providing metadata and channel configurations for the Item, basically creating the Item as if it was defined in a .items file.
The benefit of using addItem is that you can use loops, conditions, or generator functions to create lots of Items without the need to write them all out in a file or manually in the UI.
When called from script files, the created Item will share the lifecycle with the script, meaning it will be removed when the script is unloaded.
You can use the persist parameter to optionally persist the Item from script files.
When called from Script Actions, the Item will be stored permanently and will not be removed when the script is unloaded. Keep in mind that attempting to add an Item with the same name as an existing Item will result in an error.
See openhab-js : Item for full API documentation.
ItemPersistence
Calling Item.persistence returns an ItemPersistence object with the following functions:
- ItemPersistence :
object- .averageSince(timestamp, riemannType, serviceId) ⇒
PersistedState | null - .averageUntil(timestamp, riemannType, serviceId) ⇒
PersistedState | null - .averageBetween(begin, end, riemannType, serviceId) ⇒
PersistedState | null - .changedSince(timestamp, serviceId) ⇒
boolean - .changedUntil(timestamp, serviceId) ⇒
boolean - .changedBetween(begin, end, serviceId) ⇒
boolean - .countSince(timestamp, serviceId) ⇒
number - .countUntil(timestamp, serviceId) ⇒
number - .countBetween(begin, end, serviceId) ⇒
number - .countStateChangesSince(timestamp, serviceId) ⇒
number - .countStateChangesUntil(timestamp, serviceId) ⇒
number - .countStateChangesBetween(begin, end, serviceId) ⇒
number - .deltaSince(timestamp, serviceId) ⇒
PersistedState | null - .deltaUntil(timestamp, serviceId) ⇒
PersistedState | null - .deltaBetween(begin, end, serviceId) ⇒
PersistedState | null - .deviationSince(timestamp, riemannType, serviceId) ⇒
PersistedState | null - .deviationUntil(timestamp, riemannType, serviceId) ⇒
PersistedState | null - .deviationBetween(begin, end, riemannType, serviceId) ⇒
PersistedState | null - .evolutionRateSince(timestamp, riemannType, serviceId) ⇒
number | null - .evolutionRateUntil(timestamp, riemannType, serviceId) ⇒
number | null - .evolutionRateBetween(begin, end, riemannType, serviceId) ⇒
number | null - .getAllStatesSince(timestamp, serviceId) ⇒
Array[PersistedItem] - .getAllStatesUntil(timestamp, serviceId) ⇒
Array[PersistedItem] - .getAllStatesBetween(begin, end, serviceId) ⇒
Array[PersistedItem] - .lastUpdate(serviceId) ⇒
ZonedDateTime | null - .nextUpdate(serviceId) ⇒
ZonedDateTime | null - .lastChange(serviceId) ⇒
ZonedDateTime | null - .nextChange(serviceId) ⇒
ZonedDateTime | null - .maximumSince(timestamp, serviceId) ⇒
PersistedItem | null - .maximumUntil(timestamp, serviceId) ⇒
PersistedItem | null - .maximumBetween(begin, end, serviceId) ⇒
PersistedItem | null - .minimumSince(timestamp, serviceId) ⇒
PersistedItem | null - .minimumUntil(timestamp, serviceId) ⇒
PersistedItem | null - .minimumBetween(begin, end, serviceId) ⇒
PersistedItem | null - .medianSince(timestamp, serviceId) ⇒
PersistedState | null - .medianUntil(timestamp, serviceId) ⇒
PersistedState | null - .medianBetween(begin, end, serviceId) ⇒
PersistedState | null - .persist(serviceId): Tells the persistence service to store the current Item state, which is then done asynchronously.
Warning: This has the side effect, that if the Item state changes shortly after
.persisthas been called, the new Item state will be persisted. See JSDoc for a possible work-around. - .persist(timestamp, state, serviceId): Tells the persistence service to store the given state at the given timestamp, which is then done asynchronously.
- .persist(timeSeries, serviceId): Tells the persistence service to store the given
TimeSeries, which is then done asynchronously. - .persistedState(timestamp, serviceId) ⇒
PersistedItem | null - .previousState(skipEqual, serviceId) ⇒
PersistedItem | null - .nextState(skipEqual, serviceId) ⇒
PersistedItem | null - .riemannSumSince(timestamp, riemannType, serviceId) ⇒
PersistedState | null - .riemannSumUntil(timestamp, riemannType, serviceId) ⇒
PersistedState | null - .riemannSumBetween(begin, end, riemannType, serviceId) ⇒
PersistedState | null - .sumSince(timestamp, serviceId) ⇒
PersistedState | null - .sumUntil(timestamp, serviceId) ⇒
PersistedState | null - .sumBetween(begin, end, serviceId) ⇒
PersistedState | null - .updatedSince(timestamp, serviceId) ⇒
boolean - .updatedUntil(timestamp, serviceId) ⇒
boolean - .updatedBetween(begin, end, serviceId) ⇒
boolean - .varianceSince(timestamp, serviceId) ⇒
PersistedState | null - .varianceUntil(timestamp, serviceId) ⇒
PersistedState | null - .varianceBetween(begin, end, serviceId) ⇒
PersistedState | null
- .averageSince(timestamp, riemannType, serviceId) ⇒
riemannType is an optional argument for methods that require calculating an approximation of the integral value.
The approximation is calculated using a Riemann sum, with left, right, trapezoidal or midpoint value approximations.
The argument is a Java RiemannType enum with possible values: RiemannType.LEFT, RiemannType.RIGHT, RiemannType.TRAPEZOIDAL or RiemannType.MIDPOINT. If omitted, RiemannType.LEFT is used.
The RiemannType enum can be statically accessed on the items namespace, e.g.:
items.RiemannType.LEFTA Riemann sum is always calculated using seconds as unit for time.
As an example, the Riemann sum of power values in kW will result in an energy measurement in kWs.
You can rely on framework functionality to convert to the appropriate unit (e.g. kWh), or do an explicit conversion.
If you don't use units, be aware of this time factor.
Note: serviceId is optional, if omitted, the default persistence service will be used.
var yesterday = new Date(new Date().getTime() - (24 * 60 * 60 * 1000));
var item = items.KitchenDimmer;
console.log('KitchenDimmer averageSince', item.persistence.averageSince(yesterday));The PersistedState object contains the following properties, representing Item state:
state: State as stringnumericState: State as number, if state can be represented as number, ornullif that's not the casequantityState: Item state asQuantityornullif state is not Quantity-compatiblerawState: State as JavaStateobject
The PersistedItem object extends PersistedState with the following properties, representing Item state and the respective timestamp:
timestamp: Timestamp astime.ZonedDateTimeinstant: Timestamp astime.Instant
var midnight = time.toZDT('00:00');
var historic = items.KitchenDimmer.persistence.maximumSince(midnight);
console.log('KitchenDimmer maximum was ', historic.state, ' at ', historic.timestamp);See openhab-js : ItemPersistence for full API documentation.
TimeSeries
A TimeSeries is used to transport a set of states together with their timestamp.
It is usually used for persisting historic state or forecasts in a persistence service by using ItemPersistence.persist.
When creating a new TimeSeries, a policy must be chosen - it defines how the TimeSeries is persisted in a persistence service:
ADDadds the content to the persistence, well suited for persisting historic data.REPLACEfirst removes all persisted elements in the timespan given by begin and end of theTimeSeries, well suited for persisting forecasts.
A TimeSeries object has the following properties and methods:
policy: The persistence policy, eitherADDorREPLACE.begin: Timestamp of the first element of theTimeSeries.end: Timestamp of the last element of theTimeSeries.size: Number of elements in theTimeSeries.states: States of theTimeSeriestogether with their timestamp and sorted by their timestamps. Be aware that this returns a reference to the internal state array, so changes to the array will affect theTimeSeries.add(timestamp, state): Add a given state to theTimeSeriesat the given timestamp.
The following example shows how to create a TimeSeries:
var timeSeries = new items.TimeSeries('ADD'); // Create a new TimeSeries with policy ADD
timeSeries.add(time.toZDT('2024-01-01T14:53'), Quantity('5 m')).add(time.toZDT().minusMinutes(2), Quantity('0 m')).add(time.toZDT().plusMinutes(5), Quantity('5 m'));
console.log(ts); // Let's have a look at the TimeSeries
items.getItem('MyDistanceItem').persistence.persist(timeSeries, 'influxdb'); // Persist the TimeSeries for the Item 'MyDistanceItem' using the InfluxDB persistence serviceThings
The Things namespace allows interacting with openHAB Things.
See openhab-js : things for full API documentation.
- things : object
- .getThing(uid) ⇒ Thing|null
- .getThings() ⇒ Array[Thing]
getThing(uid, nullIfMissing)
Calling getThing(uid) returns a Thing object with the following properties:
- Thing : object
- .bridgeUID ⇒ String
- .label ⇒ String
- .location ⇒ String
- .status ⇒ String
- .statusInfo ⇒ String
- .thingTypeUID ⇒ String
- .uid ⇒ String
- .isEnabled ⇒ Boolean
- .setLabel(label)
- .setLocation(location)
- .setProperty(name, value)
- .setEnabled(enabled)
var thing = things.getThing('astro:moon:home');
console.log('Thing label: ' + thing.label);
// Set Thing location
thing.setLocation('living room');
// Disable Thing
thing.setEnabled(false);Actions
The actions namespace allows interactions with openHAB actions. The following is a list of standard actions.
Warning: Please be aware that (unless not explicitly noted) there is no type conversion from Java to JavaScript types for the return values of actions. Read the Javadoc linked from the JSDoc to learn about the returned Java types.
Please note that most of the actions currently do not provide type definitions and therefore auto-completion does not work.
See openhab-js : actions for full API documentation and additional actions.
Audio Actions
See openhab-js : actions.Audio for complete documentation.
BusEvent Actions
See openhab-js : actions.BusEvent for complete documentation.
CoreUtil Actions
See openhab-js : actions.CoreUtil for complete documentation.
The CoreUtil actions provide access to parts of the utilities included in openHAB core, see org.openhab.core.util.
These include several methods to convert between color types like HSB, RGB, sRGB, RGBW and XY.
Ephemeris Actions
See openhab-js : actions.Ephemeris for complete documentation.
Ephemeris is a way to determine what type of day today or the number of days before or after today is. For example, a way to determine if today is a weekend, a public holiday, someone’s birthday, trash day, etc.
Additional information can be found on the Ephemeris Actions Docs as well as the Ephemeris Javadoc.
var weekend = actions.Ephemeris.isWeekend();Exec Actions
See openhab-js : actions.Exec for complete documentation.
Execute a command line.
// Execute command line.
actions.Exec.executeCommandLine('echo', 'Hello World!');
// Execute command line with timeout.
actions.Exec.executeCommandLine(time.Duration.ofSeconds(20), 'echo', 'Hello World!');
// Get response from command line with timeout.
var response = actions.Exec.executeCommandLine(time.Duration.ofSeconds(20), 'echo', 'Hello World!');HTTP Actions
See openhab-js : actions.HTTP for complete documentation.
// Example GET Request
var response = actions.HTTP.sendHttpGetRequest('<url>');Replace <url> with the request url.
Ping Actions
See openhab-js : actions.Ping for complete documentation.
// Check if a host is reachable
var reachable = actions.Ping.checkVitality(host, port, timeout); // host: string, port: int, timeout: intScriptExecution Actions
The ScriptExecution actions provide the callScript(string scriptName) method, which calls a script located at the $OH_CONF/scripts folder, as well as the createTimer method.
You can also create timers using the native JS methods for timer creation, your choice depends on the versatility you need.
Sometimes, using setTimeout is much faster and easier, but other times, you need the versatility that createTimer provides.
Keep in mind that you should somehow manage the timers you create using createTimer, otherwise you could end up with unmanageable timers running until you restart openHAB.
A possible solution is to store all timers in the private cache and let openHAB automatically cancel them when the script is unloaded and the cache is cleared.
When using createTimer, please read Accessing Variables to avoid having unexpected results when using variables in timers.
createTimer
actions.ScriptExecution.createTimer(time.ZonedDateTime zdt, function functionRef, any param1, /* ... */ paramN);
actions.ScriptExecution.createTimer(string identifier, time.ZonedDateTime zdt, function functionRef, any param1, /* ... */ paramN);createTimer accepts the following arguments:
stringidentifier (optional): Identifies the timer by a string, used e.g. for logging errors that occur during the callback execution.time.ZonedDateTimezdt: Point in time when the callback should be executed.functionfunctionRef: Callback function to execute when the timer expires.*param1, ..., paramN: Additional arguments which are passed through to the function specified byfunctionRef.
createTimer returns an openHAB Timer, that provides the following methods:
cancel(): Cancels the timer. ⇒boolean: true, if cancellation was successfulgetExecutionTime(): The scheduled execution time or null if timer was cancelled. ⇒time.ZonedDateTimeornullisActive(): Whether the scheduled execution is yet to happen. ⇒booleanisCancelled(): Whether the timer has been cancelled. ⇒booleanhasTerminated(): Whether the scheduled execution has already terminated. ⇒booleanreschedule(time.ZonedDateTime): Reschedules a timer to a new starting time. This can also be called after a timer has terminated, which will result in another execution of the same code. ⇒boolean: true, if rescheduling was successful
var now = time.ZonedDateTime.now();
// Function to run when the timer goes off.
function timerOver () {
console.info('The timer expired.');
}
// Create the Timer.
var myTimer = actions.ScriptExecution.createTimer('My Timer', now.plusSeconds(10), timerOver);
// Cancel the timer.
myTimer.cancel();
// Check whether the timer is active. Returns true if the timer is active and will be executed as scheduled.
var active = myTimer.isActive();
// Reschedule the timer.
myTimer.reschedule(now.plusSeconds(5));See openhab-js : actions.ScriptExecution for complete documentation.
Transformation Actions
openHAB provides various data transformation services which can translate between technical and human-readable values. Usually, they are used directly on Items, but it is also possible to access them from scripts.
console.log(actions.Transformation.transform('MAP', 'en.map', 'OPEN')); // open
console.log(actions.Transformation.transform('MAP', 'de.map', 'OPEN')); // offenSee openhab-js : actions.Transformation for complete documentation.
Voice Actions
See openhab-js : actions.Voice for complete documentation.
Cloud Notification Actions
Requires the openHAB Cloud Connector to be installed.
Notification actions may be placed in rules to send alerts to mobile devices registered with an openHAB Cloud instance such as myopenHAB.org.
There are three different types of notifications:
- Broadcast Notifications: Sent to all registered devices and shown as a notification on these devices.
- Standard Notifications: Sent to the registered devices of the specified user and shown as notification on his devices.
- Log Notifications: Only shown in the notification log, e.g. inside the Android and iOS Apps.
In addition to that, notifications can be updated later be re-using the same referenceId and hidden/removed either by referenceId or tag.
To send these three types of notifications, use the notificationBuilder(message) method of the actions namespace.
message is optional and may be omitted.
It returns a new NotificationBuilder object, which by default sends a broadcast notification and provides the following methods:
.logOnly(): Send a log notification only..hide(): Hides notification(s) with the specifiedreferenceIdortag(referenceIdhas precedence overtag)..addUserId(emailAddress): By adding the email address(es) of specific openHAB Cloud user(s), the notification is only sent to this (these) user(s). To add multiple users, either calladdUserIdmultiple times or pass multiple emails as multiple params, e.g.addUserId(emailAddress1, emailAddress2)..withIcon(icon): Sets the icon of the notification..withTag(tag): Sets the tag of the notification. Used for grouping notifications and to hide/remove groups of notifications..withTitle(title): Sets the title of the notification..withReferenceId(referenceId): Sets the reference ID of the notification. If none is set, but it might be useful, a random UUID will be generated. The reference ID can be used to update or hide the notification later by using the same reference ID again..withOnClickAction(action): Sets the action to be executed when the notification is clicked..withMediaAttachmentUrl(mediaAttachmentUrl): Sets the URL of a media attachment to be displayed with the notification. This URL must be reachable by the push notification client..addActionButton(label, action): Adds an action button to the notification. Please note that due to Android and iOS limitations, only three action buttons are supported..send()⇒string|null: Sends the notification and returns the reference ID ornullfor log notifications and when hiding notifications.
The syntax for the action parameter is described in openHAB Cloud Connector: Action Syntax.
The syntax for the mediaAttachmentUrl parameter is described in openHAB Cloud Connector.
// Send a simple broadcast notification
actions.notificationBuilder('Hello World!').send();
// Send a broadcast notification with icon, tag and title
actions.notificationBuilder('Hello World!')
.withIcon('f7:bell_fill').withTag('important').withTitle('Important Notification').send();
// Send a broadcast notification with icon, tag, title, media attachment URL and actions
actions.notificationBuilder('Hello World!')
.withIcon('f7:bell_fill').withTag('important').withTitle('Important Notification')
.withOnClickAction('ui:navigate:/page/my_floorplan_page').withMediaAttachmentUrl('https://example.com/image.jpg')
.addActionButton('Turn Kitchen Light ON', 'command:KitchenLights:ON').addActionButton('Turn Kitchen Light OFF', 'command:KitchenLights:OFF').send();
// Send a simple standard notification to two specific users
actions.notificationBuilder('Hello World!').addUserId('[email protected]').addUserId('[email protected]').send();
// Send a standard notification with icon, tag and title to two specific users
actions.notificationBuilder('Hello World!').addUserId('[email protected]').addUserId('[email protected]')
.withIcon('f7:bell_fill').withTag('important').withTitle('Important notification').send();
// Sends a simple log notification
actions.notificationBuilder('Hello World!').logOnly().send();
// Sends a simple log notification with icon and tag
actions.notificationBuilder('Hello World!').logOnly()
.withIcon('f7:bell_fill').withTag('important').send();
// Sends a notification about a temperature change ...
actions.notificationBuilder('new temperature: xyz').withIcon('oh:temperature').withTag('Temperature change').withReferenceId('livingRoom').send();
// ... and hides it again after 10 minutes
setTimeout(() => {
actions.notificationBuilder().hide().withReferenceId('livingRoom').send();
}, 10 * 60 * 1000);See openhab-js : actions.NotificationBuilder for complete documentation.
Cache
The cache namespace provides both a private and a shared cache that can be used to set and retrieve data that will be persisted between subsequent runs of the same or between scripts.
The private cache can only be accessed by the same script and is cleared when the script is unloaded.
You can use it to store primitives and objects, e.g. store timers or counters between subsequent runs of that script.
When a script is unloaded and its cache is cleared, all timers (see createTimer) stored in its private cache are automatically cancelled.
The shared cache is shared across all rules and scripts, it can therefore be accessed from any automation language. The access to every key is tracked, and the key is removed when all scripts that ever accessed that key are unloaded. If that key stored a timer, the timer will be cancelled. You can use it to store primitives and Java objects, e.g. store timers or counters between multiple scripts.
Due to a multi-threading limitation in GraalJS (the JavaScript engine used by JavaScript Scripting), it is not recommended to store JavaScript objects in the shared cache. Multithreaded access to JavaScript objects will lead to script execution failure! You can work around that limitation by either serialising and deserialising JS objects or by switching to their Java counterparts.
Timers as created by createTimer can be stored in the shared cache.
The ids of timers and intervals as created by setTimeout and setInterval cannot be shared across scripts as these ids are local to the script where they were created.
See openhab-js : cache for full API documentation.
- cache : object
- .private
- .get(key, defaultSupplier) ⇒ * | null
- .put(key, value) ⇒ Previous * | null
- .remove(key) ⇒ Previous * | null
- .exists(key) ⇒ boolean
- .shared
- .get(key, defaultSupplier) ⇒ * | null
- .put(key, value) ⇒ Previous * | null
- .remove(key) ⇒ Previous * | null
- .exists(key) ⇒ boolean
- .private
The defaultSupplier provided function will return a default value if a specified key is not already associated with a value.
Example (Get a previously set value with a default value (times = 0))
var counter = cache.shared.get('counter', () => 0);
console.log('Counter: ' + counter);Example (Get a previously set value, modify and store it)
var counter = cache.private.get('counter');
counter++;
console.log('Counter: ' + counter);
cache.private.put('counter', counter);Time
openHAB internally makes extensive use of the java.time package.
openHAB-JS exports the excellent JS-Joda library via the time namespace, which is a native JavaScript port of the same API standard used in Java for java.time.
Anywhere a native Java ZonedDateTime, Instant, or Duration is required, the runtime will automatically convert a JS-Joda ZonedDateTime, Instant, or Duration to its Java counterpart.
The exported JS-Joda library is also extended with convenient functions relevant to openHAB usage.
Examples:
var now = time.ZonedDateTime.now();
var yesterday = time.ZonedDateTime.now().minusHours(24);
var item = items.Kitchen;
console.log("averageSince", item.persistence.averageSince(yesterday));actions.Exec.executeCommandLine(time.Duration.ofSeconds(20), 'echo', 'Hello World!');See JS-Joda for more examples and complete API usage.
Parsing and Formatting
Occasionally, one will need to parse a non-supported date time string or generate one from a ZonedDateTime.
To do this, you will use JS-Joda DateTimeFormatter and potentially your Locale.
However, shipping all the locales with the openhab-js library would lead to an unacceptable large size.
Therefore, if you attempt to use the DateTimeFormatter and receive an error saying it cannot find your locale, you will need to manually install your locale and import it into your rule.
JS-Joda Locales includes a list of all the supported locales.
Each locale consists of a two-letter language indicator followed by a "-" and a two-letter dialect indicator: e.g. "EN-US".
Installing a locale can be done through the command npm install @js-joda/locale_de-de from the $OPENHAB_CONF/automation/js folder.
To import and use a local into your rule, you need to require it and create a DateTimeFormatter that uses it:
var Locale = require('@js-joda/locale_de-de').Locale.GERMAN;
var formatter = time.DateTimeFormatter.ofPattern('dd.MM.yyyy HH:mm').withLocale(Locale);time.javaInstantToJsInstant()
Converts a java.time.Instant to a JS-Joda Instant.
time.javaZDTToJsZDT()
Converts a java.time.ZonedDateTime to a JS-Joda ZonedDateTime.
time.toZDT()
There will be times when this automatic conversion is not available (for example, when working with date times within a rule).
To ease having to deal with these cases a time.toZDT() function will accept almost any type that can be converted to a time.ZonedDateTime.
The following rules are used during the conversion:
| Argument Type | Rule
