historicState() gives back "wrong" value

Hello!
I wanted to make some more use of my Shelly EM devices and tried to calculate last months energy consume. I wanted to accomplish this by detracting the last days, but the value i get from historichState() and what was written in eventlog is (slightly) different.

Here’s my item with persistence:

Number:Energy               Shelly_EM3_accTotal     "Shelly em3 Gesamtverbrauch"                (gShelly)   {channel="shelly:shellyem3:84cca8ad12a6:device#accumulatedWTotal"}
gShelly*                :   strategy = everyMinute // rrd4j.persist

rule:

val ZonedDateTime firstDayPrevMonth = now.minusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0) 
val ZonedDateTime lastDayPrevMonth = firstDayThisMonth.minusSeconds(1)
logInfo("Test", "lastDayPrevMonth" + lastDayPrevMonth.toString)
logInfo("Test", Shelly_EM3_accTotal.historicState(lastDayPrevMonth).state.toString)

rule output:

2022-09-17 12:14:57.237 [INFO ] [org.openhab.core.model.script.Test  ] - lastDayPrevMonth2022-08-31T23:59:59+02:00[Europe/Berlin]
2022-09-17 12:14:57.242 [INFO ] [org.openhab.core.model.script.Test  ] - 3995.3739

but when i look into events.log the last update on 2022-08-31 is:

2022-08-31 23:58:59.893 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Shelly_EM3_accTotal' changed from 3995.842 kWh to 3995.875 kWh

i assumed i would get the exact same value (3995.875) with the rule.
does rrd4j “something” with the value or what am i missing here?

would be happy for some clarifications/help.

best regards
Peter

Yes. Older data is ‘aggregated’, or compressed. By default, that generally means it is averaged over ever larger periods as you go back in time. Keyword “archives” for rrd4j.

ok thanks!
if i understood rrd4j correctly the values get more and more aggregater/compressed, right?
would it make sense to use a proxy item ( Shelly_EM3_accTotal_beforeMidnight ) and persist that one with a different service?

That’s up to your choice.
It is also possible to configure rrd4j to aggregate in a different way i.e. record the max, not the average, for a given time slot in the archives.

Unless you are billing someone else, does that level of accuracy actually matter?

non, but as i just get the idea of rrd4j and not how it really works i’m afraid the accuracy will get worse.
i’ll take a better look at rrd4j. thanks!

Fiddling with rrd4j settings is deeply technical, and starting another persistence service is rather overkill just for this.

There are alternate means. Calculate an end-of-day reading at 23:59 or whatever, and put that in an Item, that represents “Yesterdays reading”. That Item retains that value all day until the next midnight. Persist that Item in the usual rrd4j way. It’ll persist the same value all day, that’s fine, it’s free, and the whole point of rrd4j is that the database does not grow over time.

When you want the historic reading for a given day, ask for the next day at noon, which will give “yesterdays” end-of-day reading. This will never get affected by averaging unless you have a century or so of records.

1 Like

so now i’m able to read historic values (with the default accuracy) but i’m struggling with “QuantityType”…

the item Shelly_EM3_accTotal is configured as Number:Energy
and i configured another Number:Energy item.

Number:Energy   Shelly_EM3_consumeP1    "Shelly em3 Verbrauch P1 [%.2f kWh]"

but i’m not able to update this item with this rule:

var accTotal1 = (Shelly_EM3_accTotal.historicState(firstDayPrevMonth).state as QuantityType<Energy>).doubleValue
var accTotal2 = (Shelly_EM3_accTotal.historicState(lastDayPrevMonth).state as QuantityType<Energy>).doubleValue
Shelly_EM3_consumeP1.postUpdate(accTotal2 - accTotal1)

the first line is responsible for this error:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'shelly-5' failed: Could not cast 3883.4413 to org.openhab.core.library.types.QuantityType; line 45, column 22, length 82 in shelly

am i reading the historicState in a wrong way (don’t get the value as QuantityType Energy)?

if i change Shelly_EM3_consumeP1 to Number and read the historic States as Number this rule works:

var accTotal1 = (Shelly_EM3_accTotal.historicState(firstDayPrevMonth).state as Number).doubleValue
var accTotal2 = (Shelly_EM3_accTotal.historicState(lastDayPrevMonth).state as Number).doubleValue
Shelly_EM3_consumeP1.postUpdate(accTotal2 - accTotal1)

okay, figured it out myself!
Shelly_EM3_consumeP1 as Number:Energy and this rule:

var accTotal1 = (Shelly_EM3_accTotal.historicState(firstDayPrevMonth).state as Number).doubleValue
var accTotal2 = (Shelly_EM3_accTotal.historicState(lastDayPrevMonth).state as Number).doubleValue
Shelly_EM3_consumeP1.postUpdate((accTotal2 - accTotal1).toString)

i don’t really understand why it has to be this way but i works :grimacing:

You’ve thrown away the Quantity property, effectively discarding the units.
So your result has no units either when you try to update an Item that demands units.

Work with the units, not against them. If you log out the values of your intermediate variables you will get a better idea of what’s going on.

var accTotal1 = Shelly_EM3_accTotal.historicState(firstDayPrevMonth).state as QuantityType<Energy>

That will give you accTotal1 as a Quantity type with units.
It might be in joules or kWh or Wh, who cares - so long as you sum it with another Quantity, openHAB will take care of matching/scaling the units. So you can add kWh to Wh without thinking about it.
The result will be a Quantity as well.

More exploration here

1 Like

that was my idea. tried your code:

rule "Power Consumption Range"
when
    Item Test_Test0815 changed
then
    val ZonedDateTime firstDayThisMonth = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0) 
    val ZonedDateTime firstDayPrevMonth = now.minusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0) 
    val ZonedDateTime lastDayPrevMonth = firstDayThisMonth.minusSeconds(1)

    var accTotal1 = Shelly_EM3_accTotal.historicState(firstDayPrevMonth).state as QuantityType<Energy>
    var accTotal2 = Shelly_EM3_accTotal.historicState(lastDayPrevMonth).state as QuantityType<Energy>
end

and i get this error for the line with var accTotal1 [...]:

Script execution of rule with UID 'shelly-5' failed: Could not cast 3883.4413 to org.openhab.core.library.types.QuantityType;

We’d better check what version of OH is being used here.

Persistence strips off units and stores numbers only. In OH3, it should restore the units when retrieving data. (In OH2 it doesn’t, you have to do that yourself).

So if it should but doesn’t for you - why is that? Persistence can’t guess the units of stored numeric-only data. So it looks to the particular Item’s default unit. If there isn’t an Item-level default, it looks to the locale dependent system default units. But not all quantity types have a system default - Energy type does not. You need an Item default unit…

You haven’t got an Item default unit in this Item. It’s not the source Item for persistence, but you’d better check those.

When using xxx.items files, the label [state presentation] does double duty as default units too.
Something like
Number:Energy Shelly_EM3_accTotal "Shelly em3 Gesamtverbrauch [%.1f kWh]"

A caution when messing with default units and persistence - if you change the unit it won’t go back and edit stored old data. So when you introduce a default, be sure it matches what was being used before (looks like kWh for you)

1 Like

that’s what i was missing! thank you
i’m on openHAB 3.3

thanks again rossko!

1 Like