HTTP Callouts Over LAN and User Preferences/Settings

So I’m trying to rewrite a SmartApp to connect to a device on my network (Rainmachine) via LAN instead of having to hit it from the cloud after port forwarding and all that mess.

After much pulling out of hair, I’ve managed to figure out how the callouts work and how to parse responses dealing with the async requirement and all that (beating a dead horse, I know, but THIS SUCKS SO BAD GOOD LORD).

My problem now is that the installation process for this application currently requires real-time, synchronous interaction with the user. It goes something like this:

1.) Page prompts user for login information for device
2.) Callouts happen logging into device and pulling down data
3.) Next page displays a list of items from the device for the user to choose from.
4.) Code executes to create virtual devices from those selected by the user
5.) All done. Yay.

So far, I have not been able to replicate this flow using the LAN callouts due to their asynchronous nature. I can kick off the login process which initiates the login callout, but there’s no way to connect the response back to the page to continue the process. I’ve tried putting in additional preference “waiting” pages that would essentially act as points where the user can just wait for the data to come back, but that doesn’t quite work out for some reason.

Has anyone else tried doing this? I know LAN-callouts are just insane hacks and workarounds in general, but has anyone hacked their way around this particular combination of doing those callouts within a SmartApp setup/install flow?

I have a similar scenario for an application i wrote to incorporate my alarm system with smart things. I have my smart app calling an app running on my local LAN using the sendHubCommand. As far as receiving the actual reply, I subscribe to all of the events coming from the lan. Then in my lanHandler I check the message to make sure it is mine and then take appropriate action. so somehting like this:

def initialize() {
	subscribe(location, null, localLanHandler, [filterEvents:false])

Then in the loadLanHandler I check a few things to make sure it is a response for me.

/* ***************************************************** */
/* Handle event from the j64AlarmServer on the local LAN */
/* ***************************************************** */
def localLanHandler(evt) {

	// Only handle messages from the j64AlarmServer
	def msg = parseLanMessage(evt.description)
    // The request must be valid json format
	if (msg.json == null) {
    def FromHost = msg.json.FromHost
    def Route = msg.json.Route
    // The request must have a from host property that matches the alarm server
    if (FromHost != j64AlarmServerAddress()) {

    // Ensure that the route property passed from the j64 server is what we expect     
    if (Route == "/api/AlarmSystem")
       installAllDevices(msg.json.Response.Partitions, msg.json.Response.Zones)

There are probably better ways to determine if that message is meant for me but this served my purpose. Feel free to check out the full set of code on my github.

Thanks - I think I figured it out. My issue was just not quite understanding how I needed to set the pages up to work in a flow; specifically I had install set to true on pages other than the “ending” page, which caused the flow to stop too early.

As for the response parsing - I’m doing the same thing as you :slightly_smiling:

For any curious onlooker who finds this post later, I’ll post the full code once I get it working and cleaned up.

Great idea.

So, how this story ends, @brbeaird , you finally did it? Thanks.

@inakiarr - Yes! Oh man, I totally forgot to post the code! I ended up improving my flow even more by writing “waits” into the code so “waiting pages” are no longer necessary. I haven’t gotten around to cleaning the code up yet, so it’s still kind of a huge mess, but it does work, and you can see the part at the beginning where I set up the dynamic preference pages.

1 Like