First app, detecting mode change


(Scott Windmiller) #1

I am a hacker at best, meaning I take other peoples code and manipulate it for myself :slight_smile: so dont mind my ignorance. I have to learn based off trial and error.

As a test I have an app that switches modes via a virtual on/off switch and is also based off of sunrise/sunset. I know this has already been done but my endgame is for disarming my alarm and putting it in the correct mode, either way this part works fine.

What I also want is for the switch to change to on or off based on a mode change. So in other words if I manually change the mode to Home the switch is showing as On.

Here is my code:

preferences {
    section("Select Switch to monitor"){
        input "theSwitch", "capability.switch"
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated(settings) {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def onHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
    log.debug "Daytime"
            setLocationMode("Home Day")
            }
            else {
    log.debug "Nighttime"
            setLocationMode("Home Night")
            }
    log.debug "Received on from ${theSwitch}"

}

def offHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
        log.debug "Daytime"
            setLocationMode("Away Day")
            }
            else {
     log.debug "Nighttime"
            setLocationMode("Away Night")
            }
     log.debug "Received off from ${theSwitch}"
}

def modeChangeHandler(evt) {
    if (evt.value == "Home Day")
    {
    log.debug "Changed to Home Day"
    }
    else {
    log.debug "Changed to something else"
    }
}

def initialize() {
    subscribe(theSwitch, "switch.On", onHandler)
    subscribe(theSwitch, "switch.Off", offHandler)
    subscribe(location, modeChangeHandler)
} 

I have def modeChangeHandler(evt) setup just to test to see if I did it right and it is not even being triggered based on the log when I make a mode change. I know its something stupid but with my lack of knowledge, I have no idea what :wink:

Thanks for helping a newbie!
Scott


(Eric R) #2

I just tested your code. It is registering mode changes. I don’t have “Home Day”, but when I change mode, it logs “Changed to something else”. Is there something else you are expecting to happen? How are you changing the mode?

Edit: I also tested it with a mode I do have, and it is working too.


(Tim Slagle) #3

Same :smile:



(Scott Windmiller) #4

Thanks for testing it. I guess the good news is that I actually did it right :smile:

The bad news is its not working for me.
The “Changed to something else” is what I was expecting but it does not happen for me. I select “Live Logging” in the IDE and then change the mode manually using my iphone via the dashboard…not any smartapp.

Any ideas why it would not be working for me?


(Chuck Pearce) #5

@swindmiller what does the Live Logging state regarding the app, if anything? You should get a “WARN” if the mode you are attempting to switch into is the current mode.


(Scott Windmiller) #6

@chuck_pearce, I don’t get anything for the app at all unless I hit the virtual on/off button I have set to this app. I should not need to do anything with the button at all right, as the mode change should trigger it independently of the button, right?

I just tried re-creating the app by going to “MySmartApps”, “New Smartapp”, “From Code” and pasting in:

definition(
    name: "Alarm Disarm",
    namespace: "",
    author: "Scott Windmiller",
    description: "Virtual Switch to disarm alarm",
    category: "Safety & Security",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
    iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")

preferences {
    section("Select Switch to monitor"){
        input "theSwitch", "capability.switch"
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated(settings) {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def onHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
    log.debug "Daytime"
            setLocationMode("Home Day")
            }
            else {
    log.debug "Nighttime"
            setLocationMode("Home Night")
            }
    log.debug "Received on from ${theSwitch}"

}

def offHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
        log.debug "Daytime"
            setLocationMode("Away Day")
            }
            else {
     log.debug "Nighttime"
            setLocationMode("Away Night")
            }
     log.debug "Received off from ${theSwitch}"
}

def modeChangeHandler(evt) {
    if (evt.value == "Home Day")
    {
    log.debug "Changed to Home Day"
    }
    else {
    log.debug "Changed to something else"
    }
}

def initialize() {
    subscribe(theSwitch, "switch.On", onHandler)
    subscribe(theSwitch, "switch.Off", offHandler)
    subscribe(location, modeChangeHandler)
}

Save and publish just for me. Switch to Live Logging and initiate a mode change. Nothing in the log…still!

Thanks for helping me :slight_smile:


(Chuck Pearce) #7

Open the app on your phone, then click Done in the upper right, you SHOULD see "Updated with settings: " with a block of text about the switch that is selected, do you not even see that? Make sure you have the “Live Logging” running before you open the app on your device.

I will test the app when I return from lunch


(Scott Windmiller) #8

Nevermind…its working now :smile:
I removed everything related to that switch and started over. Must have screwed something up at some point.

Thanks to everyone for helping me out :smile:
I am sure I will have more questions later.
This is really cool that I was able to write my own app…well kind of…lol


(Scott Windmiller) #9

OK I am now getting somewhere :slight_smile: but need a little more help.

How can I switch a buttons state without running the commands?
For example:

def offHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
    log.debug "Daytime"
            setLocationMode("Home Day")
            }
            else {
    log.debug "Nighttime"
            setLocationMode("Home Night")
            }
    log.debug "Received off from ${theSwitch}"

}

def onHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
        log.debug "Daytime"
            setLocationMode("Away Day")
            }
            else {
     log.debug "Nighttime"
            setLocationMode("Away Night")
            }
     log.debug "Received on from ${theSwitch}"
}

def modeChangeHandler(evt) {
    if (evt.value == "Away Day" || evt.value == "Away Night")
    {
    log.debug "Changed to armed"
        theSwitch.on()
    }
    else {
    log.debug "Changed to Disarmed"
        theSwitch.off()
    }
}

This handles the Off then the On and then also if the mode is changed manually. The way I have it now:

def modeChangeHandler(evt) {
    if (evt.value == "Away Day" || evt.value == "Away Night")
    {
    log.debug "Changed to armed"
        theSwitch.on()
    }
    else {
    log.debug "Changed to Disarmed"
        theSwitch.off()
    }
}

creates a loop or repeating event because of the “theSwitch.off()” and “theSwitch.on()”, I know this is incorrect but what I was trying to do was simply turn the switch on or off if the mode was changed manually, not run everything all over again. How can I replace the “theSwitch.on()” (or off) to just simply turn it on or off without running def onHandler(evt) again.

Thanks and sorry for the stupid questions…still learning.


(Chuck Pearce) #10

Can you paste the whole code or gist it: https://gist.github.com/

Just easier for me to look at the whole thing.

I believe what you are going to need to do is call unsubscribe after the event fires then subscribe again after the turn the switch into the other state. Also, you may not want to hard code mode names, you can easily create a selector for that.

input(“modes”, “mode”, multiple: true, title: “Modes”, required: false)

then when you want to check for the modes:

if (modes.contains(location.mode)) {
theSwitch.on()
} else {
theSwitch.off()
}


(Scott Windmiller) #11

Sorry and thanks. Here is the whole thing:

preferences {
    section("Select Switch to monitor"){
        input "theSwitch", "capability.switch"
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated(settings) {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def offHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
    log.debug "Daytime"
            setLocationMode("Home Day")
            }
            else {
    log.debug "Nighttime"
            setLocationMode("Home Night")
            }
    log.debug "Received off from ${theSwitch}"

}

def onHandler(evt) {
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
        log.debug "Daytime"
            setLocationMode("Away Day")
            }
            else {
     log.debug "Nighttime"
            setLocationMode("Away Night")
            }
     log.debug "Received on from ${theSwitch}"
}

def modeChangeHandler(evt) {
    if (evt.value == "Away Day" || evt.value == "Away Night")
    {
    log.debug "Changed to armed"
        theSwitch.on()
    }
    else {
    log.debug "Changed to Disarmed"
        theSwitch.off()
    }
}

def initialize() {
    subscribe(theSwitch, "switch.On", onHandler)
    subscribe(theSwitch, "switch.Off", offHandler)
    subscribe(location, modeChangeHandler)
}

(Chuck Pearce) #12

I believe this should fix you:

def modeChangeHandler(evt) {
if (evt.value == “Away Day” || evt.value == “Away Night”)
{
log.debug "Changed to armed"
unsubscribe(onHandler)
theSwitch.on()
subscribe(theSwitch, “switch.On”, onHandler)
}
else {
log.debug "Changed to Disarmed"
unsubscribe(offHandler)
theSwitch.off()
subscribe(theSwitch, “switch.Off”, offHandler)
}
}


(Scott Windmiller) #13

Thanks but that did not seem to work. I understand why it should have worked :smile:

I will keep trying.

Would something like this work?
sendEvent(name: “contact”, value: “closed”)
I saw it in another post but did not know if thats what I needed or how to implement it.
I tried sendEvent(name: “switch”, value: “inactive”) but that did not do anything.

Thanks,
Scott


(Brice; SmartRulesApp.com) #14

Maybe try using a flag in the state variable. Something like:

def offHandler(evt) {
  if (state.autoChange) {
    state.autoChange = false
    return
  }
  if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
    log.debug "Daytime"
            setLocationMode("Home Day")
            }
            else {
    log.debug "Nighttime"
            setLocationMode("Home Night")
            }
    log.debug "Received off from ${theSwitch}"
}

def onHandler(evt) {
  if (state.autoChange) {
    state.autoChange = false
    return
  }
if(getSunriseAndSunset().sunrise.time < now() && 
                 getSunriseAndSunset().sunset.time > now()){
        log.debug "Daytime"
            setLocationMode("Away Day")
            }
            else {
     log.debug "Nighttime"
            setLocationMode("Away Night")
            }
     log.debug "Received on from ${theSwitch}"
}
def modeChangeHandler(evt) {
  state.autoChange = true
    if (evt.value == "Away Day" || evt.value == "Away Night")
    {
    log.debug "Changed to armed"
        theSwitch.on()
    }
    else {
    log.debug "Changed to Disarmed"
        theSwitch.off()
    }
}

And don’t forget to initialize it to false.


(Scott Windmiller) #15

Thanks I will try it when I get home! Sorry but I am new but how do I initalize it false, just take everything out of def initalize()?
Thanks,
Scott


(Chuck Pearce) #16

In your “def initialize()” where you are doing your subscribes do:

state.autoChange = false

Those state variables are a godsend!


(Dome) #17

@swindmiller, thanks for sharing your progress. I was stuck working on my own SmartApp and I learned from your code.

I’m developing a SmartApp that pushes out notifications to devices (Arduino/Particle based) so that they can process certain events locally; i.e., it could turn on a night light when in night mode upon seeing motion immediately, rather than waiting for the cloud or hub. It could also sound an alarm immediately upon sensing motion in away mode also, making the home slightly more self-sufficient in case of an internet outage.


(Scott Windmiller) #18

I’m glad it helped! I too learn by tearing someone else’s code apart :smile:


(Tony Gutierrez) #19

See this: Mode change subscription bug, at least in docs