Help with slurper from JSON

HI all,

I am attempting to write a driver pulling data from a lan device.

When I attempt to call jsonSlurper on the reponse.data I get the following error and I cant seem to get around it. My need is to get the headersets.field_values.[index].value for a corresponding index by name( from the headers)
for example the value of "Temperature Sensor 1" should be displaying "11.1" and mapped to a value on the device.

I am at a loss...

Any help would be appreciated.

error: groovy.lang.MissingMethodException: No signature of method: groovy.json.JsonSlurper.parseText() is applicable for argument types: (groovy.json.internal.LazyMap) values:

The code I am currently using is:

def URIPATH = "http://"+IPAddress+"/dlx/download/live?sessionAuthUsername=admin&sessionAuthPassword="+password+"&outputType=json&source=current"
def params = [
uri: URIPATH,
contentType: 'application/json',
]
try {
httpGet(params) {resp ->

        if (debugOutput) log.debug "resp data: ${resp.data}"
        def json = resp.data
        log.debug json
        def list = new groovy.json.JsonSlurper().setType(RELAX).parseText(resp.data)
        
        
        
    }

The data for that call through a browser looks like this:

{
	"language": "en",
	"headers": [
	{
		"id": "00_0010_427B_0100",
		"description": "VBus 0: DeltaSol BS 2009",
		"channel": 0,
		"destination_address": 16,
		"source_address": 17019,
		"protocol_version": 16,
		"command": 256,
		"info": 0,
		"destination_name": "DFA",
		"source_name": "DeltaSol BS 2009",
		"fields": [
		{
			"id": "000_2_0",
			"name": "Temperature sensor 1",
			"unit": "\ u00B0C",
			"unit_code": "DegreesCelsius"
		},
		{
			"id": "002_2_0",
			"name": "Temperature sensor 2",
			"unit": "\ u00B0C",
			"unit_code": "DegreesCelsius"
		},
		{
			"id": "004_2_0",
			"name": "Temperature sensor 3",
			"unit": "\ u00B0C",
			"unit_code": "DegreesCelsius"
		},
		{
			"id": "006_2_0",
			"name": "Temperature sensor 4",
			"unit": "\ u00B0C",
			"unit_code": "DegreesCelsius"
		},
		{
			"id": "008_1_0",
			"name": "Pump speed relay 1",
			"unit": "%",
			"unit_code": "Percent"
		},
		{
			"id": "012_1_0",
			"name": "Pump speed relay 2",
			"unit": "%",
			"unit_code": "Percent"
		},
		{
			"id": "010_2_0",
			"name": "Operating hours relay 1",
			"unit": "h",
			"unit_code": "Hours"
		},
		{
			"id": "014_2_0",
			"name": "Operating hours relay 2",
			"unit": "h",
			"unit_code": "Hours"
		},
		{
			"id": "016_1_0",
			"name": "UnitType",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "017_1_0",
			"name": "System",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "020_2_0",
			"name": "ErrorMask",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "022_2_0",
			"name": "System time",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "020_1_1",
			"name": "Sensor 1 defective",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "020_1_2",
			"name": "Sensor 2 defective",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "020_1_4",
			"name": "Sensor 3 defective",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "020_1_8",
			"name": "Sensor 4 defective",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "024_4_0",
			"name": "Status mask",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "028_4_0",
			"name": "Heat quantity",
			"unit": "Wh",
			"unit_code": "WattHours"
		},
		{
			"id": "032_2_0",
			"name": "SW Version",
			"unit": "",
			"unit_code": "None"
		},
		{
			"id": "034_2_0",
			"name": "Variant",
			"unit": "",
			"unit_code": "None"
		}
		]
	},
	{
		"id": "00_0015_427B_0100",
		"description": "VBus 0: DeltaSol BS 2009 => Standard-Info",
		"channel": 0,
		"destination_address": 21,
		"source_address": 17019,
		"protocol_version": 16,
		"command": 256,
		"info": 0,
		"destination_name": "Standard-Info",
		"source_name": "DeltaSol BS 2009",
		"fields": [
		]
	}
	],
	"headerset_stats": {
		"headerset_count": 1,
		"min_timestamp": 1601386317.542000,
		"max_timestamp": 1601386317.542000
	},
	"headersets": [
	{
		"timestamp": 1601386317.542000,
		"packets": [
		{
			"header_index": 0,
			"timestamp": 1601386316.252000,
			"field_values": [
			{
				"field_index": 0,
				"raw_value": 11.100000,
				"value": "11.1"
			},
			{
				"field_index": 1,
				"raw_value": 14.200000,
				"value": "14.2"
			},
			{
				"field_index": 2,
				"raw_value": 888.800000,
				"value": "888.8"
			},
			{
				"field_index": 3,
				"raw_value": 12.200000,
				"value": "12.2"
			},
			{
				"field_index": 4,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 5,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 6,
				"raw_value": 9402.000000,
				"value": "9402"
			},
			{
				"field_index": 7,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 8,
				"raw_value": 11.000000,
				"value": "11"
			},
			{
				"field_index": 9,
				"raw_value": 1.000000,
				"value": "1"
			},
			{
				"field_index": 10,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 11,
				"raw_value": 721.000000,
				"value": "12:01"
			},
			{
				"field_index": 12,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 13,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 14,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 15,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 16,
				"raw_value": 0.000000,
				"value": "0"
			},
			{
				"field_index": 17,
				"raw_value": 8850203.000000,
				"value": "8850203"
			},
			{
				"field_index": 18,
				"raw_value": 1.020000,
				"value": "1.02"
			},
			{
				"field_index": 19,
				"raw_value": 2.000000,
				"value": "2"
			}
			]
		},
		{
			"header_index": 1,
			"timestamp": 1601386316.783000,
			"field_values": [
			]
		}
		]
	}
	]
}

When the httpget passes the data to jsonSlurper it seems to strip all of the quotes off if the contentType flag is set to "application/json" . I dont know if that could be part of the problem.

Do you need to parse the JSON? The resp.data object in this case should already be a Map (if JSON data is returned, and I assume only if you didn't override the content type; I'm not sure Hubitat's docs are clear on this). You'd need the slurper if you were trying to parse the string yourself, but that work is already being done for you here (yay!).

I think I do.. The initial issue is that each firmware update of the lan device seems to change the order of the field values. Where I could do

resp.data.headersets.packets.field_values[0].value

to get my "11.1" for Temperature Sensor 1, that array location could be 0,10, or somewhere in between, so I need to look up what that is from the position of

resp.data.headers.fields[i].name = "Temperature sensor 1" in the fields array.

I could loop through the fields array to find this but it just seems sloppy, and there must be a better way.

It seems like you should just be able to use a closure to search for the name or whatever identifier you're looking for in the Map (not effectively different from looping through yourself, but much Groovy-ier and probably implemented more efficiently):

http://docs.groovy-lang.org/next/html/documentation/working-with-collections.html#_filtering_and_searching

I am feeling quite stupid and Groovy has a steep learning curve. Do you have a code example that might work with tweaking?

resp.data.headersets.packets.field_values.length() for example returns 1, which to me looks like its not showing as an array, even though when put to the log it looks like

[[[[field_index:0, raw_value:29.200000, value:29.2], [field_index:1, raw_value:14.200000, value:14.2], [field_index:2, raw_value:888.800000, value:888.8], [field_index:3, raw_value:23.700000, value:23.7], [field_index:4, raw_value:90.000000, value:90], [field_index:5, raw_value:0.000000, value:0], [field_index:6, raw_value:9403.000000, value:9403], [field_index:7, raw_value:0.000000, value:0], [field_index:8, raw_value:11.000000, value:11], [field_index:9, raw_value:1.000000, value:1], [field_index:10, raw_value:0.000000, value:0], [field_index:11, raw_value:721.000000, value:12:01], [field_index:12, raw_value:0.000000, value:0], [field_index:13, raw_value:0.000000, value:0], [field_index:14, raw_value:0.000000, value:0], [field_index:15, raw_value:0.000000, value:0], [field_index:16, raw_value:0.000000, value:0], [field_index:17, raw_value:8851157.000000, value:8851157], [field_index:18, raw_value:1.020000, value:1.02], [field_index:19, raw_value:2.000000, value:2]], []]]

I'm not 100% sure what format your data is returned in, but if it always looks like the above, something like this should do it:

def sensor1 = resp.data.headers.fields[0].find({ it.name == "Temperature sensor 1" })

Ignore my lack of typing (if you have a preference) and non-null-safe assumptions (you can address that if needed: resp?.data?.headers?.fields[0]?.find ( ... ) or whatnot).

the data looks exactly like above.

        def sensor1 = resp.data.headers.fields[0].find({ it.name == "Temperature sensor 1" })

        log.debug "Temp Sensor 1: ${sensor1}"

returns

Temp Sensor 1: [id:000_2_0, name:Temperature sensor 1, unit: °C, unit_code:DegreesCelsius]

The following doesnt seem to work though it follows the same logic.

def index0 = resp.data.headersets.packets.field_values[0].find({ it.field_index == "1" })

this should return "14.2" but returns null. What am I missing?

The second issue is that the array position of the first find needs to be fed into the second find as its field_index. How would I do that?

@bertabcd1234 I got the data for the field_values, but am still at a loss of how to get the index from the first query. is there something like indexof() ?

You could use the .findIndexOf() method with the same closure if all you want is the index in the JSON array (or both .find() and .findIndexOf() if you want both...not sure if there's a more elegant way to do that).

I should note that both of these will return only the first object that matches the criteria, which shouldn't be a problem if you expect only one (at most) in all cases.

Thank you!!! This code works!

        def FeildName = "Temperature sensor 2"
        def index = resp.data.headers.fields[0].findIndexOf({ it.name == FeildName })  
        log.debug index
        def value = resp.data.headersets[0].packets[0].field_values[index].value
        log.debug "${FeildName} data: ${value}"
1 Like