How to distinguish between manual push of a switch vs. automating turning on a switch


#1

I have a GE 12730 Z-wave wall switch and I’ve created a SmartApp to automatically turn the switch on/off using mySwitch.on() and mySwitch.off()

I also want to capture the user manually pushing the wall switch so I have code that does the following:

subscribe(mySwitch, “switch.on”, switchOnHandler)
subscribe(mySwitch, “switch.off”, switchOffHandler)

The problem is that the switchOnHandler and switchOffHandler events are being called when the switch is toggled automatically and when it’s toggled manually. How do I distinguish between the two cases?


(Eric) #2

I think you want to look at the source of the event.

http://docs.smartthings.com/en/latest/ref-docs/event-ref.html#source

if(evt.source == "USER") {

     ...

}

#3

Thank you so much Eric.

That is exactly what I’m looking for but unfortunately evt.source keeps showing up as “DEVICE” in my event handler. I’ve tried 3 ways to turn the switch on: 1) using the Android app 2) calling sw.on(), and 3) manually pressing the switch. Unfortunately, evt.source always returns “DEVICE”.

Has anyone got this to work or any ideas what I’m doing wrong?


(Eric) #4

This could be one of the many/few things that are documented that don’t work.

@slagle - Any ideas, I also tested this and got the same results as @jsilver.


(George) #5

Also, try isPhysical()
see http://docs.smartthings.com/en/latest/ref-docs/event-ref.html


#6

George, thank you for that idea. I tested with evt.isPhysical() and it always returned false, so that didn’t work.

For now, I’ve found an ugly workaround/hack by recording the time just before the app calls “switch.on()” and checking again in the switch.on event handler. If the two times are within a few seconds, I assume the event handler was called by the app. It’s not perfect, but it’s close enough for my purposes.

BTW, I have a SmartApp that’s now checked into github that I’d like to share. What’s the best way to announce or share this?


(Ben W) #7

This functionality has been removed by most device handlers. There was some issues with it not being reported correctly and was “hackish”.

Thread can be found here:


(Tim Slagle) #8

Yep, it was very hackish, there are still some DTHs it works well with but they are few and far between. I’d use the “source” of the event.


(Eric) #9

I suggested he use source in the second post of this thread. It isn’t working, see the third post. I think the source functionality might be broken.


(Smuts) #10

This would be useful. I want to automatically turn on a light when there is motion unless it has recently been turned off manually. Otherwise you end up fighting ST when you want the light off. I put in a delay in a CoRE Piston so that it won’t be turned on if it has recently been changed, but that isn’t ideal. If a Piston turned off the light due to lack of motion, it won’t come on until the delay is up. If I could distinguish between a manual flip and the Piston I could avoid this issue. . . .


#11

I never could identify a physical press of the button based on the suggestions above but I’ve finally got my app to work using the workaround I mentioned above.

If you’re interested, my source code is at

and you can see the workaround I used in the switchHandler() event handler.

As for the SmartApp, it allows turning on/off a fan based on motion, manual button presses, and temperature offset between two rooms. Even though there seem to be a lot of fan related SmartApps, I couldn’t find any that did exactly what I needed which is why I wrote this.


(Eric) #12

Notice they all say DEVICE.

This is from changing the switch with the SmartThings app.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug Broken — switchHandler()
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.value = on.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.source = DEVICE.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.name = switch.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.displayName = RF9500.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.device = RF9500.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.descriptionText = RF9500 switch is on.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug evt.date = Mon Oct 24 22:52:13 UTC 2016.
a73f1850-2e61-4d65-926f-09c0296186ce 6:52:13 PM: debug Broken — switchHandler()

This was from a physical press of a switch
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug Broken — switchHandler()
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.value = off.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.source = DEVICE.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.name = switch.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.displayName = RF9500.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.device = RF9500.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.descriptionText = RF9500 switch is off.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug evt.date = Mon Oct 24 22:51:37 UTC 2016.
a73f1850-2e61-4d65-926f-09c0296186ce 6:51:37 PM: debug Broken — switchHandler()

This was from a toggle in CoRE
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug Broken — switchHandler()
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.value = off.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.source = DEVICE.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.name = switch.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.displayName = RF9500.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.device = RF9500.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.descriptionText = RF9500 switch is off.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug evt.date = Mon Oct 24 22:57:55 UTC 2016.
a73f1850-2e61-4d65-926f-09c0296186ce 6:57:55 PM: debug Broken — switchHandler()


(ELllv) #13

There’s an anther workaround that I use.
Each time my app calls for on/off on any device it declares some variables which can be compared in the handler to figure out what happened:

def SwitchesOn(){
    // declare 2 variables
    state.TurnedOnByTheApp = 1
    state.TurnedOffByTheApp = 0
    switches?.on() 
} 
def SwitchesOff(){
    // declare 2 variable
    state.TurnedOnByTheApp = 0
    state.TurnedOffByTheApp = 1
    switches?.off() 
}

    /// handler will now know whether the command came from within the app or 
def SwitchHandler(){

    if(evt.value == "on" && state.TurnedOnByTheApp = 0){
    log.debug "This command did not come from within the app"
// 

    else {
    log.debug "This command came from within the app"
    }

    if(evt.value == "off" && state.TurnedOffByTheApp = 0){
    log.debug "This command did not come from within the app"
    else {
    log.debug "This command came from within the app"
    }
}

for the rest, you need to figure out under which conditions you want each variable to be reset. For instance, I use this principle in a multi thermostat manager that I wrote so I can override its settings and undo the override just by either turning on/off one of my thermostats, or by changing its temperature set points, which leads to a laborious and complex set of comparative loops, using sets of arrays. If anyone is interested I can share this code, it would actually greatly help to learn a bit more on how to simplify it… I’ve been working on this for a while now and it starts to be quite stable… but I went through hell, especially when my wife ended up sweating or freezing while I was working on it at night… :smiley:

Elfege


(Fernando) #14

anyone had any luck with this? I’ve been trying to see if there’s anything I could use to differentiate a command from the physical switch or my phone (either smartthings app, iphone integration, etc.). as discussed here, the source is always DEVICE, physical is always false, etc.

most of my commands come from the json API (integrated with my iphone home kit)… I was wondering If I could inject something there when it triggers the device, so I could parse on the CoRE rule code and set this as “not physical”…