Somfy ZWave Blinds (Dimmer)

This is the DTH that worked in ST. I managed to port the driver over to hubitat, but open/close on/off do not work.

/**
 * 
 *
 * Version 1.0.7
 *
 * Version History
 *
 * 1.0.7    26 Mar 2017		Few updates  (be sure to go into each device, select settings (gear), and hit done
 * 1.0.6    29 Dec 2016		Health Check
 * 1.0.5    01 May 2016		bug fixes
 * 1.0.4    01 May 2016		Sync commands for cases where blinds respond to multiple channels (all vs. single)
 * 1.0.3    17 Apr 2016		Expanded runIn timer for movement and  completed states
 * 1.0.2    04 Apr 2016		Added runIn timer for movement vs. completed states
 * 1.0.1    07 Mar 2016		Add Blinds support by edit device to set to blinds type
 * 1.0.0    24 Feb 2016		Multi-tile, Window Shade Capability, Device Handler attempts to maintain state
 *
 * Notes:
 *
 * Somfy ZRTSII does not report accurate status for the device.
 *
 * This device handler maintains an internal view of device status based on last command
 * reissuing a command to the shade (up, down, preset (when stopped)) does not move the shade/blinds if it is already in that position
 * My/stop command does different actions depending if the shade is idle (go to MY or closed position) or moving (stop)
 *
 * Once the device is installed, it defaults to "shade" operation.  If "blinds" operation is desired, for the device go to settings (gear)
 * and change the device operation to Window Blinds
 *
 *	Shade and Blinds operate differently in ZRTSII buttons
 *	- Shades actions: up button: open (on switch),  down button: close (off switch),       my/stop button: presetPosition (50%)
 *	- Blinds actions: up button: open (on switch),  down button: tilt open (off switch),   my/stop button: close (50%)
 *
 * Window Shade Capability standardizes:  (these should not be changed, except by SmartThings capabilities updates)
 *	- windowShade: unknown, closed, open, partially open, closing, opening 
 *	- Commands:  open(), close(), presetPosition()
 *
 */
  metadata {
    definition (name: "Somfy Z-Wave Shades and Blinds Multi tile", namespace: "E_Sch", author: "Eric, Ash, Others") {
        capability "Switch Level"
        capability "Switch"
        capability "Window Shade"
        //capability "Polling"
        capability "Refresh"
        capability "Actuator"
        capability "Health Check"

        attribute "stopStr", "enum", ["preset/stop", "close/stop"]

        command "OpenSync"
        command "CloseSync"
        command "TiltSync"
        command "levelOpenClose", [ "number" ]

	attribute "lastPoll", "STRING"

        fingerprint deviceId: "0x1105", inClusters: "0x2C, 0x72, 0x26, 0x20, 0x25, 0x2B, 0x86"
    }

    simulator {
        status "on":  "command: 2003, payload: FF"
        status "off": "command: 2003, payload: 00"
        status "09%": "command: 2003, payload: 09"
        status "10%": "command: 2003, payload: 0A"
        status "33%": "command: 2003, payload: 21"
        status "66%": "command: 2003, payload: 42"
        status "99%": "command: 2003, payload: 63"
        
        // reply messages
        reply "2001FF,delay 5000,2602": "command: 2603, payload: FF"
        reply "200100,delay 5000,2602": "command: 2603, payload: 00"
        reply "200119,delay 5000,2602": "command: 2603, payload: 19"
        reply "200132,delay 5000,2602": "command: 2603, payload: 32"
        reply "20014B,delay 5000,2602": "command: 2603, payload: 4B"
        reply "200163,delay 5000,2602": "command: 2603, payload: 63"
    }

    preferences {
	input ("shadeType", "enum", options:[
		"shades": "Window Shades",
		"blinds": "Window Blinds"],
		title: "Window Shades or Blinds?", description: "set type (shades or blinds)", defaultValue: "shades",
                required: false, displayDuringSetup: true )
	}

    tiles(scale: 2) {
        multiAttributeTile(name:"shade", type: "lighting", width: 6, height: 4) {
            tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") {
                attributeState("unknown", label:'${name}', action:"refresh.refresh", icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e")
                attributeState("closed",  label:'${name}', action:"open", icon:"st.doors.garage.garage-closed", backgroundColor:"#bbbbdd", nextState: "opening")
                attributeState("open",    label:'up', action:"close", icon:"st.doors.garage.garage-open", backgroundColor:"#ffcc33", nextState: "closing")
                attributeState("partially open", label:'preset', action:"presetPosition", icon:"st.Transportation.transportation13", backgroundColor:"#ffcc33")
                attributeState("closing", label:'${name}', action:"presetPosition", icon:"st.doors.garage.garage-closing", backgroundColor:"#bbbbdd")
                attributeState("opening", label:'${name}', action:"presetPosition", icon:"st.doors.garage.garage-opening", backgroundColor:"#ffcc33")
            }
            tileAttribute ("device.level", key: "SLIDER_CONTROL") {
                attributeState("level", action:"switch level.setLevel")
            }
            tileAttribute ("device.speedLevel", key: "VALUE_CONTROL") {
                attributeState("level", action: "levelOpenClose")
            }
        }

        standardTile("switchmain", "device.windowShade") {
            state("unknown", label:'${name}', action:"refresh.refresh", icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e")
            state("closed",  label:'${name}', action:"open", icon:"st.doors.garage.garage-closed", backgroundColor:"#bbbbdd", nextState: "opening")
            state("open",    label:'up', action:"close", icon:"st.doors.garage.garage-open", backgroundColor:"#ffcc33", nextState: "closing")
            state("partially open", label:'preset', action:"presetPosition", icon:"st.Transportation.transportation13", backgroundColor:"#ffcc33")
            state("closing", label:'${name}', action:"presetPosition", icon:"st.doors.garage.garage-closing", backgroundColor:"#bbbbdd")
            state("opening", label:'${name}', action:"presetPosition", icon:"st.doors.garage.garage-opening", backgroundColor:"#ffcc33")

//            state("on", label:'up', action:"switch.off", icon:"st.doors.garage.garage-open", backgroundColor:"#ffcc33")
//            state("off", label:'closed', action:"switch.on", icon:"st.doors.garage.garage-closed", backgroundColor:"#bbbbdd")
//            state("default", label:'preset', action:"presetPosition", icon:"st.Transportation.transportation13", backgroundColor:"#ffcc33")
        }

        standardTile("on", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state("on", label:'open', action:"switch.on", icon:"st.doors.garage.garage-opening")
        }
        standardTile("off", "device.stopStr", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state("close/stop", label:'close/stop', action:"switch.off", icon:"st.doors.garage.garage-closing")
            state("default", label:'close', action:"switch.off", icon:"st.doors.garage.garage-closing")
        }
        standardTile("preset", "device.stopStr", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state("close/stop", label:'slats open', action:"switch level.setLevel", icon:"st.Transportation.transportation13")
            state("default", label:'preset/stop', action:"switch level.setLevel", icon:"st.Transportation.transportation13")
        }
        controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false) {
            state("level", action:"switch level.setLevel")
        }

        standardTile("refresh", "command.refresh", width:2, height:2, inactiveLabel: false, decoration: "flat") {
                state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
        }

//  Poll provides data, but the ZRTSII does not provide accurate status
//
//      standardTile("poll", "command.poll", width:2, height:2, inactiveLabel: false, decoration: "flat") {
//              state "default", label:'poll', action:"poll", icon:"st.secondary.poll"
//      }

        main(["switchmain"])
        details(["shade", "on", "off", "preset"])
    }
}

def configure() {
    log.trace "configure() called"
    updated()
}

def ping() {
	log.trace "ping called"
	def now=new Date()
	def tz = location.timeZone
	def nowString = now.format("MMM/dd HH:mm",tz)
	sendEvent("name":"lastPoll", "value":nowString, displayed: false)
	refresh()
}

def updated() {
    log.trace "updated() called"

    sendEvent(name: "checkInterval", value: 60 * 60 * 1, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID], displayed: false)

    def currstat = device.latestValue("level")
    def currstat1 = device.latestValue("windowShade")

    log.debug "Shade type: ${settings?.shadeType}"
    if (settings?.shadeType) {
        if (settings.shadeType == "shades") {
            sendEvent(name: "stopStr", value: "preset/stop")
        } else {
            sendEvent(name: "stopStr", value: "close/stop")
        }
    } else {
        sendEvent(name: "stopStr", value: "preset/stop")
    }

    log.debug "switch state: ${currstat}  windowShade state: ${currstat1}"
    if ( (currstat == null) || (currstat1 == null)) {
        if (currstat > null) {
            if (currstat >= 75) {
                //sendEvent(name: "windowShade", value: "open")
                finishOpenShade()
            } else if (currstat <= 25) {
                //sendEvent(name: "windowShade", value: "closed")
                finishCloseShade()
            } else {
                //sendEvent(name: "windowShade", value: "partially open")
                finishPartialOpenShade()
            }
        }
    }
}

def parse(String description) {
    description
    def result = []
    def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
    //log.debug "Parsed ${description} to ${cmd}"
    if (cmd) {
        result = zwaveEvent(cmd)
        log.debug "zwaveEvent( ${cmd} ) returned ${result.inspect()}"
    } else {
        log.debug "Non-parsed event: ${description}"
    }
    def now=new Date()
    def tz = location.timeZone
    def nowString = now.format("MMM/dd HH:mm",tz)
    result << createEvent("name":"lastPoll", "value":nowString, displayed: false)
    return result
}

def levelOpenClose(value) {
    log.trace "levelOpenClose called with value $value"
    if (value) {
        on()
    } else {
        off()
    }
}

// Somfy ZRTSII does not report accurate status for the device.
// This device handler maintains an internal view of device status based on last command
// reissuing a command to the shade (up, down, preset (my) (when stopped)) does not move the shade if it is already in that position
// My/stop command does different actions depending if the shade is idle (go to MY position) or moving (stop)

def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd)
{
    def result = []
    def tempstr = ""
    def statstr = "SAME"

    //log.trace "Basic report cmd.value:  ${cmd.value}"

    if (cmd.value == 0) {
        //result << createEvent(name: "switch", value: "off")

        tempstr = "closed"
        if (settings?.shadeType) {
            if (settings.shadeType == "blinds") {
                tempstr = "tilted open"
            }
        }
    } else if (cmd.value == 0xFF) {
        //result << createEvent(name: "switch", value: "on")
        tempstr = "open"

    } else {  // This has never happend
        //result << createEvent(name: "switch", value: "default")
        tempstr="neither open or closed"
    }
    def swstatstr = "${device.latestValue('switch')}"
    if (cmd.value == 0 && swstatstr == "on") { statstr = "DIFFERENT" }
    if (cmd.value == 0xFF && swstatstr == "off") { statstr = "DIFFERENT" }
        
    //log.debug "${statstr} Zwave state is ${tempstr}; device stored state is ${device.latestValue('switch')} dimmer level: ${device.latestValue('level')} "
    return result
}

def zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
    def result = []
    def tempstr = ""

    log.debug "SwitchBinaryReport cmd.value:  ${cmd.value}"
    
    if (cmd.value == 0) {
        tempstr = "closed"
        if (settings?.shadeType) {
            if (settings.shadeType == "blinds") {
                tempstr = "tilted open"
            }
        }

    } else if (cmd.value == 0xFF) {
        tempstr = "open"

    } else {  // this has never happened
        tempstr="neither open or closed"
    }
    log.debug "Reported state is ${tempstr}; device is ${device.latestValue('switch')}  ${device.latestValue('level')} "
    
    //result << createEvent(name:"switch", value: cmd.value ? "on" : "off")
    //result << createEvent(name: "level",value: cmd.value, unit:"%",
        //descriptionText:"${device.displayName} dimmed ${cmd.value==255 ? 100 : cmd.value}%")
    return result
}

def zwaveEvent(hubitat.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd)
{
    def result = []
    def tempstr = ""

    log.trace "SwitchMultilevelReport cmd.value:  ${cmd.value}"
    
    if (cmd.value == 0) {
        //result << createEvent(name: "switch", value: "off")
        tempstr = "closed"
        if (settings?.shadeType) {
            if (settings.shadeType == "blinds") {
                tempstr = "tilted open"
            }
        }

    } else if (cmd.value == 0xFF) {
        //result << createEvent(name: "switch", value: "on")
        tempstr = "open"
    } else {
        //result << createEvent(name: "switch", value: "default")
        tempstr="neither open or closed"
    }
    //result << createEvent(name: "level",value: cmd.value, unit:"%",
      //descriptionText:"${device.displayName} dimmed ${cmd.value==255 ? 100 : cmd.value}%")
    log.debug "Reported state is ${tempstr}; device is ${device.latestValue('switch')}  ${device.latestValue('level')} "
    return result
}

def on() {
    int level = 100
    log.trace "on() treated as open()"
    setLevel(level) 
}

def off() {
    int level = 0
    log.trace "off() treated as close()"
    setLevel(level) 
}

def setLevel() {
    log.trace "setLevel() treated as preset position"
    setLevel(50) 
}

def open() {
    log.trace "open()"
    on()
}

def close() {
    log.trace "close()"
    off()
}

def presetPosition() {
    log.trace "presetPosition()"
    setLevel(50)
}

def OpenSync() {
    log.trace "OpenSync()"
    finishOpenShade()
}

def CloseSync() {
    log.trace "CloseSync()"
    finishCloseShade()
}

def TiltSync() {
    log.trace "TiltSync()"
    finishPartialOpenShade()
}

def refresh() {
    log.trace "refresh()"
    delayBetween([
        //zwave.switchBinaryV1.switchBinaryGet().format(),
        //zwave.switchMultilevelV1.switchMultilevelGet().format(),
        //zwave.meterV2.meterGet(scale: 0).format(),      // get kWh
        //zwave.meterV2.meterGet(scale: 2).format(),      // get Watts
        //zwave.sensorMultilevelV1.sensorMultilevelGet().format(),
        //zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1).format(),  // get temp in Fahrenheit
        //zwave.batteryV1.batteryGet().format(),
        zwave.basicV1.basicGet().format()
    ], 3000)
}

// If you add the Polling capability to your device type, this command
// will be called approximately every 5 minutes to check the device's state
// zrtsII does not provide accurate status of shade position

//def poll() {
//        log.trace "Poll"
//        zwave.basicV1.basicGet().format()
//}

def setLevel(level) {
    log.trace "setLevel(level)  {$level}"
    log.debug "level.inspect " + level.inspect()

    int newlevel = level

    if (level > null) {

        if (level >= 75) {
            sendEvent(name: "windowShade", value: "opening")
            sendEvent(name: "level", value: level)
            sendEvent(name: "switch", value: "on")
            runIn(25, "finishOpenShade", [overwrite: true])
            delayBetween([
                zwave.switchMultilevelV1.switchMultilevelSet(value: 0xFF).format(),
                zwave.basicV1.basicGet().format()
//                sendEvent(name: "windowShade", value: "open"),
//                sendEvent(name: "switch", value: "on")
            ], 4000)
        } else if (level <= 25) {
            sendEvent(name: "windowShade", value: "closing")
            sendEvent(name: "switch", value: "off")
            runIn(25, "finishCloseShade", [overwrite: true])
            if (settings.shadeType == "shades") {
                delayBetween([
                    zwave.switchMultilevelV1.switchMultilevelSet(value: 0x00).format(),
                    zwave.basicV1.basicGet().format()
//                    sendEvent(name: "windowShade", value: "closed"),
//                    sendEvent(name: "switch", value: "off")
                ], 4000)
            } else {
                delayBetween([
                    zwave.switchMultilevelV1.switchMultilevelStopLevelChange().format(),
                    zwave.basicV1.basicGet().format()
//                    sendEvent(name: "windowShade", value: "closed"),
//                    sendEvent(name: "switch", value: "off")
                ], 4000)
            }
        } else {
            def currstat = device.latestValue("windowShade")
            if (currstat == "open") { sendEvent(name: "windowShade", value: "closing") }
            else { sendEvent(name: "windowShade", value: "opening") }
            sendEvent(name: "level", value: level)
            sendEvent(name: "switch", value: "on")
            runIn(15, "finishPartialOpenShade", [overwrite: true])
            if (settings.shadeType == "shades") {
                delayBetween([
                    zwave.switchMultilevelV1.switchMultilevelStopLevelChange().format(),
                    zwave.basicV1.basicGet().format()
//                    sendEvent(name: "windowShade", value: "partially open"),
//                    sendEvent(name: "switch", value: "default")
                ], 4000)
            } else {
                delayBetween([
                    zwave.switchMultilevelV1.switchMultilevelSet(value: 0x00).format(),
                    zwave.basicV1.basicGet().format()
//                    sendEvent(name: "windowShade", value: "partially open"),
//                    sendEvent(name: "switch", value: "default")
                ], 4000)
            }
        }

        // this code below causes commands not be sent/received by the Somfy ZRTSII - I assume delayBetween is asynchronous...

        //log.trace("finished level adjust")
        //if (newlevel != level) { 
            //log.trace("finished level adjust1")
            //delayBetween([
                //sendEvent(name: "level", value: newlevel)
            //], 1000)
        //}
    }
}

def finishOpenShade() {
    sendEvent(name: "windowShade", value: "open")
    def newlevel = 99
    sendEvent(name: "level", value: newlevel)
    sendEvent(name: "switch", value: "on")
}

def finishCloseShade() {
    sendEvent(name: "windowShade", value: "closed")
    def newlevel = 0
    sendEvent(name: "level", value: newlevel)
    sendEvent(name: "switch", value: "off")
}

def finishPartialOpenShade() {
    sendEvent(name: "windowShade", value: "partially open")
    def newlevel = 50
    sendEvent(name: "level", value: newlevel)
    sendEvent(name: "switch", value: "on")
}

// this appears to never be called

//def setLevel(level, duration) {
//    log.trace "setLevel(level, duration)  {$level} ${duration}"
//    setLevel(level)
//    return
//}

With all due respect, if you're not able to get that custom driver ported, you won't have a better experience using our dimmer.

I would hope you would place a bit more faith in customers to at least try. I see an opportunity to at least try to make a minor change to a default device to customize it to my needs. The z wave dimmer works to turn on/off my blinds. In working with ST I successfully got the custom driver to work with open close rather than on/off and it all started because there were repositories with default DTHs so users could tweak the code.

I was simply asking for the same courtesy to at least try and maybe lean on the awesome fellow customers to test and develop and not lean so heavily on the hubitat staff/leadership.

You released a z wave shade and many users stated it did not work and the response from hubitat is ā€œI wish I had the device to testā€. Well I have the device, let me burn the candle at both ends with others on this thread to make the product better.

We have a policy regarding publishing our application and driver code, that is what it is currently.

We do appreciate all the work that the community does in porting tweaking and and making their hard work available to fellow members to enhance their experience with Hubitat.

As I write most of the drivers, I can tell you thereā€™s no secret sauce going on in there, we donā€™t have nor use any special internal methods or functions in drivers that arenā€™t available to use via our code editor.

Our zwave dimmer code was written to operate a line level zwave dimmer, the events and functionality of a dimmer designed for lighting control is quite a bit different than how a blind operates, it isnā€™t simply a matter of swapping out on for open, will that work?, yes, but not any better than just using the existing driver as is.

Even a casual review of the Somify driver you posted reveals the additional complexity involved in dealing with a shade, and in the end the code looks and functions nothing like a lighting control driver.

So even if we did publish the code for our dimmer, its not going to helpā€¦

@mike.maxwell One thing to keep in mind when looking at the driver above is that we may be talking about several different generations of Somfy blinds. When I purchased mine around two months ago I was told that they have the new Somfy Zwave Plus motors, and that I should use the standard dimmer DH for ST. Not sure if the driver posted above would work with my blinds in ST. May or may not.

FWIW, my blinds are close to 2 years old. Let me be clear as to not offend.

  1. When on the ST platform the custom device driver worked _almost perfectly to suit my needs except that you had to tell ā€œAlexa turn on the curtainsā€ which simply did not fit the vernacular.

  2. I edited the device code by changing the wording of on/off to open/close thereby exchanging on/off functionality for open close functionality so on/off were no longer options in the ST tiles nor in Alexa. This worked. I am oversimplifying my steps because it actually involved treating 100 on the dimmer as open and 0 as close but after much trial and error I got it working.

  3. I have ported the ST driver into hubitat and the code posted above will import as a driver. However the net effect is that the open/close buttons have no effect with my actual device.

  4. Notwithstanding (and I fully admit my brain is feeble in these areas), the Z-Wave dimmer default device works just like the original ST device before I made my edits (on/off = open/close). My thinking (as 8th grade as it is) was to simply spend hours of trial and error with the code to get it to do what I wanted to do.

  5. The curtain driver released with the most recent firmware update. That is to say on/off and open/close have no effect on my device. How can I help get this right.

Therefore my solutions were two fold: (i) enlist the help of the community to look at the ST device to try and figure out why on/off open/close have no effect with my device or; (ii) have a look at the Generic Z-Wave dimmer device and try to manipulate the code to do what I want. Choice 1 is way above my skill level and burdensome to the community who may not have the same smoky device I have so I feel choice 2 is/was my only option.

I am not here to upset hubitat and I recognize the existence of the policy of not releasing the driver code for the default devices so whatever becomes of this is fine by me. My curtains automate and the WAF decreases a because nobody turns on curtains, so if anyone needs a guinea pig to test my device or provide logs, I am all in._

PS - Alea and Homekit workarounds are not sufficient. If you group curtains into a room (ie. bedroom) turning on the lights in the bedroom opens the curtains which is not optimal.

Not a real solution, but a very usable workaround for Alexa voice commands is to create Alexa Routines that allow much more natural voice commands. Have you tried using An Alexa Routine to open/close a group of blinds that only respond to on/off commands?

It is a work around that can be done with Alexa or Homekit, but it creates a new problem. Since both Alexa and Homekit believe the device to be a dimmer, any command to turn on the lights in a room where you have placed curtains will open/close the curtains. :frowning:

In the Amazon Alexa platform, you can create groups of smart devices. I would suggest creating a group for lights, and a group for blinds. That way, when you create an Alexa Routine, you can simply specify one of the two groups to turn on. No need to lump everything into the same group, correct?

Maybe the issue is more of a problem on Homekit? I rarely use Siri voice control as I have Amazon devices in most of the rooms these days.

Would be great, but I appear to be the only person who cannot get Alexa to work with hubitat.

Ah yesā€¦ Forgot about that. Youā€™re one of the Apple Airport Extreme users, correct?

Hopefully the native Alexa skill isnā€™t too far offā€¦

Yup. Iā€™m the guy.

I've made some updates to this driver, when the next release comes out, I would appreciate it if you could try this driver again, thanks

1 Like

Thank you, I most certainly will.

Curtains work!!! Thank You.

1 Like

I know you have bigger fish to fry and frankly the effort you put into this is amazing considering its just curtains.

I have a minor request. The current iteration of your device registers within home kit as a dimmer switch still. (this is through @tonesto7 app which is a port of @pdlovelace app from ST).

In ST the custom driver (previously posted herein) was selectable as a window shade. Again, I know this is a minor thing and I can ask Siri or Alexa to open the curtains VIA a routine/homekit automation, BUT as it is still a light asking either to turn on/off the lights in the bedroom result in the curtains opening or closing.

Again, I can't stress how minor this is, but if you could maybe examine the driver I posted and see whether an accommodation could be made to have the device exclusively be seen as curtains and NEVER be seen as a dimmer that would be great!

Much thanks!

this would have been my preference from the start, let me run this by the team.

This does mean that you would need to call setPosition vs setLevel, is this the method that the app is using?

Correct... set position.

In the recent smart app I released it has special inputs which allow you to define how devices are discovered in HomeKit. Adding an input for these would require very little effort.

Honestly HomeKit has native blind/curtain support so I would really like to get this added soon.

Just so Iā€™m clear setPosition() will accept values 0-100 correct?

I meant to change (and forgot) to do this for the current release.
Yes, it will accept 0 to 100, however 100 gets thunked down to 99 since that's the largest value you can send to most zwave devices.
We had a somewhat lively internal debate on if 99 should map to 100 when the device reports in...
It doesn't, and won't.
So you send it 100, the device will report back 99.

2 Likes