controlTile and valueTile usage

I’m new to both SmartThings and Arduino and as a starting point to learn/practice I wanted to write a pet feeder Device Type with options to vary the portions amount via a slider and a value tile that shows the portions amount. I am able to get a standardTile to fire off my servo but now I’m a little confused as to how to pass values from the controltileTile/slider and how to update the valueTile (I read the documentation but I’m not that clear as to how to use these tiles)
Question#1: a slider is predefined from 0 to 100. Is there a way to limit it to 0 to 3 (for example - as in: slide the portion amount you want the feeder to release)? For now I’m handling it by defining 0 to 33 as 1 portion, 33-66 2 portions and 66+ three portions, and handle the amounts in the Arduino code.

Next question: when I run my code in the the simulator I have a setLevel Switch Level command where if I enter a value and click the setLevel button it gets correctly sent to my device. In the mobile app, though, I have the slider but I don’t know how to get it to fire the ‘setLevel’ command. So basically I can slide the slider but nothing gets sent to my device. How do I get to fire the setLevel command from my mobile app as well?

Third question: How to I update the valueTile with the portion amount?

Below is the code I’m using with bits and pieces taken from various examples around the web. Again, I’m trying to learn so a) please be nice :smile: and b) any suggestion on how should I go about doing this is greatly appreciated.
Thanks!

metadata {
// Automatically generated. Make future change here.
definition (name: “myFeeder”, namespace: “rt”, author: “rt”) {
capability "Actuator"
capability "Switch"
capability "Sensor"
capability “Switch Level”

}

// Simulator metadata
simulator {
	status "on":  "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E"
	status "off": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666"

	// reply messages
	reply "raw 0x0 { 00 00 0a 0a 6f 6e }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E"
	reply "raw 0x0 { 00 00 0a 0a 6f 66 66 }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666"
}

// UI tile definitions
tiles {
	standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
		state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
		state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
	}
	controlTile("level", "device.level", "slider", width: 2, height: 1, canChangeIcon: false, canChangeBackground: false) {
		state "level", action: "setLevel"
    }
    valueTile("portions", "device.level", width: 1, height: 1) {
		state "level", label:'${currentValue}'
	}
        
	main "switch"
	details "switch", "level", "portions"
}

}

// Parse incoming device messages to generate events
def parse(String description) {

def value = zigbee.parse(description)?.text
if (value == "ping" || value == " ") 
{
	return
}
def name = value in ["on","off"] ? "switch" : null
def result = createEvent(name: name, value: value, isStateChange: true)
log.debug "Parse returned ${result?.descriptionText}"
return result

}

// Commands sent to the device
def on() {
zigbee.smartShield(text: “on”).format()
}

def off() {
zigbee.smartShield(text: “off”).format()
}

def setLevel(to)
{
zigbee.smartShield(text: ‘portion:’ + to.round()).format()
}

I don’t think slider is the best UI for increments. Take a look at some of the thermostat device types and their respective UI designs. You could have up and down arrows flanking a numerical display. This would let you know exactly how many portions you had set. That exact number would also be accessible via api and would be easier to work with on the arduino.

Good point. I’ll look into them. Thanks!

Take a look at this snippet I converted from a thermostat button. I have changed all of the labels to portion for this example. Note the “action” is calling a method named “setPortion” this is how the button triggers an event.

 standardTile("portionLevelUp", "device.portionSetPoint", canChangeIcon: false, inactiveLabel: false) {
                        state "portionLevelUp", label:'  ', action:"setPortion", icon:"st.thermostat.thermostat-up"
        }

Good advice from @jody.albritton about using the Thermostat up/down UI rather than a slider, but I thought I’d chime in to try and help you understand what may have been causing issues in your current code.

Try action:“switch level.setLevel” in your slider tile parameters instead of just setLevel as the action. I think because you are using Switch Level capability, you need to use the full action name.

For both the valueTile update and for the slider to update, you need to create/send events to update variables. Below is a link to the code for a custom devicetype for the Lightify bulb. This includes a new slider for color temp and 2 new valuetiles. Notice the sendEvent() lines within the setColorTemp() command. Each of those sendEvent() lines updates one of the valueTiles and the slider.

Hopefully this helps you make some changes!

HA! Thanks @Sticks18! Looking at your example I was able to fix my code and everything works… in simulator. I mean, if I move the slider in the simulator I see the valueTile update and I see the value being received by the Arduino device (I’m testing with the actual device, not the virtual one).
But if I move the slider in the mobile app the app crashes and in the debug log I get this:

error groovy.lang.MissingMethodException: No signature of method: java.lang.Integer.round() is applicable for argument types: () values: [] 
Possible solutions: find(), find(groovy.lang.Closure), and(java.lang.Number), mod(java.lang.Number), minus(java.lang.Number), minus(java.lang.Character) @ line 65

and Line 65 is

zigbee.smartShield(text: 'portion:' + to.round()).format()

If I remove the ‘round()’ everything works in the mobile app AND simulator as expected.
So first of all thank you for the explanation I think I understand things a little better now. I’ll try to implement @jody.albritton suggestion.
However if you have any idea why I get the error running the app on my phone and not from the simulator that would help in the future I’m sure.
Thanks!

Make sure you are not trying to round a null value.

It doesn’t look like it’s null since I see the value come in the Arduino serial monitor correctly if I use the simulator. Also if I remove round() it works.
What it looks like it’s happening is that in the simulator a slider returns a double – in fact I see for example ‘54.0’ being passed – while the mobile app returns (I guess) an int – I get ‘54’ passed to the monitor.
My mobile app is the Windows Phone one, I don’t know if that makes any difference…