Local POST Request for Device Type Help


(Nicholas Wilde) #1

This post is for @Ben, @tslagle13, @pstuart, @adam, and whomever else can help. I’m trying to create a local LAN device type that is able to send a POST request and receive a response back from it. It took me a while to figure out that my Device Id needed to be my device IP and port encoded as hex and also that the response from the POST method is handled by the parse method.

I’ve created the following code but can’t seem to get it to show up on my LAN device logs. Any help is appreciated.

Method: POST
IP: 192.168.1.150
Port: 8000
Authenticaion: Basic
path: /macros/getCPUTemp

Edit: My ST logs are as follows:
12:03:31 PM:
debug POST /marcos/getCPUTemp HTTP/1.1

Accept: */*
User-Agent: Linux UPnP/1.0 SmartThings
HOST: 192.168.1.150:8000
Authorization: Basic d2ViaW9waTpxXxxxxxxxxX=

/**
 *  LAN Temperature Device
 *
 *  Copyright 2014 Nicholas Wilde
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
 
preferences {
        input("ip", "string", title:"IP Address", description: "IP Address", required: true, displayDuringSetup: true)
        input("port", "string", title:"Port", description: "Port", defaultValue: 8000 , required: true, displayDuringSetup: true)
        input("username", "string", title:"Username", description: "Username", required: true, displayDuringSetup: true)
        input("password", "password", title:"Password", description: "Password", required: true, displayDuringSetup: true)
}

metadata {
    definition (name: "Computer", namespace: "nicholaswilde/smartthings", author: "Nicholas Wilde") {
        capability "Polling"
        capability "Refresh"
        capability "Temperature Measurement"
    }

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

    tiles {
        valueTile("temperature", "device.temperature", width: 2, height: 2) {
            state "temperature", label:'${currentValue}°', unit: "F",
            backgroundColors:[
                    [value: 31, color: "#153591"],
                    [value: 44, color: "#1e9cbb"],
                    [value: 59, color: "#90d2a7"],
                    [value: 74, color: "#44b621"],
                    [value: 84, color: "#f1d801"],
                    [value: 95, color: "#d04e00"],
                    [value: 96, color: "#bc2323"]
                ]
        }
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
            state "default", action:"refresh.refresh", icon: "st.secondary.refresh"
        }
        main "temperature"
        details(["temperature", "refresh"])
    }
}

// parse events into attributes
def parse(String description) {
    log.debug "Parsing '${description}'"
    def map = [:]
    def retResult = []
    def descMap = parseDescriptionAsMap(description)
    log.debug "parse returns $descMap"
}

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

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

// Get the sensor reading
private getReading() {
  setDeviceNetworkId(ip,port)
  
  log.debug("Executing hubAction on " + getHostAddress())
  
  def userpassascii = "${username}:${password}"
  def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
  
  def uri = "/marcos/getCPUTemp"
  def headers = [:]
  headers.put("HOST", getHostAddress())
  headers.put("Authorization", userpass)
  log.debug "Headers are ${headers}"
  
  def hubAction = new physicalgraph.device.HubAction(
    method: "POST",
    path: uri,
    headers: headers
  )
  log.debug hubAction
  hubAction    
}



//helper methods

private getHeader(){

}

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
}

Reference threads:



(swanny) #2

Are you able to verify if the POST is being received to know if it is the sending or response that is the issue?


(Nicholas Wilde) #3

My server logs don’t show any sign of receiving the POST request from ST. However, the logs do show the requests when using a REST client.


(Nicholas Wilde) #4

Okay, I just solved my problem. I didn’t have my hub chosen in my device list.

For future reference, when creating your device from the IDE, make sure the device ID is base64 hex encoded (e.g. c0a80196:1f40) and that a hub is specified in the device list.

I also had a typo for the uri which should be /macros/getCPUTemp instead of /marcos/getCPUTemp


(swanny) #5

Cool. I had the same hub issue myself before. Totally forgot about it until now. :smile:


(Patrick Stuart [@pstuart]) #6

Its not base64 its hex


(Nicholas Wilde) #7

Bah, I got confused with the Authorization header. Thanks.


(Patrick Stuart [@pstuart]) #8

No problems, just spent way too much time figuring out DNI’s and hex converting (properly) IP addresses… Base64 would have been so much easier, but not practical…

Can’t wait for IPv6…