httpGet cast issue

Ah, finally saw the issue, I think. Your headers parameter needs to be declared as a map (line 171). Right now it is just a string.

Here's an illustration from one of my drivers (with a couple of irrelevant headers entries removed):

def params =
        [
            uri: getBaseURI() + "users/_this/token",
            headers:
            [
                'AppVersion': '2.10.1',
                'BuildVersion': '131'
              ]
        ]

thanks..does this achieve what you suggest?? it still gives the same error, maybe i need to change how i'm doing it?

image

Try this:

def daikinUUID = ["X-Daikin-uuid" : settings.AdapterUUID]

1 Like

OMG. comma, colon. fussy damn compiler. whats it want next? correct spelling??

you're a freaking GENIUS. thank you thank you thank you.

1 Like

here's a snippet of using async.. which I'd suggest:

def params = [
    uri: "https://xxxxxxx",
    headers: [
        'Accept': '*/*', // */ comment
        'dataType': 'json',
        'Accept-Encoding': 'plain',
        'Accept-Language': 'en-US,en,q=0.8',
        'Connection': 'keep-alive',
        'Cookie': device.data.cookiess
    ],
timeout: 10
]

if (debugOutput) log.debug "sending getStatus request"
asynchttpGet("getStatusHandler", params)

}

def getStatusHandler(resp, data) {
if(resp.getStatus() == 200 || resp.getStatus() == 207) {
def setStatusResult = parseJson(resp.data)

sync http waits for the response.. if the Site takes 2 seconds to respond, the hub's going to be hit by that. Async on the other hand, splits the send and the response, allowing the hub to work while the Site is responding.

Obviously, if the httpGet is run once an hour, the hub isn't going to falter significantly. But for the most part, these are usually polled and at a high cycle time. Async is the better choice.

However, back to your actual question, yes, the Headers need to be a Map as shown in my snippet...

1 Like

hi csteele...thanks for the explanation, i read the method guide but it wasn't clear to me what the difference is between sync and async httpGETs are in this context.
i even gave async a try during my many hours of frustration, but i couldn't get it working either, and i seemed to be getting further with the sync version.

i agree with your suggestion...i'm almost too scared to try. :slight_smile:

yes, Sync is "easier"

Converting is easy too.

The "trick" is to recognize that the response is 'stale' until the next arrives. In my case, I have to login in two sequential http get's.. once to get some cookies, then a real login with the cookies sent along. Quite clearly, I can't fall into the 2nd http get til the first returns the cookies. With sync of course, falling is precisely what works and is easy.

1 Like

hi @csteele i';ve given it a go...but error "Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 182 column: 5. File: Script1.groovy @ line 182, column 5."

image

also: in this case is the return variable resp.Data ?

close your apiGet with a } before the def of getStatusHandler:

asynchttpGet("getStatusHandler", params)
}
def getStatusHandler(resp, data)

In other words, apiGet() finishes.. the hub gets control back and goes off and does other work... when the response comes in.. maybe 2 seconds later, the getStatusHandler method runs.

hmm..i thought being a "def" not a "private" meant you were defining a type of variable, not creating a new routine. OK that makes sense. i thought your } was a typo :slight_smile:

yea, that's the problem with snippets.. context is lost, traded for intense focus :smiley:

and the returned data is a Map of JSON data in "setStatusResult" -- if your response data is NOT json, then don't use the parseJson.

The snippet is from Honeywell TCC.. you can inspect the full code at:

Error: groovy.json.JsonException: Lexing failed on line: 1, column: 1, while reading 'r', no possible valid JSON value or punctuation could be recognized. on line 185 (getStatusHandler)

OK so i don't think its JSON (whatever that is), i think its just text, i used the HTTP standard content type "application/x-www-form-urlencoded" when using my (sync)httpGet.

what parse options are there?

sorry for the simpleton questions....i'm no gun groovy coder at the best of times and its 3:30am down here in Awwwstraylia. :slight_smile:

This is a good reference: Async HTTP calls

you can resp.getData(), resp.getJson(), or resp.getXml() in the async response handler. I usually check for resp.hasError() first before trying to get at the data (since it may not be there if there was an error).

OK several days later trying to figure this async thing out. this is doing my head in.
how do i get the data returned to the calling function?
so in my main driver script, the apiGet(apiCommand) function is called, with apiCommand essentially being the path parameter required at the time.
e.g. apiGet ("/aircon/get_sensor_info")
apiGet does the asynchttpGet call, and "getStatusHandler" is the callback.
getStatusHandler assigns the data to the variable ahgData
..but no matter what i do ahgData is not returned to apiGet function, which means it can't be passed back to the original function that calls apiGet in the first place.

i must be missing something fundamental here...can anyone help explain what i'm doing wrong? (responses like: you're coding without knowing what you're doing will not help :slight_smile: )

Variables exist only in the scope in which they are defined. For ahgData, that's the getStatusHandler() method. If you want to save the data elsewhere, the traditional approach is to use state (e.g., state.aghData). The behavior of state, a Map, is generally well documented (and similar) for both SmartThings and Hubitat. On (at least) Hubitat, I've also seen people use a @Field-annotated static variables defined at the "top" level of a script (outside any method), though this behavior is not well documented on Hubitat--but from what I can tell will give you something similar, aside from being harder to inspect (even users can see state content, so debugging is a bit easier--but state has limits as to both the types of data it will hold as well as, at least on SmartThings, the length), aside from probably not persisting between reboots.

But in general, the solution you need is to find a way to either store the data for use elsewhere or to do what you want with it in the callback method itself (or something else that it calls). You're still thinking a bit too synchronously--besides the scope problem, your apiGet() function will have finished probably well before getStatusHandler() is run as the callback. Asynchronous means it doesn't hold execution up at that part of the code--so, as mentioned above, a bit more thinking is required as to how to handle the data, but it's generally the recommended path unless you truly want to block execution until a response is heard (I would not personally do that often, if at all).

1 Like

Thanks Bert. I do appreciate you reading my issue and providing a thoughtful answer.
If I understand what you're saying (and it makes sense), its likely going to take a complete re-write/re-structure, is it not?

with the initial intent to make a few minor mods to apiGet function to poll the different adapter, i got there in the end using httpGet instead of hubAction with some help from csteele and tomw, but the suggestion to do it 'properly' (i.e. async calls) its introducing an hugely broader scope to the project because it works so differently..i fear the scope is too broad for my abilities. that said, i've learnt a lot.

Note to Self 1 : why oh why did i attempt this?
Note to Self 2: now i've burnt countless hours getting this far, does it even make sense to continue when the scope is so much bigger?
Note to Self 3: i wonder which will be done first - this driver or this frigging election? i figure i've got about 6 weeks :laughing:
edit: Note to Self 4: @eriktack you've been kind enough to get the 'standard version' driver together for the HE community. You know this driver well I would think. Am I missing something and this should be fairly straight forward?

@sanewton72
My work is mostly copy+paste in regards to the driver, but on the topic of async:

Async calls doesnt return anything to the caller after theyre done. You are telling the application to "call this address, and when you eventually get the response, call this other method (in this case getStatusHandler)".
after the asynchttpGet call on line 164, the apiGet method continues without waiting for the response from the async call. If you would wait for the response to log on line 165, it would be the opposite of async - synchronous, as the program have to wait for the response before continuing.

The getStatusHandler isnt returning anything to apiGet, and never will. If you want something returned to the apiGet method, you cant use async calls.

If you want something done with the response, do this in the getStatusHandler method.

1 Like

HttpGet will be fine for your use. Just go back to that.

3 Likes

Yup...i'm thinking maybe you're right. implementing the changes required to implement async calls is beyond my knowledge. maybe someone who actually knows this stuff properly, with a dislike of poor code [sorry eriktack no offense i just mean sync calls!), will buy an AC unit with one of these adapters. And sort this out.
Until then, i think i'll revert to sync. it seems to be working (gathering data with no errors in the logs), now i just need to ensure the driver actually makes the AC behave as it should....

thanks to all for your help and support. hopefully thread closed bc its all working.

2 Likes