Hubaction not working with setLevel

Hi,

I have a device with switch and switchlevel capabilities.
On/Off and Level commands work fine but setLevel does not work.
There are right() and left() commands on the device.
If the level set is higher the current level it should run the right() command, if lower than the current level it should run the left() command.

And according to the logs , it runs these commands. But the server does not receive the commands. So I guess hubaction is not triggered.
What is wrong in my code ?

Btw, if I hit the "right" or "left" buttons on Hubitat UI, these commands run fine and the server receives the command.


metadata {
	definition (name: "Coffee Cup Mover", namespace: "ilkeraktuna", author: "ilkeraktuna") {
		capability "Switch"
        capability "SwitchLevel"
        command "on"
        command "off"
        command "right"
        command "left"
	}
    preferences {
		section {
			input title: "", description: "Coffee Cup Mover", displayDuringSetup: true, type: "paragraph", element: "paragraph"
			input("ip", "string", title:"LAN IP address", description: "LAN IP address", required: true, displayDuringSetup: true)
			input "username", "string", title: "Username", required: true
			input "password", "password", title: "Password", required: true
        }
    }
	
	tiles(scale: 2) {
        standardTile("switch", "device.switch", width: 6, height: 6, canChangeIcon: true) {
    		state "off", label: 'Offline', icon: "st.Electronics.electronics18", backgroundColor: "#ff0000"
    		state "on", label: 'Online', icon: "st.Electronics.electronics18", backgroundColor: "#79b821"
		}
    	main("switch")
        details(["switch"])
    }
    
}

def off() {
    if(debugEnable)log.debug "turning off"
    sendEvent(name: "switch", value: "off");
    def userpass
  
  if(password != null && password != "") 
    userpass = encodeCredentials(username, password)
    
  def headers = getHeader(userpass)

  def hubAction = new hubitat.device.HubAction(
    method: "GET",
    path: "/disabledrv",
    headers: headers,
    body: "\r\n\r\n"
  )
  return hubAction 
}

def on() {
    if(debugEnable)log.debug "turning on"
    sendEvent(name: "switch", value: "on");
	def userpass
  
  if(password != null && password != "") 
    userpass = encodeCredentials(username, password)
    
  def headers = getHeader(userpass)
    
  def hubAction = new hubitat.device.HubAction(
    method: "GET",
    path: "/enabledrv",
    headers: headers,
    body: "\r\n\r\n"
  )
  return hubAction    
}

def right() {
    log.debug "Right x"
	def userpass
  
  if(password != null && password != "") 
    userpass = encodeCredentials(username, password)
    
  def headers = getHeader(userpass)
    
  def hubAction = new hubitat.device.HubAction(
    method: "GET",
    path: "/right",
    headers: headers,
    body: "\r\n\r\n"
  )
  return hubAction    
}

def left() {
    log.debug "Left x"
	def userpass
  
  if(password != null && password != "") 
    userpass = encodeCredentials(username, password)
    
  def headers = getHeader(userpass)
    
  def hubAction = new hubitat.device.HubAction(
    method: "GET",
    path: "/left",
    headers: headers,
    body: "\r\n\r\n"
  )
  return hubAction    
}

def setLevel(level){
    def lastLevel = device.currentValue("level")
    if(level > lastLevel) {
        right()
        log.debug "Right"
    }
    if(level < lastLevel) {
        left()
        log.debug "Left"
    }
    log.debug "Level '${lastLevel}'"
    sendEvent(name: "level", value: level)
}


private encodeCredentials(username, password){
	def userpassascii = "${username}:${password}"
    def userpass = "Basic " + userpassascii.bytes.encodeBase64().toString()
    return userpass
}

private getHeader(userpass = null){
    def headers = [:]
    headers.put("Host", ip)
    headers.put("Content-Type", "application/x-www-form-urlencoded")
    if (userpass != null)
       headers.put("Authorization", userpass)
    return headers
}

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
}

def parse(String description) {
    log.debug "Parsing '${description}'"
}

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

def installed() {
    initialize()
}

def updated() {
    initialize()
}

def poll(){
    refresh()
}

def initialize() {
    unschedule()
}

def refresh() {
    def host = ip
}

def setUp(str1) {
    device.updateSetting("ip",[value:"$str1",type:"string"])
}

A HubAction is not sent unless it is the return value of a method that corresponds to a command. This is the case for your methods like left() and right() because you are explicitly returning this object. You can see that in your setLevel() method, you are doing no such thing.

One solution is to save the return value from calling right() or left(), then return that. For example:

def setLevel(level){
    // ...
    def returnVal // new!
    if(level > lastLevel) {
        returnVal = right() // change to this
       // ...
   // ...
return returnVal // new!
}

Alternatively, you can work around this by "manually" sending the HubAction yourself, e.g., replacing your calls to right() and left() with sendHubCommand(right()) and sendHubCommand(left()).

Also, you do not need tiles() { ... } in a Hubitat driver. It does not do anything, and it is likely leftover from a copy/pate of a classic SmartThings DTH.

1 Like

thanks. it works as you suggested.

1 Like

I have another problem now. This is not directly related to the topic but sort of related...

The remote side is an esp8266 nodemcu module.
It responds with a basic html page and when I call that endpoint from a browser , I can get the html output fine.
But on the Hubitat logs , it gives a "Connection reset" warning.

this is the code from webserver (Arduino)


              client.println("HTTP/1.1 200 OK");
              client.println("Content-type:text/html");
              //client.println("Connection: close");
              client.println();

              // Display the HTML web page
              client.println("<!DOCTYPE html><html>");
              client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
              client.println("<link rel=\"icon\" href=\"data:,\"></head>");
              
              client.println("<body><h1>Coffee Cup Web Server</h1>"); 
              client.println("</body></html>");

why do I get a "connection reset" ?

Not sure about that one. Maybe someone who's worked with something similar might have some ideas. They would probably want to see what you're doing on the Hubitat side, too.

hubitat code is already on the OP.

btw, I also have aparse function on the driver code. But nothing is written to the log:

def parse(String description) {
    log.debug "Parsing '${description}'"
}

it means it does not receive anything ?

You might want to try one of the built-in HTTP methods rather than building a HubAction yourself. Not sure that it will make a difference, but at least they're are generally easier to use. There are both synchronous and asynchronous methods available, documented here: Common Methods | Hubitat Documentation

You only need parse() if the driver is receiving "unsolicited" data, sent from the device directly to the hub. For HTTP GETs, your callback or returned object will handle the data.

So you mean "use httpGet instead of hubAction" ?
I remember once trying httpGet and I was not successful.
The documentation does not have examples in it and I can hardly understand how groovy works.
So I go with the hubaction command because I have several working examples already.

If I could find example httpGet with basic authorization headers, I would try that.

You can probably find more examples by searching the forum, but here some async examples (which I'd suggest using unless you truly need the other version):

1 Like

Use the asynchttpGet and process the response. Might look at: https://raw.githubusercontent.com/thebearmay/hubitat/main/airthings/airThingsCntrl.groovy

2 Likes

thanks. using asynchttpget it works.
But I really don't understand why I get "connection reset" when using hubaction.

I'd appreciate if anyone who has an idea can write it.

method which works without "connection reset":

def off() {
    httpSend("disabledrv")
    sendEvent(name: "switch", value: "off");
}
def httpSend(command) {
    
    if(password != null && password != "") 
        userpass = encodeCredentials(username, password)
    def headers = [:]
    headers.put("Host", ip)
    headers.put("Content-Type", "application/x-www-form-urlencoded")
    
    if (userpass != null)
       headers.put("Authorization", userpass)
    def Params = [
		uri: "http://192.168.254.201/"+command,
		requestContentType: 'text/html',
		contentType: 'application/x-www-form-urlencoded',
		headers: headers
	]
    
	asynchttpGet('myCallbackMethod', Params, null)
}

def myCallbackMethod(response, data) {
    log.debug "status of post call is: ${response.status}"
}

method which works but produces "connection reset" :

def off() {
    if(debugEnable)log.debug "turning off"
    sendEvent(name: "switch", value: "off");
    def userpass
  
  if(password != null && password != "") 
    userpass = encodeCredentials(username, password)
    
  def headers = getHeader(userpass)
    
  def hubAction = new hubitat.device.HubAction(
    method: "GET",
    path: "/disabledrv",
    headers: headers,
    body: "\r\n\r\n"
  )
  return hubAction 
}

Been I while since I played with the hubAction but it may be because you need to close the connection explicitly after you get the response.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.