Need Detailed httpPost tutorial with parsing JSON response


(Brian) #1

I am learning the ins & outs of groovy and have a couple device types of my own running and successfully muddled together some other peoples apps. I’m trying to write a SmartApp that calls an outside REST API ( http://thisfancyapi.com/query?key=MYKEY&param1=yes&param2=no ) which gives me a JSON response.

I have poured through the forums and the documentation. Being new to REST and groovy I’m hitting a big hurdle on how to call my httpPost handler (based on time of day) and how to parse the JSON elements from the response.

Here is the git to what I have so far

Any fork/pull requests are welcome!


(Convinced ST will never be unbroken…) #2

I get JSON back from my thermostat. Haven’t done an external post. Is what you get back in base64 or ascii?


(Brian) #3

ASCII

{"route":{"hasTollRoad":false,"computedWaypoints":[],"fuelUsed":0.49,"hasUnpaved":false,"hasHighway":false,"realTime":943

I just need to know how to parse out elements like realTime value to use in the app. "realTime":943 represents trip time in seconds that I need to do a calculation based on.


(Convinced ST will never be unbroken…) #4

Give this a shot…

import groovy.json.JsonSlurper

def map = [:]
def descMap = parseDescriptionAsMap(returnedResponse)
def body = new String(descMap["body"])
def slurper = new JsonSlurper()
def result = slurper.parseText(body)

if (result.containsKey("realTime")){
    def realTime = result.realTime
}
    

def parseDescriptionAsMap(description) {
description.split(",").inject([:]) { map, param ->
	def nameAndValue = param.split(":")
	map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
	}
}

(Brian) #5

would that go

httpPost(params) {response ->

HERE?

    return result
}

(Convinced ST will never be unbroken…) #6

Yeah… but I just spied this in the samples and it is much simpler provided you know the valueKeys your looking for…

httpGet("http://api.wunderground.com/api/${apikey}/conditions/q/pws:${stationid}.json") 
    	{ response ->

		def windspeed = response.data.current_observation.wind_mph.floatValue()
        def tempf = response.data.current_observation.temp_f.floatValue()
	    def hourlyprecip = Float.parseFloat(response.data.current_observation.precip_1hr_in)

(Brian) #7

Since my value is time, is there an equivelent for parsing a time variable in return? similar to floatValue() ?


(Convinced ST will never be unbroken…) #8

I dunno as I don’t know all the classes Groovy/SmartThings may support. So is 943 supposed to evaluate to 9:43 AM? If so you might try the timeToday() function… but I think it wants to see a colon between hours and minutes.


(Brian) #9

no 943 is an integer in seconds, but i have another time value that is formatted as 00:16:30 that I would like to be recognized as time.

Also when requesting an input type of time in ST it appears to pass it as a string…its becoming problematic. I want to check that a time is between time A and time B given by the user.

this:

section("Expected Arrival Time:"){
		input "arrivalTime", "time", title: "When?"
section("Begin Checking At:"){
		input "checkTime", "time", title: "When?"
	}

def now = new Date().format("HH:mm:ssZ")
log.debug "Now is = ${now}"
log.debug "Arrival Time is = ${arrivalTime}"
log.debug "Check Time = ${checkTime}"

gives me this:

debug Check Time = 2014-06-02T13:00:00.000-0700
debug Arrival Time is = 2014-06-02T14:00:00.000-0700
debug Now is = 20:33:42+0000

hard to compute this

if(now > arrivalTime && now < checkTime){
        checkTrafficHandler()
}

I know groovy has some awesome time conditionals, I just havent gotten there yet.

formatting is the bane of my existence.


(Convinced ST will never be unbroken…) #10

try this

//don't define now; use the function
def arrivalTime = timeToday(arrivalTime)
def checkTime = timeToday(checkTime)
    if ((now() > arrivalTime.time) && (now() < checkTime.time)) {
        checkTrafficHandler()
}

(Brian) #11
groovy.lang.MissingMethodException: No signature of method: java.lang.String.call() is applicable for argument types: () values: []
Possible solutions: wait(), any(), wait(long), each(groovy.lang.Closure), take(int), any(groovy.lang.Closure) @ line 124

(Convinced ST will never be unbroken…) #12

whats at line 124, and the ones on either side of it as that pointer isn’t always accurate.

Those time comparisons are working in one of my apps as…

section("And it is after...") {
    	input "time1", "time", title: "Time"
    }

def motionActive(evt) {
	def onlyAfter = timeToday(time1)
    if ((now() > onlyAfter.time) &&
    	(switch1.latestValue("switch") == "off")) {
    	log.debug "were golden"
        sendHAM()
    } 
}

(Brian) #13

finally got it working this way

def initialize() {
	if(now() > timeToday(checkTime).time && now() < timeToday(arrivalTime).time){
    	log.debug "ok we made it ${now()}"
        checkTrafficHandler()
    } 

}

thanks for pointing me in the right direction…now for the JSON!

with this code

def checkTrafficHandler() {
    def todayFormatted = new Date().format("MM/dd/yyyy")
    log.debug "Today is ${todayFormatted}"

    // Connect to mapquest API
    httpGet("http://www.mapquestapi.com/directions/v2/route?key=Fmjtd%7Cluur20u82u%2Can%3Do5-9ay506&from=${from}&to=${to}&narrativeType=none&ambiguities=ignore&routeType=fastest&unit=m&outFormat=json&useTraffic=true&timeType=3&dateType=0&date=${todayFormatted}&localTime=15:00") {response ->
      	def actualTime = response.route.realTime.floatValue()
        def expectedTime = response.route.time.floatValue()
      return result
    }
}

I get java.lang.reflect.UndeclaredThrowableException @ line 129 (httpGet)