SmartThings Community

Custom DTH HTML POST Commands with Basic Login


(SimonS) #1

Hello,
I packet captured a device’s original app and it’s making basic POST commands with basic authorization. I can fully emulate that in Tasker and WebCore for example. Here is what it looks like in WebCore:

Not parsing the response yet but I am grabbing that in Tasker.

I want to create a DTH so I can keep it’s state (and eventually syncing it every minute). So far, I am not able to sent a single successful POST command and spent like 8+ hours reading about it. Can anyone spot what my problem is? Trying to do a simple on/off switch for now. With Tasker, I could login via http://admin:pass@192.168.1.93 but learned that WebCore does not work with this method. So in DTH I tried both methods with no success.

> metadata {
>   definition (name: "Test", namespace: "SS", author: "SS") {
>     capability "Switch"
> 
>     command "sendremotecommand"
> }
> 
> simulator {
>   status "on": "on/off: 1"
>   status "off": "on/off: 0"
> }
> 
> tiles(scale:2) {
>   standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
>     state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
>     state "on", label: 'ON', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
>   }
> 
>    main "switch"
>    details(["switch"])
>  }
> 
>    preferences {
>    
>   }
>  }
> 
>  def on() {
>  log.debug "Executing 'on'"
> 	def source = new physicalgraph.device.HubAction(
>             method: "POST",
>             path: "/OutletSubmit.cgi",
>             body: ("outlet=4&command=REBOOT&OutletDelay=3"),
>             headers: [
>         HOST:       "http://192.168.1.93:80",
>         Accept:     "text/*",
>         "Content-Type": 'text/*',
>          Connection: 'keep-alive',
>          Authorization: ("Basic YWRtaW46YWRtaW4="),
>     
>     ],   	
>     )
>     
>    //log.trace()
>     log.debug result.toString()
>     sendHubCommand(source);
> }
> 
>  def off() {
>  log.debug "Executing 'off'"
> 	def source = new physicalgraph.device.HubAction(
>             method: "POST",
>             path: "/OutletSubmit.cgi",
>             body: ("outlet=4&command=OFF&OutletDelay=3"),
>             headers: [Host:"http://admin:admin@192.168.1.93"]
>     )
>     log.debug result.toString()
>     sendHubCommand(source);
>     }

Created a virtual switch but it never flips to ON and logs return:
image


(Tony Fleisher) #2

do you mean the physical device doesn’t go on, or that the dth doesn’t change the device is ST to on state?


(SimonS) #3

Both actually. But I was referring that the virtual switch in the ST app doesn’t turn blue.


(Tony Fleisher) #4

the device state in ST is event driven, so you need to send an event (usually from the parse method) to change the device state. sending a command is an intent to change, but not itself a indication of state change.


(SimonS) #5

Ok. In this case I just need to figure out the HTTP POST for now. Since I am seeing “Execute On” in debugger it is hitting that function when I press the switch button.

Did I mention I am a newbie? I hated programming in school and now my limits are Tasker and WebCore.

If anyone have a tip for the HTTP post command - please share. I will have to read more ST IDE 101 to finish the DTH.


#6

You aren’t going to see a result as you have pulled the variable ‘result’ out of the sky and then printed it before you’ve even sent the POST command. The virtual switch will never change state as you haven’t instructed it to.

https://docs.smartthings.com/en/latest/cloud-and-lan-connected-device-types-developers-guide/building-lan-connected-device-types/building-the-device-type.html is admittedly vague but gives you a rough guide once you realise what it is telling you.

The basic idea is you create a physicalgraph.device.HubAction with the details of your HTTP request, and then submit it using sendHubCommand().

You have basically done that though if you compare it to the ‘UPnP/SOAP requests’ example code you won’t notice the sendHubCommand() being used explicitly because in the example the command method returns a HubAction object and the system takes care of submitting it. That’s a feature of command methods. No harm in doing it yourself though.

Any HubAction response comes to the parse() method but there is a ‘gotcha’ as SmartThings has to know to send it there. It does this by comparing the Mac Address of the actual hardware device (folded to upper case without any punctuation), or failing that the IP address and port in a funny hex pair format, to the device network ID of your device.

In the ‘Getting the addresses’ section of the document linked to previously, what they haven’t told you is that the device network ID is using the hex IP address and port format and they are processing it into something recognisable. So C0A8000D:0050 would translate to 192.168.0.10:80.

You need to do a sendEvent(name: 'switch', value: 'on') or sendEvent(name: 'switch', value: 'off') to actually set the state of your virtual switch. If you trust the HubAction to work you can do that in the on() or off() commands. If you want to reflect the actual state of your device you do it in the parse() command once you’ve checked what is going on.

None of that touches on the format of the HTTP command you actually need to send. That makes my head explode at the best of times so I’ll defer to others on that one.


(SimonS) #7

Thanks. This basically tells me I am not ready for this. I will stick with virtual devices that trigger WebCore pistons till I have time to read more.


#8

There is certainly a bit of a learning curve. Personally I find the documentation doesn’t always tell you everything you need to know, or if it does it probably isn’t all in one place. Between the documentation, the archives of this community, reading other people’s existing code, and trial and error, I have found I can often piece things together.