Send ZWave command from an app to a device

I have been trying to figure out how to send a ZWave command to a device from within an App. Lets assume I have the DNI or Node number or whatever is needed. So far the public apps I have seen use standard methods to call on the device driver, such as setLevel, On, Off, etc....

But one stock App, the ZWave "Device Firmware Updater", seems to somehow be sending commands right to the device and catching the replies back. I am very curious as to how this is done, as something I want to work on would need to make use of this. Going to keep digging in other apps to see if I can find an example, any help would be appreciated.

EDIT: May have just found something in the docs building a HubAction with a specific dni. Still if anyone knows of an app that uses this I would be interested to see real examples. I will follow up if/when I get this working. HubAction Object - Hubitat Documentation

To my absolute shock, this worked for me. I was only expecting this to work from a driver, as it was my assumption that you would need information like the node ID that the hub handles for you, but it turns out that the method signature you find that lets you specify it does indeed work. I wrote this little app to test setting the selected dimmer to 1%, and it works:

definition(
    name: "Test App (With Button)",
    namespace: "RMoRobert",
    author: "Robert Morris",
    description: "Minimal test app",
    category: "Convenience",
    iconUrl: "",
    iconX2Url: "",
    iconX3Url: ""
)

preferences {
    page name: "pageMainPage"
}

def pageMainPage() {
    dynamicPage(name: "pageMainPage", install: true, uninstall: true) {  
        section("Test App") {
             input name: "dev1",  type: "capability.switchLevel", title: "Select device:", submitOnChange: true
             input name: "btn1", type: "button", title: "Push Me!"
        }
    }
}

void appButtonHandler(String btn) {
    switch (btn) {
        case "btn1":
            Short targetLevel = 0x01
            hubitat.zwave.Command cmd = new hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelSet(value: targetLevel)
            hubitat.device.HubAction hubAction = new hubitat.device.HubAction(cmd.format(), hubitat.device.Protocol.ZWAVE, dev1.deviceNetworkId)
            log.trace "doing sendHubCommand for hubAction: $hubAction"
            sendHubCommand(hubAction)
            break
        default:
            log.warn "Unhandled button: $btn"
    }
}

Perhaps even more shockingly, it works even with secure devices. I was expecting to need to use zwaveSecureEncap() like you do in a driver (and was expecting that to fail since the app probably wouldn't have the data it needs, if this method is even implemented there at all), but either the platform handles this on its own, or there is something going on with the fact that I left the "lower" grants selected (as I usually do) when pairing an S2 Authenticated device I tested this with.

So, in case you haven't figured anything out already, it looks like this might actually work. Now, if someone could tell me why, particularly in the secure case... :rofl:

This is great thanks for the example. That is exactly where I was heading but I know so little about making apps I was still making the structure of the app just to get a selection menu for the device. That's where I stopped and have not had time to resume. I see the "dev1" input just gets created as a global variable of sorts, similar to the drivers I suppose with the preferences.

For the security, have not tested it on a driver but maybe you can send unsecure commands to a secure device without issues? I dont see why it would be a problem, its bad coding but the device should be able to tell its not secure and unwrap it just like any other command (same as a driver would handle incoming commands). Might be worth trying on a driver as well. I would also test the app with the cmd.format() wrapped in zwaveSecureEncap to see if it works but guessing it is not available in apps. If not, might have to code a custom function that detects the security type and does the correct encapsulation just like had to be done before this handy function was added.

OK I thought getting the info back from the device would be the easier part. I was expecting to be able to subscribe to something like "VersionReport" and get that info.

There has to be some trick to it, because again the Firmware update app is getting reports back from the device to know when to send the next chunk of the file over.

Yeah, I'm not sure how an app can parse data directly from the device now that I think about it. Obviously the firmware updater app has a way to do this, but since it's built in, it's possible they're using some technique not available to user apps (there are a few such things). But it's equally possible there's just some trick they're using that I don't know about. I suppose @bcopeland could say for sure if this technique is available to user apps. :slight_smile:

No.. Firmware updater is completely backend.. The app you see is just a frontend ui…

Download the Hubitat app