SmartApp accessing LAN device

I’ve searched and found a few related threads that had various clues, but I just can’t get it to work. Many other people also had problems, a few got it to work, I found all their code on github (by searching for unique strings from their posted snippets), but I can’t see why one would work when another would not, or what I need to do.

What I want to do is interface a SmartApp with my Hikvision NVR - it’d expose various child devices that would allow snapshots to be taken. Hikvision have a proprietary API so I already knocked together a quick C-based CGI app that can be pinged over HTTP for my server, to get the number of cameras, or a snapshot of a specific camera.

As an experiment, I plumbed it in for channel 0, and it worked perfectly - but obviously, this limits me to channel 0, as the hub won’t allow additional smart devices attempting to talk to the same port on the server.

Obviously, HubAction and friends are kind of vaguely documented, but the basics appear to be:

	subscribe(location, null, locationHandler, [filterEvents:false])
        def data = getHostPathForInfo()
        def deviceNetworkId = getHostAddress()
        def action = new physicalgraph.device.HubAction("""GET $data HTTP/1.1\r\nHOST: $deviceNetworkId\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}")
        log.debug action
  	sendHubCommand(action)

Running this code does report the query in the debug log, and the server does indeed receive the request and reply with the number of cameras. However, locationHandler is never called.

Consulting various examples, for the last parameter, some people pass in “1234”, some pass in hex ip:hex port, some simply pass in hex ip, and some pass in the remote device’s MAC address. I can’t remember but at least one of these is the Philips Hue support, which I assume works! However, I’ve tried all of these parameters, and nothing ever happens.

Is there anything else i need to do? Am I going to have to just create a child device to do all the network stuff, and have the smart app mediate between the “real” (child) device and all of the actual “image capture” child devices?

Thanks in advance for any guidance anybody may have :wink:

hubAction requires you to set your DNI as the IP:PORT in hex. All responses are handled by the parse() function. Also, if you are calling hubAction within a function then you may need to return the action in order for it to work properly. Check out my D-Link camera devicetype for an example of a working LAN device using hubAction:

That’s a DeviceType - as I mentioned, I had that working for a single channel, but need a way to get it working where I have multiple DeviceTypes accessing the same service :smile: I actually already used your sample to get it going as the image stuff is a bit bizarre.

However, to do so, it appears using a SmartApp as a Service Manager is the way to go, but it doesn’t appear to have a DNI (if it does, where do I set it?). I assumed the parameter passed to HubAction was the equivalent to DNI, and it appears based on the hue/etc. code on github that the parse method is replaced by a location event containing the HTTP response, if you can get it to work.

It’s parsed in the location subscription. a Smartapp sending a local hubaction needs to subscribe to location and look for the response.

So subscribe to the location in your initialize function and then look for them in there.

Ahh gotcha, sorry I misunderstood. Patrick will be way more knowledgeable in this area, I actually learned about the hubAction command from his generic camera devicetype :smile:

Thanks for your reply - as I mention in the original, I’d figured out that this appears to be the “way it’s meant to work”, so I basically do the following:

subscribe(location, null, locationHandler, [filterEvents:false])
def action = new physicalgraph.device.HubAction("""GET $data HTTP/1.1\r\nHOST: $deviceNetworkId\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}")
sendHubCommand(action)

The subscription definitely works - I get a periodic notification that seems to be nothing relevant (I assume it’s some general “location” thing), but the reply never turns up, so I assume there’s some piece of the puzzle I’m missing :frowning:

Is the data either xml or json or http post/get wrapped? If it is just a raw response or other response types, it will never show up.

Interesting - currently it’s just a plain value. In my case, the NVR has 8 supported inputs, so my little web app just returns a text/plain body of length 1 with “8” in it. This worked okay for the DeviceType “parse” method, but it sounds like it might not be okay here? Obviously it’s no big deal to change it to JSON :wink:

Also, can’t remember off hand but try removing the dni parameter at the end.

So, some clues in case anyone else is following along:

  1. As @pstuart says, it should be JSON. If you make it JSON, it just suddenly works.
  2. The SmartApp can still request images using the S3 storage thing, it works fine
  3. HubAction has a requestId property. When your parse (for device) or locationHandler (for app) are called, it’s one of the properties you’re passed, so you can use it to identify the matching request when it comes back. Initially it’s a UUID, but you can also set it to something useful and not need to do any mapping.