Skip to content

Commit

Permalink
[Persistence] Add improvements (#535)
Browse files Browse the repository at this point in the history
* Additional improvements to persistence article

Addressing comments left over from #527
-  Changed that -> than
-  Resolved clashing headlines
-  Strategies section:  added `default` and explained its operation
-  Changed persistence extensions from code block to itemized list

* Improve readability of Strategies and Items sections

-  Reworded some of tne introductory material
-  Reorganized and changed some sub-section titles in Strategies and Items area to improve comprehension.
-  Item Persistence Configuration -> Persistence Configuration
-  Added Persistence Trigers section
-  Strategies section -> Strategies
-  Items section -> Items
-  Addressed comments by @Confectrician

* Address numerous comments from @ThomDietrich

-  Deleted one configuration headline
-  Added intro sentence to configuration section
-  Combined all text about default in one section of the document
-  corrected cronexpression angle bracket error
-  added code fence around everyChange, etc.
-  Removed detail of Quartz stuff and just added a pointer to Rules article
-  Replaced "persist everything" example to persisting Heating_Mode, etc..."
-  Added example of how default works.

* Finishes "nit" pass through Persistence article

-  Numerous small changes to improve readability

* Expand explanation of how one may specify persistence for an Item

-  Existing text was not clear about the syntax one would use with a Persistence Extension in order to specify a persistence store in cases where multiple stores are available.
-  Clarified language and added an example.

* Correct formating of Persistence Extensions

-  Removed extra lines
-  Added code fences

Signed-off-by: Brad Gilmer <[email protected]> (github: bgilmer77)

* Format Persistence Extensions as a table

-  Changed Persistence Extensions section from a non-enumerated list to a table
-  Fixed a spelling error in the section on restoring items after a restart

Signed-off-by: Brad Gilmer <[email protected]> (github: bgilmer77)

* Fix markdown table style

Signed-off-by: Thomas Dietrich <[email protected]> (github: ThomDietrich)
  • Loading branch information
bgilmer77 authored and Thomas Dietrich committed Nov 3, 2017
1 parent a215d77 commit cd91117
Showing 1 changed file with 91 additions and 61 deletions.
152 changes: 91 additions & 61 deletions configuration/persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,59 +11,73 @@ openHAB can store data over time; this is known as persistence.
The data may be retrieved at a later time, for example to restore your system after startup, or to prepare graphs for display on a UI.

openHAB persists Item states in a database, and most popular databases are supported.
You may have more that one persistence add-on loaded, and each of these may be configured independently.
You may have more than one persistence add-on loaded, and each of these may be configured independently.

A complete list of supported persistence add-ons may be found in the [persistence]({{base}}/addons/persistence.html) section of the on-line openHAB documentation.

## Persistence Add-on Configuration

Each persistence add-on you install will need to be configured.
Please refer to the specific [on-line documentation]({{base}}/addons/persistence.html) for your selected persistence add-on for configuration instructions.
Please refer to the [available persistence service add-on]({{base}}/addons/persistence.html) documentation for your selected persistence add-on for configuration instructions.

## Default Persistence Service

You may install more than one persistence add-on.
Therefore, it is important to select a default persistence service.
It is important to select a default persistence service.
You should do this even if you have only one persistence add-on installed.

To select a default persistence service, in paper UI, select Configuration and then System from the side menu.
Scroll down to "Persistence", and select your Default Service from the drop-down list.
Scroll down to "Persistence", and select your default service from the drop-down list.
Note that you must first install a persistence add-on before you make this selection.
Be sure to save your choice once you have selected your default service.

## Configuration
## Persistence Configuration

The information below allows you to determine which Item states are persisted, when they are persisted, and where they are stored.

Persistence Strategies are configured in a file named `<persistenceservice>.persist`, stored in `$OPENHAB_CONF/persistence` ("persistenceservice" is replaced by the name of your add-on (e.g. `rrd4j.persist`)).
Persistence Strategies are configured in a file named `<persistenceservice>.persist`, stored in `$OPENHAB_CONF/persistence`.
Replace "persistenceservice" with the name of your persistence add-on (e.g. `rrd4j.persist`).

Strategies may be used to persist an Item state when some event has occurred (e.g. an Item state has been updated or changed), on a time schedule, or at a specific time of day (e.g. through a [cron expression](http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/crontrigger).
### Persistence Triggers

Persistence configuration files consist of several sections:
The persistence of an Item's state may be triggered when that Item changes state or when the Item is updated (even if its state did not change).
Persistence may also be triggered by a time-related event (see Cron Persistence Triggers below).

### Strategies section
### Strategies

This section allows you to define strategies and to declare a set of default strategies to use for this persistence service. The syntax is as follows:
This section allows you to name and define one or more `Strategies` and to select a default strategy.
The syntax is as follows:

```java
Strategies {
<strategyName1> : "cronexpression1>"
<strategyName1> : "cronexpression1"
<strategyName2> : "cronexpression2"
...
default = everyChange
...
}
```

The following strategies are defined internally:
The `default` parameter assigns a strategy to be used if one is not specified in the `Items` section below.
The `default` parameter may be omitted from the `Strategies` section, but only if a strategy is provided in each line of the `Items` section.
If the `strategy` portion of the `itemlist` is omitted in the `Items` section, the `default` strategy specified in the `Strategies` section will be applied.

#### Predefined Strategies

The following strategies are defined internally and may be used in place of `strategyName` above:

- `everyChange`: persist the Item state whenever its state has changed
- `everyUpdate`: persist the Item state whenever its state has been updated, even if it did not change
- `restoreOnStartup`: load and initialize the last persisted state of the Item on openHAB startup (if the Item state is undefined (`UNDEF`)).

- everyChange: persist the Item state whenever its state has changed
- everyUpdate: persist the Item state whenever its state has been updated, even if it did not change
- restoreOnStartup: load and initialize the last persisted Item state on openHAB startup (if the Item state is undefined (`UNDEF`)). See below.
#### Cron Persistence Triggers
openHAB uses [Quartz](http://www.quartz-scheduler.org/documentation/quartz-2.1.x/quick-start.html) for time-related cron events.
See the [Rules article]({{base}}/rules-dsl.html#time-based-triggers) for more information.

### Items section
### Items

This section defines which items should be persisted with which strategy.
The syntax is as follows:

```java
Items {
<itemlist1 [-> "<alias1>"] : [strategy = <strategy1>, <strategy2>, ...]
<itemlist1> [-> "<alias1>"] : [strategy = <strategy1>, <strategy2>, ...]
<itemlist2> [-> "<alias2>"] : [strategy = <strategyX>, <strategyY>, ...]
...

Expand All @@ -76,10 +90,27 @@ where `<itemlist>` is a comma-separated list consisting of one or more of the fo
- `<itemName>` a single Item identified by its name. This Item can be a group Item. But note that only the group value will be persisted. The value of the individual group members will not be persisted using this option.
- `<groupName>*` - all members of this group will be persisted, but not the group itself. If no strategies are provided, the default strategies that are declared in the first section are applied. Optionally, an alias may be provided if the persistence service requires special names (e.g. a table to be used in a database, a feed id for an IoT service, etc.)

A valid persistence configuration file might look like this:
The example `Items` section below takes advantage of a `default` entry in the `Strategies` section.
Assume the `Strategies` section contains the line:

```java
// persistence strategies have a name and a definition and are referred to in the "Items" section
default = everyChange
```

then the following section,

```java
Items {
GF_Hall_Light
}
```

will cause the state of `GF_Hall_Light` to be persisted on every change.

Below you will find a complete example persistence configuration file:

```java
// persistence strategies have a name and definition and are referred to in the "Items" section
Strategies {
everyHour : "0 0 * * * ?"
everyDay : "0 0 0 * * ?"
Expand All @@ -94,15 +125,15 @@ Strategies {
* Item (excl. the group Item itself).
*/
Items {
// persist all items once a day and on every change and restore them from the db at startup
* : strategy = everyChange, everyDay, restoreOnStartup
// persist the Item state of Heating_Mode and Notifications_Active on every change and restore them from the db at startup
Heating_Mode, Notifications_Active: strategy = everyChange, restoreOnStartup

// additionally, persist all temperature and weather values every hour
Temperature*, Weather* : strategy = everyHour
}
```

## Restoring Item States on restart
## Restoring Item States on Restart

When restarting your openHAB installation you may find there are times when your logs indicate some Items have the state, `UNDEF`.
This is because, by default, Item states are not persisted when openHAB restarts - even if you have installed a persistence add-on.
Expand All @@ -120,13 +151,11 @@ Items {
}
```

## Persistence Extensions in Scripts and rules
## Persistence Extensions in Scripts and Rules

To make use of persisted states inside scripts and rules, a few useful extensions have been defined on items.
In contrast to an action (which is a function that can be called anywhere in a script or rule), an extension is a function that is only available like a method on a certain type.
This means that the persistence extensions are available like methods on all items.

<!-- TODO: Reword the above section to replace the word "like" with something that is more clear-->
Note that these extensions are only available to be applied to Items.
They are not generally available for use in Scripts or Rules.

Example:

Expand All @@ -139,29 +168,30 @@ You can easily imagine that you can implement very powerful rules using this fea

Here is the full list of available persistence extensions:

```java
<item>.persist - Persists the current state
<item>.lastUpdate - Query for the last update timestamp of a given Item.
<item>.historicState(AbstractInstant) - Retrieves the historic Item at a certain point in time
<item>.changedSince(AbstractInstant) - Checks if the state of the Item has (ever) changed since a certain point in time
<item>.updatedSince(AbstractInstant) - Checks if the state of the Item has been updated since a certain point in time
<item>.maximumSince(AbstractInstant) - Gets the Item with the maximum value (state) since a certain point in time
<item>.minimumSince(AbstractInstant) - Gets the Item with the minimum value (state) since a certain point in time
<item>.averageSince(AbstractInstant) - Gets the average value of the state of a given Item since a certain point in time.
<item>.deltaSince(AbstractInstant) - Gets the difference value of the state of a given Item since a certain point in time.
<item>.previousState() - Retrieves the previous Item (returns HistoricItem).
<item>.previousState(true) - Retrieves the previous Item, skips items with equal state values and searches the first Item with state not equal the current state (returns HistoricItem).
<item>.sumSince(AbstractInstant) - Retrieves the sum of the previous states since a certain point in time. (OpenHab 1.8)
```

These extensions use the default persistence service that is configured as the default persistence service. (Refer to Default Persistence Service above to configure this.)

Note that you can specify that a different persistence service be used with a particular extension.
Do this by appending a String as an optional additional parameter at the end of the extension (e.g. "rrd4j" or "sense").

<!-- TODO:Add an example of this. I assume it is as simple as adding .rrd4j to the end of one of these, but this should be verified before being published. -->

### Date and Time extensions
| Persistence Extension | Description |
|-----------------------------------------|-------------|
| `<item>.persist` | Persists the current State of the Item |
| `<item>.lastUpdate` | Queries for the last update timestamp of a given Item |
| `<item>.historicState(AbstractInstant)` | Retrieves the State of an Item at a certain point in time |
| `<item>.changedSince(AbstractInstant)` | Checks if the State of the Item has (ever) changed since a certain point in time |
| `<item>.updatedSince(AbstractInstant)` | Checks if the state of the Item has been updated since a certain point in time |
| `<item>.maximumSince(AbstractInstant)` | Gets the maximum value of the State of a persisted Item since a certain point in time |
| `<item>.minimumSince(AbstractInstant)` | Gets the minimum value of the State of a persisted Item since a certain point in time |
| `<item>.averageSince(AbstractInstant)` | Gets the average value of the State of a persisted Item since a certain point in time |
| `<item>.deltaSince(AbstractInstant)` | Gets the difference in value of the State of a given Item since a certain point in time |
| `<item>.previousState()` | Gets the previous State of a persisted Item (returns HistoricItem) |
| `<item>.previousState(true)` | Gets the previous State of a persisted Item, skips Items with equal State values and searches the first Item with State not equal the current State (returns HistoricItem) |
| `<item>.sumSince(AbstractInstant)` | Gets the sum of the previous States of a persisted Item since a certain point in time |

These extensions use the default persistence service.
(Refer to 'Default Persistence Service' above to configure this.)
You may specify a different persistence service by appending a String as an optional additional parameter at the end of the extension.

**Example**
To persist an Item called `Lights` in an rrd4j database, you would enter the following:
`Lights.persist("rrd4j")`

### Date and Time Extensions

A number of date and time calculations have been made available in openHAB through incorporation of [Jodatime](http://joda-time.sourceforge.net/).
This makes it very easy to perform actions based upon time.
Expand All @@ -179,15 +209,15 @@ See the [Jodatime documentation](http://joda-time.sourceforge.net/api-release/or

## Startup Behavior

Persistence services and the rule engine are started in parallel.
Because of this, it is possible that, during an openHAB startup, rules will execute before Item states used by those rules have been restored.
(In this case, those unrestored items have an "undefined" state when the rule is executed.)
Therefore, rules that rely on persisted Item states may not work consistently.
Persistence services and the Rule engine are started in parallel.
Because of this, it is possible that, during an openHAB startup, Rules will execute before Item states used by those Rules have been restored.
(In this case, those unrestored Items have an "undefined" state when the Rule is executed.)
Therefore, Rules that rely on persisted Item states may not work correctly on a consistent basis.

### Workaround 1

A workaround which helps in some cases is to create an Item e.g. "delayed_start" that is set to "OFF" at startup and to "ON" some time later (when it can be assumed that persistence has restored all items.
You then write a rule that restores items from your persistence service after the delay has completed.
A workaround which helps in some cases is to create an Item e.g. "delayed_start" that is set to "OFF" at startup and to "ON" some time later (when it can be assumed that persistence has restored all items).
You can then write a Rule that restores Items from your persistence service after the delay has completed.
The time of the delay must be determined by experimentation.
How long you need to wait before changing your "delayed_start" Item from "OFF" to "ON" depends upon the size of your home automation project and the performance of your platform.

Expand All @@ -210,7 +240,7 @@ then
end
```

Create a refresh script `$OPENHAB_CONF/rules_refresh.sh` and make it execuitable (`chmod +x rules_refresh.sh`):
Create a refresh script `$OPENHAB_CONF/rules_refresh.sh` and make it executable (`chmod +x rules_refresh.sh`):

```sh
#This script is called by openHAB after the persistence service has started
Expand Down

0 comments on commit cd91117

Please sign in to comment.