Tile state changing with no response in parse

I’ve managed to go through the api on my own and get a handler working with a raspberry pi.

Now I’m stuck on one problem. In the parse I update the state of the tile. The problem is even if I turn off the raspberry to test, when I click the tile button it still updates to the “On” state in the app.

What should happen is that the button does not turn to “On” since the raspberry is offline.
What am I missing here? I’m trying to track something down in other handlers or the api but have not come across the needle in the haystack.

/**
 *  Raspberry Pi
 *
 *  Copyright 2014 Nicholas Wilde
 *
 *  Monitor your Raspberry Pi using SmartThings and WebIOPi <https://code.google.com/p/webiopi/>
 *
 *  Companion WebIOPi python script can be found here:
 *  <https://github.com/nicholaswilde/smartthings/blob/master/device-types/raspberry-pi/raspberrypi.py>
 *
 *  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.
 *
 */
 
import groovy.json.JsonSlurper

preferences {
        input("ip", "string", title:"IP Address", description: "192.168.1.150", required: true, displayDuringSetup: true)
        input("port", "string", title:"Port", description: "8000", defaultValue: 8000 , required: true, displayDuringSetup: true)
}

metadata {
	definition (name: "Pool Controller", namespace: "jaswalters", author: "Jason Walters") {
		capability "Polling"
		capability "Refresh"
		capability "Temperature Measurement"
        capability "Switch"
        capability "Sensor"
        capability "Actuator"
        attribute "SuctionValvePos", "enum", ["SpaPos", "PoolPos"]
        attribute "ReturnValvePos", "enum", ["FountainPos", "WaterFallPos"]
        attribute "cpuPercentage", "string"
        attribute "memory", "string"
        attribute "diskUsage", "string"
        attribute "Fountain", "string"
        
        command "restart"
        command "FountainModeOn"
        command "FountainModeOff"
        command "WaterFallMode"
        command "SpaMode"
	}

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

	tiles {
		valueTile("temperature", "device.temperature", width: 1, height: 1) {
            state "temperature", label:'${currentValue}°F CPU', unit: "F",
            backgroundColors:[
                [value: 26, color: "#153591"],
                [value: 52, color: "#1e9cbb"],
                [value: 78, color: "#90d2a7"],
                [value: 104, color: "#44b621"],
                [value: 130, color: "#f1d801"],
                [value: 156, color: "#d04e00"],
                [value: 185, color: "#bc2323"]
            ]
        }
        standardTile("button", "device.switch", width: 1, height: 1, canChangeIcon: true) {
			state "off", label: 'Off', icon: "st.Electronics.electronics18", backgroundColor: "#ffffff", nextState: "on"
			state "on", label: 'On', icon: "st.Electronics.electronics18", backgroundColor: "#79b821", nextState: "off"
		}
        valueTile("cpuPercentage", "device.cpuPercentage", inactiveLabel: false) {
        	state "default", label:'${currentValue}% CPU', unit:"Percentage",
            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("Fountain", "device.Fountain", width: 1, height: 1) {
        	state "off", action:"FountainModeOn", label: '${name}', icon: "st.Outdoor.outdoor13", backgroundColor: "#ffffff", nextState: "on"
            state "turningOn", action:"FountainModeOff", label: '${name}', icon: "st.Outdoor.outdoor13", backgroundColor: "#ffffff", nextState: "turningOff"
            state "turningOff", action:"FountainModeOff", label: '${name}', icon: "st.Outdoor.outdoor13", backgroundColor: "#ffffff", nextState: "turningOn"
			state "on", action:"FountainModeOff", label: '${name}', icon: "st.Outdoor.outdoor13", backgroundColor: "#79b821", nextState: "off"
        }
        valueTile("diskUsage", "device.diskUsage", width: 1, height: 1) {
        	state "default", label:'${currentValue}% Disk', unit:"Percent",
            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("restart", "device.restart", inactiveLabel: false, decoration: "flat") {
        	state "default", action:"restart", label: "Restart", displayName: "Restart"
        }
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
        	state "default", action:"refresh.refresh", icon: "st.secondary.refresh"
        }
        main "button"
        details(["button", "temperature", "cpuPercentage", "Fountain", "diskUsage", "restart", "refresh"])
    }
}

// ------------------------------------------------------------------

// parse events into attributes
def parse(String description) {
    def map = [:]
    def descMap = parseDescriptionAsMap(description)
    log.debug "Parsed"
    def body = new String(descMap["body"].decodeBase64())
    log.debug "body: ${body}"
    def slurper = new JsonSlurper()
    def result = slurper.parseText(body)
	if (result){
    	log.debug "Computer is up"
   		sendEvent(name: "switch", value: "on", isStateChange: true)
    }
    
    
    if (result.containsKey("cpu_temp")) {
        log.debug "cpu_temp: ${result.cpu_temp}"
    	sendEvent(name: "temperature", value: result.cpu_temp)
    }
    
    if (result.containsKey("cpu_perc")) {
        sendEvent(name: "cpuPercentage", value: result.cpu_perc)
    }
    
    if (result.containsKey("mem_avail")) {
    	log.debug "mem_avail: ${result.mem_avail}"
        sendEvent(name: "memory", value: result.mem_avail)
    }
    if (result.containsKey("disk_usage")) {
    	log.debug "disk_usage: ${result.disk_usage}"
        sendEvent(name: "diskUsage", value: result.disk_usage)
    }
    if (result.containsKey("FountainMode")) {
    	log.debug "Parse result Fountain ${result.FountainMode}"
        sendEvent(name: "Fountain", value: result.FountainMode)
        if (result.FountainMode == "On") {
        log.debug "Return Valve has been set"
        	state.ReturnValvePos = "FountainPos"
        } else{
        	state.ReturnValvePos = "WaterFallPos"
        }
    }
}

//commands

def FountainModeOn() {
	log.debug "FountainMethodCalled"
	def uri = "/macros/FountainOn"
    postAction(uri)
}

def FountainModeOff() {
	def uri = "/macros/FountainOff"
    postAction(uri)
}

def WaterFallMode() {

}

def SpaMode() {

}

def poll() {
	log.debug "Executing 'poll'"
    sendEvent(name: "switch", value: "off")
    getRPiData()
    
}

def refresh() 
{
	log.debug "Executing 'refresh'"
    sendEvent(name: "switch", value: "off")
    getRPiData()
    
}
    

def restart(){
	log.debug "Restart was pressed"
    sendEvent(name: "switch", value: "off")
    def uri = "/macros/reboot"
    postAction(uri)
}

// Get CPU percentage reading
private getRPiData() {
	def uri = "/macros/getRPiData"
    postAction(uri)
}

// ------------------------------------------------------------------

private postAction(uri){
  setDeviceNetworkId(ip,port)  
  
  def hubAction = new physicalgraph.device.HubAction(
    method: "POST",
    path: uri
  )//,delayAction(1000), refresh()]
  log.debug("Executing hubAction on " + getHostAddress())
  log.debug hubAction
  return hubAction    
}

// ------------------------------------------------------------------
// Helper methods
// ------------------------------------------------------------------

def parseDescriptionAsMap(description) {
	description.split(",").inject([:]) { map, param ->
		def nameAndValue = param.split(":")
		map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
	}
}

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
}

Remove the “nextstate“ portions of your fountain on/off tile. Hopefully your RPi will fill in that data via the parse routine. Adding nextstate automatically changes the value displayed in the tile.

1 Like

Thank you! that seems to have done it. I was pulling away pieces one by one but did not think that would have that affect. So next state must pull from the platform for it’s update?

I never get the turning on state on the tile. Once it gets a response from the Pi it goes from “On” to “Off” or vice versa. Do you know if the custom state on the tile is possible without the nextstate option?

Never mind, I figured out how to handle it in the response.

I had to use another sendEvent to update the status.

1 Like

The ‘tiles’ section defines the UI for the mobile app. When you use ‘nextstate’ with custom states like ‘turningon’ and ‘turningoff’ you are providing instructions to the UI in the app. The idea is to give you visual feedback that you’ve clicked a button and something is meant to be happening. The actual attributes/states of the device remain unchanged until an event is generated to change them. You don’t see ‘turningon’ and ‘turningoff’ outside the UI in the app.

1 Like