Any Documentation on "physicalgraph device HubAction"?


(Patrick Stuart [@pstuart]) #1

I am banging my head against a wall trying to figure out how this action actually works.

Since it is a custom function developed by Physical Graph, I was hoping there would be reference API documentation on how it functions, working examples, etc.

I have a kludge working with a SmartApp but am trying to use a local hub action to pull an image from a local camera, and can’t see to get a response.

This platform is supposed to be open, but there is a seriously lacking documentation issue with most functions.

Can someone provide the full command set for physicalgraph.device.HubAction?

I’ve seen it used this way:

def hubAction = [new physicalgraph.device.HubAction(
	method: "POST",
	path: uri,
	body: command,
	headers: [Host:getHostAddress(), "Content-Type":"application/x-www-form-urlencoded" ]
	), delayAction(1000), refresh()]
hubAction

But trying to subscribe to any response seems impossible without understanding this method furthur.

and this way:

def res = new physicalgraph.device.HubAction("""GET /blah HTTP/1.1\r\nHOST: $ip\r\nAuthorization: Basic $userpass\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${hosthex}")

Can someone provide working examples of how to get basic GET and POST (with or without Authorization) local hub queries?

I spent 5 hours last night desparately trying to do a simple GET to a webcam and return the image. This shouldn’t be this hard and shouldn’t require me to port forward my cameras for it to work.


Looking for RESTful LAN Skeleton
Multiple Hub Z-Wave Networks
Finding Public IP Address of Cable Modem serving the SmartHub
(Kent) #2

Working example at the bottom that connects to 192.168.0.10 on port 8080.
Note the local/internal LAN connection stuff can’t use HTTPS yet, only HTTP.
Also you can’t get any data back from that function, if you want to talk to internal devices Smartthings seems to really want you to use upnp/soap and callbacks instead of direct communication/returned data via HTTP.

Some docs for this but not all:
http://docs.smartthings.com/en/latest/cloud-and-lan-connected-device-types-developers-guide/index.html

private push() {
  def ip = "192.168.0.10"
  def deviceNetworkId = "C0A8000A:1F90"
  sendHubCommand(new physicalgraph.device.HubAction("""GET /myurl HTTP/1.1\r\nHOST: $ip\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}"))

  // Get Hub firmware version if needed
  log.debug location.hubs*.firmwareVersionString.findAll { it }
}

(Patrick Stuart [@pstuart]) #3

but I can and do get responses back if i go looking for them… this action just feels like it escaped from alpha development and isn’t fully fleshed out…

the issue is the same exact code doesn’t get a response when used as a device but in a smartapp it does return a response.

can’t use upnp on devices that don’t support upnp…

local hub to device communication needs to be improved dramatically, or at least this function needs proper documentation…


(Kent) #4

Agreed on all points, it’s basically a big mess with the internal lan stuff right now.
I used the code above to hit my internal web server but that’s as far as I got with that particular test. I was told at the time that the function didn’t/couldn’t return any data, maybe that’s changed. Either way the docs for that function are pretty sparse.


(Patrick Stuart [@pstuart]) #5

WOW!!!

I think I finally got this hubaction to work. Thanks to code clues from @scottinpollock I was able to figure out how the hubaction is supposed to work.

It is all tied to the HEX address and Port within the device configuration.

Not exactly sure how to get a virtual device to work, but I just got my panasonic camera to return an image local.

I will clean up the code and post a working example of a local http request in a device.

Documentation would be nice, but ultimately, hacking around will ultimately figure something out :smile:


(Convinced ST will never be unbroken…) #6

I just wanna see how you parsed your imageData; haven’t figured out how to get that right.


(Patrick Stuart [@pstuart]) #7

All details are in this, it finally makes sense… Your code for your tstat finally made it work for me once I understood device.deviceNetworkId had to be in hex


(Patrick Stuart [@pstuart]) #8

Found a GIANT BUG in using the hubAction. It will NEVER respond if you have a 10.x.x.x ip address range.

It can’t parse the hex back to a proper IP!

So if you are trying to get any local hub actions and responses to work, right now you are going to have to use a range that starts with a 3 digit ip range, 192.x.x.x ideally.


(Geko) #9

Shocking! I’m sure @urman is kicking himself in the head this very minute. :slight_smile:


(Patrick Stuart [@pstuart]) #10

So this is what I have been able to figure out:

10.0.0.5 should convert to “0A” “00” “00” “05”  however, in the hub this shows up as “A000005” which will not translate back to 10.0.0.5 because it is missing the leading zero for the first set.

I now know this, and will change the way I get the IP to Hex functions to add the leading zero. Had to do the same thing for port numbers…

What I don’t understand is how or why anyone would ever think average users would be able to know what their hex IP and hex port code is?

Why can’t the deviceNetworkId be stored as a string like “10.0.0.5:80” as everyone knows it, and then behind the scenes convert it to Hex (properly) and then magic, everything should work much better…


(Convinced ST will never be unbroken…) #11

Do we know if this is a groovy function or a SmartThings function? Seems IP2Hex and Dec2Hex should be pretty standard stuff.

BTW, you might want to try dealing with this as an array or list and using a Dec2Hex function on each value (assuming there is one that works).


(Convinced ST will never be unbroken…) #12

But now that I think about it a little more, ‘A’ is a valid result for Dec2Hex(10).

Don’t know the reason why hex is needed, but guessing that’s what the hub’s hardware needs and it is too stupid to figure it out on its own.

Anyway… hope you reported this via email.


(Patrick Stuart [@pstuart]) #13

Here’s a function I wrote to potentially solve the issue, but I can’t test it in my office since the IDE doesn’t work behind a firewall for whatever reason… (Have to dig into that later)

Can someone saavy with code test this and then set back the device NetworkId to be the debug’d string

private convertIPtoHex(ipAddress) { //expecting a string like xxx.xxx.xxx.xxx
    //debuging ip addresses
    log.debug “convert hit”
    //ipAdddress = “10.0.0.5”
   log.debug ipAddress
    //String hex = ‘0x’ + ipAddress.tokenize( ‘.’ ).collect {  String.format( ‘%02x’, it.toInteger() ) }.join()
    String hex = ipAddress.tokenize( ‘.’ ).collect {  String.format( ‘%02x’, it.toInteger() ) }.join()
    log.debug hex
    
}

otherwise I’ll test it tonight when I get home.

The issue is simple, converting decimal “10” to Hex is “A” but for IP notation, it is “0A” because decimal “192” is “C0” so in order to cover the entire range of 1-255 you need a double byte HEX.

So when the hub is trying to match up a device at “0A000005” (10.0.0.5) and the deviceNetworkId is only “A000005” it won’t work.

Simple issue, just the code examples of how to convert a string IP to hex are all wrong.

The same issue was with port numbers which can range from 1-65535

So 80 would be “50” but really needs to read “0050”

Where as 5000 would be “1388” and works or 65534 would be “FFFE”

So the existing functions someone wrote to convert IP to Hex need to be fixed, along with ports.

Wouldn’t it just be easier to do this behind the scenes and let users enter standard IP and Port notation, 10.0.0.5:80?

Why make it so difficult.


Question about httpPost
(Geko) #14

@pstuart, I don’t get it why you need to convert IP address to hex. HTTP GET works for me with dotted addresses (192.168.1.100:80). Although I’m calling it from the app, not the device handler.


(Patrick Stuart [@pstuart]) #15

@geko,

The deviceNetworkId in ST for the local hubaction GET needs a hex ip and port in the device settings.

HTTPGET which is cloud based, external does not.

If you want to port forward your cameras, then you can use HTTPGET but if you don’t want the world seeing your cameras, then you can use my code for the generic camera device. In the preferences you enter the IP and Port and I automatically convert it to Hex in the device.


(Geko) #16

I’m not talking about “external” HTTP GET. I’m talking to my WiFi thermostat locally using sendHubAction() and I don’t need to do any hex conversion.

Here’s my log reading thermostat version (GET /tstat/version):

5ce516f6-38cc-4e24-8102-793536912397 10:57:49 PM PDT: debug body: {“version”:100}
5ce516f6-38cc-4e24-8102-793536912397 10:57:49 PM PDT: debug headers: HTTP/1.1 200 OK
Server: Marvell 8688WM
Connection: close
Transfer-Encoding: chunked
Content-Type: application/json
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Pragma: no-cache
5ce516f6-38cc-4e24-8102-793536912397 10:57:49 PM PDT: debug parseLanResponse([index:01, mac:5CDAD424AC32, ip:C0A80169, port:0050, headers:SFRUUC8xLjEgMjAwIE9LDQpTZXJ2ZXI6IE1hcnZlbGwgODY4OFdNDQpDb25uZWN0aW9uOiBjbG9zZQ0KVHJhbnNmZXItRW5jb2Rpbmc6IGNodW5rZWQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KQ2FjaGUtQ29udHJvbDogbm8tc3RvcmUsIG5vLWNhY2hlLCBtdXN0LXJldmFsaWRhdGUNCkNhY2hlLUNvbnRyb2w6IHBvc3QtY2hlY2s9MCwgcHJlLWNoZWNrPTANClByYWdtYTogbm8tY2FjaGU=, body:eyJ2ZXJzaW9uIjoxMDB9, hubId:130e9d28-2efd-4f1f-bfc3-87bf35f06bc2])
5ce516f6-38cc-4e24-8102-793536912397 10:57:49 PM PDT: debug onLocation(index:01, mac:5CDAD424AC32, ip:C0A80169, port:0050, headers:SFRUUC8xLjEgMjAwIE9LDQpTZXJ2ZXI6IE1hcnZlbGwgODY4OFdNDQpDb25uZWN0aW9uOiBjbG9zZQ0KVHJhbnNmZXItRW5jb2Rpbmc6IGNodW5rZWQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KQ2FjaGUtQ29udHJvbDogbm8tc3RvcmUsIG5vLWNhY2hlLCBtdXN0LXJldmFsaWRhdGUNCkNhY2hlLUNvbnRyb2w6IHBvc3QtY2hlY2s9MCwgcHJlLWNoZWNrPTANClByYWdtYTogbm8tY2FjaGU=, body:eyJ2ZXJzaW9uIjoxMDB9)
5ce516f6-38cc-4e24-8102-793536912397 10:57:48 PM PDT: debug Executing GET /tstat/version HTTP/1.1
Accept: /
User-Agent: Linux UPnP/1.0 SmartThings
HOST: 192.168.1.105:80
on Home Hub via sendHubCommand


(Patrick Stuart [@pstuart]) #17

In your device settings, what is your device Network ID set as? I can almost guarantee it is in HEX… You can even see it in the debug ip:C0A80169, port:0050


Starting point hubAction
(Geko) #18

Nope. It’s easier than you think :smile:

def sendRequest() {
    TRACE("sendRequest()")

	def httpRequest = [
      	method:		settings.httpMethod,
        path: 		settings.httpResource,
        headers:	[
        				HOST:		state.networkAddr,
						Accept: 	"*/*",
                    ]
	]

	def hubAction = new physicalgraph.device.HubAction(httpRequest)
	sendHubCommand(hubAction)
}

where ‘state.networkAdd’ is IP:PORT in dotted notation.


Sending http requests to the local network (Hue)
Convert hostname to IP Address
(Patrick Stuart [@pstuart]) #19

Apples and oranges… The HOST: in the request has to be in IP:PORT notation. But it all responds on the dni. if you don’t provide it in the hubaction it will default to the configured “Device Network Id”

What code are you using. Also, go into devices, click edit on the device, and what is the “Device Network Id”


(Geko) #20

I’m not passing deviceNetworkId to sendHubAction() like you do, so I don’t need to do any conversion. And like I said, this function is called from the smart app, there is no deviceNetworkId.