Multiple Virtual Wall Switch

Here is a smartapp and a virtual device to create a multiple wall switch.
With old cell phones prices ranging from $15 to $25 it is cheaper to turn a cell phone into a switch than buying one.

The problem is that you can’t have in Smartthings app one screen that can controls multiple devices (except for the things page). Therefore, you have to create a virtual device that interacts through a smartapp with multiple devices (such as light switches), if you want to create a panel. Here is the finished product on the wall:

It will be nice if Samsung includes a builtin feature in the Smartthings app to create something like this. Another nice feature will be to dark the screen (or dim it) inside the app. That will allow wall switches that glow only when clicked.

here is the code for the device handler and the smartapp :

/**
 *  Virtual Four Switches
 * Works with the fourSwitch smartapp
 
 *  Copyright 2016 Shay Z
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */


metadata {
	definition (name: "Virtual Four Switches", namespace: "shayz", author: "shayz") {
		capability "Switch"
		capability "Sensor"
		capability "Actuator"
    capability "switchLevel"

attribute "SwitchOne", "string"
attribute "SwitchTwo", "string"
attribute "SwitchThree", "string"
attribute "Switchfour", "string"
attribute "Virtual3Switch", "string"
attribute "SW1Name", "string"
attribute "SW2Name", "string"
attribute "SW3Name", "string"
attribute "SW4Name", "string"

command "switch1On"
command "switch1Off"
command "switch2On"
command "switch2Off"
command "switch3On"
command "switch3Off"
command "switch4On"
command "switch4Off"

}

preferences {
       input("Switch1", "string", title:"Switch 1", description: "Please enter switch 1 name", defaultValue: "Switch One" , required: true, displayDuringSetup: true)
       input("Switch2", "string", title:"Switch 2", description: "Please enter switch 2 name", defaultValue: "Switch Two" , required: true, displayDuringSetup: true)
       input("Switch3", "string", title:"Switch 3", description: "Please enter switch 3 name", defaultValue: "Switch Three" , required: true, displayDuringSetup: true)
       input("Switch4", "string", title:"Switch 4", description: "Please enter switch 4 name", defaultValue: "Switch Four" , required: true, displayDuringSetup: true)
   }


//  tile definitions
tiles {
	    standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
        	state "off", label: '${name}', action: "switch.on", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff"
        	state "on", label: '${name}', action: "switch.off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821"
     	} 
        standardTile("switch1", "device.SwitchOne", width: 2, height: 1, canChangeIcon: true) {
        	state "off", label: '${name}', action: "switch1On", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
        	state "on", label: '${name}', action: "switch1Off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821"
     	}
			standardTile("switch2", "device.SwitchTwo", width: 2, height: 1, canChangeIcon: true) {
        	state "off", label: '${name}', action: "switch2On", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
        	state "on", label: '${name}', action: "switch2Off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821"
     	}
			standardTile("switch3", "device.SwitchThree", width: 2, height: 1, canChangeIcon: true) {
        	state "off", label: '${name}', action: "switch3On", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
        	state "on", label: '${name}', action: "switch3Off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821"
     	}
			standardTile("switch4", "device.SwitchFour", width: 2, height: 1, canChangeIcon: true) {
        	state "off", label: '${name}', action: "switch4On", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
        	state "on", label: '${name}', action: "switch4Off", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821"
     	}
        
    
          
      
        valueTile("devN1", "device.SW1Name", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
            state "SW1Name", label: '${currentValue}', icon: ""
        } 
        valueTile("devN2", "device.SW2Name", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
            state "SW2Name", label: '${currentValue}', icon: ""
        } 
        valueTile("devN3", "device.SW3Name", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
            state "SW3Name", label: '${currentValue}', icon: ""
        } 
        valueTile("devN4", "device.SW4Name", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false, decoration: "flat") {
            state "SW4Name", label: '${currentValue}', icon: ""
        } 
        /*
			multiAttributeTile(name:"switch1", type: "generic", width: 3, height: 1) {
            tileAttribute ("device.SwitchOne", key: "PRIMARY_CONTROL") {
            	attributeState "on", action:"switch1Off", icon:"st.lights.philips.hue-single" 
            	attributeState "off", action:"switch1On", icon:"st.lights.philips.hue-single"
            }
            tileAttribute ("device.SW1Name", key: "SECONDARY_CONTROL") {
            	attributeState "SW1Name", label:'${currentValue}', icon: ""
            }
         }
         multiAttributeTile(name:"switch2", type: "generic", width: 3, height: 1) {
            tileAttribute ("device.SwitchTwo", key: "PRIMARY_CONTROL") {
            	attributeState "on", action:"switch2Off", icon:"st.lights.philips.hue-single" 
            	attributeState "off", action:"switch2On", icon:"st.lights.philips.hue-single"
            }
         }
         multiAttributeTile(name:"switch3", type: "generic", width: 3, height: 1) {
            tileAttribute ("device.SwitchThree", key: "PRIMARY_CONTROL") {
            	attributeState "on", action:"switch3Off", icon:"st.lights.philips.hue-single" 
            	attributeState "off", action:"switch3On", icon:"st.lights.philips.hue-single"
            }
         }
      */
      
    main "switch"
    details "switch1","devN1","switch2","devN2","switch3","devN3","switch4","devN4"

		}     
}


def installed() {
	initialize()
}

def updated() {
	initialize()
}

def initialize(){
	sendEvent(name: "SW1Name", value: "$Switch1")
	sendEvent(name: "SW2Name", value: "$Switch2")
	sendEvent(name: "SW3Name", value: "$Switch3")
	sendEvent(name: "SW4Name", value: "$Switch4")
}
    
// handle commands
def on() {
sendEvent(name: "switch", value: "on")
}

def off() {
sendEvent(name: "switch", value: "off")
}

def switch1On(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchOne", value: "on", descriptionText: "Physical")
else sendEvent(name: "SwitchOne", value: "on")
 //   log.debug "sw1 vir on $evtSource"
}

def switch1Off(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchOne", value: "off", descriptionText: "Physical")
else sendEvent(name: "SwitchOne", value: "off")
 //       log.debug "sw1 vir off $evtSource"
}

def switch2On(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchTwo", value: "on", descriptionText: "Physical")
else sendEvent(name: "SwitchTwo", value: "on")
}

def switch2Off(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchTwo", value: "off", descriptionText: "Physical")
else sendEvent(name: "SwitchTwo", value: "off")
}

def switch3On(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchThree", value: "on", descriptionText: "Physical")
else sendEvent(name: "SwitchThree", value: "on")
}

def switch3Off(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchThree", value: "off", descriptionText: "Physical")
else sendEvent(name: "SwitchThree", value: "off")
}

def switch4On(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchFour", value: "on", descriptionText: "Physical")
else sendEvent(name: "SwitchFour", value: "on")
}

def switch4Off(evtSource) {
	if (evtSource == "Physical") sendEvent(name: "SwitchFour", value: "off", descriptionText: "Physical")
else sendEvent(name: "SwitchFour", value: "off")
}

Here is the smartapp that interacts with the devicehandler:

/**
 *  FourSwitch device connect
 * Works with the Virtual Three Switches device handler
 *
 *  Copyright 2016 Shay Z
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
 
definition(
    name: "fourSwitch",
    namespace: "shayz",
    author: "Shay",
    description: "4 switch controller",
    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",
    iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")


preferences {
	section("Switches selection") {
    	input "switch1", "capability.switch", title:"Select Switch 1"
    	input "switch2", "capability.switch", title:"Select Switch 2"
    	input "switch3", "capability.switch", title:"Select Switch 3"
    	input "switch4", "capability.switch", title:"Select Switch 4"
    	input "VirtualSw", "device.virtualFourSwitches"
	}
}


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

	initialize()
}

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

	unsubscribe()
	initialize()
}

def initialize() {
	subscribe(VirtualSw, "switch", VSwitchEvt)
	subscribe(VirtualSw, "SwitchOne", VSwitchEvt)
	subscribe(VirtualSw, "SwitchTwo", VSwitchEvt)
	subscribe(VirtualSw, "SwitchThree", VSwitchEvt)
	subscribe(VirtualSw, "SwitchFour", VSwitchEvt)
	subscribe(switch1, "switch", SwOneEvt)
	subscribe(switch2, "switch", SwTwoEvt)
	subscribe(switch3, "switch", SwThreeEvt)
	subscribe(switch4, "switch", SwThreeEvt)
}

// send events to real switches
def VSwitchEvt(evt) {

//Physical prevents event loops i.e. it means it gets here when the event was triggered by the the real device then-> calls virtualSW (from below) then-> returns here without Physical to stop
    if (evt.descriptionText != "Physical") {
   // 	log.debug "turning real switch"
        switch ( evt.name ) {
        case "SwitchOne":
            switch1."$evt.stringValue"()
            break

        case "SwitchTwo":
            switch2."$evt.stringValue"()
            break

        case "SwitchThree":
            switch3."$evt.stringValue"()
            break
            
        case "SwitchFour":
            switch4."$evt.stringValue"()
            break

        case "switch":
            switch1."$evt.stringValue"()
            switch2."$evt.stringValue"()
            switch3."$evt.stringValue"()
            switch4."$evt.stringValue"()
            break
        }   
    }
}

// send events to Virtual Switch (toggle tile)
def SwOneEvt(evt) {
// Physical prevents events loop
	if (evt.stringValue == 'on') VirtualSw.switch1On("Physical")
    else if (evt.stringValue == 'off') VirtualSw.switch1Off("Physical")
//    log.debug "send event to virtual device $evt.stringValue"
}

def SwTwoEvt(evt) {
	if (evt.stringValue == 'on') VirtualSw.switch2On("Physical")
    else if (evt.stringValue == 'off') VirtualSw.switch2Off("Physical")
 //   log.debug "event rec from real sw 2 $evt.stringValue"

}

def SwThreeEvt(evt) {
	if (evt.stringValue == 'on') VirtualSw.switch3On("Physical")
    else if (evt.stringValue == 'off') VirtualSw.switch3Off("Physical")
}

def SwFourEvt(evt) {
	if (evt.stringValue == 'on') VirtualSw.switch4On("Physical")
    else if (evt.stringValue == 'off') VirtualSw.switch4Off("Physical")
}
2 Likes

Hmm, interesting. I have about 3 old iPhones just hanging around. I was thinking of doing a control panel like this with SmartTiles but then thought, I have to get power to the tablet for an always on scenario. Worth the effort for the “cool factor” department. Great Job!

1 Like

Yes. You need to install a 5v adapter inside a nearby outlet box, run a low voltage wire through the walls and connect it ( two wires, red and black only) to a usb that plugs to the cell phone. And of course, you also have to make a custom hole in your wall. It’s takes an hour or two… but it is nice and better than a huge panel everywhere. BTW you can improve the code but it works very well.

I like this idea. I have a couple of Android cheap tablets I’ve picked up waiting for the next version of Smartiles to come out. I haven’t played around with Androids too too much, but is there a way to lock the device to only this screen would appear so no one else could pull up any other apps or anything?

1 Like

Unfortunately, no software solution withing smartthing app (until Samsung will get to it). But you can limit the access to the phone buttons physically (and then it is pretty static), although you need to have the ability to control the phone without dismantling everything from the wall (this is why there is a small creek in the frame that gives me access to the on off button).

Added this, started setup, selected 4 switches, then there is a field called Which? in red that says You can’t currently add this. Won’t let me hit done because of it.

You have to create the device first. In the smartapp you have to choose the switches and the virtual switch.
The reason you can’t choose the VirtualSwitch is either:

  1. It is not installed
  2. You haven’t created a device “virtual switch” with it
  3. You changed the name of the device handler (has to be ‘Virtual Four Switches’ unless you change it also in the smartapp)

Yeah, just realized that as I came back here to look for a response. Sorry, blonde moment!

There is a SmartApp called SmartTiles, that runs a webpage and allows you to interface with your devices.Seems to be some what of what you are looking for.

There is also the Room, under My Home, you put the devices in the rooms that way you only see the devices you want to control for that Room.

1 Like

This has the benefit of not timing out like SmartTiles currently does, since it’s IN the ST app. I like that for some of my smaller unused devices. I have ST on a number of tablets and use it daily, but this has a more niche application that I can see myself using.

1 Like

The problem with Room is that it is not big enough for a wall switch and limited in the visual setup. The other problem is if you want a certain device to be in one room but on a different virtual remote switch. for ex., if the light is in the living room (and you want it in that room) but you want to have a switch on the wall without all the other living room devices. You can bypass it by creating a different user but it is very inconvenient.

That will be where SmartTiles gets the advantage here, as it can run in the Fully brand kiosk-mode browser which can be configured to run at boot and not allow access to any other web page or tablet function.

This is what I do at work on a cheap Amazon tablet, works great when ST isn’t wanting me to re-auth and login every few days…

1 Like

We are sooooo… excited to get “V6” released to fix this!

In the meantime, if the tablet is dedicated to SmartTiles and Fully, try using the “Auto Reload on Idle” setting in Fully. It should help keep the login session from timing out, if you use a value like 15 minutes or something…

3 Likes

l am new to Smartthinqs. I looked at Smart Tiles and thought you really did a nice thing. One problem that I had with ST is that I don’t want to expose my home devices to another entity . Samsung has access to everything at my Home but they also have a deep pocket if someone there chooses to exploit the access . I am not sure it is the same when it comes to a startup. Am I missing something?

The same risk applies to SmartRules, Sharp Tools, IFTTT, Amazon Alexa, etc…

###Exactly what “exploit(s)” are you concerned about???

(SmartTiles will have liability insurance in case of gross negligence or outright illegal activities, but our Terms of Use contain the same full disclaimer of responsibility as SmartThings.)

Alarm system, for ex. Cameras is another.
There may be other people like me who are concerned about privacy and control. I think choosing what devices are exposed (if technically possible) would be a nice feature for ST that may increase the demand for the nice software you developed. Just a thought.

I can’t tell you the last time I’ve had to log in on my tablet. I use 15 minutes and refresh on open. I have also started using the built in camera detection vice the motion app .

1 Like

You need to understand how the ST authentication before commenting about security risk and how it’s used in 3rd party app

1 Like

double post… removed