MissingPropertyException: No such property

Perhaps this is the wrong category to post this. However, I'm working on integrating a number of devices; sort of figuring things out as I go and applying changes recursively as I figure out issues. My biggest issue currently, is the error in the title.

When trying to parse information received from an HTTP call, I'm able to use json notation (${response.json.getAt(3).property.value}) to get the response down to the following snippet of information.

{"soundStatus":"0","soundMute":"0","sleepVolume":"6","sleepSound":"310","pageVol":"5","balance":"0","soundMode":"1","relaxSound":"520","relaxVolume":"4","lightStatus":"0","lightLevel":"0","lightColor":"00ff00","soundScheduled":"1","lightScheduled":"0","soundOn":"00:10","soundOff":"07:00","lightOn":"22:00","lightOff":"06:00","Ramp":"60","disableBtn":"1","roomName":"Living Room","dwelling":"Home"}

When I add .soundStatus or any of these other items to response.json.getAt(3).property.value, my logs return

groovy.lang.MissingPropertyException: No such property: sleepVolume for class: java.lang.String on line 189 (getDevice)

Using a json path evaluator, I am able to retrieve the values in this block of information. No matter what I have done, hubitat is not able to get at this information. Any help would be appreciated. The entire response, if it would help figure out where I am going wrong, is as follows.

[[property:[type:Property, name:ble_mac, base_type:string, read_only:true, direction:output, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:Bluetooth Mac, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:true, retention_days:30]],
[property:[type:Property, name:ble_name, base_type:string, read_only:false, direction:input, scope:user, data_updated_at:null, key:666, device_key:666, product_name:Nbig surprise, track_only_changes:false, display_name:Bluetooth Name, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:true, retention_days:30]],
[property:[type:Property, name:Blue_button, base_type:boolean, read_only:true, direction:output, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:Blue_button, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:false, retention_days:30]],
[property:[type:Property, name:cmd, base_type:string, read_only:false, direction:input, scope:user, data_updated_at:2021-03-22T13:00:08Z, key:555, device_key:666, product_name:big surprise, track_only_changes:false, display_name:cmd, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:
{"soundStatus":"0","soundMute":"0","sleepVolume":"6","sleepSound":"310","pageVol":"5","balance":"0","soundMode":"1","relaxSound":"520","relaxVolume":"4","lightStatus":"0","lightLevel":"0","lightColor":"00ff00","soundScheduled":"1","lightScheduled":"0","soundOn":"00:10","soundOff":"07:00","lightOn":"22:00","lightOff":"06:00","Ramp":"60","disableBtn":"1","roomName":"Living Room","dwelling":"Home"},
denied_roles:[], ack_enabled:false, retention_days:30, ack_status:null, ack_message:null, acked_at:null]],
[property:[type:Property, name:device_host_version, base_type:string, read_only:true, direction:output, scope:user, data_updated_at:2021-02-23T13:40:34Z, key:666, device_key:666, product_name:big surprise, track_only_changes:true, display_name:device_host_version, host_sw_version:true, time_series:false, derived:false, app_type:null, recipe:null, value:g14-0.02.034 g1d-0.02.003, denied_roles:[], ack_enabled:false, retention_days:null]],
[property:[type:Property, name:enableBtn, base_type:boolean, read_only:false, direction:input, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:Enable Button, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:true, retention_days:30]],
[property:[type:Property, name:log, base_type:string, read_only:true, direction:output, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise track_only_changes:false, display_name:log, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:false, retention_days:30]],
[property:[type:Property, name:play, base_type:string, read_only:false, direction:input, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:Play Sound Once, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:true, retention_days:30]],
[property:[type:Property, name:sec_token, base_type:string, read_only:true, direction:output, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:Secure Token, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:false, retention_days:30]],
[property:[type:Property, name:settings, base_type:string, read_only:false, direction:input, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:Settings, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:false, retention_days:30]],
[property:[type:Property, name:version, base_type:string, read_only:true, direction:output, scope:user, data_updated_at:null, key:666, device_key:666, product_name:big surprise, track_only_changes:false, display_name:version, host_sw_version:false, time_series:false, derived:false, app_type:null, recipe:null, value:null, denied_roles:[], ack_enabled:false, retention_days:30]]]

And if anyone has a simple method for scheduling a defined http call within a driver, that will help before I release anything.

annnd this is the pertinent section of the driver

def postParams = [
    uri: "this is a real link",
	    requestContentType: 'application/json',
	    contentType: 'application/json',
        headers: ["Authorization": "Bearer ${state.accessToken}"]


asynchttpGet('getDevice', postParams)

def getDevice(response, data) {

    log.debug "status of post call is: ${response.status}"
    log.info "${response.json.getAt(3).property.value}"

    def relaxSound = "${response.json.getAt(3).property.value.sleepVolume}"
        sendEvent(name: "Relax Sound", value: relaxSound)

Besides the fact I have relaxSound pointing to SleepVolume, wth?

OK, so looking at the log string you listed as the entire response, it appears that what you're getting with this call:

response.json.getAt(3).property.value

is in fact a literal string of JSON, not JSON that got automatically parsed into a Map for you (why, I'm not sure; likely something to do with how the API you're working with returns it and what Groovy automatically does for you, with my guess being it's a string and not a JSON object itself).

This means that at this point you are just working with a string that is, literally:

{"soundStatus":"0","soundMute":"0","sleepVolume":"6","sleepSound":"310","pageVol":"5","balance":"0","soundMode":"1","relaxSound":"520","relaxVolume":"4","lightStatus":"0","lightLevel":"0","lightColor":"00ff00","soundScheduled":"1","lightScheduled":"0","soundOn":"00:10","soundOff":"07:00","lightOn":"22:00","lightOff":"06:00","Ramp":"60","disableBtn":"1","roomName":"Living Room","dwelling":"Home"}

What you will probably want to do is parse that JSON string into a Map so it works like you appear to be expecting it to--maybe something like:

Map parsedMap = new groovy.json.JsonSlurper().parseText(response.json.getAt(3).property.value)

(I'm not saying that's really how you'll want to write that line; for clarity--or debugging should the data along any point not look like you expect--you may wish to split it into different steps.)

On a related note, is this data always returned exactly like this, with the data you're looking for buried inside index 3? My guess is no, or at least that this would not be guaranteed by the API you're working with. Is there another way you can identify the line you're looking for? A guess on my part suggests that name: "cmd" could be what you want, and in that case, something like this will find the value of value for that regardless of where (what order) it may appear in the list:

response.json.find { it.property.name == "cmd" }.property.value

(You may need to adjust that depending on what you're really looking for, and depending on the data that may get returned, you may wish to do null-checks and whatnot--that's just an example.)

1 Like

This is absolutely something I was looking for. I have not tried your suggestion yet but it seems like exactly the gigantic time saver for this and other projects.

and this, is essentially the answer to my post. I figured the data was being defined as a string and wondered if that had to do with the quotations. I tried to achieve the concept of a new map to work from without the language to do so. Sure enough, after trying your solution, problem solved. Thank you.

I am an ox. I'm almost positive there are a few other methods of achieving this same information. Typically my success' come from tunnel vision and persistence. There seem to be a number of smart home devices (that sink) which use this api provider. Considering I own a number of defunct devices and some currently in-business devices using the same api, I'm sure your help will go far.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.