Z Wave Poller on Fibaro Roller Shutter 2

Hi, first of all thanks for all the valuable contributions. It helped me a lot doing the switch from Zipato towards HE about a month ago and I am quite satisfied.

My setup: I am running around 50 Z-Wave dimmers, switches, motion sensors, smoke and water detectors, all from Fibaro

Here is my current problem: I have 18 "Fibaro Roller Shutter 2" that run all my shades. Based on the feedback of other users I set these up as "Generic Z-Wave Dimmers". All shades are automated based on room temperature, day time, outside lux levels and current state of each shade.

Unfortunately, HE does not seem to get any correct states for these "dimmers". I have installed "Z-Wave Poller" and started polling ALL of these dimmers but it does not seem to work at all. If I hit the "Poll" or "Refresh" switch manually in the devices section it will also not update to the correct state, so I suppose this may be a driver problem?

Can anyone please help here?

Thanks
Christian

If you don't get the correct value when refreshing, it is likely either:

  1. a driver issue (most likely)
  2. a communication issue to the device (less likely if the level commands are working)
  3. your zwave mesh is saturated/bogged down (can happen, but again, if the level commands are working that probably isn't it).
  4. Reports aren't associated with the hub (can happen). Try hitting Configure on the device details page, and see if status reports start working if you hit Refresh.

So, for driver issues you have 3 options:

  1. Submit a support ticket/email and see if you can get @mike.maxwell to look at it.
  2. See if the user community already made a user driver for it
  3. See if there is a SmartThings user driver for it, and port it to Hubitat

Thanks Jason for your quick reply. I think I can rule out #2 and #3. #4 I tried and it did not get me any positive results.

So I will start looking into the driver issue as recommended.

Assuming it is an FGR-222, this seems to be the most commonly used user driver on SmartThings maybe worth a shot in porting it:

@christian1 I had a few minutes, so made a quick port for you.

No idea if it works (very likely it does not, at least not fully) as I don't have one of these devices. But it may give you a head start:
https://raw.githubusercontent.com/Botched1/Hubitat/master/Drivers/Fibaro%20FGR-222/FGR-222.groovy

Install as a user driver, change the driver on one of the shutter devices to this driver, save, click Configure, test it out.

2 Likes

Awesome! Many thanks for your great support JasonJoel!

I did a quick test-run and your port seems to resolve my issue. It now automatically updates the current position and also gives me live power consumption and other parameters I did not get before.

I can recommend this to anyone who is running the Fibaro Roller Shutters 2 (FGR-222)

1 Like

Thank Fibaro for sticking to the zwave specs and not doing something crazy in their driver...

To be fair, the guy that wrote the SmartThings driver did all of the real work, I just massaged it for the couple of changes needed to get it to work in Hubitat. That is why I just left all of the credits in the driver to him.

Has anyone tried the ported driver with the Fibaro Rolling Shutter v3 (FGR-223) yet?

Hi, interested in the roller shutter 2 driver you massaged but link is broken... Dontas you have it anymore? /Mattias

Hi do you have the driver still available? Jasonjoel s lik is broken.. /MAttias

Hi does anyone still have the above driver for the FGR 222? The above link is busted unfortunately

Looked like I deleted it a while back during housecleaning as I didn't think it was needed any more.

No problem sorry I bothered you, maybe the OP still has the driver and can share it.

Here you go. No idea if it works any more.

Driver
metadata {
    definition (name: "Fibaro FGR-222", namespace: "julienbachmann", author: "Julien Bachmann") {
        capability "Sensor"
        capability "Actuator"

        capability "Switch"
        capability "Switch Level"
        capability "Window Shade"

        capability "Polling"
        capability "Power Meter"
        capability "Energy Meter"
        capability "Refresh"
        capability "Configuration"

        attribute "syncStatus", "enum", ["syncing", "synced"]

        command "sync"
        command "stop"        
        command "up"   
        command "down"   

        fingerprint inClusters: "0x26,0x32"
    }

    preferences {
        input name: "invert", type: "bool", title: "Invert up/down", description: "Invert up and down actions"
        input name: "openOffset", type: "decimal", title: "Open offset", description: "The percentage from which shutter is displayerd as open"
        input name: "closeOffset", type: "decimal", title: "Close offset", description: "The percentage from which shutter is displayerd as close"
        input name: "offset", type: "decimal", title: "offset", description: "This offset allow to correct the value returned by the device so it match real value"

        section {
            input (
                type: "paragraph",
                element: "paragraph",
                title: "DEVICE PARAMETERS:",
                description: "Device parameters are used to customise the physical device. " +
            "Refer to the product documentation for a full description of each parameter."
        )

            getParamsMd().findAll( {!it.readonly} ).each { // Exclude readonly parameters.

                def lb = (it.description.length() > 0) ? "\n" : ""

                switch(it.type) {
                    case "number":
                        input (
                            name: "configParam${it.id}",
                        title: "#${it.id}: ${it.name}: \n" + it.description + lb +"Default Value: ${it.defaultValue}",
                        type: it.type,
                        range: it.range,
                        required: it.required
                    )
                        break

                    case "enum":
                        input (
                            name: "configParam${it.id}",
                        title: "#${it.id}: ${it.name}: \n" + it.description + lb + "Default Value: ${it.defaultValue}",
                        type: it.type,
                        options: it.options,
                        required: it.required
                    )
                        break
                }
            }
        } // section
    }
}

def parse(String description) {
    log.debug("parse ${description}")
    def result = null
    def cmd = zwave.parse(description, [0x20: 1, 0x26: 3, 0x70: 1, 0x32:3])
    if (cmd) {
        result = zwaveEvent(cmd)
        if (result) {
            log.debug("Dispatch events ${result}")
        }
    } else {
        log.debug("Couldn't zwave.parse ${description}")
    }
    result
}

def correctLevel(value) {
    def result = value
    if (value == "off") {
        result = 0;
    }
    if (value == "on" ) {
        result = 100;
    }
    result = result - (offset ?: 0)
    if (invert) {
        result = 100 - result
    }
    return result
}

def createWindowShadeEvent(value) {
    def theWindowShade = "partially open"
    if (value >= (openOffset ?: 95)) {
        theWindowShade = "open"
    }
    if (value <= (closeOffset ?: 5)) {
        theWindowShade = "closed"
    }
    return createEvent(name: "windowShade", value: theWindowShade)
}

def createSwitchEvent(value) {
    def switchValue = "on"
    if (value >= (openOffset ?: 95)) {
        switchValue = "on"
    }
    if (value <= (closeOffset ?: 5)) {
        switchValue = "off"
    }
    return createEvent(name: "switch", value: switchValue)
}

def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd) {
    logger.debug("basic report ${cmd}")
    def result = []
    if (cmd.value != null) {
        def level = correctLevel(cmd.value)
        result << createEvent(name: "level", value: level, unit: "%")  
        if (device.currentValue('windowShade') == "opening" || device.currentValue('windowShade') == "closing") {
        	result << response([zwave.meterV2.meterGet(scale: 2).format()])
        }
        else {
            result << createWindowShadeEvent(level) 
        }        
    }
    log.debug("basic result ${result}")
    return result
}

def zwaveEvent(hubitat.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) {
    log.debug("switch multi level report ${cmd.value}")
    def result = []
    if (cmd.value != null) {
        def level = correctLevel(cmd.value)
        result << createEvent(name: "level", value: level, unit: "%")   
        if (device.currentValue('windowShade') == "opening" || device.currentValue('windowShade') == "closing") {
        	result << response([zwave.meterV2.meterGet(scale: 2).format()])
        }
        else {
            result << createWindowShadeEvent(level) 
        }
    }
    log.debug("switch result ${result}")
    return result
}

def zwaveEvent(hubitat.zwave.Command cmd) {
    log.debug("other event ${cmd}")
}

def zwaveEvent(hubitat.zwave.commands.meterv3.MeterReport cmd) {
    if (cmd.meterType == 1) {
        if (cmd.scale == 2) {
            def result = []
            result << createEvent(name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W")
            if (cmd.scaledMeterValue < 1.0) {
              result << createWindowShadeEvent(device.currentValue('level'))
              result << response(["delay 500", zwave.switchMultilevelV3.switchMultilevelGet().format()])
            }
            else {
              result << response(["delay 2000", zwave.switchMultilevelV3.switchMultilevelGet().format()])
            }
            log.debug("power result ${result}")
            return result
        } else {
            return createEvent(name: "electric", value: cmd.scaledMeterValue, unit: ["pulses", "V", "A", "R/Z", ""][cmd.scale - 3])
        }
    }
}

def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
    log.debug("zwaveEvent(): Configuration Report received: ${cmd}")
}

def updated() {
    setSynced();
}

def on() {
    open()
}

def off() {
    close()
}

def stop() {
    def cmds = []
    logger.debug("stop")
	cmds << zwave.switchMultilevelV1.switchMultilevelStopLevelChange().format()
    cmds << zwave.switchMultilevelV3.switchMultilevelGet().format()
    return delayBetween(cmds, 2000)
}

def up() {
    def currentWindowShade = device.currentValue('windowShade')
    if (currentWindowShade == "opening" || currentWindowShade == "closing") {      
        return stop()        
    }
    return open()
}

def down() {
    def currentWindowShade = device.currentValue('windowShade')
    if (currentWindowShade == "opening" || currentWindowShade == "closing") {
        return stop()        
    }
    return close()
}

def open() {
    logger.debug("open")
    sendEvent(name: "windowShade", value: "opening")
    if (invert) {
        return privateClose()
    }
    else {
        return privateOpen()
    }
}

def close() {
    logger.debug("close")
    sendEvent(name: "windowShade", value: "closing")    
    if (invert) {
        return privateOpen()
    }
    else {
        return privateClose()
    }
}

def privateOpen() {
    def cmds = []
    cmds << zwave.basicV1.basicSet(value: 0xFF).format()
    cmds << zwave.switchMultilevelV3.switchMultilevelGet().format()
    log.debug("send CMD: ${cmds}")
    return delayBetween(cmds, 2000)
}

def privateClose() {
    def cmds = []
    cmds << zwave.basicV1.basicSet(value: 0).format()
    cmds << zwave.switchMultilevelV3.switchMultilevelGet().format()
    log.debug("send CMD: ${cmds}")
    return delayBetween(cmds, 2000)
}

def presetPosition() {
    setLevel(50)
}

def poll() {
    delayBetween([
        zwave.meterV2.meterGet(scale: 0).format(),
        zwave.meterV2.meterGet(scale: 2).format(),
], 1000)
}

def refresh() {
    log.debug("refresh")
    delayBetween([
        zwave.switchMultilevelV3.switchMultilevelGet().format(),
        zwave.meterV2.meterGet(scale: 2).format(),
], 500)
}

def setLevel(level) {
    if (invert) {
        level = 100 - level
    }
    if(level > 99) level = 99
    if (level <= (openOffset ?: 95) && level >= (closeOffset ?: 5)) {
        level = level - (offset ?: 0)
    }

    log.debug("set level ${level}")
    delayBetween([
        zwave.basicV1.basicSet(value: level).format(),
        zwave.switchMultilevelV1.switchMultilevelGet().format()
], 10000)
}

def configure() {
    log.debug("configure roller shutter")
    delayBetween([
        zwave.configurationV1.configurationSet(parameterNumber: 29, size: 1, scaledConfigurationValue: 1).format(),  // start calibration
        zwave.switchMultilevelV1.switchMultilevelGet().format(),
        zwave.meterV2.meterGet(scale: 0).format(),
        zwave.meterV2.meterGet(scale: 2).format(),
], 500)
}

def sync() {
    log.debug("sync roller shutter")
    def cmds = []
    sendEvent(name: "syncStatus", value: "syncing", isStateChange: true)
    getParamsMd().findAll( {!it.readonly} ).each { // Exclude readonly parameters.
        if (settings."configParam${it.id}" != null) {
            cmds << zwave.configurationV1.configurationSet(parameterNumber: it.id, size: it.size, scaledConfigurationValue: settings."configParam${it.id}".toInteger()).format()
            cmds << zwave.configurationV1.configurationGet(parameterNumber: it.id).format()
        }
    }
    log.debug("send cmds ${cmds}")
    runIn(0.5 * cmds.size(), setSynced)
    delayBetween(cmds, 500)
}

def setSynced() {
    log.debug("Synced")
    sendEvent(name: "syncStatus", value: "synced", isStateChange: true)
}

private getParamsMd() {
    return [
        [id:  3, size: 1, type: "number", range: "0..1", defaultValue: 0, required: false, readonly: false,
        name: "Reports type",
        description: "0 – Blind position reports sent to the main controller using Z-Wave Command Class.\n" +
    "1 - Blind position reports sent to the main controller using Fibar Command Class.\n" +
    "Parameters value shoud be set to 1 if the module operates in Venetian Blind mode."],
    [id:  10, size: 1, type: "number", range: "0..4", defaultValue: 0, required: false, readonly: false,
        name: "Roller Shutter operating modes",
        description: "0 - Roller Blind Mode, without positioning\n" +
    "1 - Roller Blind Mode, with positioning\n" +
    "2 - Venetian Blind Mode, with positioning\n" +
    "3 - Gate Mode, without positioning\n" +
    "4 - Gate Mode, with positioning"],
    [id: 12, size:2, type: "number", range: "0..65535", defaultValue: 0, required: false, readonly: false,
        name: "Time of full turn of the slat",
        description: "In Venetian Blind mode (parameter 10 set to 2) the parameter determines time of full turn of the slats.\n" +
    "In Gate Mode (parameter 10 set to 3 or 4) the parameter defines the COUNTDOWN time, i.e. the time period after which an open gate starts closing. In any other operating mode the parameter value is irrelevant.\n" +
    "Value of 0 means the gate will not close automatically.\n" +
    "Available settings: 0-65535 (0 - 655,35s)\n" +
    "Default setting: 150 (1,5 s)"],
    [id: 13, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Set slats back to previous position",
        description: "In Venetian Blind Mode (parameter 10 set to 2) the parameter influences slats positioning in various situations. In any other operating mode the parameter value is irrelevant.\n" +
    "0 - Slats return to previously set position only in case of the main controller operation\n" +
    "1 - Slats return to previously set position in case of the main controller operation, momentary switch operation, or when the limit switch is reached.\n" +
    "2 - Slats return to previously set position in case of the main controller operation, momentary switch operation, when the limit switch is reached or after " +
    " receiving a β€œSTOP” control frame (Switch Multilevel Stop)."],
    [id: 14, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Switch type",
        description: "The parameter settings are relevant for Roller Blind Mode and Venetian Blind Mode (parameter 10 set to 0, 1, 2).\n" +
    "0 - Momentary switches\n" +
    "1 - Toggle switches\n" +
    "2 - Single, momentary switch. (The switch should be connected to S1 terminal)"],
    [id: 18, size:1, type: "number", range: "0..255", defaultValue: 0, required: false, readonly: false,
        name: "Motor operation detection.",
        description: "Power threshold to be interpreted as reaching a limit switch. \n" +
    "Available settings: 0 - 255 (1-255 W)\n" +
    "The value of 0 means reaching a limit switch will not be detected \n" +
    "Default setting: 10 (10W)."],
    [id: 22, size:2, type: "number", range: "0..65535", defaultValue: 0, required: false, readonly: false,
        name: "Motor operation time.",
        description: "Time period for the motor to continue operation. \n" +
    "Available settings: 0 – 65535 (0 – 65535s)\n" +
    "The value of 0 means the function is disabled.\n" +
    "Default setting: 240 (240s. – 4 minutes)"],
    [id: 30, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Response to general alarm",
        description: "0 - No reaction.\n" +
    "1 - Open blind.\n" +
    "2 - Close blind."],
    [id: 31, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Response to flooding alarm",
        description: "0 - No reaction.\n" +
    "1 - Open blind.\n" +
    "2 - Close blind."],
    [id: 32, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Response to smoke, CO or CO2 alarm",
        description: "0 - No reaction.\n" +
    "1 - Open blind.\n" +
    "2 - Close blind."],
    [id: 33, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Response to temperature alarm",
        description: "0 - No reaction.\n" +
    "1 - Open blind.\n" +
    "2 - Close blind."],
    [id: 35, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Managing slats in response to alarm.",
        description: "0 - Do not change slats position - slats return to the last set position\n" +
    "1 - Set slats to their extreme position"],
    [id: 40, size:1, type: "number", range: "0..2", defaultValue: 0, required: false, readonly: false,
        name: "Power reports",
        description: "Power level change that will result in new power value report being sent." +
    "The parameter defines a change that needs to occur in order to trigger the report. The value is a percentage of the previous report.\n" +
    "Power report threshold available settings: 1-100 (1-100%).\n" +
    "Value of 0 means the reports are turned off."]

]
}
1 Like

Excellent thank you man!

No problem - just had to go dig it out of github deletion history. I should have done that when asked last time - just forgot. :confused:

I really appreciate you taking the time, just making the switch from ST but those drivers were holding me back.

1 Like

Hi. I'm a brand new user to Hubitat and this is the first driver I've added as I'm migrating from SmartThings. I seem to have it working, I struggled initially as I wasn't sure how to calibrate it and the position was reading a level of 254 when transitioning from open > close, close > open. The configure button resolved this.

What I can't do that I could in SmartThings is read the preferences. I have the preference panes visible, but when I enter a value for each option and save the preferences, the number disappears from the pane so I cannot read what is set/current. How can I see these settings as at a glance it's not obvious and I have to trust that the value has been saved correctly.

Another issue that I've discovered is that if I open the curtain attached using the manual wall mounted button connected to the Fibaro module, the status is not updated on my SharpTools panel. The ones that are still connected to the SmartThings Hub are slow to update SharpTools but the one now connected to Hubitat doesn't update at all.

The driver of the FGR 222 does not work in the Hubitat C7.

Could someone make this work for the Hubitat C7?

Thanks

And the link doesn't work