(Beginner) Sending commands to an API via Device Handler, help?


#1

Note: I haven’t written anything yet, but I do have some experience in writing device handlers, I wrote one for my Osram light bulbs. So I’m not completely new, just new to accessing an API via the handler code.

So I’m creating this thread separately from my actual project because I don’t think (due to the name of the thread) I will get many responses, but here is the link:

After some research I found out my Vizio TV has an API. Using cURL (for the first time) I figured out how to pair to the TV and get an Authorization string, which I’ve tested and found that I can use this string on any device, it’s not restricted by MAC or IP.

I’ve got a couple batch files on my computer one for TV On and one for TV Off just to test and they work perfectly.

Does anyone have any advice or samples I could use to figure out how to write a Device Handler for my TV? I don’t need start to finish help. Once I have a basic idea of how to run a command on the API with code in the handler, I can replicate that out to all the commands I want to run and build in the functions I need.

I was thinking I could just copy the auth string and hard code it into the device handler since I only have the one TV. Unless there is an easy way to write the pairing code in the handler code (requires pairing then inputting a code displayed on the TV’s screen for the response).


#2

Is the TV discoverable via UPNP? This might be a good place to start. The possible problems you might run into is the whole running local vs in the cloud - since you probably only want your TV accessible from inside your LAN.

http://docs.smartthings.com/en/latest/cloud-and-lan-connected-device-types-developers-guide/building-lan-connected-device-types/index.html


(Dave Gutheinz) #3

Is your DH LAN or WAN (cloud) based?

If LAN, are the curl commands TCP or UDP, as opposed to straight HTTP?

If LAN and HTTP, there are examples in the templates that may give guidance:

Samsung Smart TV Device Handler
Samsung TV (Connect) Service Manager.

If LAN and TCP or UDP, you are probably out-of-luck unless you create a bridge device to do actual control (HubAction is used for LAN devices and does not currently work with TCP/UDP).

I also have an example that started out with curl commands at this thread. However, it is long - but the raw commands I used are at the end of the device handler. I can provide some curl commands so you can see the transition to HubAction commands (curl commands URL encoded, HubAction not). Another thing, if I take the non-curl command and place with IP/Port in the address line of my browser, the command works and you get the return data in the browser window. Comes in handy while developing parse methods.

{BETA} Samsung WiFi Soundbar Integration

Good luck.


#4

@zavex:
I’m not sure about UPNP but the API documentation did mention something about discovering it via an SSDP query. But that was just to discover it on the network and obtain it’s IP. Whereas UPNP is more about dynamic port forwarding, right?

@Gutheinz
I’m not sure if I can answer all of your questions hahaha. I’m very new to cURL and anything related to API’s. All of my development experience is in SQL databases/development (my day job), so I don’t get exposed to this stuff very often.

Here’s the actual curl command being run from a windows PC on the network, this will turn the TV On:

curl -k
-H "Content-Type: application/json"
-H "AUTH: blahblahblah"
-X PUT
-d "{\"KEYLIST\": [{\"CODESET\": 11,\"CODE\": 1,\"ACTION\":\"KEYPRESS\"}]}" 
https://192.168.0.107:9000/key_command/

Really I just want the ability to turn the TV off with CoRE. I’m not looking to do much more than that with the SmartThings platform as of right now.


(Dave Gutheinz) #5

If doing a simple on-off, you should be able to do a device handler only. Will have to have the IP entry in the preference section and make the TV IP address static. I do that in the soundbar.

Curl Command decoded is probably without the backslash. Yours is not URL and the command looks like http. The two template examples definitely apply (although yours may be a lot simpler!!!)


#6

Okay perfect, TV is already static (well, DHCP reserved). I’ll take a look at those examples and see if I can get it done that way.

For now I’m going to stick with hard coding the auth string into the DH rather than trying to implement some sort of pairing process in the DH itself. That seems too complicated, especially because it requires inputting the code from the screen. I’ve tested using the same auth string on multiple computers, so there’s no security restriction there.

And yeah, it should be very simple. As of now, I just need the one button for on/off.


#7

I can’t find those templates in the IDE, were they removed? Or are they community written?


(Dave Gutheinz) #8

You need to log on, go to My Device Handlers. Select New Device Handler. There will be a tab From Templates. Go down to the Samsung Smart TV. Same for the Service Manager. Check today and they are still there.


#9

That’s exactly what I did…I don’t have those in my templates.

My templates jump from RGBW Light, to Secure Dimmer…I even did a search in the browser and I don’t have any handlers with the words “TV” or “Samsung” in the name.

11-6-2017 16-55-27


(Dave Gutheinz) #10

Must be a regional difference. (I am in US.) I do not have any other great examples. Let me think a bit on this. If I get time, I may provide a “what would I write”.


(Dave Gutheinz) #11

I put together an example that may work for you. Testing confirms that the buttons work; however, I could not test any results since I do not have the device.

    /*
This example is provided in response to a query by Chadbaldwi

This is a small portion of a Device Handler I am writing for
a wifi speaker set.  I have modified it to accommodate the
simpler design and HMI needed in this specific use case.
*/

metadata {
	definition (name: "Simple Example for TV", namespace: "example", author: "example") {
		capability "Switch"
		capability "refresh"
		capability "Sensor"
		capability "Actuator"
	}
	tiles(scale: 2) {
//	The below is from a switch DH I authored.  Should work as-is.
		multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
			tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
				attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc",
				nextState:"waiting"
				attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff",
				nextState:"waiting"
				attributeState "waiting", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#15EE10",
				nextState:"waiting"
				attributeState "commsError", label:'Comms Error', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#e86d13",
				nextState:"waiting"
			}
 			tileAttribute ("deviceError", key: "SECONDARY_CONTROL") {
				attributeState "deviceError", label: '${currentValue}'
			}
		}
		standardTile("refresh", "capability.refresh", width: 2, height: 2,  decoration: "flat") {
			state ("default", label:"Refresh", action:"refresh.refresh", icon:"st.secondary.refresh")
		}		 
		
		main("switch")
		details("switch", "refresh")
	}
//	I add preferences (accessed in device details in the smartpone app
//	via the gear icon in upper right corner.
	preferences {
		input("deviceIP", "text", title: "Device IP", required: true, displayDuringSetup: true)
		input("devicePort", "text", title: "Device Port", required: true, displayDuringSetup: true)
    }
	main "switch"
	details(["switch", "refresh"])
}
def installed() {
	updated()
}
def updated() {
	unschedule()
}

//	----- ON/OFF COMMANDS -----
//	The on command.  Here I created your CURL command with a variable
//	on-off inserted.  This may take some playing with in your example.
def on() {
	def onOff = "1"		//	I assume "1" is the keycode for ON.
/*	
	Generating.  Starting with the Curl Command you provided
	{\"KEYLIST\": [{\"CODESET\": 11,\"CODE\": 1,\"ACTION\":\"KEYPRESS\"}]}
	I replaced the Code of "1" with KEY_CODE and converted to standard 
    by removing the "\" characters.
    {"KEYLIST": [{"CODESET": 11,"CODE": KEY_CODE,"ACTION":"KEYPRESS"}]}
    I then convert to URL format from site https://www.urlencoder.org/
    %7B%22KEYLIST%22%3A%20%5B%7B%22CODESET%22%3A%2011%2C%22CODE%22%3A%20KEY_CODE%2C%22ACTION%22%3A%22KEYPRESS%22%7D%5D%7D
    this is placed in a command to send to the unit.
    
    The KEY_CODE is replaced by the variable onOff as '${onOff}'
    
    I then add a specific parse method, used later.
*/
    sendCommand("/key_command/%7B%22KEYLIST%22%3A%20%5B%7B%22CODESET" +
                "%22%3A%2011%2C%22CODE%22%3A%20${onOff}%2C%22ACTION%22" +
                "%3A%22KEYPRESS%22%7D%5D%7D", "parseResponse")
//	Finally, I fire an event (will publish that this occurred to any 
//	handlers or apps that subscribe.
	sendEvent(name: "switch", value: "on")
    log.info "${device.label}: On/Off state is ${device.currentValue("switch")}."
}
def off() {
	def onOff = "0"		//	I assume "0" is the keycode for OFF.
    sendCommand("/key_command/%7B%22KEYLIST%22%3A%20%5B%7B%22CODESET" +
                "%22%3A%2011%2C%22CODE%22%3A%20${onOff}%2C%22ACTION%22" +
                "%3A%22KEYPRESS%22%7D%5D%7D", "parseResponse")
	sendEvent(name: "switch", value: "off")
    log.info "${device.label}: On/Off state is ${device.currentValue("switch")}."
}

//	----- SEND COMMAND  -----
private sendCommand(command, action){
	def cmdStr = new physicalgraph.device.HubAction([
		method: "PUT",	// I use 'GET' here.
		path: command,		//  The command I generated goes here.
		headers: [
//	deviceIP and devicePort were entered by you.  You can also hard
//	code these parameters.
//	I assumed the AUTH would go here.
			AUTH: "blahblahblah",
			HOST: "${deviceIP}:${devicePort}"
		]],
		null,
		[callback: action]
	)
//	for initial testing, I log the command string.  Assures I have reached
//	the send.  I remove this when I have verified.
    log.debug cmdStr
	sendHubCommand(cmdStr)
}
//	----- PARSE RESPONSE DATA BASED ON METHOD -----
def parseResponse(resp) {
//	for initial testing, I log the parse response received from the
//	device.
	log.debug "RAW RESPONSE:  ${resp}"
//	The below is an example for my device.  Yours may not return
//	anything (key press interface) or may return a success of some
//	sort.  The below may result in a clear text response that could
//	be readily read.
	def responseBody = (new XmlSlurper().parseText(resp.body))
    log.debug "BODY:  ${responseBody}"
}

For me (I do not have the device), the log results are (last log item first)

debug BODY: 500 Error500 Error Not Support Method
debug RAW RESPONSE: physicalgraph.device.HubResponse(index:17, mac:D8E0E1B5D2AF, ip:C0A80071, port:D6D9, requestId:5e11010f-3c89-48fe-9859-bc4438906035, hubId:8f7f96d1-f145-4452-afab-0fa6f5261aa1, callback:parseResponse)

info zzzzz: On/Off state is on.

debug PUT /key_command/%7B%22KEYLIST%22%3A%20%5B%7B%22CODESET%22%3A%2011%2C%22CODE%22%3A%201%2C%22ACTION%22%3A%22KEYPRESS%22%7D%5D%7D HTTP/1.1
Accept: /
User-Agent: Linux UPnP/1.0 SmartThings
AUTH: blahblahblah
HOST: 192.168.0.113:55001


#12

Wow, thanks so much for putting the time aside to do this however long it may have taken. It’s much appreciated.

And I’m also in the US (Southern California)…but yeah…I don’t know what’s going on with the IDE.

I will give this code a shot to see what I can do with it. I’ll let you know how it goes.


(Dayne Putnam) #13

Hi, I found this to be a great help, but the commands do not work for me,

here is my log for an On and off event

1ab8a3a1-2e13-4faa-a592-a8a0e232948a  10:16:42 PM: info VizioTV: On/Off state is on.
1ab8a3a1-2e13-4faa-a592-a8a0e232948a  10:16:41 PM: debug PUT /key_command/%7B%22KEYLIST%22%3A%20%5B%7B%22CODESET%22%3A%2011%2C%22CODE%22%3A%201%2C%22ACTION%22%3A%22KEYPRESS%22%7D%5D%7D HTTP/1.1 
Accept: */* 
User-Agent: Linux UPnP/1.0 SmartThings 
AUTH: blah
HOST: 192.168.1.244:9000 

1ab8a3a1-2e13-4faa-a592-a8a0e232948a  10:16:24 PM: info VizioTV: On/Off state is off.
1ab8a3a1-2e13-4faa-a592-a8a0e232948a  10:16:23 PM: debug PUT /key_command/%7B%22KEYLIST%22%3A%20%5B%7B%22CODESET%22%3A%2011%2C%22CODE%22%3A%200%2C%22ACTION%22%3A%22KEYPRESS%22%7D%5D%7D HTTP/1.1 
Accept: */* 
User-Agent: Linux UPnP/1.0 SmartThings 
AUTH: blah
HOST: 192.168.1.244:9000

#14

@Gutheinz Just wanted to say thank you for this code example – I used it as a template to build something similar but different (temperature sensor whose response is available via a web server) and found the code and especially the comments very helpful in understanding how the system works.


#15

Bumping this thread…

I just purchased a Vizio Smartcast TV and am looking to integrate it into Smartthings. Has anyone had any success getting it working?