Http Post to local lan using sendHubCommand in SmartApp?

I’ve searched and searched and couldn’t find an answer (many potential answers were from 2014/2015, but didn’t exactly fit the bill). Hoping this is an easy fix.

I’m trying to send a local lan HTTP Post to a destination behind my router inside a SmartApp (NOT a device). My code is:

hubGet("/ControllerName.json") // inside initialize, and yes, I realize I've hard-coded it below.  :)

private hubGet(def apiCommand) {
def result = new physicalgraph.device.HubAction(
            method: "POST",
            path: "/ControllerName.json",
            headers: [
                    "HOST" : "11.11.11.13:80",
                    "Accept":"application/json"
                    ]
    )
        log.debug result.toString()
        sendHubCommand(result);
}

and I’ve tried to subscribe with

subscribe(location, null, parse, [filterEvents:false])

and my parse function is

def parse(description) {
log.debug "in parse"
    def msg = parseLanMessage(description) 
}

I’ve also tried other combinations with no luck. After a while, I resorted to WireShark and noticed I never see any requests to 11.11.11.13, so something is clearly wrong with my sendHubCommand parameters.

Using CURL

curl -X POST 11.11.11.13/ControllerName.json

gives me a JSON response object. Why am I not seeing any activity on my local network? I’m new to ST, so thanks for the help!

Example 1. Sending a command with a body to a pc running a node.js application:

private sendCmdtoServer(encrCmd, action){
	sendHubCommand(
		new physicalgraph.device.HubAction([
        	body: encrCmd,
        	headers: [
            HOST: "$gatewayIP:8082",
            "target-ip": deviceIP
        	]],
 			device.deviceNetworkId,
			[callback: action]
		)
	)
}

Notes:

a. I am connecting directly to a PC on port 8082. The node.js application has a listener at port 8082, therefore no path.
b. encrCmd is an encrypted command for a local device over TCP
c. targetIp is the local device (not the pc) IP.
d. [callback: action] I call an explicit response method. you do not need this.

Example 2. Sending to a device running several apps that can be addressed through an API. This is from a Device Handler (but should work in a Smart App).

private sendCmd(command, action){
	def deviceIP = getDataValue("deviceIP")
	def cmdStr = new physicalgraph.device.HubAction([
		method: "GET",
		path: command,
		headers: [
			HOST: "${deviceIP}:55001"
		]],
		null,
		[callback: action]
	)
	sendHubCommand(cmdStr)

Note: Here, the path is a command to a device in URL format. One command looks like this in normal format:

/UIC?cmd=<name>GetAcmMode</name>

but translates to this in URL format (what curl does)

/UIC?cmd=%3Cname%3EGetAcmMode%3C/name%3E

Thanks for the reply… If I add the following to my HubAction definition

,null
,[callback: parse]

and use the following parse function

def parse(evt) {
log.debug "in parse: $evt"
}

I see the following in my logs:

4fc70601-33f4-4226-baa1-0c065250669f  9:15:46 AM: debug in parse: 
physicalgraph.device.HubResponse(index:15, mac:001EC018BC5C, ip:0B0B0B0D, port:0050, 
requestId:96415dd9-d11b-4b37-8350-a8497463db41, hubId:36b7cf48-53a2-447a-93fe-f704308cb841, 
callback:parse)

which is definitely coming from my parse function. But still no activity in Wireshark, nor does this look like a response. It looks more like a Async Promise function definition. I think there is something different about the Smart Apps from the Device callbacks because it should otherwise be working. :frowning:

I also tried

def parse(physicalgraph.device.HubResponse hubResponse) {
log.debug "in parse: $hubResponse"
}

I’m not clear what is the difference between the method: path: headers: approach above and

sendHubCommand(new physicalgraph.device.HubAction("""GET /xml/device_description.xml 
HTTP/1.1\r\nHOST: $ip\r\n\r\n""", physicalgraph.device.Protocol.LAN, myMAC, [callback: calledBackHandler]))

as outlined at HubAction.

I tried using

sendHubCommand(new physicalgraph.device.HubAction("""POST /ControllerName.json 
HTTP/1.1\r\nHOST: 11.11.11.13\r\n\r\n""", physicalgraph.device.Protocol.LAN, null, [callback: parse]))

but this yielded nothing in my parse function either.

Success! Thank you very much @Gutheinz

Here is my working code

def hubGet() {
def result = new physicalgraph.device.HubAction(
        method: "POST",
        path: "/ControllerName.json",
        headers: [
                "HOST" : "11.11.11.13:80",
                "Content-Type": "application/json"],
                null,
                [callback: parse]
	)
    log.debug result.toString()
    sendHubCommand(result);
} 

def parse(physicalgraph.device.HubResponse hubResponse) {
    log.debug "in parse: $hubResponse"
    log.debug "hubResponse json: ${hubResponse.json}"
}

I was getting a correct reply above when seeing

physicalgraph.device.HubResponse(index:15, mac:001EC018BC5C, ip:0B0B0B0D, port:0050, 
requestId:96415dd9-d11b-4b37-8350-a8497463db41, hubId:36b7cf48-53a2-447a-93fe-f704308cb841, 
callback:parse)

I assumed that

	log.debug "in parse: $hubResponse"

would print the entire response, but it didn’t. I also had ${hubResponse.xml} but my response was json.

${hubResponse.json}

was the key to seeing the response.

you could try various prints. The system automatically creates the following parse strings (if applicable), as stated in the documentation. To do Json, you could try (in your code):

log.debug hubResponse.json

This should return the json data.

def parse(description) {

def msg = parseLanMessage(description)

def headersAsString = msg.header // => headers as a string
def headerMap = msg.headers      // => headers as a Map
def body = msg.body              // => request body as a string
def status = msg.status          // => http status code of the response
def json = msg.json              // => any JSON included in response body, as a data structure of lists and maps
def xml = msg.xml                // => any XML included in response body, as a document tree structure
def data = msg.data              // => either JSON or XML in response body (whichever is specified by content-type header in response)
...

}