JavaScript Library for openHAB Automation
npm install openhab

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
- Default Installation
- Custom Installation
- Compatibility
- Configuration
- Rules in Main UI
- Event Object
- Scripting Basics
- require
- console
- Timers
- Paths
- Deinitialization Hook
- JS Transformation
- Standard Library
- Items
- Things
- Actions
- Cache
- Time
- Quantity
- Utils
- Environment
- Rules created from Script Files
- JSRule
- Rule Builder
- Advanced Scripting
- Libraries
- @runtime
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._
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.
| 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 | |
> 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:
``javascript`
items.KitchenLight.sendCommand('ON');
console.log('Kitchen Light State', items.KitchenLight.state);
Sending a notification
`javascript`
actions.NotificationAction.sendNotification('romeo@montague.org', 'Balcony door is open');
Querying the status of a thing
`javascript`
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), the return keyword has to be used to return a boolean value (true or false). Example:
`javascript`
if (items.KitchenWindow.state === 'OPEN') {
return items.OutsideTemperature.quantityState.lessThan('12 °C')
}
return false
When using Blockly, there is a return block 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:
`javascript`
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.'use wrapper=false'
- Adding 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.
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.payload
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 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.
Raw Script Module Event Object
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:
`javascript
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 types
`
NOTE: Even with String items, simple comparison with == is not working as one would expect! See below example:
`javascript`
// Example assumes String item trigger
console.log(event.itemState == "test") // WRONG. Will always log "false"
console.log(event.itemState.toString() == "test") // OK
The openHAB JavaScript Scripting runtime attempts to provide a familiar environment to JavaScript developers.
Scripts may include standard NPM libraries by using CommonJS require.automation/js/node_modules
The library search will look in the path in the user configuration directory.
See libraries for more information.
The JS Scripting binding supports the standard console object for logging.INFO
Script logging is enabled by default at the level (messages from console.debug and console.trace won't be displayed), but can be configured using the openHAB console:
`text`
log:set DEBUG org.openhab.automation.jsscripting
log:set TRACE org.openhab.automation.jsscripting
log:set DEFAULT org.openhab.automation.jsscripting
The default logger name consists of the prefix org.openhab.automation.jsscripting and the script’s individual part .file., .rule., or .transformation..loggerName
This logger name can be changed by assigning a new string to the property of the console:
`javascript`
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.$OPENHAB_USERDATA/etc/log4j2.xml
This behaviour is due to log4j2 requiring a setting for each logger prefix in (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
Note: openhab-js is logging to org.openhab.automation.openhab-js.
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.
`javascript`
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.
`javascript`
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!
`javascript
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:
`javascript
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.
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.
It is possible to hook into unloading of a script and register a function that is called when the script is unloaded.
`javascript
require('@runtime').lifecycleTracker.addDisposeHook(() => functionToCall());
// Example
require('@runtime').lifecycleTracker.addDisposeHook(() => {
console.log("Deinitialization hook runs...")
});
`
TransformationopenHAB 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:
1. Creating a script in the $OPENHAB_CONF/transform folder with the .js extension.input
The script should take one argument and return a value that supports toString() or null:
`javascript`
(function(data) {
// Do some data transformation here, e.g.
return "String has" + data.length + "characters";
})(input);
1. Using JS( as Item state transformation.JS(
1. Passing parameters is also possible by using a URL like syntax: .
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.
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:
`js`
// 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.
The items namespace allows interactions with openHAB Items.Item
Anywhere a native openHAB is required, the runtime will automatically convert the JS-Item to its Java counterpart.
See openhab-js : items for full API documentation.
- items : objectItem
- .NAME ⇒ boolean
- .existsItem(name) ⇒ Item
- .getItem(name, nullIfMissing) ⇒ Array[Item]
- .getItems() ⇒ Array[Item]
- .getItemsByTag(...tagNames) ⇒ Item
- .addItem(itemConfig, persist) ⇒ Item|null
- .removeItem(itemOrItemName) ⇒ Item|null
- .replaceItem(itemConfig) ⇒ string
- .safeItemName(s) ⇒ items.metadata
- .metadata ⇒ namespace: Manage metadata directly without the need of going "through" the Itemitems.itemChannelLink
- .itemChannelLink ⇒ namespace: Manage Item -> channel links
`javascript`
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 : objectHostItem
- .rawItem ⇒ ItemPersistence
- .persistence ⇒ ItemSemantics
- .semantics ⇒ string
- .type ⇒ string|null
- .groupType ⇒ string
- .name ⇒ string
- .label ⇒ string
- .state ⇒ number|null
- .numericState ⇒ : State as number, if state can be represented as number, or null if that's not the caseQuantity|null
- .quantityState ⇒ : Item state as Quantity or null if state is not Quantity-compatible or without unitboolean|null
- .boolState ⇒ : Item state as boolean or null if not boolean-compatible or is NULL or UNDEF, see below for mapping of state to booleanHostState
- .rawState ⇒ string|null
- .previousState ⇒ : Previous state as string, or null if not availablenumber|null
- .previousNumericState ⇒ : Previous state as number, if state can be represented as number, or null if that's not the case or not availableQuantity|null
- .previousQuantityState ⇒ : Previous item state as Quantity or null if state is not Quantity-compatible, without unit, or not availableHostState
- .previousRawState ⇒ time.ZonedDateTime
- .lastStateUpdateTimestamp ⇒ : The time the state was last updated as ZonedDateTime or null if not availabletime.Instant
- .lastStateUpdateInstant ⇒ : The time the state was last updated as Instant or null if not availabletime.ZonedDateTime
- .lastStateChangeTimestamp ⇒ : The time the state was last changed as ZonedDateTime or null if not availabletime.Instant
- .lastStateChangeInstant ⇒ : The time the state was last changed as Instant or null if not availableArray[Item]
- .members ⇒ Array[Item]
- .descendents ⇒ boolean
- .isInitialized ⇒ boolean
- ~~.isUninitialized ⇒ ~~ use .isInitialized insteadArray[string]
- .groupNames ⇒ Array[string]
- .tags ⇒ object|null
- .getMetadata(namespace) ⇒ object
- .replaceMetadata(namespace, value, configuration) ⇒ object|null
- .removeMetadata(namespace) ⇒ value
- .sendCommand(value): can be a string, a number, a time.ZonedDateTime, a time.Instant, or a Quantityexpire
- .sendCommand(value, expire): is a time.Duration, this will return the Item to its previous state after the given expire durationonExpire
- .sendCommand(value, expire, onExpire): can be the same type as value, this will return the Item to the given onExpire value after the given expire durationboolean
- .sendCommandIfDifferent(value) ⇒ : value can be a string, a number, a time.ZonedDateTime, a time.Instant, or a Quantityboolean
- .sendIncreaseCommand(value) ⇒ : value can be a number, or a Quantityboolean
- .sendDecreaseCommand(value) ⇒ : value can be a number, or a QuantityON
- .sendToggleCommand(): Sends a command to flip the Item's state (e.g. if it is , an OFF command is sent).value
- .postUpdate(value): can be a string, a time.ZonedDateTime, or a Quantity
- .addGroups(...groupNamesOrItems)
- .removeGroups(...groupNamesOrItems)
- .addTags(...tagNames)
- .removeTags(...tagNames)
`javascript`
// 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 |null
|--------------------|----------------------------------------------------|
| Call | |OPEN
| Color | brightness > 0 |
| Contact | state === |null
| DateTime | |null
| Dimmer | state > 0 |
| Group | if no group type, else use the group state |null
| Image | |null
| Location | |PLAY
| Number | state !== 0 |
| Number:
| Player | state === |null
| Rollershutter | state > 0 |
| String | |ON
| Switch | state === |
See openhab-js : Item for full API documentation.
#### itemConfig
Calling addItem(itemConfig) or replaceItem(itemConfig) requires the itemConfig object with the following properties:
- itemConfig : objectstring
- .type ⇒ : required, e.g. Switch or Groupstring
- .name ⇒ : requiredstring
- .label ⇒ : optionalstring
- .category (icon) ⇒ : optionalArray[string]
- .groups ⇒ : optional names of groups to be a member ofArray[string]
- .tags ⇒ : optionalobject
- .group ⇒ : optional additional config if Item is group Itemstring
- .type ⇒ : optional type of the group, e.g. Switchstring
- .function ⇒ : optional aggregation function, e.g. ANDArray[string]
- .parameters ⇒ : parameters possibly required by aggregation function, e.g. ON and OFFstring | Object { channeluid: { config } }
- .channels ⇒ Object { namespace: 'value' } | Object { namespace: { value: '' , configuration: { ... } } }
- .metadata ⇒
There are a few short forms for common metadata available:
- itemConfig : objectstring
- .format ⇒ : short form for stateDescription metadata's pattern configurationstring
- .unit ⇒ : short form for the unit metadataboolean
- .autoupdate ⇒ : short form for the autoupdate metadata
Note: .type and .name are required.metadata.stateDescription.configuration.pattern
Basic UI and the mobile apps need to render the state of an Item.
Example:
`javascript
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..items
It also allows providing metadata and channel configurations for the Item, basically creating the Item as if it was defined in a file.addItem
The benefit of using 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 :objectPersistedState | null
- .averageSince(timestamp, riemannType, serviceId) ⇒ PersistedState | null
- .averageUntil(timestamp, riemannType, serviceId) ⇒ PersistedState | null
- .averageBetween(begin, end, riemannType, serviceId) ⇒ boolean
- .changedSince(timestamp, serviceId) ⇒ boolean
- .changedUntil(timestamp, serviceId) ⇒ boolean
- .changedBetween(begin, end, serviceId) ⇒ number
- .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) ⇒ PersistedState | null
- .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) ⇒ number | null
- .evolutionRateSince(timestamp, riemannType, serviceId) ⇒ number | null
- .evolutionRateUntil(timestamp, riemannType, serviceId) ⇒ number | null
- .evolutionRateBetween(begin, end, riemannType, serviceId) ⇒ Array[PersistedItem]
- .getAllStatesSince(timestamp, serviceId) ⇒ Array[PersistedItem]
- .getAllStatesUntil(timestamp, serviceId) ⇒ Array[PersistedItem]
- .getAllStatesBetween(begin, end, serviceId) ⇒ ZonedDateTime | null
- .lastUpdate(serviceId) ⇒ ZonedDateTime | null
- .nextUpdate(serviceId) ⇒ ZonedDateTime | null
- .lastChange(serviceId) ⇒ ZonedDateTime | null
- .nextChange(serviceId) ⇒ PersistedItem | 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) ⇒ PersistedState | null
- .medianSince(timestamp, serviceId) ⇒ PersistedState | null
- .medianUntil(timestamp, serviceId) ⇒ PersistedState | null
- .medianBetween(begin, end, serviceId) ⇒ .persist
- .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 has been called, the new Item state will be persisted. See JSDoc for a possible work-around.TimeSeries
- .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 , which is then done asynchronously.PersistedItem | null
- .persistedState(timestamp, serviceId) ⇒ PersistedItem | null
- .previousState(skipEqual, serviceId) ⇒ PersistedItem | null
- .nextState(skipEqual, serviceId) ⇒ PersistedState | 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) ⇒ boolean
- .updatedSince(timestamp, serviceId) ⇒ boolean
- .updatedUntil(timestamp, serviceId) ⇒ boolean
- .updatedBetween(begin, end, serviceId) ⇒ PersistedState | null
- .varianceSince(timestamp, serviceId) ⇒ PersistedState | null
- .varianceUntil(timestamp, serviceId) ⇒ PersistedState | null
- .varianceBetween(begin, end, serviceId) ⇒
riemannType is an optional argument for methods that require calculating an approximation of the integral value.RiemannType.LEFT
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.RIGHT, RiemannType.TRAPEZOIDAL or RiemannType.MIDPOINT. If omitted, RiemannType.LEFT is used.items
The RiemannType enum can be statically accessed on the namespace, e.g.:
`javascript`
items.RiemannType.LEFT
A 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.kWh
You can rely on framework functionality to convert to the appropriate unit (e.g. ), 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.
`javascript`
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, or null if that's not the casequantityState
- : Item state as Quantity or null if state is not Quantity-compatiblerawState
- : State as Java State object
The PersistedItem object extends PersistedState with the following properties, representing Item state and the respective timestamp:
- timestamp: Timestamp as time.ZonedDateTimeinstant
- : Timestamp as time.Instant
`javascript`
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.ItemPersistence.persist
It is usually used for persisting historic state or forecasts in a persistence service by using .
When creating a new TimeSeries, a policy must be chosen - it defines how the TimeSeries is persisted in a persistence service:
- ADD adds the content to the persistence, well suited for persisting historic data.REPLACE
- first removes all persisted elements in the timespan given by begin and end of the TimeSeries, well suited for persisting forecasts.
A TimeSeries object has the following properties and methods:
- policy: The persistence policy, either ADD or REPLACE.begin
- : Timestamp of the first element of the TimeSeries.end
- : Timestamp of the last element of the TimeSeries.size
- : Number of elements in the TimeSeries.states
- : States of the TimeSeries together with their timestamp and sorted by their timestamps.TimeSeries
Be aware that this returns a reference to the internal state array, so changes to the array will affect the .add(timestamp, state)
- : Add a given state to the TimeSeries at the given timestamp.
The following example shows how to create a TimeSeries:
`javascript`
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 service
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)
`javascript`
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);
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.
`javascript`
var weekend = actions.Ephemeris.isWeekend();
#### Exec Actions
See openhab-js : actions.Exec for complete documentation.
Execute a command line.
`javascript
// 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.
`javascript`
// Example GET Request
var response = actions.HTTP.sendHttpGetRequest('
Replace with the request url.
#### Ping Actions
See openhab-js : actions.Ping for complete documentation.
`javascript`
// Check if a host is reachable
var reachable = actions.Ping.checkVitality(host, port, timeout); // host: string, port: int, timeout: int
#### ScriptExecution 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.createTimer
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 , please read Accessing Variables to avoid having unexpected results when using variables in timers.
##### createTimer
`javascript
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:
- string identifier (optional): Identifies the timer by a string, used e.g. for logging errors that occur during the callback execution.time.ZonedDateTime
- zdt: Point in time when the callback should be executed.function
- functionRef: Callback function to execute when the timer expires.*
- param1, ..., paramN: Additional arguments which are passed through to the function specified by functionRef.
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.ZonedDateTime or nullisActive()
- : 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
`javascript
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.
`javascript`
console.log(actions.Transformation.transform('MAP', 'en.map', 'OPEN')); // open
console.log(actions.Transformation.transform('MAP', 'de.map', 'OPEN')); // offen
See 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.NotificationBuilder
It returns a new 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 specified referenceId or tag (referenceId has precedence over tag)..addUserId(emailAddress)
- : By adding the email address(es) of specific openHAB Cloud user(s), the notification is only sent to this (these) user(s).addUserId
To add multiple users, either call multiple 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..withOnClickAction(action)
The reference ID can be used to update or hide the notification later by using the same reference ID again.
- : 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 or null for 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.
`javascript
// 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('florian@example.com').addUserId('florian@example.org').send();
// Send a standard notification with icon, tag and title to two specific users
actions.notificationBuilder('Hello World!').addUserId('florian@example.com').addUserId('florian@example.org')
.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.
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
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))_
`js`
var counter = cache.shared.get('counter', () => 0);
console.log('Counter: ' + counter);
Example _(Get a previously set value, modify and store it)_
`js`
var counter = cache.private.get('counter');
counter++;
console.log('Counter: ' + counter);
cache.private.put('counter', counter);
openHAB internally makes extensive use of the java.time package.time
openHAB-JS exports the excellent JS-Joda library via the namespace, which is a native JavaScript port of the same API standard used in Java for java.time.ZonedDateTime
Anywhere a native Java , 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:
`javascript`
var now = time.ZonedDateTime.now();
var yesterday = time.ZonedDateTime.now().minusHours(24);
var item = items.Kitchen;
console.log("averageSince", item.persistence.averageSince(yesterday));
`javascript`
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:
`javascript`
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