One more design pattern to add here so I can find it again and reference is future posts.
#Group Persistence
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, and my.openhab integration, 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, my.openhab for IFTTT integration, 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 both charting and 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. I’ve also found getHistoricState and previousState do not work without saving every minute as well.
Strategies {
// for rrd charts, we need a cron strategy
everyMinute : "0 * * * * ?"
default = everyChange
}
Items {
// additionally persist weather info every minute
gHistory* : strategy = everyUpdate, everyMinute
gChart* : strategy = everyUpdate, everyMinute
}
myopenhab.persist:
Strategies {
default = everyUpdate
}
Items {
gMyOpenhab* : strategy = everyUpdate
}
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