See Design Pattern: What is a Design Pattern and How Do I Use Them for an explanation of what a DP is and how to use them.
Problem Statement
There are several reasons why a home automation enthusiast would want to use openHAB persistence: charting, using historical Item states in rules logic, restore previous values on openHAB restart, detailed analysis, access to the data with external tools, etc. However, different databases are more or less well suited to each of these use cases.
Concept
Since no one persistence engine is best for all use cases, configure more than one and use Groups to allocate which Items get saved to which persistence engine and how.
For example, one can set up MapDB for restoreOnStartup, rrd4j for charting recent data and historical data, and MySQL for Items for detailed external analysis.
For each use case, create a Group and only use these groups in the .persist files.
Then allocate your Items to whatever group(s) based on how that specific Item will be used.
Example
In my current setup I restoreOnStartup on all my Items, I use rrd4j for charting and historical state, I have a couple of Items I expose to IFTTT through my.openhab, and no Items that I analyze or expose the DB outside of OH.
Items:
// Persistence Groups
Group gMyOpenhab // for Items that are exposed to IFTTT
Group gChart // for Items to persist for charting
Group gHistory // for Items to preserve their history
//Group gRestore // for Items to restore on startup (currently everything so commented out)
...
// Example Item that I Chart
Number Weather_Temp_Min "Minimum Outside Temp [%.0f] °F" <temperature> (gChart, gWeather_Temp_Chart)
// Example Item that I use historical data
Contact N_D_Front "Front Door [MAP(en.map):%s]" <frontdoor> (gHistory, gDoorSensors, gRemindDoorSensors, gAlarmSensors, gHydraSensors) { mqtt="<[mosquitto:entry_sensors/main/front_door:state:default]" }
// Example Item that I expose to my.openhab NOTE: it is also a member of gHistory
Switch T_D_Garage1 "Garage Door 1" <garagedoor> (gHistory, gMyOpenhab, gGarageOpeners)
mapdb.persist file: I only use MapDB for restoreOnStartup and restoreOnStartup applies to all Items
Strategies {
default = everyUpdate
}
Items {
// persist all items on every change and restore them from the db at startup
* : strategy = everyChange, restoreOnStartup
}
NOTE: I don’t know if setting a default strategy is required, I included it anyway, but it is basically meaningless because it is never used in the Items section.
To make restoreOnStartup work we need to persist every change. The ‘*’ resolves to all Items.
rrd4j.persist file: I use rrd4j for historic data. Because of limitations of rrd4j data must be saved at least every minute for charting or else you end up with blank charts and previousState and historicState do not appear to work.
Strategies {
// for rrd charts, we need a cron strategy
everyMinute : "0 * * * * ?"
default = everyChange
}
Items {
// additionally persist weather info every minute
gHistory* : strategy = everyUpdate, everyMinute
}
**influxdb.persist file: I use InfluxDB along with Grafana for generating complex and attractive charts. See the InfluxDB+Grafana tutorial for details.
// persistence strategies have a name and a definition and are referred to in the "Items" section
Strategies {
default = everyChange
}
Items {
gChart* : strategy = everyUpdate
}
myopenhab.persist file
Strategies {
default = everyUpdate
}
Items {
gMyOpenhab* : strategy = everyUpdate
}
Advantages
Advantages
The advantages of this approach include:
- The persistence behavior for each Item is documented with the Item (i.e. the group membership) keeping as much information about the behavior of the Item in one place
- Adding new Items or changing how they are persisted simply involves changing that Item’s group membership.
- Once set up, the .persist files need never be changed unless you decide move from one persistence engine to another
- Uses the best persist engine for the desired behavior. For example MapDB can save all types of Items but only keeps the last value do it is great for restoreOnStartup but not great for historic data whereas rrd4j is great for charting recent data but can’t save anything that isn’t a numerical value so isn’t so great for restoreOnStartup
Disadvantages:
- If you have a Group with an aggregation function that you also want to persist, this DP cannot be used on that Group Item. The Group Item will need to be listed individually in the .persist files.
A note about usage:
openHAB can have only one default persistence engine. Any calls you make in Rules where you do not specify a persistence engine will use the default. When using this approach for Persistence be careful when and if you change the default persistence engine as that may break some of your Rules.
I avoid problems, I recommend always specifying the persistence engine you want to use in all of your persistence calls. For example:
MyItem.previousState("rrd4j")
MyItem.lastUpdate("mapdb")
In Scripted Automation Rules, you can define configuration constants in the configuration file (e.g. in Python that’s automation/lib/python/configuration.py) and import that variable into your Rules. For example
prev_db = "rrd4j"
lastup_db = "mapdb"
from configuration import prev_db, lastup_db
from core.actions import PersistenceExtensions
...
PersistenceExtensions.previousState(ir.getItem("MyItem"), prev_db)
PersistenceExtensions.lastUpdate(ir.getItem("MyItem"), lastup_db)
This way should you change your mind on which DB the values should be pulled from you only need update your configuration file.