Obtain a list of asset's children via API

Hello all.

My goal is to create a system involving dynamic assets.
Assets within OpenRemote will be created / deleted to match whats happening in my data.
My issue is that I shouldn’t rely on my external clients to remember each Asset ID for each asset, for various reasons.
I would prefer to use a request or series of requests to obtain an array of all my Asset IDs.
I have them all parented by a Group Asset, where it’s ID should remain constant.

There’s no “children” key, or anything similar, within the JSON returned by ‘/api/master/asset/’ or other GET requests. Nor, do I believe, there is a GET children Request.

How can I go about this?

I was thinking of comparing the paths of Assets - try to check if they contain the Group Asset’s ID. But how would I get every Asset paths to check?

When viewing the Group Asset, you can see “Underlying Assets”. I know this isn’t a real attribute, but being able to obtain this would be perfect.

There also might be a way of re-creating my own “Underlying Assets” attribute which is automated through Groovy. But I am not sure if rules can be used in this way.

Thanks a lot.
Haydn.

Hi Haydn, this group control Groovy rule is including a way to retrieve dynamically all children assets of a group. Does this help to figure out what you are looking for? openremote/ChildAssetControl.groovy at master · openremote/openremote · GitHub

Hello Pierre,

Thank you for the link.
I have worked on it today and have built a solution that works for me.
My rule automates an array attribute in the parent, given a few options.

Here’s the GROOVY code:

/*
* This rule will Automate an array of children for a parent Asset
* parentAssetId   --    The AssetID of the parent which you would like to automate
* arrayAttribute  --    The name of the Attribute within the parent which acts as the child array
* idAttribute     --    The name of the Attribute within each child that contains the Integer to use as array index
*/

package org.openremote.test.rules

import org.openremote.manager.rules.RulesBuilder
import org.openremote.model.attribute.AttributeEvent
import org.openremote.model.query.AssetQuery
import org.openremote.model.rules.AssetState
import org.openremote.model.rules.Assets
import org.openremote.model.rules.Notifications
import org.openremote.model.rules.Users

import java.util.logging.Logger

Logger LOG = binding.LOG
RulesBuilder rules = binding.rules
Users users = binding.users
Notifications notifications = binding.notifications
Assets assets = binding.assets

// Options
String parentAssetId = "3kHesLOoFlis8aNGxWPlqB"
String arrayAttribute = "children"
String idAttribute = "id"

//LOG.info("COMPILING")

rules.add()
        .name("Obtain Group Asset Children")
        .when(
            { facts ->
                
                //LOG.info("TRIGGERED")
                //LOG.info("RAW Facts: "+ facts)
                
                //Get array of children
                //-------------------------------
                
                //Obtain assets with Parent
                def children = facts.matchAssetState(
                    new AssetQuery().parents(parentAssetId)
                ).map { childState ->
                
                    //LOG.info("CHILD")
                    //LOG.info("RAW CHILD STATE: "+childState)
                  
                    //Obtain Details
                    def name = childState.assetName
                    def assetId = childState.id
                    def childId = childState.value
                    
                    //LOG.info("Found: "+name+", '"+assetId+"'")
                    
                    //Return as list of pairs
                    [childId, assetId]
                    
                }.toList()
                //LOG.info("Children: " + children)
                
                //Array of children, to be built
                def childArray = []
                
                children.each{ key, val ->
                    //Convert Optional to Int to use as key
                    def intKey = key.mapToInt(x -> x)
                    if(key.asBoolean())
                    {
                      childArray[intKey.getAsInt()] = val
                    }
                }
                //LOG.info("ARRAY: "+childArray)
                
                //Compare to previous
                //-----------------------------
                
                //Get Parent
                def parent = facts.matchAssetState(
                    new AssetQuery().ids(parentAssetId).attributeName(arrayAttribute)
                ).toList()[0]
                //LOG.info("PARENT: "+parent)
                
                //Get previous value
                def optVal = parent.value
                def oldVal = []
                if(optVal.isPresent())
                {
                  oldVal = optVal.get()
                }
                //LOG.info("VALUE: "+oldVal)
                
                def eq = Arrays.equals(oldVal, childArray.toArray())
                //LOG.info("OLD: "+oldVal+"\nNEW: "+childArray+"\nEQUAL: "+eq)
                
                //Bind child array
                //--------------------------
                
                facts.bind("children", childArray)
                
                return !eq
            }
        )
        .then(
            { facts ->
            
                //LOG.info("EXCECUTE")
                //LOG.info("RAW Facts: "+facts)
                
                //Get array and format into AttributeEvent
                //------------------------------------------------
                
                def children = facts.bound("children")
                //LOG.info("RETAINED: "+children)
                
                //Get Parent
                def parent = facts.matchAssetState(
                    new AssetQuery().ids(parentAssetId).attributeName(arrayAttribute)
                ).toList()[0]
                //LOG.info("Parent: "+parent)
                
                //Create AttributeEvent to update parent
                def assetId = parent.id
                def pub = new AttributeEvent(assetId, arrayAttribute, children, new Date().getTime())
                //LOG.info("PUBLISH EVENT: "+pub)
                
                assets.dispatch(pub)
            }
        )

Thanks again.

1 Like

Thanks for sharing Haydn!