Insteon Local Control!

I tried to play around with some code to query the state of the switch and since there’s not a lot of documentation on connecting to LAN devices, it’s been mostly trial and error.

TL;DR: I’ve been unsuccessful in polling the lights so far. My initial code for turing the lights on and off still works. But, SmartThings isn’t notified when someone turns the light on or off using the physical switches.

My learnings are below:

This doRefresh() method using HubAction() effectively queries the insteon hub for the xml file that has the status of the switch.

def doRefresh() {
	def path = "/sx.xml?" + "${InsteonID}"  + "=1900"
    def method = "GET"
    def host = InsteonIP

    log.debug "refresh path is: $path"
 
 
    def userpassascii = "${InsteonHubUsername}:${InsteonHubPassword}"
	def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
    def headers = [:] //"HOST:" 
    headers.put("HOST", "$host:$InsteonPort")
    headers.put("Authorization", userpass)
 
    try {
    def hubAction = new physicalgraph.device.HubAction(
    	method: method,
    	path: path,
    	headers: headers
        )
    log.debug "hubAction: " + hubAction
    hubAction  
    def result = hubAction
   	log.debug result.text    
    }
    catch (Exception e) {
    	log.debug "Hit Exception on $hubAction"
    	log.debug e
    }
}

What we need to do next is parse the XML file that the Insteon hub returns to determine whether the light is on or off.

<Xs>
<X D="1E65F22502FF"/>
</Xs>

If the string ends in “FF” the light is on. If it ends in “00” it’s off.

This should be fairly straightforward, but I’ve been unable to figure out how to parse the XML file.

Here’s where I’m running into problems:

After looking at @pstuart’s code on Github, my assumption is that I would need to change the device’s NetworkID to a hex version of the IP and port in order to be able to receive the XML file to parse.

He uses the code:

device.deviceNetworkId = "$hosthex:$porthex" 

The problem with this, is the SmartThings Hub does not allow multiple devices to have the same NetworkID.

I have five Insteon Devices using the same IP and port (because they are on the same Insteon hub). So this wouldn’t work. I’m not sure if I should proceed further down this road by using a child device relationship. I’ve seen it mentioned very briefly in the documentation.

The other thing I tried was using the httpGet() method. Some people have said they have gotten this to work when talking to local IPs. Others have said httpGet originates from the cloud so it can’t talk to local IPs.

It didn’t work for me. I got timeout errors in the event log when using this code:

def doRefresh2() {
	def path = "/sx.xml?" + "${InsteonID}"  + "=1900" 
    def uri = "http://${InsteonIP}:${InsteonPort}" 
	def userAgent = "curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5"
    def userpassascii = "${InsteonHubUsername}:${InsteonHubPassword}"
	def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
    
    
    def content
    httpGet(
        [
            uri: uri,
            path: path,
            headers: [Authorization: userpass, 'User-Agent': userAgent],
            requestContentType: "application/x-www-form-urlencoded"
        ],
        { response -> content = response.data }
    )
    log.debug "content: " + content
    def props = content?.items
    if (props) {
        return props[0]
    }
    return [:]
}

Maybe httpGet() would work if I set up port forwarding from my router’s WAN to the Insteon Hub on the LAN, but that seems like a lot of hoops to jump through.

This has been difficult to accomplish without documentation. So, I’m not sure if the assumptions I’ve made are correct. Anyone have any insights here on what to try next?