Fibaro Dual Switch (not relay)

Hi All,

Does anyone have the device code for a fibaro dual switch (note relay).

I've tried the relay switch driver and this doesnt work.

The Fibari single switch driver works but only operates (not surpisingly) one of the two switches its connected to

Cheers,

D

Is this the one you are referring to?

This driver doesnโ€™t work, but I believe itโ€™s because itโ€™s for the relay version rather than the switch version(I have a mix of different types)

Cheers

I'm still unsure what switch you have.
If its the 222 then you use this to create the 2 switches.

/**
 *  Virtual Device Sync
 *
 *  Copyright 2018 Eric Maycock (erocm123)
 * 
 *
 *  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.
 *
 *  2018-03-27: Adapted for Hubitat
 */
 
definition(
   name: "Virtual Device Sync",
   namespace: "erocm123",
   author: "Eric Maycock",
   description: "Creates virtual devices and keeps them in sync with the selected physical device. Inteded to be used with devices with multiple relays, SmartLife RGBW, and Fibaro RGBW.",
   category: "Convenience",
   iconUrl: "https://github.com/erocm123/SmartThingsPublic/raw/master/smartapps/erocm123/virtual-device-sync.src/virtual-device-sync.png",
   iconX2Url: "https://github.com/erocm123/SmartThingsPublic/raw/master/smartapps/erocm123/virtual-device-sync.src/virtual-device-sync-2x.png",
   iconX3Url: "https://github.com/erocm123/SmartThingsPublic/raw/master/smartapps/erocm123/virtual-device-sync.src/virtual-device-sync-3x.png"
)

preferences {
    page(name: "setupPage")
    page(name: "createVirtual")
    page(name: "removeVirtual")
    page(name: "removalPage")
    page(name: "createPage")
}

def setupPage() {
    dynamicPage(name: "setupPage", install: true, uninstall: true) {
    section { 
        if(!isVirtualConfigured()){
           input "physical", "capability.switch", title: "Which Physical Switch", multiple: false, required: true, submitOnChange: true
           if(physical != null){
              paragraph "Device Handler: $physical.typeName\r\n\r\nDetected Number of Endpoints: ${getEndpoints()}\r\n\r\nRecommended Type: ${getType()}"
              input "virtualSwitchType", "enum", title: "Virtual Switch Type", value: getType() , multiple: false, required: true, options: ["Switch","Energy Switch","Dimmer"]
              app.updateSetting("virtualSwitchType", getType())
           }
           href "createVirtual", title:"Create Virtual Devices", description:"Create virtual devices"
        }else{
           def switchNames = ""
           getChildDevices().each {
               switchNames = switchNames + it.displayName + "\r\n"
           }
           paragraph "Chosen Device: $physical\r\n\r\nTo change to a different device, please remove the virtual devices below."
           paragraph "Device Handler: $physical.typeName\r\n\r\nDetected Number of Endpoints: ${getEndpoints()}\r\n\r\nRecommended Type: ${getType()}\r\n\r\nVirtual Switches have been created. They will be kept in sync with the physical switch chosen above\r\n\r\n$switchNames"
           href "removeVirtual", title:"Remove Virtual Devices", description:"Remove virtual devices"
        }
    }
    section([title:"Available Options", mobileOnly:true]) {
            input "setLabel", "boolean", title: "Change the default name of the app?", required: false, submitOnChange: true, value: false
            if (settings.setLabel != null && setLabel.toBoolean() == true) {
               label title:"Assign a name for your app (optional)", required:false
            } 
		}
    }
}

def createVirtual(){
   dynamicPage(name: "createVirtual", title: "Associate your device's endpoints with virtual devices", nextPage: "createPage") {
		section {
			paragraph "This process will create virtual devices and associate them with the endpoints on your physical device."
            def switchNames = ""
            for (int i = 1; i <= getEndpoints(); i++){
               
               if ((physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0) ||
               (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0)){
                  switchNames = switchNames + "$physical.displayName - ${getColor(i, "upper")} Channel\r\n"
               } else {
                  switchNames = switchNames + "$physical.displayName - ${i}\r\n"
               }
            }
            paragraph "The following switches will be created:\r\n\r\n" + switchNames
		}
    }
}

def createPage(){
   dynamicPage(name: "createPage", title: "Devices have been created", nextPage: "setupPage", createVirtualDevice())
}

def removeVirtual(){
   def switchNames = ""
   dynamicPage(name: "removeVirtual", title: "Remove the virtual switches created by this app", nextPage: "removalPage") {
		section {
			paragraph "This process will remove the virtual switches created by this program. Press next to continue"
            getChildDevices().each {
               switchNames = switchNames + it.displayName + "\r\n"
            }
            paragraph "The following virtual switches will be removed:\r\n\r\n" + switchNames
		}
    }
}

def removalPage(){
   dynamicPage(name: "removalPage", title: "Devices have been removed", nextPage: "setupPage", removeVirtualDevice()) 
}

def createVirtualDevice() {
    if(!isVirtualConfigured()){
       def switchName
       try {
          for (int i = 1; i <= getEndpoints(); i++){
             if ((physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0) ||
             (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0)){
                switchName = "$physical.displayName - ${getColor(i, "upper")} Channel\r\n"
             } else {
                switchName = "$physical.displayName - ${i}\r\n"
             }
             def switchType = ""
             if (virtualSwitchType != null && virtualSwitchType == "Switch"){
                switchType = "Simulated Switch"
             } else if (virtualSwitchType != null && virtualSwitchType == "Energy Switch") {
                switchType = "Simulated Energy Switch"
             } else {
                switchType = "Simulated Dimmer"
             }
             def child = addChildDevice("erocm123", switchType, getDeviceID(i), null, [name: getDeviceID(i), label: switchName, completedSetup: true])
          }   
       } catch (e) {
          return {
		   section {
			   paragraph "Error when creating the virtual devices. Make sure that you have all of the \"Simulated\" device handlers installed."
		   }
       }
    }
    return {
	   section {
	      paragraph "Devices have been configured. Press next to go to the main page."
	   }
    }
    }else{
       return {
	      section {
		     paragraph "Devices have already been configured."
		  }
       }
    }
}

def isVirtualConfigured(){ 
    def foundDevice = false
    getChildDevices().each {
       foundDevice = true
    }
    return foundDevice
}

def removeVirtualDevice() {
    try {
       unsubscribe()
       getChildDevices().each {
          deleteChildDevice(it.deviceNetworkId)
       }
       return {
          section {
	         paragraph "Devices have been removed. Press next to go to the main page."
	      }
       }
	} catch (e) {
       return {
          section {
			paragraph "Error: ${(e as String).split(":")[1]}."
	      }
       }
    }
}

private getDeviceID(number) {
    return "${app.id}-${number}"
}

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

def updated() {
  log.debug "Updated with settings: ${settings}"
  if(physical != null && setLabel != null && setLabel.toBoolean() != true){
     app.updateLabel("Virtual Device Sync - ${physical.label ? physical.label : physical.name}")
  }
  unsubscribe()
  initialize()
}

def initialize() {
  log.debug "Initializing Virtual Device Sync"
  if ((physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0) ||
  (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0)){
     subscribe(physical, "red", physicalHandler)
     subscribe(physical, "blue", physicalHandler)
     subscribe(physical, "green", physicalHandler)
     subscribe(physical, "white", physicalHandler) // Added for Fibaro RGBW Controller
     subscribe(physical, "white1", physicalHandler)
     subscribe(physical, "white2", physicalHandler)
     subscribe(physical, "redLevel", physicalHandler)
     subscribe(physical, "blueLevel", physicalHandler)
     subscribe(physical, "greenLevel", physicalHandler)
     subscribe(physical, "whiteLevel", physicalHandler) // Added for Fibaro RGBW Controller
     subscribe(physical, "white1Level", physicalHandler)
     subscribe(physical, "white2Level", physicalHandler)
  } else {
     for (int i = 1; i <= getEndpoints(); i++){
        subscribe(physical, "switch${i}", physicalHandler)
        subscribe(physical, "power${i}", powerHandler)
        subscribe(physical, "energy${i}", energyHandler)
     }
  }
  getChildDevices().each {
     subscribe(it, "switch", virtualHandler)
  }
}

def virtualHandler(evt) {
    log.debug "virtualHandler called with event: deviceId ${evt.deviceId} name:${evt.name} source:${evt.source} value:${evt.value} isStateChange: ${evt.getIsStateChange()} isPhysical: ${evt.isPhysical()} isDigital: ${evt.isDigital()} data: ${evt.data} device: ${evt.device}"
    getChildDevices().each {
        if ("${evt.deviceId}" == "${it.id}") {
          def switchNumber = it.deviceNetworkId.split("-")[1]
          if ((physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0 && !(physical.typeAuthor.toUpperCase().indexOf("LOMAS") >= 0)) ||
          (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0)){
             switch (evt.value){
                case "setLevel":
                   physical."set${getColor(switchNumber.toInteger()).capitalize()}Level"(it.currentValue("level"))
                break
                default:
                   physical."${getColor(switchNumber.toInteger())}${evt.value.capitalize()}"()
                break
             }
          } else if (physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0) {
             switch (evt.value){
                case "setLevel":
                   physical."setLevel${getColor(switchNumber.toInteger()).capitalize()}"(it.currentValue("level"))
                break
                default:
                   physical."${evt.value}${getColor(switchNumber.toInteger()).capitalize()}"()
                break
             }
          } else {
             switch (evt.value){
                case "setLevel":
                   physical."setLevel${switchNumber}"(it.currentValue("level"))
                break
                default:
                   physical."${evt.value}${switchNumber}"()
                break
             }
          }
       }
    }
}

def physicalHandler(evt) {
  log.debug "physicalHandler called with event:  name:${evt.name} source:${evt.source} value:${evt.value} isStateChange: ${evt.getIsStateChange()} isPhysical: ${evt.isPhysical()} isDigital: ${evt.isDigital()} data: ${evt.data} device: ${evt.device}"
  if ((physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0) ||
  (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0)){
     switch(evt.name){
        case ~/.*Level.*/:
           getChildDevice("${app.id}-${getSwitchNumber(evt.name)}").extSendEvent([name:"level", value:"$evt.value", type:"physical"])
        break
        default:
           getChildDevice("${app.id}-${getSwitchNumber(evt.name)}").extSendEvent([name:"switch", value:"$evt.value", type:"physical"])
        break
  }
  } else {
     switch(evt.name){
        case ~/.*Level.*/:
           getChildDevice("${app.id}-${getSwitchNumber(evt.name)}").extSendEvent([name:"level", value:"$evt.value", type:"physical"])
        break
        default:
           getChildDevice("${app.id}-${getSwitchNumber(evt.name)}").extSendEvent([name:"switch", value:"$evt.value", type:"physical"])
        break
     }
  }
}

def powerHandler(evt) {
   log.debug "powerHandler called with event:  name:${evt.name} source:${evt.source} value:${evt.value} isStateChange: ${evt.isStateChange()} isPhysical: ${evt.isPhysical()} isDigital: ${evt.isDigital()} data: ${evt.data} device: ${evt.device}"
   getChildDevice("${app.id}-${getSwitchNumber(evt.name)}").extSendEvent([name:"power", value:"$evt.value"])
}

def energyHandler(evt) {
   log.debug "energyHandler called with event:  name:${evt.name} source:${evt.source} value:${evt.value} isStateChange: ${evt.isStateChange()} isPhysical: ${evt.isPhysical()} isDigital: ${evt.isDigital()} data: ${evt.data} device: ${evt.device}"
   getChildDevice("${app.id}-${getSwitchNumber(evt.name)}").extSendEvent([name:"energy", value:"$evt.value"])
}


private getColor(number, format = null){
   switch (number) {
      case 1:
         if(format == "upper") return "R" else if(format == "lower") return "r" else return "red"
      break
      case 2:
         if(format == "upper") return "G" else if(format == "lower") return "g"  else return "green"
      break
      case 3:
         if(format == "upper") return "B" else if(format == "lower") return "b"  else return "blue"
      break
      case 4:
         if (physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0){
            if(format == "upper") return "W" else if(format == "lower") return "w"  else return "white"
         } else {
            if(format == "upper") return "W1" else if(format == "lower") return "w1"  else return "white1"
         }
      break
      case 5:
         if(format == "upper") return "W2" else if(format == "lower") return "w2"  else return "white2"
      break
   }
}

private getSwitchNumber(value){
   switch (value) {
      case ~/.*red.*/:
         return 1
      break
      case ~/.*green.*/:
         return 2
      break
      case ~/.*blue.*/:
         return 3
      break
      case ~/.*white1.*/:
         return 4
      break
      case ~/.*white2.*/:
         return 5
      break
      case ~/.*white.*/:
         return 4
      break
      case ~/.*switch.*/:
         return value.substring(6).toInteger()
      break
      case ~/.*energy.*/:
         return value.substring(6).toInteger()
      break
      case ~/.*power.*/:
         return value.substring(5).toInteger()
      break
   }
}

private getEndpoints() {
   def endpoints = 0
   if (physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0){
      endpoints = 4
   } else if (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0){
      endpoints = 5
   } else {
      physical.supportedCommands.each {
         switch (it) {     
            case ~/.*on.*/:
               for (int i = 1; i <= 10; i++){
                  if (it.toString().indexOf("$i") >= 0) if (i > endpoints) endpoints = i
               }
            break
         }
      }
   } 
   return endpoints
}

private getType() {
   String hasCapability = ""
   
   if (physical.hasCapability("Switch")) {
      hasCapability = "Switch"
   }
   if ((physical.hasCapability("Power Meter")) || (physical.hasCapability("Energy Meter"))) {
      hasCapability = "Energy Switch"
   }
   if (physical.hasCapability("Switch Level")) {
      hasCapability = "Dimmer"
   }
   if ((physical.typeName.toUpperCase().indexOf("FIBARO") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0) ||
   (physical.typeName.toUpperCase().indexOf("SMARTLIFE") >= 0 && physical.typeName.toUpperCase().indexOf("RGBW") >= 0)) {
      hasCapability = "Dimmer"
   }
   
   
   return hasCapability
}

After a bit of research its a FGS-223

Assign the 222 driver to the device.
Try creating the 2 virtual switches for the relay using the app above.
Then see if you can turn on and off each virtual device that has been created for the Fibaro.

Sadly this doesnt work ..

Oh well. Worth a try.
Can't say I've see a 223 driver published by anyone.

Maybe some of this can be ported ?

1 Like

Hi There

I see there has been no response in a few months
I have a number of Fibaro FSG-223's Dual Switch 2 here talking to my STT Hub. Only 1 FGS-222.
Did anyone get a device handler working?

I am planning my migration of all switches, motion sensors, contacts etc from STT to my new Hubitat and would appreciate your advice..

So I have got my FGS-223's working using the Dual Relay Driver.
But I notice that the driver is generating a load of messages in the Log. Is this an issue to be concerned about as the switches are working all ok

If no error(red) on the logs then it's ok, probably you can turn off the logs but if no option to turn off it's ok too, some ported drivers doesn't have the option.

Hello,
I have the same problem. I am new to Hubitat, I've been a Vera user since the beginning and this a whole different approach for me.
Anyways, I have a Fibaro FGS-222 which is found correctly, I since then installed following drivers:
222 driver, metered service, the virtual device sync app and simulated switch.
The virtual device sync creates 2 child nodes which I can control. The physical switch is momentary (has a spring) and my problem is: No matter if I press the physical button or the button on the webbpage ON will light upp the lamp right away, however, OFF will have a delay of c:a 10 seconds.



Hope somebody can help, I happen to have quite a few of these FGS-222.