How to invoke command / sendHubCommand from device type code

Is there a way to invoke a device command or do a sendHubCommand from device type code?

From my understanding, commands can return a hubAction, which is then invoked in the platform. I have a need to perform the equivalent of a sendHubCommand as the result of the parse() function.

In my specific case, my LAN device type code needs to negotiate a session id with the device. I have no idea when this session id expires. I basically try to perform the command that the user pressed from the device tile, and then, if I get an unauthorized response back, I clear the session id. Then on the next command, I see that the session id is blank, and instead of performing the command, I request a session id. So only the third command will actually do the action, as that is when the session id is available. I am trying to simplify this exchange to get a better user experience.

I have defined a refresh command that will request a session id. So if I press that first, the device will work “first” time. What I actually want to do, is cache the command, try it, if I get a unauthorized back in the parse function, then perform the sendHubCommand equivalent to request the session id, and when I have that (from the parse funtion), then perform the cached command.

I tried sending a refresh event from the parse function, hoping that will fire the refresh command, but no luck.

Another option would be to get a hook into when the user opens the device page. I have not seen any examples or documentation that makes me believe that is possible.

Any suggestions from the code gurus here?

Thanks!

The “canonical” way of doing this is using Connection/Device Manager app. Sonos or Ecobee are good examples.

3 Likes

I’ve been trying the approach above, where the child device sends events to the “manager” smart app and then the smart app will invoke commands on the device to achieve what I want.

However, this seems to only work “once”. Not sure what I am doing wrong. Are events filtered out when they don’t change, or am I missing something in subscribing to events, or haven’t defined the events properly?

I tried to set isStateChange to true in the event and tried to subscribe with the filterEvents true or false, but that had no effect.

In the DeviceType:

definition (...) 
{
    ...
    capability "Refresh"
    ...
    command "resend"
}

private parseSubFunction (output) {
    ...
    log.debug "Unauthorized - clearing session value"
    sendEvent(name:'retry', value:'retry', displayed:false, isStateChange: true)
    ...
}

And in the SmartApp

def initialize() {
    ...
    d = getChildDevice(dni)
    log.debug "found ${d.displayName} with id $dni"
    subscribe(d, "retry", retryHandler, [filterEvents: false])
    subscribe(d, "resend", resendHandler, [filterEvents: false])	
	....
}

def retryHandler(evt) {
    log.debug "Retry Event: $evt"
    def deviceSettings = selectedTv.split("!")
    def ipAddressHex = deviceSettings[1]
    def ipAddress = convertHexToIP(ipAddressHex)
    def dni = "${ipAddressHex}:${convertPortToHex(8080)}"
    def d = getChildDevice(dni)
    d.refresh()
}

def resendHandler(evt) {
    log.debug "Resend Event: $evt"
    def deviceSettings = selectedTv.split("!")
    def ipAddressHex = deviceSettings[1]
    def ipAddress = convertHexToIP(ipAddressHex)
    def dni = "${ipAddressHex}:${convertPortToHex(8080)}"
    def d = getChildDevice(dni)
    d.resend()    
}

Just out of curiousity, why are you trying to do all the http logic in the devicetype instead of the SmartApp?

The smartApp has far better control of response and can handle multiple queries and update the child devices.

Take a look at the sonos connect example in the ide for guidance, and the sonos devicetype (which is simple).

2 Likes

I did look at the Sonos code.

It doesn’t seem “right” to me that the control app should be involved in device specific things. The way I understand the SmartThings architecture is that the device type is involved in translating device specific messages and commands to and from generic platform messages and commands. The smart app should be involved with the generic messages and in managing / discovering the device.

My smart app is involved with discovering, creating and pairing with the device, but after that I would like to be able simply send commands to the device, and the device handles itself. I’m trying to work around what I consider to be a deficiency in the platform where the device type can’t send “unsolicited” messages to the physical device.

So no real reason - just my object-oriented OCD :smile:

I concur with your theory.

Device / Service Manager SmartApps are a bit of a “hack”, as far as I can tell, but probably a necessary one unless a new object type would be added to the Platform.

SmartApps are generally used to control interactions between Devices (Note: devices don’t have any permissions or methods to directly interact with each other). Only SmartApps can manage events, attributes and commands on multiple devices.

There should be a different way to handle service type devices since SmartApps are mostly thought of as configurable automation rules, rather than basic device management, I think.

So many use cases, so few options.

If you need to discover devices outside of the add new device in the ST App, then you need a SmartApp to handle device discovery (child devices) and a simple devicetype to handle the proxy / tiles for individual devices. Discovery and setup is done at the SmartApp install and/or configure screens.

If you have a device that has the ability to be found, ie Zigbee / Zwave, etc. then you can do just a DeviceType and discover via the App. UI is in the Things view.

If you want to control existing devices you select, then a SmartApp needs to be developed to control those devices.

The smartapp child device model makes sense, especially when you are interacting with a 3rd party that might have lots of child devices, ie sonos.

I too was confused by this at first, and wrote all the logic for IP cameras just in a devicetype, but realistically this should have been done in a SmartApp to find and configure IP cameras and spawn devicetypes and do the local hub action inside the SmartApp for each of the child devices.

The reason this makes sense, is all the logic is contained in the SmartApp, so you only need to update it in one spot and just keep the spawning child devicetypes simple. Plus the child devices are automatically removed when removing the smartApp and don’t have to be manually removed one by one.

May not make sense for a few devices, but once you consider integrating other 3rd party devices, like wink connected devices, or sonos speakers throughout a house, or my control4 stuff, I don’t want to update 50 different devicetypes, just want one smartapp with all the logic in it for all devicetypes I want to spawn and control.

1 Like

My suggestion would be to forget about “right and wrong” or how things “should be” from the abstract/theoretical point of view. That is, if your goal is to get the job done as opposed to complaining endlessly about architectural deficiencies of their beloved platform. :wink: :wink:

One particular example where the “right” way won’t work is when you’re talking to multiple devices behind the IP bridge, because all the devices have the “same” IP address and port and therefore would have to have same device network ID, which is not permitted.

1 Like

I apologize if you read my post as “complaining endlessly about architectural deficiencies” - not at all my intent. If I wanted to complain endlessly, it would be about the lack of API documentation :smiley:. The “job” that I’m trying to get done is learning about the platform and language and IP devices, and maybe automatically annoying my kids if I get the latest code going properly. As I’m doing this as a way to pass the snowy winter evenings here, I allow myself some philosophizing about the concepts. BTW, your VLCThing contributed some code to what I am playing with, so thanks for sharing!

Anything constructive on the post above about why the SmartApp isn’t seeing the events from the device?

1 Like

Sorry, that was a rather generic observation, not specifically addressed to you. These’s been a lot of pointless (IMHO) architectural discussion lately, as if some folks believe they have power to change architecture of the system that’s been in production for two years. It’s nagganahappen. :smile:

Anything constructive on the post above about why the SmartApp isn’t seeing the events from the device?

It’s hard to tell from the snippets of your code. You seem to set up event handles right, but it’s not clear when the events are generated.

Oooo… that stings, Geko, that stings … :flushed: :cry: … :stuck_out_tongue_winking_eye: … :smile:

I tried to quote the essence of the issue. I see the debug statements where the events are sent, so I know the code is executed. But I don’t see the debug statements from the event handlers in Live Logging. I was hoping there’s something obvious that I’m overlooking when sending the events / setting up the handlers.

Are there scenarios where events are not sent? I send the events inside of a function that gets called from the parse() function. Other devices that I’ve modified (my connected smoke alarm, for example) do send the events from the parse() function.

I’ll keep hacking at it.

You can see your events in the IDE (go to http://graph.api.smartthings.com/location/list and click “events”). You can also verify your event subscriptions by clicking on “smartapps” and then clicking on your smart app name. You should see them in the “Event Subscriptions” section.