Previous attribute value access

Hi,

I have a problem accessing the previous values of an attribute
Let’s say we get a value every 15 minutes via MQTT, how do we access previous values (e.g. one hour ago) to subtract it from the current value.

@Rich are retained messages implemented in the new broker?

@Joh must it be over mqtt? else you can use http.

https://domainname/api/master/asset/AssetID
check out the swagger documentation: yourdomainname/swagger

@Denis Yes It must be on MQTT.
I actually get the data from liveobject every 15 minutes. For example I would like to be able to subtract the current value from the one collected an hour ago and display this difference.

What you try to achieve?

You can solve this for example by a rule and put the result in a attribute, which you can subscribe.

I would like to use a rule for this, but the problem is the access to the previous data.
As I said, let’s suppose that I receive a data at 12:00 and another one at 13:00. The value collected at 12:00 is overwritten by the one at 13:00. My question is : how can I get access to the 12:00 value using the rules?

If you are writing groovy rules the previous value of the attribute is available in the AssetState object.

This will just get you the previous value, if you need something like all the values for the last hour then you can use the RULE_EVENT configuration item (an example groovy rule using this can be found in the test suite).

1 Like

Thanks @Rich
I tried to retrieve the previous value using the groovy rule. I get no result.

val is the attribute that contains the retrieved values
and oldval is the attribute that will contain the old value of val

Here is the code:

package demo.rules

import org.openremote.manager.rules.RulesBuilder
import org.openremote.model.notification.*
import org.openremote.model.rules.AssetState
import org.openremote.model.asset.Asset
import org.openremote.model.asset.impl.*
import org.openremote.model.query.*
import org.openremote.model.query.filter.*
import org.openremote.model.rules.Assets
import org.openremote.model.rules.Notifications
import org.openremote.model.rules.Users
import org.simplejavamail.email.Email

import java.util.logging.Logger
import java.util.stream.Collectors

Logger LOG = binding.LOG
RulesBuilder rules = binding.rules
Notifications notifications = binding.notifications
Users users = binding.users
Assets assets = binding.assets
rules.add()
.name(“oldvalue”)
.when({
facts →

    // Find first matching asset state using an asset query

    facts.matchFirstAssetState.map { assetState ->
            // Find asset state by asset type and attribute name
            new AssetQuery().types(GroundwaterSensorAsset).attributeNames("val")
            //new AssetQuery().types(GroundwaterSensorAsset).attributeNames("minold")


    ).map { assetState ->

        // Use logging to help with debugging if needed            //LOG.info("ATTRIBUTE FOUND")

        // Check if this rule really should fire this time
        Optional<Long> lastFireTimestamp = facts.getOptional("val")
        if (lastFireTimestamp.isPresent() && assetState.getTimestamp() <= lastFireTimestamp.get()) {
            return false
        }

        // OK to fire if we reach here

        // Compute and bind any facts required for the then closure
        facts.bind("assetState", assetState)
        true
    }.orElseGet {
        // Asset state didn't match so clear out any custom facts to allow the rule to fire next time the when closure matches
        facts.remove("val")
        false
    }

})
.then({
facts →

    // Extract any binded facts
    AssetState assetState = facts.bound("assetState")

    // Insert the custom fact to prevent rule loop
    facts.put("val", assetState.getTimestamp())
    Optional<Long> oldval = assetState.getOldValue()
    assets.dispatch(assetState.id, "oldval", oldval)

})

In your then you are trying to push the Optional<Long> into the attribute rather than the value you probably want something like:

assets.dispatch(assetState.id, "oldval", oldval.orElse(null))
1 Like

Hi @Rich,
I am also interested in getting not only the previous value. In which test suite is the example groovy rule? I checked the Smart City Demo as well as the Manufacturer Demo, but could not find it. Can you help me out?
Cheers

Would be very happy about an answer :slight_smile:

You can access historical data of an attribute from groovy rules by using the HistoricDatapoints object from the rule binding:

import org.openremote.model.rules.HistoricDatapoints

HistoricDatapoints historicDatapoints = binding.historicalDatapoints

def datapoints = historicDatapoints.getValueDatapoints(ref, new AssetDatapointAllQuery(LocalDateTime.now().minusHours(1), LocalDateTime.now())

Be careful where you use this in your rule (i.e. it should be in the then part so it only executes when needed to avoid affecting performance too much).