Easily Change Virtual to Group?

So I didn't realize that Virtual Devices don't handle command optimization until after I migrated everything from ST and command op is extremely important on a virtual device. I found that group switches do this.

So my question. Is there any easy way to change the device from virtual switch to group switch and then be able to edit it for command op? I can change the device type but that of course doesn't get the group switch to show in the group and scenes app so that I am able to change this setting.

Is there any easy way to do this so that I don't have to recreate all the devices and move all my automations (webCoRE, RM, Maker API...etc.)?

I tried changing the device ID to the same as a created one in the groups and scenes app and this still didn't do the trick.

Can you say more about what you're actually trying to do and what the problem is? (And by this, I mean the original issue; you won't be able to create a device on your own and trick Groups and I'm into thinking that it's a group or scene device, as those must be child devices of those apps, which can only be created by the apps themselves.)

Specifically, I'm not sure what the issue with "command optimization" is or even what you mean, though I assume "Enable on/off optimization" may be part of that. I just did a quick test with all virtual devices in a group, and that setting worked as expected: if the virtual device was already on, it did not send another "on" command to the device. This, of course, depends on the device accurately reporting state back, but all the built-in virtual drivers should do this. If you're using one of your own, I'd verify this. If you're using built-in, I'd verify that you're using the actual "Virtual..." driver (that would be in the name) and not some "real" driver or a "Component" driver that is not meant to be used in this way and that you didn't enable the auto-off setting or are accommodating this behavior.

But, again, if you explain what you're really trying to do, you'll probably get better ideas than these general suggestions.

Ok I use webCoRE. Let's say I want to trigger my Good Morning Off Piston which is triggered
by a virtual switch. Now if the Good Morning Virtual Switch is already off and I press the off button nothing happens. By using a group and scenes switch and just not putting any bulbs or switches in it, and leaving on the "Enable on/off optimaztion," works fine for this use case but I have several of them that I now have to switch over and was hoping there was an easy way to do this.

I would not recommend using a Group or Scene device for this. While I'm glad it does work, I'm not sure they're really guaranteed to work in that way, and using one without any actual devices was certainly not the intent. If this behavior changes in the future, you'll be out of luck again. (Actually, a Scene device would probably work if you just rely on the button pushed event--calling the push() command should always generate an event--but you could do that with a virtual button, too.)

The typical workaround here is to use a virtual switch like you are. Hubitat's virtual switch driver has an "auto off" preference you can set to whatever value. This effectively makes it a momentary switch and, crucially, allows subsequent "On" commands to cause a state change (because it will be off) and an event (which you can use in apps that subscribe to this, like a webCoRE piston)--without you manually needing to set the switch to "off" in the meantime. This is a particularly good workaround for apps that only accept switches as "triggers." But it's a bit backwards from your description: the "resting state" here is off, not on. I'm not sure if that is crucial for your application. A custom driver could easily be written to reverse this (or to generate an event/"state change" with any command, even if the device is currently in that state if being able to do that is particularly important).

With a WebCoRE piston, you probably don't event need that: a virtual button device should be able to be used as a a trigger condition in a piston, and any push() (or similar button command/event) on that device should always be an event. This, of course, won't work if you have an app that requires a switch capability, but if it's just your piston, the design is entirely up to you, and this would work.

Is there a reason that one of the above will not work here?

Momentary buttons don't work for how I have my routines setup.

For example my Good Morning switch has an on that triggers certain things, like turning on my bathroom light and turning off my alarm. Then when I turn this virtual switch off it turns off the bathroom, turns my tv on and turns on the living room light. Sometimes my Harmony Hub sucks and will miss the command from webCoRE. In ST I could turn the light off again without turning it on and it would still trigger the webCoRE piston. Using auto switching as you can see would cause a lot of broken pistons.

Using a virtual button doesn't give me a way to have on/off for the switch...i.e. "Turn on Good Night and Turn off Good Night." My routines are all setup with switch capabilities.

So would a virtual switch driver that just sends an event any time an "on" or "off" command is issued, regardless of the current state, work? You could try this as a driver (just threw it together quick, but I tested and it seems to work):

/*

 * ========+=============  Virtual Switch: State Change (Driver) =======+==================

 *

 *  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.

 *

 * =======================================================================================

 *

 *  PLATFORM: Hubitat

 *  PURPOSE: Virtual switch driver that always causes events (state change) with on() or off() comamnds,

 *           regardless of current device state.

 *  Last modified: 2021-04-05

 *

 *  Changelog:

 *  v1.0    - Initial Release

 */ 

metadata {

   definition (name: "Virtual Switch: State Change", namespace: "RMoRobert", author: "Robert Morris", importUrl: "https://raw.githubusercontent.com/RMoRobert/Hubitat/master/drivers/virtual-switch-state-change.groovy") {

      capability "Actuator"

      capability "Switch"

   }

       

   preferences {

      input name: "autoOff", type: "enum", title: "Automatically switch back to off this many seconds after being turned on:",

         options: [[0:"Do not automatically switch off"],[1:"1 second"],[2:"2 seconds"],[5:"5 seconds"],[10:"10 seconds"],[30:"30 seconds"]]      

      input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true

      input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true 

   }

}

void installed() {

   log.debug "installed()"

}

void updated() {

   log.debug "updated()"

}

void on() {

   if (logEnable) log.debug "on()"

   sendEvent(name: "switch", value: "on", descriptionText: "${device.displayName} is on", isStateChange: true)

   if (txtEnable) log.info "${device.displayName} is on"

   if (autoOff) {

      Integer disableTime = autoOff as Integer

      if (disableTime > 0) {

         runIn(disableTime,"off")

      }

   }

}

void off() {

   if (logEnable) log.debug "off()"

   sendEvent(name: "switch", value: "off", descriptionText: "${device.displayName} is off", isStateChange: true)

   if (txtEnable) log.info "${device.displayName} is off"

}
2 Likes

For some reason Google Assistant kicks this back as an unsupported device.

I thought it was being finicky but even relinking it, it wouldn't be recognized by GAssistant.

My guess is that the driver is missing some capability definition that Google Home wants. Any GH users happen to know? (But I really can't think what more you could possibly use for a switch besides "Light", which if anything might confuse it more.) If it's a new device, I'd also toggle the state on/off once so you get "switch" under "Current States" on the device page, since it may also be picky about that (but if you're just switching from an existing driver, that should remain).

GAssistant was just being finicky.

Is there any chance you can create one like this for a virtual lock?

Sure! Assuming you just have a "plain" lock and don't need to worry about the lock code capability, something like this should work:

/*
 * ======================  Virtual Lock: State Change (Driver) ==========================
 *
 *  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.
 *
 * =======================================================================================
 *
 *  PLATFORM: Hubitat
 *  PURPOSE: Virtual lock driver that always causes events (state change) with lock() or unlock() comamnds,
 *           regardless of current device state.
 *  Last modified: 2021-04-10
 *
 *  Changelog:
 *  v1.0    - Initial Release
 */ 


metadata {
   definition (name: "Virtual Lock: State Change", namespace: "RMoRobert", author: "Robert Morris", importUrl: "https://raw.githubusercontent.com/RMoRobert/Hubitat/master/drivers/virtual/state-change/virtual-lock-state-change.groovy") {
      capability "Actuator"
      capability "Lock"
   }
       
   preferences { 
      input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
      input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true 
   }
}

void installed() {
   log.debug "installed()"
}

void updated() {
   log.debug "updated()"
}

void lock() {
   if (logEnable) log.debug "lock()"
   sendEvent(name: "lock", value: "locked", descriptionText: "${device.displayName} is locked", isStateChange: true)
   if (txtEnable) log.info "${device.displayName} is locked"
}

void unlock() {
   if (logEnable) log.debug "unlock()"
   sendEvent(name: "lock", value: "unlocked", descriptionText: "${device.displayName} is unlocked", isStateChange: true)
   if (txtEnable) log.info "${device.displayName} is unlocked"
}

Perfect I'm using it as a dummy lock so i can create a two factor auth on my locks via voice control if everyone is either not home or in bed... I'm having it be triggered by google with the community app...which will send a notification to tasker depending on those variables the actual lock won't unlock unless i press the notification on my phone.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.