Design Pattern: Group Based Persistence

That depends entirely on the binding-device combination. There is no built-in OH mechanism to ‘refresh’ all item states because that wouldn’t work for many device types.
So, for items that receive very frequent updates of the status from linked devices, there really isn’t a need for RestoreOnStartup, but if the device only sends its status when it changes, it would certainly help to persist its status.
The main purpose of RestoreOnStartup is for OH not to lose state in case of a restart for instance.

1 Like

No, it does not. The Item will remain NULL until such time something changes that. That something can be restoreOnStartup, the binding, a Rule, or manual interaction from a UI.

You might be surprised to learn that technologies that support having their current state reported on demand is in the minority. But indeed, for Items linked to devices that do get immediately updated you would not want to use restoreOnStartup in the off chance that the binding updates the Items before persistence gets a chance to.

1 Like

I am a little surprised by that. Guess I’ll find out which of my devices do it later tonight, with the expectation that the answer will be “few to none”. Thanks!

rlkoshak thanks so much for this contribution and all your others!

One point to note that caught me up for a while. If you are using more than 1 persistence service and you want to call a specific one to use it has to be the last string in the parentheses!
e.g. item.previousState(false,“rrd4j”) NOT item.previousState(“rrd4j”)
(note item.previousState() works and uses the default persistence service and I believe it assumes False input. Specifying True returns last state different to current state).
Just noting on this thread as this seems the go to thread for setting up persistence apart from the official docs.

hi i am looking for the way to use my db to learn haw we use the lights and then replay them when we are not home. say we are away for longer then a week. so i can turn on leave mode. and it will run it as if we where there. ?

Bit of a random thread to post to. Are people shy of making new threads?

2 Likes

Rich, could I ask why you don’t use rrd4j any more - is there a better way for charting?

It doesn’t support Switches and Contacts and doesn’t work with external graphing packages.

Though I believe HABPanel has pretty good charting and OH 3’s UI will come with some better charting options than the defaultsold openHAB 1/2 charting.

1 Like

Hi I’m struggling to receive the average temperature of a room using groups.

if (myActualTemp !== null) {
logInfo (myRuleName,"Item: " + myActualTemp.name.toString)
var Number n_AvgTempDay=myActualTemp.averageSince(now.withTimeAtStartOfDay,“mysql”)
logInfo (myRuleName,"Status: " + myActualTemp.state.toString)
logInfo (myRuleName,"Durchschnitt: " + n_AvgTempDay.toString) }

I assume that I cannot cast the average temperature using the myActualTemp item. The return value of n_AvgTempDay=myActualTemp.avg… is null.
How to solve?

Martin

Bear in mind that we don’t know what kind of thing myActualTemp is.
You mention that is an Item, perhaps it is a Group type Item?

The obvious candidate for a no-data return would be that you did not persist any data. You can persist the value of Group Items, if that is what we are dealing with here. First you must give the Group a state, by defining a type and aggregation function for it. Then you must explicitly include the Group Item in your xxx.persist file. No “wildcards” * because they are not wildcards and mean something special to persistence.

as an aside -

this is not really a sensible test for an Item

Thanks, I missed to provide some more information about this.
I do have for each room an item storing the actual temperature. This value is persisted at every change.
All of them are assigned to a group called gRoomActualTemp.

Number    Wohnzimmer_IstTemp    "Wohnzimmertemp [%.1f °C]"          <temperature>   (gRoomActualTemp)   
Number    Wohnzimmer_IstTemp_DailyAvg       "Durchschnittliche Zimmertemperatur" <temperature>  (gRoomDailyAvgTemp)

In a rule, once a day, I want to calculate the average temperature for the room. In order to ease the coding I use the following code:

try{
	gRoomActualTemp.members.forEach[myActualTemp | 
	if (myActualTemp !== null) {
		var Number n_AvgTempDay=myActualTemp.averageSince(now.withTimeAtStartOfDay,"mysql")
		logInfo (myRuleName,"Durchschnittliche Temperatur im Zimmer " + myActualTemp.label.toString + " ist " + n_AvgTempDay.toString)
		val myDailyAvgTemp = gRoomDailyAvgTemp.members.findFirst[ myTempItem | myTempItem.name == myActualTemp.name.toString + "_DailyAvg"] as NumberItem
		logInfo(myRuleName,"durchschnittliche " + myActualTemp.label + " gesetzt auf " + n_AvgTempDay.toString)
		if (myDailyAvgTemp !== null) {myDailyAvgTemp.postUpdate(n_AvgTempDay)}
	}]

But I think that this is not working, but not sure how to solve using a pattern instead of considering each item separate in the rule.

Martin

You’ve placed helpful logInfo, but not shown us the result. Maybe there’s error messages? We cannot see over your shoulder.
for-eaching a Group can be a bit funny about the objects that you get, but let’s see the detail. I think the generic Item returned does support persistence functions.

logInfo (myRuleName,"Durchschnittliche Temperatur im Zimmer " + myActualTemp.label.toString + " ist " + n_AvgTempDay.toString)

This lead to the following error in the logger:

Error: cannot invoke method public java.lang.String java.lang.Object.toString() on null

I found out that the error is cause by the variable n_AvgTempDay as it seems this is null. The item myActualTemp is working, I can access the state, the label and the name without problems.

Martin

Okeydoke, as that is derived by
var Number n_AvgTempDay=myActualTemp.averageSince(now.withTimeAtStartOfDay,"mysql")
the next logical step is to find out if there is any data for that to operate on.

Use REST API to see if the Item has any persistence records. You’ll need to log out the name of your Item, like you did in your earlier post, to make the same comparison.

If it does, check the timestamps to see if there is any data for the given timespan, midnight to now.

I just check via MySQL in the database and via Rest, data is available

{
    "name": "Wohnzimmer_IstTemp",
    "datapoints": "47",
    "data": [
        {
            "time": 1597010501000,
            "state": "25.48"
        },
        {
            "time": 1597010671000,
            "state": "25.49"
        },
        {
            "time": 1597013810000,
            "state": "25.39"
        },
        {
            "time": 1597016828000,
            "state": "25.42"
        },
        {
            "time": 1597020137000,
            "state": "25.41"
        },
        {
            "time": 1597020649000,
            "state": "25.43"
        },
        {
            "time": 1597023577000,
            "state": "25.45"
        },
        {
            "time": 1597026866000,
            "state": "25.48"
        },
        {
            "time": 1597035359000,
            "state": "25.51"
        },
        {
            "time": 1597036883000,
            "state": "25.48"
        },
        {
            "time": 1597037325000,
            "state": "25.52"
        },
        {
            "time": 1597037756000,
            "state": "25.45"
        },
        {
            "time": 1597040864000,
            "state": "25.22"
        },
        {
            "time": 1597043422000,
            "state": "24.94"
        },
        {
            "time": 1597043933000,
            "state": "25.05"
        },
        {
            "time": 1597047072000,
            "state": "25.33"
        },
        {
            "time": 1597047243000,
            "state": "25.38"
        },
        {
            "time": 1597049549000,
            "state": "25.89"
        },
        {
            "time": 1597050401000,
            "state": "26.06"
        },
        {
            "time": 1597051284000,
            "state": "26.4"
        },
        {
            "time": 1597053199000,
            "state": "26.91"
        },
        {
            "time": 1597053661000,
            "state": "27.1"
        },
        {
            "time": 1597054173000,
            "state": "27.35"
        },
        {
            "time": 1597056799000,
            "state": "26.84"
        },
        {
            "time": 1597057150000,
            "state": "26.77"
        },
        {
            "time": 1597059637000,
            "state": "26.53"
        },
        {
            "time": 1597060249000,
            "state": "26.43"
        },
        {
            "time": 1597063267000,
            "state": "26.39"
        },
        {
            "time": 1597064711000,
            "state": "26.34"
        },
        {
            "time": 1597066456000,
            "state": "26.47"
        },
        {
            "time": 1597066717000,
            "state": "26.68"
        },
        {
            "time": 1597067660000,
            "state": "27.22"
        },
        {
            "time": 1597070026000,
            "state": "27.35"
        },
        {
            "time": 1597070217000,
            "state": "27.34"
        },
        {
            "time": 1597072383000,
            "state": "26.83"
        },
        {
            "time": 1597073185000,
            "state": "27.0"
        },
        {
            "time": 1597076283000,
            "state": "27.14"
        },
        {
            "time": 1597079733000,
            "state": "27.04"
        },
        {
            "time": 1597081488000,
            "state": "27.02"
        },
        {
            "time": 1597081608000,
            "state": "27.17"
        },
        {
            "time": 1597081618000,
            "state": "27.15"
        },
        {
            "time": 1597081669000,
            "state": "27.21"
        },
        {
            "time": 1597081769000,
            "state": "27.12"
        },
        {
            "time": 1597082381000,
            "state": "27.05"
        },
        {
            "time": 1597083273000,
            "state": "26.88"
        },
        {
            "time": 1597084617000,
            "state": "26.6"
        },
        {
            "time": 1597086322000,
            "state": "26.46"
        }
    ]
}

Okay, there’s data for today. Is your rule trying to get data for the same Item?

yes, there are several entries for today and using the query
var Number n_AvgTempDay=myActualTemp.averageSince(now.withTimeAtStartOfDay,"mysql")
shall return the average of today.

Okay, what’s your problem?

I got the problem, there was one Item that did not have a temperature persistent. Now it is working.

Thanks for pointing me to the right direction.
Martin

1 Like

I would like to use Group Based Persistence in OH3.4. In my example I have put the items StromHaus_Verbrauch/StromHaus_Zaehlerstand into the group gPersistenceMysql, but for these items the default persistance is still used as my rule gives following error:
[WARN ] [nce.extensions.PersistenceExtensions] - There is no default persistence service configured!
[WARN ] [nce.extensions.PersistenceExtensions] - There is no queryable persistence service registered with the id ‘null’
[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘d3745560f2’ failed: cannot invoke method public abstract org.openhab.core.types.State org.openhab.core.persistence.HistoricItem.getState() on null

Any idea what is wrong?

jdbc.persist

Strategies {
    // if no strategy is specified for an item entry below, the default list will be used
    everyMinute : "0 * * * * ?"
    every5Minutes : "0 */5 * * * ?"
    everyHour   : "0 0 * * * ?"
    everyDay    : "0 0 0 * * ?"
    default = everyChange
}

Items {
    gPersistenceMysql* : strategy = everyUpdate
}

rrd4j.persist

Strategies {
    // if no strategy is specified for an item entry below, the default list will be used
    everyMinute : "0 * * * * ?"
    every5Minutes : "0 */5 * * * ?"
    everyHour   : "0 0 * * * ?"
    everyDay    : "0 0 0 * * ?"
    default = everyChange
}

Items {
    gPersistenceRrd4j* : strategy = everyUpdate, everyMinute
}