Virtual switch to trigger another switch but return status of a 3rd switch

So, I’m basically trying to avoid having two different tiles for my garage door. I want to combine a momentary contact switch (for garage door) when you press the virtual switch, but have it return the status of the sensor that tells if the door is open or not and set it as the status of the virtual switch. Meaning have a virtual switch that tells you if the door is open or not, and on press to trigger the momentary contact switch to open/close it.

Would that be possible via a virtual switch?

That sounds a lot like a SmartApp I created to open/close my garage from a real switch, where the blue LED on the switch indicates whether the door is opened or closed. You could just replace the real switch with a virtual switch, and it should do what you want.

3 Likes

Thats perfect!

I tried adding my garage door sensor but it does not give the option (it is not a threeAxis type). I got it to show up if I changed it to capability.contactSensor but then the app doesnt seem to work. What am I doing wrong?

Ok, for a contact sensor, you’ll also need to change “status” to “contact”. I think this should work (not tested):

    definition(
    name: "Control garage with switch",
    namespace: "com.obycode",
    author: "ObyCode",
    description: "Use a z-wave light switch to control your garage. When the switch is pressed down, the garage door will close (if its not already), and likewise, it will open when up is pressed on the switch. Additionally, the indicator light on the switch will tell you if the garage door is open or closed.",
    category: "Convenience",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png"
)


preferences {
    section("Use this switch...") {
        input "theSwitch", "capability.switch", multiple: false, required: true
    }
    section("to control this garage door...") {
        input "theOpener", "capability.momentary", multiple: false, required: true
    }
    section("whose status is given by this sensor...") {
        input "theSensor", "capability.contactSensor", multiple: false, required: true
    }
}

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

    initialize()
}

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

    unsubscribe()
    initialize()
}

def initialize() {
    subscribe(theSwitch, "switch", switchHit)
    subscribe(theSensor, "contact", statusChanged)
}

def switchHit(evt) {
    log.debug "in switchHit: " + evt.value
    def current = theSensor.currentState("contact")
    if (evt.value == "on") {
        if (current.value == "closed") { 
            theOpener.push()
        }
    } else {
        if (current.value == "open") {
            theOpener.push()
        }
    }
}

def statusChanged(evt) {
    if (evt.value == "open") {
        theSwitch.on()
    } else if (evt.value == "closed") {
        theSwitch.off()
    }
}
2 Likes

Hi guys -

I have been trying to do exactly this same thing with the help of @JDRoberts over at this thread…

I am migrating my efforts here so we can merge ideas and successes. I don’t know if I needed to do this or not, but I made a custom device driver that implemented the sensor and momentary capabilities. Your approach looks simpler.

Youre a genius! Thank you!!

2 Likes

obycode’s method worked perfectly, and best of all its a passive smartapp so it works all in the background and I can use the virtual switch like a normal switch. it even updates the status if the garage door was opened with the actual opener outside of smartthings.

2 Likes

Okay guys… I finally got this figured out. Basically Varun you are right - obycode’s method was the ticket. All of my prior attempts to make a custom device were barking up the wrong tree. Using this simple virtual sensor and a clever smart app worked perfectly. I made a few tweaks to the code because I wanted to use the simulated garage door device to show opening and closing while the door was in transit. This also meant using the opening and closing event triggers instead of open and close. And because I have two garage doors I had to install two virtual devices each with a unique name. They both use the same smart application. If anyone is trying to install a garage door button this in my opinion is the way to do it. Using a simple momentary switch will leave you guessing about the state - or it will require you to keep a separate sensor icon like I had. With this method there is only one icon and it shows the state and triggers the actions. The other icons have to be there so I just hid them in a group that I use to hide my motion sensors that have no useful HMI function. Hope this helps someone.

definition(
    name: "Status My Garage Door",
    namespace: "kewashi",
    author: "KenWashington",
    description: "Sets the status of a garage door open/close relay switch based on switch state",
    category: "Convenience",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/light_contact-outlet.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/light_contact-outlet@2x.png"
)


preferences {
    section("This garage door...") {
        input "theDoor", "capability.doorControl", multiple: false, required: true
    }
    section("is controlled by this switch...") {
        input "theOpener", "capability.momentary", multiple: false, required: true
    }
    section("whose status is given by this sensor...") {
        input "theSensor", "capability.contactSensor", multiple: false, required: true
    }
}

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

    initialize()
}

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

    unsubscribe()
    initialize()
}

def initialize() {
    subscribe(theDoor, "door", switchHit)
    subscribe(theSensor, "contact", statusChanged)
}

def switchHit(evt) {
    log.debug "Virtual button: " + theDoor.name + ", generated value: " + evt.value
    def current = theSensor.contactState
    log.debug "  -> Sensor: " + theSensor.name + " status = " + current.value

	// if the state is unknown or the door is moving, push the button to stop or reverse
    // if (evt.value == "unknown") {
    //     theOpener.push()
    // }
    
    // if the sensor state is closed and open button is pushed activate
    // it is more reliable to check the virtual opening state instead of open
    if (evt.value == "opening") {
        if (current.value == "closed") { 
            theOpener.push()
        }
    }    
    // if sensor state is open and closed button is pushed then activate
    // it is more reliable to check the virtual closing state instead of close
     
    else if (evt.value == "closing") {
        if (current.value == "open") {
            theOpener.push()
        }
    } 
    

}

// handle the cases where sensor state changes for reasons other than button press
// such as manual wall press or the original button press tied to physical relay
// note that the physical button must still be installed - I just hide it in a group
def statusChanged(evt) {
    log.debug "Sensor [" + theSensor.name + "] status = " + evt.value + " door state = "+ theDoor.doorState.value
    if (evt.value == "open" && theDoor.doorState.value=="closed") {
        theDoor.open()
    } else if (evt.value == "closed" && theDoor.doorState.value=="open") {
        theDoor.close()
    }
}