openhab
Version:
JavaScript Library for openHAB Automation
878 lines (662 loc) • 96.3 kB
Markdown
# openHAB JavaScript Library
[](https://github.com/openhab/openhab-js/actions/workflows/build.yaml)
[](https://badge.fury.io/js/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](https://www.openhab.org/addons/automation/jsscripting/).
- [Installation](#installation)
- [Default Installation](#default-installation)
- [Custom Installation](#custom-installation)
- [Compatibility](#compatibility)
- [Configuration](#configuration)
- [Rules in Main UI](#rules-in-main-ui)
- [Event Object](#event-object)
- [Scripting Basics](#scripting-basics)
- [`require`](#require)
- [`console`](#console)
- [Timers](#timers)
- [Paths](#paths)
- [Deinitialization Hook](#deinitialization-hook)
- [`JS` Transformation](#js-transformation)
- [Standard Library](#standard-library)
- [Items](#items)
- [Things](#things)
- [Actions](#actions)
- [Cache](#cache)
- [Time](#time)
- [Quantity](#quantity)
- [Log](#log)
- [Utils](#utils)
- [Environment](#environment)
- [Rules created from Script Files](#rules-created-from-script-files)
- [JSRule](#jsrule)
- [Rule Builder](#rule-builder)
- [Advanced Scripting](#advanced-scripting)
- [Libraries](#libraries)
- [@runtime](#runtime)
## Installation
### Default Installation
When installing the openHAB [JavaScript Scripting add-on](https://www.openhab.org/addons/automation/jsscripting/),
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](https://www.openhab.org/addons/automation/jsscriptingnashorn/), 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](https://www.openhab.org/addons/automation/jsscripting/#configuration).
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
<!-- Copy everything from here to update the JS Scripting documentation. -->
### 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](#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](#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](#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](#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](#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.
- 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 | |
| `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](https://www.openhab.org/docs/developer/utils/events.html#the-core-events) 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****Trigger`s use the equivalent `Item****Trigger` as trigger for each member.
See [openhab-js : EventObject](https://openhab.github.io/openhab-js/global.html#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.
<details>
<summary>Raw Script Module Event Object</summary>
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](https://www.openhab.org/javadoc/latest/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](https://www.openhab.org/javadoc/latest/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](https://www.openhab.org/javadoc/latest/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
```
</details>
## Scripting 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](#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](https://www.openhab.org/docs/administration/console.html):
```text
log:set DEBUG org.openhab.automation.script
log:set TRACE org.openhab.automation.script
log:set DEFAULT org.openhab.automation.script
```
The default logger name consists of the prefix `org.openhab.automation.script` and the script’s individual part `.file.filename` or `.ui.ruleUID`.
This logger name can be changed by assigning a new string to the `loggerName` 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`.
This behaviour is due to [log4j2](https://logging.apache.org/log4j/2.x/) 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](https://github.com/openhab/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](https://developer.mozilla.org/en-US/docs/Web/API).
When a script is unloaded, all created timeouts and intervals are automatically cancelled.
#### `setTimeout`
The global [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/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)`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) method cancels a timeout previously established by calling `setTimeout()`.
If you need a more verbose way of creating timers, consider to use [`createTimer`](#createtimer) instead.
#### `setInterval`
The global [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/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)`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) 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`](#createtimer).
### Paths
For [Rules created from Script Files](#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.
```javascript
require('@runtime').lifecycleTracker.addDisposeHook(() => functionToCall());
// Example
require('@runtime').lifecycleTracker.addDisposeHook(() => {
console.log("Deinitialization hook runs...")
});
```
## `JS` Transformation
openHAB provides several [data transformation services](https://www.openhab.org/addons/#transform) 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](https://openhab.org/docs/configuration/transformations.html#script-transformation) 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.
The script should take one argument `input` 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(<scriptname>.js):%s` as Item state transformation.
1. 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](https://openhab.github.io/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](https://code.visualstudio.com).
To use the type definitions, install the [`openhab` npm package](https://npmjs.com/openhab) (read the [installation guide](https://github.com/openhab/openhab-js#custom-installation) 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](https://openhab.github.io/openhab-js/items.html) for full API documentation.
- items : `object`
- .NAME ⇒ `Item`
- .existsItem(name) ⇒ `boolean`
- .getItem(name, nullIfMissing) ⇒ `Item`
- .getItems() ⇒ `Array[Item]`
- .getItemsByTag(...tagNames) ⇒ `Array[Item]`
- .addItem([itemConfig](#itemconfig), persist) ⇒ `Item`
- .removeItem(itemOrItemName) ⇒ `Item|null`
- .replaceItem([itemConfig](#itemconfig)) ⇒ `Item|null`
- .safeItemName(s) ⇒ `string`
- .metadata ⇒ [`items.metadata` namespace](https://openhab.github.io/openhab-js/items.metadata.html): Manage metadata directly without the need of going "through" the Item
- .itemChannelLink ⇒ [`items.itemChannelLink` namespace](https://openhab.github.io/openhab-js/items.itemChannelLink.html): 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 : `object`
- .rawItem ⇒ `HostItem`
- .persistence ⇒ [`ItemPersistence`](#itempersistence)
- .semantics ⇒ [`ItemSemantics`](https://openhab.github.io/openhab-js/items.ItemSemantics.html)
- .type ⇒ `string`
- .groupType ⇒ `string|null`
- .name ⇒ `string`
- .label ⇒ `string`
- .state ⇒ `string`
- .numericState ⇒ `number|null`: State as number, if state can be represented as number, or `null` if that's not the case
- .quantityState ⇒ [`Quantity|null`](#quantity): Item state as Quantity or `null` if state is not Quantity-compatible or without unit
- .boolState ⇒ `boolean|null`: Item state as boolean or `null` if 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, or `null` if not available
- .previousNumericState ⇒ `number|null`: Previous state as number, if state can be represented as number, or `null` if that's not the case or not available
- .previousQuantityState ⇒ [`Quantity|null`](#quantity): Previous item state as Quantity or `null` if state is not Quantity-compatible, without unit, or not available
- .previousRawState ⇒ `HostState`
- .lastStateUpdateTimestamp ⇒ [`time.ZonedDateTime`](#time): The time the state was last updated as ZonedDateTime or `null` if not available
- .lastStateUpdateInstant ⇒ [`time.Instant`](#time): The time the state was last updated as Instant or `null` if not available
- .lastStateChangeTimestamp ⇒ [`time.ZonedDateTime`](#time): The time the state was last changed as ZonedDateTime or `null` if not available
- .lastStateChangeInstant ⇒ [`time.Instant`](#time): The time the state was last changed as Instant or `null` if not available
- .members ⇒ `Array[Item]`
- .descendents ⇒ `Array[Item]`
- .isUninitialized ⇒ `boolean`
- .groupNames ⇒ `Array[string]`
- .tags ⇒ `Array[string]`
- .getMetadata(namespace) ⇒ `object|null`
- .replaceMetadata(namespace, value, configuration) ⇒ `object`
- .removeMetadata(namespace) ⇒ `object|null`
- .sendCommand(value): `value` can be a string, a number, a [`time.ZonedDateTime`](#time), a [`time.Instant`](#time), or a [`Quantity`](#quantity)
- .sendCommand(value, expire): `expire` is a [`time.Duration`](#time), this will return the Item to its previous state after the given `expire` duration
- .sendCommand(value, expire, onExpire): `onExpire` can be the same type as `value`, this will return the Item to the given `onExpire` value after the given `expire` duration
- .sendCommandIfDifferent(value) ⇒ `boolean`: `value` can be a string, a number, a [`time.ZonedDateTime`](#time), a [`time.Instant`](#time), or a [`Quantity`](#quantity)
- .sendIncreaseCommand(value) ⇒ `boolean`: `value` can be a number, or a [`Quantity`](#quantity)
- .sendDecreaseCommand(value) ⇒ `boolean`: `value` can be a number, or a [`Quantity`](#quantity)
- .sendToggleCommand(): Sends a command to flip the Item's state (e.g. if it is `ON`, an `OFF` command is sent).
- .postUpdate(value): `value` can be a string, a [`time.ZonedDateTime`](#time), or a [`Quantity`](#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` |
|--------------------|----------------------------------------------------|
| 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:<Dimension> | state !== 0 |
| Player | state === `PLAY` |
| Rollershutter | state > 0 |
| String | `null` |
| Switch | state === `ON` |
See [openhab-js : Item](https://openhab.github.io/openhab-js/items.Item.html) 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. `Switch` or `Group`
- .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. `ON` and `OFF`
- .channels ⇒ `string | Object { channeluid: { config } }`
- .metadata ⇒ `Object { namespace: 'value' } | Object { namespace: { value: '' , configuration: { ... } } }`
There are a few short forms for common metadata available:
- itemConfig : `object`
- .format ⇒ `string`: short form for `stateDescription` metadata's pattern configuration
- .unit ⇒ `string`: short form for the `unit` metadata
- .autoupdate ⇒ `boolean`: short form for the `autoupdate` metadata
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:
```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](https://openhab.github.io/openhab-js/global.html#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](https://openhab.github.io/openhab-js/items.html#.addItem) 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 `.persist` has been called, the new Item state will be persisted. See [JSDoc](https://openhab.github.io/openhab-js/items.ItemPersistence.html#persist) 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`](#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`
`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.:
```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`.
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.
```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 string
- `numericState`: State as number, if state can be represented as number, or `null` if that's not the case
- `quantityState`: Item state as [`Quantity`](#quantity) or `null` if state is not Quantity-compatible
- `rawState`: 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.ZonedDateTime`](#time)
- `instant`: Timestamp as [`time.Instant`](#time)
```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](https://openhab.github.io/openhab-js/items.ItemPersistence.html) 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`](#itempersistence).
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.
Be aware that this returns a reference to the internal state array, so changes to the array will affect the `TimeSeries`.
- `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
```
### Things
The Things namespace allows interacting with openHAB Things.
See [openhab-js : things](https://openhab.github.io/openhab-js/things.html) for full API documentation.
- things : <code>object</code>
- .getThing(uid) ⇒ <code>Thing|null</code>
- .getThings() ⇒ <code>Array[Thing]</code>
#### `getThing(uid, nullIfMissing)`
Calling `getThing(uid)` returns a `Thing` object with the following properties:
- Thing : <code>object</code>
- .bridgeUID ⇒ <code>String</code>
- .label ⇒ <code>String</code>
- .location ⇒ <code>String</code>
- .status ⇒ <code>String</code>
- .statusInfo ⇒ <code>String</code>
- .thingTypeUID ⇒ <code>String</code>
- .uid ⇒ <code>String</code>
- .isEnabled ⇒ <code>Boolean</code>
- .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);
```
### 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](https://openhab.github.io/openhab-js/actions.html) for full API documentation and additional actions.
#### Audio Actions
See [openhab-js : actions.Audio](https://openhab.github.io/openhab-js/actions.html#.Audio) for complete documentation.
#### BusEvent Actions
See [openhab-js : actions.BusEvent](https://openhab.github.io/openhab-js/actions.html#.BusEvent) for complete documentation.
#### CoreUtil Actions
See [openhab-js : actions.CoreUtil](https://openhab.github.io/openhab-js/actions.html#.CoreUtil) for complete documentation.
The `CoreUtil` actions provide access to parts of the utilities included in openHAB core, see [org.openhab.core.util](https://www.openhab.org/javadoc/latest/org/openhab/core/util/package-summary).
These include several methods to convert between color types like HSB, RGB, sRGB, RGBW and XY.
#### Ephemeris Actions
See [openhab-js : actions.Ephemeris](https://openhab.github.io/openhab-js/actions.html#.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](https://www.openhab.org/docs/configuration/actions.html#ephemeris) as well as the [Ephemeris Javadoc](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris).
```javascript
var weekend = actions.Ephemeris.isWeekend();
```
#### Exec Actions
See [openhab-js : actions.Exec](https://openhab.github.io/openhab-js/actions.html#.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](https://openhab.github.io/openhab-js/actions.html#.HTTP) for complete documentation.
```javascript
// Example GET Request
var response = actions.HTTP.sendHttpGetRequest('<url>');
```
Replace `<url>` with the request url.
#### Ping Actions
See [openhab-js : actions.Ping](https://openhab.gi