Can’t get iOS app to show the tiles for my device handler

After slogging through the learning curve to get a working handler, I’m stuck on the UI/tile layout for my device in the iOS app.

Basically, the device is a multi-channel that supports four binary switches. The relevant part of the code is:

tiles(scale:2) {
  standardTile(“switch1”, “device.switch1”,canChangeIcon: true, width: 1, height: 1) {
    state “on”, label: “switch1”, action: “off1”, icon: “st.switches.switch.on”, backgroundColor: “#79b821”
    state “off”, label: “switch1”, action: “on1”, icon: “”, backgroundColor: “#ffffff”
  standardTile(“switch2”, “device.switch2”,canChangeIcon: true, width: 1, height: 1) {
    state “on”, label: “switch2”, action: “off2”, icon: “st.switches.switch.on”, backgroundColor: “#79b821”
    state “off”, label: “switch2”, action: “on2”, icon: “”, backgroundColor: “#ffffff”
  standardTile(“switch3”, “device.switch3”,canChangeIcon: true, width: 1, height: 1) {
    state “on”, label: “switch3”, action: “off3”, icon: “st.switches.switch.on”, backgroundColor: “#79b821”
    state “off”, label: “switch3”, action: “on3”, icon: “”, backgroundColor: “#ffffff”
  standardTile(“switch4”, “device.switch4”,canChangeIcon: true, width: 1, height: 1) {
    state “on”, label: “switch4”, action: “off4”, icon: “st.switches.switch.on”, backgroundColor: “#79b821”
    state “off”, label: “switch4”, action: “on4”, icon: “”, backgroundColor: “#ffffff”
  // Set switch1 to be the one we see in the Things view

At the very least, this displays the four switches in the simulator (and they work… triggering the device and also properly representing the actual state of the switches):

But, when I look at it in the iOS app, I get these “broken cloud” icons (the dimmer section is left over from when I temporarily changed the handler to a dimmer-capable third-party handler so that I could see how their code differed):

Any suggestions?

The tiles() method defined the UI used by the now obsolete Classic apps. It is not used by the current mobile apps. You would also appear to be using custom attributes to implement the switches. Those will only work with legacy apps that are aware of them.

While you could implement the switches with custom capabilities, the typical approach to the sort of device you seem to be creating is to build a composite device with multiple component child devices, each with the Switch capability, and to create a device config via the CLI to create a useful UI.

That assumes you are creating a hub connected device - something controlled via the hub using Zigbee, Z-Wave or directly over the LAN. If you aren’t then you are probably best served by one of the other types of integrations.

I am aware that those last two paragraphs would benefit from some links but I’m not on the best device to add any.

(Ok… this is going to get a bit ranty for a sec… but it’s not about you, it’s about Smartthings…)
This is so infuriating and dispiriting… all of 2020 I’ve been googling to try to figure out how to make a working device-handler, and the top hits all point to One would suppose this would contain the latest API info (as we see with Rust, Java, Node.js, Idris, etc). So, after a year of trying to make sense of the oddly-written documentation, I find out that Samsung hasn’t just added another API (that part I knew), but the old way has been deliberately made to not work.

Hey Samsung:

  • Why is “” pointing to obsolete documentation? “docs” and “latest” are in the URL. WTF?
  • Why is there only a header at the top of those docs inviting readers to learn about a new developer portal (suggesting that there is now an additional way to develop for ST) instead of a pop-up alerting users that the stuff they’re reading there won’t work, anymore?
  • Why does the IDE still let you do things the old way (i.e. why doesn’t the syntax-highlighting, at least, flag when you try to use “tile(…)”)?

Ok… so with that out of the way… a few follow-up questions and clarifications:

Yes, it’s a hub-connected device (Z-wave, in this case).

The custom attributes were so that I could reference them via a string. That way, when a z-wave multi-channel report came in, the same bit of code could update the state of whichever switch it came from:

def name = "switch$cmd.sourceEndPoint"
def value = (cmd.parameter == [0])?"off":"on"
return createEvent(name: name, value: value)

The examples I had seen seemed to access the properties/attributes via hard-coded lvalues (made possible through a well-meaning-but-insane attempt at syntactic sugar) like "device.switch.status = ‘on’ " or something like that, but I didn’t want to make something ugly like:

def value = (cmd.parameter == [0])?"off":"on"
if ($cmd.sourceEndPoint == 1) {
  device.switch1.status = value;
} else if ($cmd.sourceEndPoint == 2) {
  device.switch2.status = value;
} else if ($cmd.sourceEndPoint == 3) {
  device.switch3.status = value;
} else if ($cmd.sourceEndPoint == 4) {
  device.switch4.status = value;
} else {
  // Error

OK… makes sense. So, where’s some documentation about that this is not at, since those docs seem to describe the old doesn’t-work-anymore way?

Again… fair enough, but where is some documentation on this that is reliably current?

Last question: If the tiles() method is no longer supported, how are the 3rd-party DTH’s (downloaded from github, etc for things like Xiaomi, Aeotec, HomeSeer, etc) which worked in the Classic app still working in the new one? Did the new iOS app do some kind of one-time conversion of them from the Classic app?

It is simply that the app has been told how to present many / most of the standard capabilities in a useful fashion. Take something like the ‘Switch’ capability. For the Classic app you define a tile to display the value of the ‘switch’ attribute and then say how to display the ‘on’ and ‘off’ values, and then to call the ‘on()’ and ‘off()’ methods to change states. The ‘new’ app already knows all that and that it would be useful to display it as a push button.

If the DTHs defined tiles to work with custom attributes or custom commands then that functionality was lost from the UI.