Using physicalgraph.device.HubAction

It seems that for some devices I have to use physicalgraph.device.HubAction and sendhub and for others I can just use the regular zwave command and get a response. I thought I read that hubaction/sendhub was a bit of an archaic usage for some devices that’s the only way I can get them to work.On others, things work fine.

Is there any special trick/magic or anything to explain why I see this? Or what I might be doing to make it that way?

If you’re returning zwave commands from the “update” or “parse” methods you have to use the response method.

return response(zwave.basicV1.basicGet().format())

You can also use response like:

def cmds = []
cmds << zwave.basicV1.basicGet().format()
return response(cmds)

It seems some activities automatically do that and don’t need response (like configure for example) and others don’t. I guess that’s what I’m missing - when is it necessary and when isn’t it.

Updated always gets called twice and I ignore the duplicate so it’s possible that it doesn’t require “response”, but it’s always required the first time updated is called.

Configure doesn’t need it, but if a sleeping device was paired with a different DTH and then switched to yours, the configure method most likely won’t work so you’ll have to call it manually from the wakeup notifiction event handler and use response because it’s returned by the parse method.

When a smart app or the client calls a device command like on or refresh, it’s not actually directly calling the method. The platform first takes the command and arguments and checks if it’s a command declared by a capability the device implements or a custom command, then it loads up the DTH and calls the command method, then it executes the string that’s returned as a hub action and creates a command event.

When the platform calls parse() with a device message from the hub, it goes through the returned values and converts all Map objects to device events, and takes all HubAction, HubMultiAction, etc objects and executes the enclosed commands.

This API was put together pretty quickly when we first launched. They thought we’d only be needing to create events from parse and commands from command methods, so that’s why they went with the declarative interface. Obviously it’s a mess now and we want to revamp the whole DTH system, but there’s a lot going on.

There was a time before sendHubCommand() was added when we realized we wanted to be able to execute commands from updated() so we added code to execute any HubActions returned from that. We couldn’t just treat it like a device command because there were already lots of DTHs implementing updated() and returning who-knows-what due to the dynamic nature of Groovy.

1 Like

Thank you for explaining, but can you expand on:

  • Why is updated always called twice?

  • Why does “response” work from updated and parse, but hubaction explicitly needed for scheduled methods?

1 Like

Glad you acknowledge it’s a mess and hopefully it’ll be cleaned up sometime. :neutral_face:

After recently discovering that schedule() doesn’t process any command responses returned to it, I have now adopted the standard practice of using sendHubCommand() and sendEvent() in all commands (unless I’m absolutely sure it will only ever be executed via parse()).

I would definitely like to see this kind of stuff clarified in the SmartThings Developers Documentation.

1 Like

That is a bug that we’ve tried a bit to track down, but it hasn’t been prioritized as far as I know.

As @zcapr17 mentioned, scheduled methods aren’t wrapped or processed at all. I assume you are talking about needing to call sendHubCommand()? The response() helper is just shorthand for new physicalgraph.device.HubAction() so I think you should be able to do sendHubCommand(response(command)) though that isn’t what response() is intended for, so it might not be a good idea.

It looks like what we really need is to allow sendHubCommand() to be passed a command object or string directly. I’ll make a ticket for that.

1 Like

It would be good to clear this up, as the above is what I now do to as standard to send commands, unless the code is within parse() or a zwaveEvent() handler.