The Top 5 Use-Cases for Persistence in OpenHAB

Johannes Schildgen
(Smart)²Home
Published in
8 min readApr 10, 2021

A transient state means, when an item state changes, then the previous state is overwritten and lost. And the opposite of transient is persistent. OpenHAB supports different persistency options to store the state somewhere, so that you can look at the historical states of your items. In this article, you will learn to top five use cases for using persistency in OpenHAB 3.

Persistency Services in OpenHAB

You have the choice between different persistency services. They differ in the way how to set up a service, which data is persisted, and what kind of queries you can later ask to that service.

  • MapDB: A very simple service that only stores the current (and no historical) state into a simple embedded key-value database. Its main use case is to keep up item states when you restart OpenHAB or after a reboot or system crash.
  • RRD4J: RR stands for round-robin. This means you configure a maximum database size, and when this size is reached, RRD4J will compact historical data. An example: You can access the state of a temperature sensor of 3 hours and 27 minutes ago. But for the temperatures of two years ago, only a daily average is stored.
  • InfluxDB, JDBC, JPA, MongoDB, DynamoDB, …: OpenHAB can connect to many different relational databases, NoSQL databases, and time-series databases. They require some further steps to set up, but as a benefit, you can also query these databases with external tools like Grafana to generate custom dashboards and charts.

In this article, we will mainly focus on RRD4J, because it simple to set up and supports all our use cases.

Setting Up Persistence in OpenHAB 3

  1. Install persistence add-ons
  2. Choose a default persistence service
  3. Configurations in persistence files

(1.) Before we begin, make sure that both the MapDB and the RRD4J persistence add-ons are installed in your OpenHAB instance: In the Main UI of OpenHAB 3 click Settings, Add-ons, Persistence, and add them if necessary.

Installing persistency addons in OpenHAB 3.

(2.) Next, make sure that you select a default persistence service under Settings, System Settings, Persistence. I recommend using RRD4J here. Default does not mean, that items are persistent using this service by default. It means: When you want to read a historical state in a script, or when you want to generate a chart, this default service is used to get the historical values.

Selecting a default persistence service.

(3.) In OpenHAB, persistence is deactivated by default. You need to manually configure which items should be persisted under which persistence service. Unfortunately, this cannot be managed in the Main UI yet. So, it is required to connect to your OpenHAB machine via SSH and edit files:

ssh 192.168.xxx.yyy   # the IP of the OpenHAB machine
sudo vim /etc/openhab/persistence/mapdb.persist

You can use the following template for this file:

Strategies {
default = everyChange
}
Items {
* : strategy = everyChange, restoreOnStartup
}

The row with the star is the most important one. The star stands for all items. For each item, whenever its state changes, its new state is written into MapDB. This is useful for restoring the state of all items when the system restarts. As MapDB does not store historical states, we will configure this within another persistence file rrd4j.persist:

Strategies {
everyMinute : “0 * * * * ?”
}
Items {
Temperature_Bathroom : strategy = everyMinute
Humidity_Bathroom : strategy = everyMinute
Temperature_Livingroom : strategy = everyMinute
}

That’s it! Simply write all names of the items whose state you want to persist in this file. From now on, OpenHAB will save the states in RRD4J every minute.

Use Case 1: Restoring Item States on StartUp

Okay, this is something I already explained above. But without setting up MapDB and restoreOnStartup, a few strange things can happen. In most cases, your system works fine even without this persistence setting. For example, after OpenHAB starts, the states of all temperature sensors, lights, and so on are retrieved by the things directly. So not all lights will turn off, when you restart OpenHAB.

But, if you have items that are not directly connected to a thing channel, OpenHAB will set their state to NULL on startup. For, example, an item Dehumidifier_Mode that you only control manually within a sitemap.

Use Case 2: Charts

I guess most of the times, persistency is used for generating charts. The following chart shows the outside temperature over the last 12 hours:

Chart within an OpenHAB sitemap.

Within a sitemap, such a chart can be defined by using the textual sitemap notation:

Chart item=Localweatherandforecast_Outsidetemperature refresh=60 period=”12h”

The chart shows the temperature over the last 12 hours. It is rebuilt every 60 seconds. So, when you take a look at the same chart twice within one minute, the same picture is shown. As no persistence service is specified in the definition, the default one is taken. In our case, that’s RRD4J. Charts can also be inspected directly in the Main UI when clicking on an item. It’s also possible to generate custom charts under Settings, Pages, Create Chart.

Little chart within an item view in OpenHAB 3.
Interactive chart tool within the item view in OpenHAB 3.

Use Case 3: Accessing Old Item States

Take a look at the following ECMAScript rule, which is triggered every 15 minutes, but only if the garage door has is open (Garagedoor_State = OFF):

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var ZonedDateTime = Java.type('java.time.ZonedDateTime');
var PersistenceExtensions = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions');
var NotificationAction = org.openhab.io.openhabcloud.NotificationAction;
var old_state = PersistenceExtensions.historicState(
itemRegistry.getItem("Garagedoor_State"),
ZonedDateTime.now().minusMinutes(15)
).state;
if(old_state == "OFF") {
NotificationAction.sendBroadcastNotification("The garage door is still open.");
}

The method PersistenceExtensions.historcState takes two arguments: an item and a timestamp. In our example, we retrieve the state of the garage-door item which it had 15 minutes ago. As no persistence service is provided to the metod, the default service is used, in our case, RRD4J. Mind that the item Garagedoor_State has to be listed in the rrd4j.persist file. But this holds for all use cases in this artice.

The script checks every 15 minutes whether the garage door is open and also was open 15 minutes ago. Okay, basically, persistence is not necessary for this example. The following example script that does not use persistency at all would also do the same:

var current_state = itemRegistry.getItem("Garagedoor_State").getState();if(current_state == "OFF" && this.old_state == "OFF" && this.older_state == "ON") {
NotificationAction.sendBroadcastNotification("The garage door is still open.");
}
this.older_state = this.old_state;
this.old_state = current_state;

When this script is triggered every 15 minutes, a notification is sent when the garage door is open now and it was open at the previous rule execution, which was 15 minutes ago. It also checks whether the garage door wasn’t open two iterations ago (30 minutes) to avoid that a notification is sent again and again every 15 minutes.

But there are other use cases when it is quite useful to access a historical state of an item. For example, presence simulation / vacation mode: When a vacation mode is activated (e.g., via a Switch item), every minute, all lights and rollershutters will receive the same state as 7 days ago. Simply put all affected items in the rrd4j.persist file and in a vacation group. Within a script, use a loop to iterate over the items of that group and set their state to the historical state. Then, on Tuesday 6AM, the bathroom light turns on automatically because it was manually turned on last week Tuesday 6AM.

Use Case 4: Min/Max/Average-Queries over Time Windows

The class PersistenceExtensions has many more methods, not only for accessing the state of an item at a specific point in time in the past but also methods for window queries. Take a look at the following example:

var max10 = PersistenceExtensions.maximumSince(
itemRegistry.getItem(“Washing_Machine_Power”),
ZonedDateTime.now().minusMinutes(10)
).state;
var max5 = PersistenceExtensions.maximumSince(
itemRegistry.getItem(“Washing_Machine_Power”),
ZonedDateTime.now().minusMinutes(5)
).state;
if(max10 > 50 && max5 < 10) {
NotificationAction.sendBroadcastNotification(“The washing machine is finished”);
}

The script computes the maximum power consumption over the last 5 minutes. If it is less than 10 Watts, this is an indicator that the washing machine is finished. But of course, you only want to receive a notification when the washing machine was actually running before. So, we also check whether the maximum power over the last 10 minutes was more than 50 Watts. When the script is run every 5 minutes, a notification is sent only once when the washing machine is finished.

Use Case 5: More Charts!

The nice thing is you can create very simple charts showing the trend of an item state in just a minute, see Use Case 2.

Here is another example chart:

Chart item=Humidity refresh=60 period=”12h”

Humidity is a group item. OpenHAB will automatically integrate all items of that group within one chart.

Chart over a group item

OpenHAB 3 also offers you a custom chart tool to build even more complex charts. Take a look at the following chart. It shows the air humidity in 4 rooms plus the state of a dehumidifier:

Custom chart created with the chart tool in OpenHAB 3

Actually, this chart is not very complex. It only has one common x- and one common y-axis. But it has a marked area whenever the dehumidifier was turned on. Here is the YAML definition for such a marked area:

component: oh-time-series
config:
name: Dehumidifier
gridIndex: 0
xAxisIndex: 0
yAxisIndex: 0
type: line
areaStyle: {}
slots:
markArea:
- component: oh-mark-area
config:
name: Dehumidifier
item: Dehumidifier

Try out the chart tool. Add a legend, or a toolbox. You can add them to the sidebar menu of the Main UI for faster access. Click Sidebar & Visibility, Show on Sidebar.

That’s it! These were 5 reasons why to use persistence in OpenHAB 3. Now set up your persistence service, write your item names in *.persist files and create charts, rules, and access historical states! Have fun trying it out!

Why is the humidity level increasing?

--

--