Writing Custom Device Handler for Leviosa Shades

Background:
I have recently installed Leviosa Shades. It does work in the new ST app but not in the Classic app.
I noticed that Leviosa creates a device for each shade group but they don’t have a device type. ie. “placeholder”. After playing around with those devices and trying different device handlers, I realized that some other shades like Springs will actually work meaning if I change the Leviosa shades to that device type, I’m able to open/close the shades via the classic app. (by tapping on the tile icon).
However, unfortunately, the routines/automations doesn’t work (e.g. I cannot open the shades automatically at sunrise).
After some research and debugging I realized the automation routines calls a method called setLevel() and this is why it doesn’t work because Leviosa shades (and many others) do not support that.
Therefore, I decided to create my own DH and implement setLevel too.

Ok, here’s the actual question:
In the classic app, when we tap on a tile, apparently SmartThings sends an action command to the device (i.e “open”/“close”) and then calls the corresponding method in the DH. All I want to do is doing the same in the setLevel method. Directly calling open() or close() doesn’t work as it doesn’t actually send the command to the device itself. All I know is that ST sends an “open” or “close” action and that must be generic because I didn’t do any coding for it.

Does anyone know how to accomplish that?

Here’s the DH code that can open/close the shade:

metadata {
	definition (name: "sk-generic-window-shade", namespace: "sk", author: "sk", cstHandler: true) {
		capability "Window Shade"
	}

	simulator {
	}

	tiles {
        standardTile("switchmain", "device.windowShade") { 
            state "open", label:'${name}', action:"close", icon:"st.shades.shade-open", backgroundColor:"#79b821", nextState:"closing"
            state "closed", label:'${name}', action:"open", icon:"st.shades.shade-closed", backgroundColor:"#ffffff", nextState:"opening"
            state "partially open", label:'Open', action:"close", icon:"st.shades.shade-open", backgroundColor:"#79b821", nextState:"closing"
            state "opening", label:'${name}', action:"stop", icon:"st.shades.shade-opening", backgroundColor:"#79b821"
            state "closing", label:'${name}', action:"stop", icon:"st.shades.shade-closing", backgroundColor:"#ffffff"
        }
        main(["switchmain"])
	}
}

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

// handle commands
def open() {
	log.debug ">>> Executing 'open'"
}

def close() {
	log.debug ">>> Executing 'close'"
}

def pause() {
	log.debug ">>> Executing 'pause'"
}

def setLevel(level) {
	//send "open" or "close" commands to the device based on the given level 

	//direct calling close() or open() doesn't work
}

P.S. I’m a software engineer and been using ST since 2014 but I’m new to writing device handlers.

The ‘Window Shade’ capability has the documented commands ‘open’, ‘close’ and ‘presetPosition’. ‘setLevel’ is from the ‘Switch Level’ capability and really intended for setting the levels on lights and dimmer switches. It sounds like some fudging may have been going on in the past, perhaps to implement a window shade like a dimmer.

Hmm. I would describe the ‘Classic’ environment as working more like this:

The ‘action’ IS the command method in the DH. Let’s say the current state of your device’s ‘windowShade’ attribute is ‘closed’. The DH will probably have ‘action: open’ associated with this. So when you click on the tile the ‘open()’ method from the DH will be run and this method will do whatever is necessary to instruct the window shade to open.

This is not really any different to an automation telling the window shade to ‘open’. The result is the same, in that the ‘open()’ method in the DH should run. It just so happens that the Classic app is a bit more plumbed in to the internals than you might expect, something that is perhaps less true of the ‘new’ app. Does the UI definition for a mobile app really belong in the device handler? But I digress …

Depending on the nature of the device the ‘open{}’ command method might ask the hub to send a Zigbee or Z-Wave command, ask the hub to do something with local TCP/IP, make something happen with cloud services, shift the job up to a parent SmartApp, or do something else that doesn’t immediately come to mind. The bottom line is the ‘open()’ method starts things happening.

Once the window shade is opened it will communicate back to SmartThings (be it the hub or the cloud) that it is open and this information should eventually appear as an argument to the ‘parse()’ method of the DH. The DH will then see what has happened and create an event to say that its ‘windowShade’ attribute should now be ‘open’.

Where there is a SmartApp involved, the demarcation between the roles of the SmartApp and the Device Handler might be more fluid.

Thanks for the reply.
The DH I shared is the actual one I use with the device. While tapping on the tile works, calling ‘open()’ or ‘close()’ within the DH doesn’t do anything. I can see the log messages and pretty sure that open/close method are being called (when I want to test) but they don’t actually open/close the shade.

FWIW, it’s a Network/Lan integrations. No zigbee or zwave. I’m quite sure that the app does something else behind the scene. Another thing is that, I don’t see log messages when I tap on the tile. So it works but nothing is logged. I know it’s got something to do with the metadata because with wrong capabilities or wrong actions nothing work.

Yes, I think what you are seeing is two worlds colliding. I’m not really familiar with the ‘new’ environment but I am guessing that the ‘classic’ structure I described is likely to only apply, if it does at all, to hub connected devices and that for cloud based integrations the device handler is little more than a profile and the command and event handling is in SmartApps or so standardised that it can be implemented in the system itself. So e.g. the DH tells the Classic app enough that it knows to request to run the device’s ‘open’ command but that is actually somewhere else now, which is pretty much what you said in the first place.

In other words I’m more of a hindrance than a help. Hopefully I may be inspired to learn more and someone will offer insight.

What you are saying makes sense and there is an SmartApp for Leviosa. So, behind the scene it must be calling the open (or something) on the smartApp.

The question is how we can do the same thing in the DH.

It shoud be posible to exceute predefined commands from the DH.
Maybe something like device.open() (which of course doesn’t work)

Anyone has any ideas?