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.
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).
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))
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
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).
Hi,
I have tried to use the HistoricDatapoints example shown, however I cannot get it to work. I have assumed “ref” to be the attribute name as a string, is there something else I should be doing not shown in the example. I am using the demo groovy rules template and have modified it to get the current attribute value successfully.
The class type AttributeRef
we use is an object containing two fields, like so:
{
"id": "<your asset id>"
"name": "<name of your attribute>"
}
The class can be found at this path;
/model/src/main/java/org.openremote.model/attribute/AttributeRef.java
Thanks, but how do I use the object in this context. I have tried the following without success.
def datapoints = historicDatapoints.getValueDatapoints((“id”) “2jII1qSCPO2dwoC1kVdKm7”, (“name”) “Gravity”, new AssetDatapointAllQuery(LocalDateTime.now().minusHours(1), LocalDateTime.now())
I’ve tried this too without success.
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText(‘{“id”: “2jII1qSCPO2dwoC1kVdKm7”, “name”: “Gravity” }’)
def datapoints = historicDatapoints.getValueDatapoints(object, new AssetDatapointAllQuery(LocalDateTime.now().minusHours(1), LocalDateTime.now())
Using JsonSlurper
should not be needed. You can use a variable like normal.
What error are you receiving exactly for the getValueDatapoints()
function?
Does an exception get thrown?
Oh, and can you make sure that, in the Manager UI, you can see the datapoints of that attribute?
You can verify through either the Assets- or the Insights page. In our system, not every attribute has data points; they need the meta item STORE_DATAPOINTS
to historically store their data.
Yes I can see the datapoints in Assets page and Insights page, and I can access the current value using groovy rules script, but I cannot make the example historical datapoints work.
This is my error message from the log page - startup failed:
Script358.groovy: 86: unable to resolve class AssetDatapointAllQuery
@ line 86, column 113.
This is the part of the script that fails:
def datapoints = historicDatapoints.getValueDatapoints(AttributeRef(assetState.getId(), “iSpindelGravity”), new AssetDatapointAllQuery(LocalDateTime.now().minusHours(1), LocalDateTime.now()))
I have now removed Jsonslurper, as per your previous reply.
I’ve resolved the issue, I was missing this crucial declaration:
import org.openremote.model.datapoint.query.AssetDatapointAllQuery
All working well now!