Proposal: Offsetting RRD4J timestamp

A topic that has been mentioned by occasion in this forum is how to ‘time offset’ item states as they are persisted in the database.
My use case is similar:

  • One Item (bound to my Homewizard P1 energy meter Thing) contains my current power usage (in W) of my home
  • A second Item contains the amount of energy (in Wh) used in the last 15-minute block. This value is calculated by a rule that triggers every 15 minutes (using a third Item that records absolute energy usage from the same Thing).
    (Why is this useful? Well, my grid operator charges me partially based on the highest energy usage in such a time block)

But this means that, say I have an peak in my power usage between 10:05 and 10:10.
The rules triggers at 10:15, calculating and storing the peak in energy usage at 10:15 (and until the next calculation at 10:30), so in the time block after the one where the peak actually occured.
This makes it quite hard to work with, or to accurately display on a graph (together with my first power usage item).

As far as I can tell, there is currently no way to store an Item value with any other timestamp than the current time.

Looking at how the RRD4jPersistenceService is currently implemented, I made the following modification:

replace both occurances of:

    long now = System.currentTimeMillis() / 1000;

with a call to a new method:

private long getTimestamp(String name) {
    Instant timestamp = Instant.now();

    Metadata metadata = metadataRegistry.get(new MetadataKey(SERVICE_ID, name));
    if (metadata != null) {
        try {
            String offset = (String) metadata.getConfiguration().get("timestamp-offset");
            if (offset != null) {
                timestamp = timestamp.plus(Duration.parse(offset));
            }
        } catch (Exception e) {
            logger.warn("Could not parse timestamp-offset value '{}': {}", metadata.getValue(), e.getMessage());
        }
    }
    return timestamp.getEpochSecond();
}

Then, by adding a ‘rrd4j’ namespace to the relevant item with configuration (the offset is in ISO-8601 duration notation),

timestamp-offset : -PT15M

the Item state seems to be correctly stored with the provided time offset.

Is this something worth pursuing? If so, I can create a PR for this.

Yes but it needs to be something supported by all the persistence databases, not just rrd4j.

In the meantime, there is a .persist action that can be called from a rule to save the state with a given timestamp. In JS Scripting

  • .persist(timestamp, state, serviceId): Tells the persistence service to store the given state at the given timestamp, which is then done asynchronously.

I do like the ItemPersistence object you can get from an item, as methods like .deltaBetween() makes my rule logic significantly simpler.

Unfortunately, as I was using RRD4J, .persist() doesn’t seem to work:

There is no modifiable persistence service registered with the id 'rrd4j'

as RRD4jPersistenceService does not implement ModifiablePersistenceService, and probably never will, as some of its methods require functionality that the underlying database does not support.

So my best way forward for now seems to be to switch to InfluxDB.

For people with similar requirements, here’s the rule I’ve written so far:

var coeff = 1000 * 60; // 1 minute
var end = new Date(Math.floor(new Date() / coeff) * coeff); // round down to closest minute, which is the exact time the rule should have fired
var begin = new Date(end);
begin.setMinutes(end.getMinutes() - 15); // 15 min intervals

var measurement = items.getItem(‘p1_meter_total_energy_import’).persistence.deltaBetween(begin, end).numericState * 4; // 4 = conversion 15 min to hour

console.debug("measurement from " + begin + " until " + end + " = " + measurement);

items.getItem(‘energy_last_time_block’).persistence.persist(time.toZDT(begin), new Number(measurement));