Sort Attribute List

I'm trying to add a list type attribute in my app/driver. I've successfully implemented creating the list but am struggling figuring out how to sort the list alphabetically (I presume the list would do this by default).

App Function
def getCurrentCount() {
	def device = getChildDevice(state.contactDevice)
	def totalOpen = 0
    def totalClosed = 0
    def openList = []
	contactSensors.each { it ->
		if (it.currentValue("contact") == "open")
		{
			totalOpen++
                        openList.add(it.name)
		}
		else if (it.currentValue("contact") == "closed")
		{
			totalClosed++
                }
    }
    state.totalClosed = totalClosed
    logDebug "There are ${totalClosed} sensors closed"
    logDebug "There are ${totalOpen} sensors open"
    logDebug "Open sensors are ${openList}"
    device.sendEvent(name: "TotalClosed", value: totalClosed)
    device.sendEvent(name: "TotalOpen", value: totalOpen)
    device.sendEvent(name: "OpenList", value: openList)
}

Resulting list:

These should be alphabetical, at least if they were all there when the page loaded (anything added after the fact will appear at the end, as far as I can tell--but any attribute that is declared should have some value, or apps might crash, an issue that can be worked around but may not always be; this would be the only case where they wouldn't appear).

If this isn't happening for you, my guess is that the sorter is treating all capital letters as coming before any lowercase letter, an issue that isn't normally encountered since Hubitat attribute names normally begin with lower case (I'm not aware of any strict rule for this, but it is a convention for sure; there are the "convenience" .currentX properties for an attribute named x where it might).

2 Likes

This :point_up:. It's a simple ASCII sort.

2 Likes

I should have been clearer. I'm not looking to sort the device attributes themselves but the values inside of the OpenList attribute.

Ah, in that case, you can just use the sort() method on the List. If you call it exactly as sort(), it will use the default/natural ordering and mutate the list itself (as opposed to returning a new object that is sorted and leaving the original one alone). This will probably work. If not, there are more varieties of this call you can use, including one that takes a closure as a parameter where you can specify custom sorting: Iterable (Groovy JDK enhancements)

Also, what is the type of this attribute? A list is not a valid attribute type. If it's a String, I think Groovy will automatically convert, though it can't hurt to be specific. If you want something that an app can work with more easily (though it is a bit more work for you in the driver), a JSON_OBJECT might be best. Groovy has methods to convert lists to JSON. This is very nearly it above except you'd need quotes around the items in the list (but I'd use the methods if you go this route).

2 Likes

Well, for now, adding this line seems to have done the trick:

openList = openList.sort()

image

The attribute type is set to string. For now, unless someone tells me otherwise, I think this will be OK. The desire is to have a list of devices that trigger a state change for the virtual device. For example, the app can monitor a group of motion sensors with a user defined threshold for how many devices in the group will need to be active before the child virtual device will update to active. This way, users can add the attribute to a tile in a dashboard or (once I get it added) the description text from the event to push a notification.

Download the Hubitat app