I’ve never written a Groovy rule myself to be honest. Where did you get these methods that you are using?
Maybe you can take the example that pops up when you create a Groovy rule in the UI as a starting point to rewrite your rule. I’ll paste it here for your convenience:
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
/*
* A groovy rule is made up of a when closure (LHS) which must return a boolean indicating whether the then closure (RHS)
* should be executed. The rule engine will periodically evaluate the when closure and if it evaluates to true then the
* rule then closure will execute.
*
* NOTE: DO NOT MODIFY THE FACTS IN THE WHEN CLOSURE THIS SHOULD BE DONE IN THE THEN CLOSURE
*
* To avoid an infinite rule loop the when closure should not continually return true for subsequent executions
* so either the then closure should perform an action that prevents the when closure from matching on subsequent
* evaluations, or custom facts should be used, some ideas:
*
* - Change the value of an attribute being matched in the when closure (which will prevent it matching on subsequent evaluations)
* - Insert a custom fact on first match and test this fact in the when closure to determine when the rule should match again (for
* example if a rule should match whenever the asset state changes the asset state timestamp can be used)
*/
rules.add()
.name("Example rule")
.when({
facts ->
// Find first matching asset state using an asset query
facts.matchFirstAssetState(
// Find asset state by asset type and attribute name
new AssetQuery().types(ThingAsset).attributeNames("someAttribute")
// Find asset state by asset ID and attribute name
//new AssetQuery().ids("7CaBoyiDhtdf2kn1Xso1w5").attributeNames("someAttribute")
// Find asset state by asset type, attribute name and value string predicate
//new AssetQuery().types(ThingAsset).attributes(
// new AttributePredicate()
// .name("someAttribute")
// .value(new StringPredicate()
// .value("someValue")
// .match(AssetQuery.Match.EXACT)
// .caseSensitive(true)))
// Find asset state by asset type and location attribute predicate
//new AssetQuery().types(ThingAsset).attributes(
// new AttributePredicate()
// .name(Asset.LOCATION)
// .value(new RadialGeofencePredicate()
// .radius(100)
// .lat(50.0)
// .lng(0.0)))
).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("someAttribute")
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("someAttribute")
false
}
})
.then({
facts ->
// Extract any binded facts
AssetState assetState = facts.bound("assetState")
// Insert the custom fact to prevent rule loop
facts.put("someAttribute", assetState.getTimestamp())
// Write to attributes
def otherAttributeValue = null
if (assetState.getValue().orElse{null} == "Value 1") {
otherAttributeValue = "Converted Value 1"
} else if (assetState.getValue().orElse{null} == "Value 2") {
otherAttributeValue = "Converted Value 2"
} else {
otherAttributeValue = "Unknown"
}
assets.dispatch(assetState.id, "otherAttribute", otherAttributeValue)
// Generate notifications (useful for rules that check if an attribute is out of range)
//notifications.send(new Notification()
// .setName("Attribute alert")
// .setMessage(new EmailNotificationMessage()
// .setTo("no-reply@openremote.io")
// .setSubject("Attribute out of range: Attribute=${assetState.name} Asset ID=${assetState.id}")
// .setText("Some text body")
// .setHtml("<p>Or some HTML body</p>")
// )
//)
})
Hi @Don ,
What i actually need
Create a attribute A (Json) from i extract the value of attribute B(text/no) for same asset without using any service outside of openremote.
As @Don mentioned, not sure where you found the rule syntax you used, guess you wrote it to explain what you are trying to do.
Explaining groovy is not a quick answer as it is it has access to java language with groovy syntax on top…
Sounds like you want to extract a value from one attribute and write it through to another attribute; you could try using agent link and value filters to extract the value you want into the attribute.
If you were to use groovy rules then the template @Don provided is quite helpful; facts.matchFirstAssetState() will allow you to find the source attribute value and then you can apply regex or substring to get the value you want and then bind this value to the facts for use in the right hand side.
If the values being searched for are not dynamic then maybe a when then rule could be used