Send ST Events to Local WCF Service


(Anthony S.) #1

Hello…
I’m new to API’s (SOAP and REST) i’m used to writing desktop apps. I already created the WCF web-service that accepts a JSON message and saves it to SQL server but i’m still confused by how to setup the SmartApp correctly so that it registers and sends the events to my web service.

Any advice would be very helpful


(Jody) #2

If you can accept json payloads, it should be fairly simple.

First in your smart app you need to collect some devices to monitor.

input "dimmers", "capability.switchLevel", title: "Which Dimmers?", multiple: true, required: false

Then you need to subscribe to those events

subscribe(dimmers, "level", handleSwitchLevelEvent)

Handle the events

def handleSwitchLevelEvent(evt) {
    logField(evt) { it.toString() }
}

Finally pass that event over to your json web service

private logField(evt, Closure c) {

httpPostJson(uri: "http://yourserver/example.json",   body:[device: evt.deviceId, name: evt.name, value: evt.value, date: evt.isoDate, unit: evt.unit]) {
    log.debug evt.name+" Event data successfully posted"
}

}

Full example here


(Anthony S.) #3

Thanks Jody…
I’m surprised it’s that easy. This is why I coding.


(Anthony S.) #4

Okay so here is my event logging code:

// Send events to external HTTP\HTTPS url
private logEvent(evt, Closure c) {
if (state.enableEvtServer == true) {
	try {
    	httpPostJson(uri: "${state.evtServerAddr}", body:[deviceId: evt.deviceId, evtName: evt.displayName, evtValue: evt.value, evtType: evt.name, 
    			evtUnit: evt.unit, evtIsStateChanged: evt.isStateChange, evtSource: evt.source, evtDescription: evt.description, date: evt.isoDate ]) { resp ->
        	log.debug "response data: ${resp.data}"
        	log.debug "response contentType: ${resp.contentType}"
    	}
    	if(resp.data == 0) {
			log.debug evt.name+" Event has been successfully posted to ${state.evtServerAddr}"
    		log.debug "\'$evt.name\' event received from: $evt.displayName, isStateChanged: $evt.isStateChange, Value: $evt.value, Unit: $evt.unit, Source: $evt.source, Description: $evt.description, Device Id: $evt.deviceId"
		}
    } catch (e) {
    	log.debug "HttpPostJson error: $e"
	}
}
if (state.enableEvtServer == false) {
	log.debug "\'$evt.name\' event received from: $evt.displayName, isStateChanged: $evt.isStateChange, Value: $evt.value, Unit: $evt.unit, Source: $evt.source, Description: $evt.description, Device Id: $evt.deviceId"
}

}

I am able to post the following json to the service without issue:

{ "deviceId":"d23123-2321312de-f232323123", "evtName":"Dumby Device", "evtValue":"on", "evtUnit":"none", "evtType":"switch", "evtIsStateChanged":"true", "evtSource":"DEVICE", "evtDescription":"zw device: 48", "evtIsoDate":"08-14-2015 01:00:00pm" }

In the logs i’m getting this:

error groovyx.net.http.HttpResponseException: Not Found @ line 314 (which is the code above)

I know its reaching out to the service but its not telling me anything else…


(Jody) #5

Log your ${state.evtServerAddr} to make sure it is in fact holding a valid address.

Just a guess, but is this a private address?


(Anthony S.) #6

that was my first step… I even typed in directly to the Uri: field


(Jody) #7

is it an address on your local area network?


(Jody) #8

I see from the title that it is. You will need to port forward a rule into your local network. Your events are going to be coming from graph.api.smartthings.com. You can just allow incoming from smartthing’s servers but the sql server will need to recieve these json payloads from the internet.


(Anthony S.) #9

Yea I guess that’s misleading. It’s actually already exposed to the web through my IIS server. I can post data to it using web post tools. It’s just not accepting any posts from the Smart App


(Jody) #10

Which line is 314 exactly? Is the the line with httpPostJson?


(Anthony S.) #11

Yes line 314 is the httpPostJson


(Jody) #12

Make sure you are forming the url correctly.

Here are the docs on that method.

http://docs.smartthings.com/en/latest/smartapp-developers-guide/calling-web-services-in-smartapps.html


(Anthony S.) #13

Ok… I have made some changes to the code because I determined that the SmartApp is not sending data in the proper format.

// Send events to external HTTP\HTTPS url
private logEvent(evt, Closure c) {
	def evtJson = new groovy.json.JsonOutput().toJson([
      	deviceId: 			evt.deviceId,
      	evtName: 			evt.displayName,
        evtValue: 			evt.value, 
        evtType: 			evt.name, 
    	evtUnit: 			evt.unit, 
        evtIsStateChanged: 	evt.isStateChange, 
        evtSource: 			evt.source, 
        evtDescription: 	evt.description, 
        date: 				evt.isoDate
    ])
    
    if (state.enableEvtServer == true) {
  		log.debug "Attempting to POST Data to ${state.evtServerAddr}"
        
        httpPost(uri: "${state.evtServerAddr}", body: [evtJson]) { resp ->
        resp.headers.each {
        	log.debug "${it.name} : ${it.value}"
        }
        log.debug "response contentType: ${resp.contentType}"
        }
        if(resp.data == 0) {
    		log.debug evt.name+" Event has been successfully posted to ${state.evtServerAddr}"
        	log.debug "\'$evt.name\' event received from: $evt.displayName, isStateChanged: $evt.isStateChange, Value: $evt.value, Unit: $evt.unit, Source: $evt.source, Description: $evt.description, Device Id: $evt.deviceId"
  		}
    } 
    if (state.enableEvtServer == false) {
    	log.debug "\'$evt.name\' event received from: $evt.displayName, isStateChanged: $evt.isStateChange, Value: $evt.value, Unit: $evt.unit, Source: $evt.source, Description: $evt.description, Device Id: $evt.deviceId"
    }
}

Here is what is returned in the event log:

error groovy.lang.MissingMethodException: No signature of method: groovyx.net.http.EncoderRegistry.encodeForm() is applicable for argument types: (java.util.ArrayList, groovyx.net.http.ContentType) values: [[{"deviceId":"090f4f7c-0682-4020-b00a-a1cf794ea149","evtName":"Multisensor - Playroom","evtValue":"active","evtType":"motion","evtUnit":null,"evtIsStateChanged":"true","evtSource":"DEVICE","evtDescription":"zw device: 4C, command: 9881, payload: 00 30 03 FF","date":"2015-08-19T22:19:18.475Z"}], ...]
    Possible solutions: encodeForm(java.lang.String, java.lang.Object), encodeForm(java.util.Map), encodeForm(java.util.Map, java.lang.Object), encodeAsJs(), encodeAsURL(), encodeAsRaw() @ line 334

(Jody) #14

I think this should just be body: evtJson

You are already creating a json object. The brackets are likely causing an error.


(Anthony S.) #15

I’ve had to modify some code to handle location events handling failing so I had to add a if statement to the LogEvents.

Device Events work fine but once I added the if (evt.source == "LOCATION") it returns evtJson as null. which is odd because I can see that evt.source is returning either DEVICE or LOCATION. So what would cause this IF statement not to work?

The code below is just a snip…

if (state.enableEvtServer == true) {
	def evtSrc = evt.source
	def evtJson
    
   	if (evt.source == "DEVICE") {
    	evtJson = new groovy.json.JsonOutput().toJson([ devIdentity: evt.deviceId, evtName: evt.displayName, evtValue: evt.value, evtType: evt.name, 
    		evtUnit: evt.unit, evtIsStateChanged: evt.isStateChange, evtSource: evt.source, evtDescription: evt.description, evtIsoDate: evt.isoDate ])
        log.debug "Source: ${evtJson}"
    }
    if (evt.source == "LOCATION") {
    	evtJson = new groovy.json.JsonOutput().toJson([ devIdentity: evt.name, evtName: evt.name, evtValue: evt.value, evtType: evt.name, 
    			evtUnit: evt.unit, evtIsStateChanged: evt.isStateChange, evtSource: evt.source, evtDescription: "Mode is Set to: ${evt.name}.toString().toUpperCase()", evtIsoDate: evt.isoDate ])
            log.debug "Location: ${evtJson}"
    }

}


(Anthony S.) #16

Aparently i had to do this

def evtSrc = "${evt.source}"


(Jody) #17

Glad you got it working. You might also be able to use evt.source.toString(). Are your events logging to your sql database now?


(Anthony S.) #18

The .toString() was the first thing I tried but it returned a Java Exception error that I can’t remember

It is working now and I’m absolutely loving that it’s even possible so Thank you SmartThings for that.

In regards to the SmartApp I am just getting some more features working while trying to optimize the code and that all the code is commented.
After that I will post the code to Github for anybody looking for it. I’m also thinking of packaging up the web service and database into an installable package so people can install on a pc at home.
Right now the web service does the following:

  • Adds events received from ST to the database.
  • Retrieve event data for use in external apps or programs (Work In Progress)