Accessing the index of a nested JSON

(cjcharles) #1

Hi all, I have a JSON that looks like this (well this is a simplified version of it):

"stat_str":"Armed Home",
"panelTypeStr":"PowerMax Complete Part",
"enroled_zones":[{"zoneName":"Front door",
"sensorMake":"Visonic Door/Window Contact"},
{"zoneName":"Living room",
"zoneTypeStr":"Home Delay",
"sensorMake":"Visonic PIR"},
"sensorMake":"Visonic PIR"}]}

I am able to get into the nested JSON using:

def parse(description) {
    def map = [:]
    def events = []
    def cmds = []
    if(description == "updated") return
    def descMap = parseDescriptionAsMap(description)

    def body = new String(descMap["body"].decodeBase64())

    def slurper = new JsonSlurper()
    def result = slurper.parseText(body)
    if (result.containsKey("enroled_zones")) {
    	for (zone in result.enroled_zones) {
			log.debug "zone " + ZONEINDEX + " data: " + zone.zoneName + " = " + zone.sensorType
        	def zonestr = "visonic"+ZONEINDEX
            sendEvent(name: ${zonestr}, value: ${zone.zoneName}, displayed: false, isStateChange: true)
			//for (item in zone) {

However no matter what I put into the ZONEINDEX code I cannot get the index of the for loop I am iterating through. I.e. the map index for ‘enrolled_zones’ doesnt seem to exist… Has anybody get any ideas to help me please?

(codersaur) #2

Use eachWithIndex. Also, I think if you use result?.enroled_zones then you don’t need to the result.containsKey("enroled_zones") test.


result?.enroled_zones.eachWithIndex { zone, zoneIndex -> 
	log.debug "zone " + zoneIndex + " data: " + zone.zoneName + " = " + zone.sensorType
	def zonestr = "visonic" + zoneIndex
	sendEvent(name: ${zonestr}, value: ${zone.zoneName}, displayed: false, isStateChange: true)

(cjcharles) #3

Thank you very much.

I did discover this and had a play, but couldnt get it working. With your code I have managed to get it working,so thank you very much!

Strangely, I am finding that the Live Logging doesnt seem to capture some of the things I post to the logs. Not sure why that is (or if you have seen it before), but some of the log.debug messages dont seem to happen, even though the code runs successfully. Also if I re-run the command I get different messages appearing in the logs with the same input code…

E.g. if the above code posts a log for each zone, I will find sometimes it shows 2/5 zones in the log, and sometimes 4/5, but then misses out some of the other log.debug messages…

(codersaur) #4

This is a well-known bug/feature of the IDE Live Logging. I suspect that the log messages are sent using UDP, hence there is no guarantee that you get all messages displayed, or that they are in the right order. :imp:

(cjcharles) #5

Good to know its not just me! In that case Im all set now thanks to you. Apart from getting delays working inside the device handler (no matter where I put the command I cant get SmartThings to do sendEvent() after a delay of ~5s (it either never happens or it happensimmediately) Im now sorted!

FYI for anybody reading this in future, you need to include a double quote around variables passed into the sendEvent command i.e.
sendEvent(name: "${zonestr}", value: "${zone.zoneName}", displayed: true, isStateChange: true)

(codersaur) #6

Nah, just do this:

sendEvent(name: zonestr, value: zone.zoneName, isStateChange: true)

Also, you don’t really need displayed: true, as that’s the default.
Also, unless you know you need it, you usually wouldn’t force isStateChange: true either, as it’s calculated automatically.

(cjcharles) #7

Thanks! Not sure why I made it so complicated as that would have been my initial guess, I think I struggled referencing sub fields of the JSON and obviously this was the first thing I found which worked (I never managed the next step below so found a workaround)

If the JSON object is zone, and I wanted to access a field in the JSON which is stored in a string (i.e. fieldName=“JSON1key”), then zone.fieldname gave me a null since it was then looking for zone.fieldName rather than zone.JSON1key