Contact switches from JSON LAN webserver

devicetype
hubv2

(Leoforney) #1

Hi everyone, I have been trying to make a solution to use all of our existing door contacts that we purchased through ADT with ST. To do this, I am using a Raspberry Pi ($35) and a $5 wifi dongle. I used a library called pi4j and used java to make a web application that takes two gpio ports and checks if they broadcasts if they are open in JSON format. Here is an example of what the json looks like.

{"Door1":"true","Door2":"true"}

I created a device type called Door Security and it just makes tiles for each boolean value. This was just so I can get the data into smartthings. I am brand new to smartthings so I have no clue how to write any code using the IDE. Neither do I have experience using Groovy but I have about two years of experience on Java. I run the code on a new device and named it Raspberry Pi. When I hit the refresh button, as it should, it sets the device network id. However, it doesn’t log anything inside the live logging… I took at Nicholas Wilde’s berryio smartthings integration and that didn’t work, but I decided to use the device type as the boilerplate of mine as I would only need to get the tile of where it extracts the GPIO from the berryio json. Here is my device type:

import groovy.json.JsonSlurper
import com.google.common.base.Splitter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

preferences {
       input("ip", "string", title:"IP Address", description: "192.168.1.105", required: false, displayDuringSetup: true)
       input("port", "string", title:"Port", description: "8080", defaultValue: "8080" , required: false, displayDuringSetup: true)
}
metadata {
	definition (name: "Door Security", namespace: "leoforney", author: "Leo Foney") {
		capability "Contact Sensor"
        capability "Refresh"
	}

	simulator {
		// TODO: define status and reply messages here
	}

	tiles {
		standardTile("door_1", "device.contact", width: 1, height: 1) {
            state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
            state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
   		}
        standardTile("door_2", "device.contact", width: 1, height: 1) {
            state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
            state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
   		}
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
        	state "default", action:"refresh.refresh", icon: "st.secondary.refresh"
        }
        main "door_1"
        details(["door_1", "door_2", "refresh"])
	}
}

// ------------------------------------------------------------------

// parse events into attributes
def parse(String description) {
    def map = [:]
    def descMap = parseDescriptionAsMap(description)
    log.debug "descMap: ${descMap}"
    
    def body = new String(descMap["body"].decodeBase64())
    log.debug "body: ${body}"
    
    def slurper = new JsonSlurper()
    def result = slurper.parseText(body)
    
    log.debug "result: ${result}"

	if (result){
    	log.debug "Raspberry Pi is responding!"
    }
    
  	if (result.containsKey("Door1")) {
    	log.debug "Door1: ${result.Door1}"
        if (result.Door1.contains("true")){
        	log.debug "Door1: open"
            sendEvent(name: "door_1", value: "open")
        } else {
        	log.debug "Door1: closed"
            sendEvent(name: "door_1", value: "closed")
        }
    }
    
    if (result.containsKey("Door2")) {
    	log.debug "Door2: ${result.Door2}"
        if (result.Door2.contains("true")){
        	log.debug "Door2: open"
            sendEvent(name: "door_2", value: "open")
        } else {
        	log.debug "Door2: closed"
            sendEvent(name: "door_2", value: "closed")
        }
    }
  	
}

// handle commands
def poll() {
	log.debug "Executing 'poll'"
    getRPiData()
}

def refresh() {
	log.debug "Executing 'refresh'"
    getRPiData()
}

private getRPiData() {
    postAction("/")
}

// ------------------------------------------------------------------

private postAction(uri){
  setDeviceNetworkId(ip,port)  

  def hubAction = new physicalgraph.device.HubAction(
    method: "POST",
    path: uri,
    headers: headers
  )//,delayAction(1000), refresh()]
  log.debug("Executing hubAction on " + getHostAddress())
  //log.debug hubAction
  hubAction    
}

// ------------------------------------------------------------------
// Helper methods
// ------------------------------------------------------------------

def parseDescriptionAsMap(description) {
	description.split(",").inject([:]) { map, param ->
		def nameAndValue = param.split(":")
		map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
	}
}

private getHeader(){
	log.debug "Getting headers"
    def headers = [:]
    headers.put("HOST", getHostAddress())
    return headers
}

private delayAction(long time) {
	new physicalgraph.device.HubAction("delay $time")
}

private setDeviceNetworkId(ip,port){
  	def iphex = convertIPtoHex(ip)
  	def porthex = convertPortToHex(port)
  	device.deviceNetworkId = "$iphex:$porthex"
  	log.debug "Device Network Id set to ${iphex}:${porthex}"
}

private getHostAddress() {
	return "${ip}:${port}"
}

private String convertIPtoHex(ipAddress) { 
    String hex = ipAddress.tokenize( '.' ).collect {  String.format( '%02x', it.toInteger() ) }.join()
    return hex

}

private String convertPortToHex(port) {
	String hexport = port.toString().format( '%04x', port.toInteger() )
    return hexport
}

The tiles do not change from the JSON and my live logging doesn’t work so I can’t tell any debug info. If anyone can help out that would be awesome, thanks in advance… :slight_smile:


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #2

My first recommendation is to write 2 or 3 much simpler code examples first. SmartThings doesn’t have a debugger, so you need to understand how to manually simulate (hard-coded) events from a Device… ie, put some expected REST return JSON data right into the code and see if you can fire sendEvent, etc., to consistently update the Tile states and values.

Then you know as you increase complexity you will always be able to manually trace and debug when an edit breaks something…