NZW1201 Quick Setup for SmartThings

Z-Wave Plus Door & Temperature Sensor (NZW1201 - Inovelli)

Thank you for your purchase of the NZW1201 Door/Temp Sensor. If you run into any problems along the way, please contact us. We’re here to help!

Step by Step Instructions – Android Users

(iOS Users, please click here or scroll down about halfway)

– Step 1 –
Gather Your Materials & Find an Appropriate Spot for Your Door/Temp Sensor

Materials Needed:

Locate an interior area to install your door/temp sensor within the recommended distance (calculated on Page 2-3 in your manual) from your HUB. Please keep in mind the large sensor portion and the small magnet portion cannot exceed a distance of 3/4″ (inches) from each other.

Walls, furniture, and other obstructions may affect the communication between the Sensor and your Hub/Gateway, so please keep this in mind when selecting your location.

**If you are having issues pairing your device, please ensure your sensor is within range of your HUB. 95% of the pairing/including failures stem from this issue. Best practice is to start with Z-Wave products near your HUB and build your network out. The more Z-Wave devices, the more efficient your network.**

-Step 2-
Adding (Including) to the Network & Completing the Setup Process

Please do not insert the battery until you start the actual inclusion process — this sensor has, “Auto-Inclusion” so if you insert the battery too early, it will not auto-include and you will have to do the backup method.

Now that you’re ready, we’ll start the inclusion process.

Including Steps:

  • Open up your SmartThings app and click on the, “My Home” tab, followed by the, “Things” tab
  • Press, “Add a Thing” (at the bottom) or the (+) at the top right to start adding the sensor and SmartThings will automatically start looking for devices
  • Insert the battery immediately after you press, “Add a Thing”
  • Wait for auto-inclusion to do its thing. It will automatically include/pair to your HUB
    • If successful, your device will flash signaling a successful pairing (NOTE: Auto-Inclusion will time out after 30 seconds)
    • If it does not flash within 30 seconds, please use the alternate method of pairing which is pressing the white button (located above the battery) 3x within 1 second
  • You should now see that your device is detected (“Z-Wave Door/Window Sensor” should appear)

Setup After Inclusion

  • After your device was detected, press, “Save” (or if you’d like to rename your device, you can do that and then click, “Save”)
  • Once you click, “Save” a pop up will appear asking you to, “Confirm Paired Devices” — Click, “OK”
  • Now you are back at the, “My Home” screen and you will see the Z-Wave sensor on the screen which is labeled, “Z-Wave Door/Window Sensor”

You may notice there is no temperature that shows up. This is because SmartThings does not have a default device handler that has temperature built in. We are working with them on a native device handler, but in the meantime, we’ll use ours located in Step 3.

**If you are having issues pairing your device, please ensure your switch is within range of your HUB. 95% of the pairing/including failures stem from this issue. Best practice is to start with Z-Wave products near your HUB and build your network out. The more Z-Wave devices, the more efficient your network.**

-Step 4-
Adding Our Custom Device Handler

While this step may look intimidating, we promise it isn’t. The best part is that you’ll also learn how to use IDE, which is the engine under the hood of your SmartThings HUB. We’re working on a more integrated way to activate scenes with SmartThings, but in the meantime, please follow the directions below. As always, if you run into any issues, please let us know!

Ready? Let’s Go!

Open up IDE on your Computer/Tablet:

  • Go to: graph.api.smartthings.com (it’s free)
    • Login using the same Username/Password as your SmartThings Phone App
  • Click on the green, “Login” button on the top right of the screen and login using the same credentials as your SmartThings Phone App
  • Once logged in, click, “My Locations” (top left of the screen) — you should see your HUB’s location there
  • Click on your HUB’s location underneath where it says, “Name”
    • You may be prompted to login again — if so, please do

Now We’re Going to Install the Device Handler

  • While still in IDE, click on, “My Device Handlers” located at the top/middle of your screen
  • Click the green button labeled, “Create New Device Handler”
  • Then click, “From Code”
  • Copy the code below
/**
 *  Inovelli Door/Window Sensor NZW1201
 *  Author: Eric Maycock (erocm123)
 *  Date: 2017-08-17
 *
 *  Copyright 2017 Eric Maycock
 *
 *  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: "Inovelli Door/Window Sensor NZW1201", namespace: "erocm123", author: "Eric Maycock", ocfDeviceType: "x.com.st.d.sensor.contact") {
        capability "Contact Sensor"
        capability "Sensor"
        capability "Battery"
        capability "Configuration"
        //capability "Health Check"
        capability "Temperature Measurement"
        
        attribute "lastActivity", "String"
        attribute "lastEvent", "String"

        fingerprint mfr:"015D", prod:"2003", model:"B41C", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"0312", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"015D", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"015D", prod:"C100", model:"C100", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"0312", prod:"C100", model:"C100", deviceJoinName: "Inovelli Door/Window Sensor"
    }

    simulator {
    }
    
    preferences {
        input "tempReportInterval", "enum", title: "Temperature Report Interval\n\nHow often you would like temperature reports to be sent from the sensor. More frequent reports will have a negative impact on battery life.\nRange: 1 to 3600", description: "Tap to set", required: false, options:[10: "10 Minutes", 30: "30 Minutes", 60: "1 Hour", 120: "2 Hours", 180: "3 Hours", 240: "4 Hours", 300: "5 Hours", 360: "6 Hours", 720: "12 Hours", 1440: "24 Hours"], defaultValue: 180
        input "tempOffset", "number", title: "Temperature Offset\n\nCalibrate reported temperature by applying a negative or positive offset\nRange: -10 to 10", description: "Tap to set", required: false, range: "-10..10"
    }

    tiles(scale: 2) {
        multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
            tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
                attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13"
                attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00a0dc"
            }
            tileAttribute("device.temperature", key: "SECONDARY_CONTROL") {
                attributeState("default", label:'${currentValue}°',icon: "")
            }
        }
        
        valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 1) {
            state "battery", label:'${currentValue}% battery', unit:""
        }

        valueTile("lastActivity", "device.lastActivity", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
            state "default", label: 'Last Activity: ${currentValue}',icon: "st.Health & Wellness.health9"
        }
        
        valueTile("info", "device.info", inactiveLabel: false, decoration: "flat", width: 3, height: 1) {
            state "default", label: 'After adjusting the Temperature Report Interval, open the sensor and press the small white button'
        }
        
        valueTile("icon", "device.icon", inactiveLabel: false, decoration: "flat", width: 3, height: 1) {
            state "default", label: '', icon: "https://inovelli.com/wp-content/uploads/Device-Handler/Inovelli-Device-Handler-Logo.png"
        }
    }
}

def parse(String description) {
    def result = null
    if (description.startsWith("Err 106")) {
        if (state.sec) {
            log.debug description
        } else {
            result = createEvent(
                descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.",
                eventType: "ALERT",
                name: "secureInclusion",
                value: "failed",
                isStateChange: true,
            )
        }
    } else if (description != "updated") {
        def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1])
        if (cmd) {
            result = zwaveEvent(cmd)
        }
    }
    def now
    if(location.timeZone)
    now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
    else
    now = new Date().format("yyyy MMM dd EEE h:mm:ss a")
    sendEvent(name: "lastActivity", value: now, displayed:false)
    return result
}

def installed() {
    // Device-Watch simply pings if no device events received for 482min(checkInterval)
    sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "0"])
}

def updated() {
    // Device-Watch simply pings if no device events received for 482min(checkInterval)
    sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
    if (state.realTemperature != null) sendEvent(name:"temperature", value: getAdjustedTemp(state.realTemperature))
    def cmds = []
    if (!state.MSR) {
        cmds = [
            command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()),
            "delay 1200",
            zwave.wakeUpV1.wakeUpNoMoreInformation().format()
        ]
    } else if (!state.lastbat) {
        cmds = []
    } else {
        cmds = [zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
    }
    response(cmds)
}

private getAdjustedTemp(value) {
    value = Math.round((value as Double) * 100) / 100
    if (tempOffset) {
       return value =  value + Math.round(tempOffset * 100) /100
    } else {
       return value
    }
}

def configure() {
    commands([
        zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW),
        zwave.manufacturerSpecificV2.manufacturerSpecificGet()
    ], 1000)
}

def sensorValueEvent(value) {
    if (value) {
        createEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open")
    } else {
        createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed")
    }
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
{
    sensorValueEvent(cmd.value)
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd)
{
    sensorValueEvent(cmd.value)
}

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd)
{
    sensorValueEvent(cmd.sensorValue)
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)
{
    log.debug "WakeUpIntervalReport ${cmd.toString()}"
    state.wakeInterval = cmd.seconds
}

def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd)
{
    log.debug cmd
    def result = []
    if (cmd.notificationType == 0x06 && cmd.event == 0x16) {
        result << sensorValueEvent(1)
    } else if (cmd.notificationType == 0x06 && cmd.event == 0x17) {
        result << sensorValueEvent(0)
    } else if (cmd.notificationType == 0x07) {
        if (cmd.event == 0x00) {
            result << createEvent(descriptionText: "$device.displayName covering was restored", isStateChange: true)
            result << response(command(zwave.batteryV1.batteryGet()))
        } else if (cmd.event == 0x01 || cmd.event == 0x02) {
            result << sensorValueEvent(1)
        } else if (cmd.event == 0x03) {
            result << createEvent(descriptionText: "$device.displayName covering was removed", isStateChange: true)
            if(!state.MSR) result << response(command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()))
        }
    } else if (cmd.notificationType) {
        def text = "Notification $cmd.notificationType: event ${([cmd.event] + cmd.eventParameter).join(", ")}"
        result << createEvent(name: "notification$cmd.notificationType", value: "$cmd.event", descriptionText: text, displayed: false)
    } else {
        def value = cmd.v1AlarmLevel == 255 ? "active" : cmd.v1AlarmLevel ?: "inactive"
        result << createEvent(name: "alarm $cmd.v1AlarmType", value: value, displayed: false)
    }
    result
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
    def event = createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
    def cmds = []
    if (!state.MSR) {
        cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
        cmds << "delay 1200"
    }
    
    cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1).format()
    
    if(state.wakeInterval == null || state.wakeInterval != (tempReportInterval? tempReportInterval.toInteger()*60:10800)){
        log.debug "Setting Wake Interval to ${tempReportInterval? tempReportInterval.toInteger()*60:10800}"
        cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: tempReportInterval? tempReportInterval.toInteger()*60:10800, nodeid:zwaveHubNodeId).format()
        cmds << zwave.wakeUpV1.wakeUpIntervalGet().format()
    }

    if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) {
        cmds << command(zwave.batteryV1.batteryGet())
    } else { // If we check the battery state we will send NoMoreInfo in the handler for BatteryReport so that we definitely get the report
        cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
    }

    [event, response(cmds)]
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd)
{
    log.debug "SensorMultilevelReport: $cmd"
    def map = [:]
    switch (cmd.sensorType) {
        case 1:
            map.name = "temperature"
            def cmdScale = cmd.scale == 1 ? "F" : "C"
            state.realTemperature = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
            map.value = getAdjustedTemp(state.realTemperature)
            map.unit = getTemperatureScale()
            log.debug "Temperature Report: $map.value"
            break;
        default:
            map.descriptionText = cmd.toString()
    }
    return createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
    def map = [ name: "battery", unit: "%" ]
    if (cmd.batteryLevel == 0xFF) {
        map.value = 1
        map.descriptionText = "${device.displayName} has a low battery"
        map.isStateChange = true
    } else {
        map.value = cmd.batteryLevel
    }
    state.lastbat = now()
    [createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
    def result = []

    def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
    log.debug "msr: $msr"
    updateDataValue("MSR", msr)

    result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
    result << response(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
    if (!device.currentState("battery")) {
        result << response(zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format())
    } else {
        result << response(command(zwave.batteryV1.batteryGet()))
    }

    result
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
    def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1])
    if (encapsulatedCommand) {
        state.sec = 1
        zwaveEvent(encapsulatedCommand)
    }
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
    createEvent(descriptionText: "$device.displayName: $cmd", displayed: false)
}

private command(physicalgraph.zwave.Command cmd) {
    if (state.sec) {
        zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
    } else {
        cmd.format()
    }
}

private commands(commands, delay=200) {
    delayBetween(commands.collect{ command(it) }, delay)
}
  • After the code is copied (above), paste it in the, “From Code” section (white space)
  • Then click, “Create”
  • Next click, “Publish”
  • Finally, click, “For Me”

To confirm you have the handler installed, please open your SmartThings app, locate your Inovelli switch and click on it. Your menu should look like this:

NZW1201 Device Handler

-Step 4-
Run a Z-Wave Refresh to Update Your Mesh Network With Your New Sensor (OPTIONAL: But Recommended)

This step is highly recommended whenever a new Z-Wave device is added to your network. It tells your HUB to re-map the network which, ultimately, will make your network faster and more efficient.

Z-Wave Refresh Steps:

  • In the SmartThings app, click on the, “Menu” button
  • Then click, “Hub is Online”
  • Next click, “Z-Wave Utilities”
  • Next click, “Repair Z-Wave Network”
  • Finally, click, “Start Z-Wave Network Repair”
  • Wait 20 minutes for your SmartThings HUB to re-map (discover) the network
    NOTE: Do not touch anything on your network during this time

Congratulations, you now have a smart sensor!

-Device Removal-
Removing Your Smart Sensor From SmartThings

Please follow the below directions to remove your smart sensor from your SmartThings HUB.
(NOTE: this is the same process for SmartThings HUB’s 1.0 & 2.0)

Removal Steps:

  • From the, “My Home” screen (make sure you are on your, “Things” tab — located at the top) click on the device you’d like to remove
  • Click on the gear icon (top right of the screen)
  • Press the red, “Remove” button at the bottom
  • On the removal screen, you may receive a pop-up asking if you’re sure you want to remove this device
    • Press, “Remove Anyway”
  • Press the White Button (located above the battery) on your NZW1201 three (3) times within 1 second
    • If successful, you will see a message saying that the device was successfully removed from SmartThings
    • If unsuccessful, you will see a message saying that the device failed to be removed from SmartThings — if this happens, please move the sensor closer to the HUB and try again.

Your smart sensor should now be removed from the SmartThings HUB.

Full Installation Videos

(Coming Soon)

SmartThings Light Schedule Setup

Step by Step Instructions – iOS

(Android Users, please click here or scroll up to the top)

– Step 1 –
Gather Your Materials & Find an Appropriate Spot for Your Door/Temp Sensor

Materials Needed:

Locate an interior area to install your door/temp sensor within the recommended distance (calculated on Page 2-3 in your manual) from your HUB. Please keep in mind the large sensor portion and the small magnet portion cannot exceed a distance of 3/4″ (inches) from each other.

Walls, furniture, and other obstructions may affect the communication between the Sensor and your Hub/Gateway, so please keep this in mind when selecting your location.

**If you are having issues pairing your device, please ensure your sensor is within range of your HUB. 95% of the pairing/including failures stem from this issue. Best practice is to start with Z-Wave products near your HUB and build your network out. The more Z-Wave devices, the more efficient your network.**

-Step 2-
Adding (Including) to the Network & Completing the Setup Process

Please do not insert the battery until you start the actual inclusion process — this sensor has, “Auto-Inclusion” so if you insert the battery too early, it will not auto-include and you will have to do the backup method.

Now that you’re ready, we’ll start the inclusion process.

Including Steps:

  • Open up your SmartThings app and click on the, “My Home” tab, followed by the, “Things” tab
  • Press, “Add a Thing” (at the bottom) or the (+) at the top right to start adding the sensor and SmartThings will automatically start looking for devices
  • Insert the battery immediately after you press, “Add a Thing”
  • Wait for auto-inclusion to do its thing. It will automatically include/pair to your HUB
    • If successful, your device will flash signaling a successful pairing (NOTE: Auto-Inclusion will time out after 30 seconds)
    • If it does not flash within 30 seconds, please use the alternate method of pairing which is pressing the white button (located above the battery) 3x within 1 second
  • You should now see that your device is detected (“Z-Wave Door/Window Sensor” should appear)

Setup After Inclusion

  • After your device was detected, press, “Save” (or if you’d like to rename your device, you can do that and then click, “Save”)
  • Once you click, “Save” a pop up will appear asking you to, “Confirm Paired Devices” — Click, “OK”
  • Now you are back at the, “My Home” screen and you will see the Z-Wave sensor on the screen which is labeled, “Z-Wave Door/Window Sensor”

You may notice there is no temperature that shows up. This is because SmartThings does not have a default device handler that has temperature built in. We are working with them on a native device handler, but in the meantime, we’ll use ours located in Step 3.

**If you are having issues pairing your device, please ensure your switch is within range of your HUB. 95% of the pairing/including failures stem from this issue. Best practice is to start with Z-Wave products near your HUB and build your network out. The more Z-Wave devices, the more efficient your network.**

-Step 4-
Adding Our Custom Device Handler

While this step may look intimidating, we promise it isn’t. The best part is that you’ll also learn how to use IDE, which is the engine under the hood of your SmartThings HUB. We’re working on a more integrated way to activate scenes with SmartThings, but in the meantime, please follow the directions below. As always, if you run into any issues, please let us know!

Ready? Let’s Go!

Open up IDE on your Computer/Tablet:

  • Go to: graph.api.smartthings.com (it’s free)
    • Login using the same Username/Password as your SmartThings Phone App
  • Click on the green, “Login” button on the top right of the screen and login using the same credentials as your SmartThings Phone App
  • Once logged in, click, “My Locations” (top left of the screen) — you should see your HUB’s location there
  • Click on your HUB’s location underneath where it says, “Name”
    • You may be prompted to login again — if so, please do

Now We’re Going to Install the Device Handler

  • While still in IDE, click on, “My Device Handlers” located at the top/middle of your screen
  • Click the green button labeled, “Create New Device Handler”
  • Then click, “From Code”
  • Copy the code below
/**
 *  Inovelli Door/Window Sensor NZW1201
 *  Author: Eric Maycock (erocm123)
 *  Date: 2017-08-17
 *
 *  Copyright 2017 Eric Maycock
 *
 *  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: "Inovelli Door/Window Sensor NZW1201", namespace: "erocm123", author: "Eric Maycock", ocfDeviceType: "x.com.st.d.sensor.contact") {
        capability "Contact Sensor"
        capability "Sensor"
        capability "Battery"
        capability "Configuration"
        //capability "Health Check"
        capability "Temperature Measurement"
        
        attribute "lastActivity", "String"
        attribute "lastEvent", "String"

        fingerprint mfr:"015D", prod:"2003", model:"B41C", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"0312", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"015D", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"015D", prod:"C100", model:"C100", deviceJoinName: "Inovelli Door/Window Sensor"
        fingerprint mfr:"0312", prod:"C100", model:"C100", deviceJoinName: "Inovelli Door/Window Sensor"
    }

    simulator {
    }
    
    preferences {
        input "tempReportInterval", "enum", title: "Temperature Report Interval\n\nHow often you would like temperature reports to be sent from the sensor. More frequent reports will have a negative impact on battery life.\nRange: 1 to 3600", description: "Tap to set", required: false, options:[10: "10 Minutes", 30: "30 Minutes", 60: "1 Hour", 120: "2 Hours", 180: "3 Hours", 240: "4 Hours", 300: "5 Hours", 360: "6 Hours", 720: "12 Hours", 1440: "24 Hours"], defaultValue: 180
        input "tempOffset", "number", title: "Temperature Offset\n\nCalibrate reported temperature by applying a negative or positive offset\nRange: -10 to 10", description: "Tap to set", required: false, range: "-10..10"
    }

    tiles(scale: 2) {
        multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
            tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
                attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13"
                attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00a0dc"
            }
            tileAttribute("device.temperature", key: "SECONDARY_CONTROL") {
                attributeState("default", label:'${currentValue}°',icon: "")
            }
        }
        
        valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 1) {
            state "battery", label:'${currentValue}% battery', unit:""
        }

        valueTile("lastActivity", "device.lastActivity", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
            state "default", label: 'Last Activity: ${currentValue}',icon: "st.Health & Wellness.health9"
        }
        
        valueTile("info", "device.info", inactiveLabel: false, decoration: "flat", width: 3, height: 1) {
            state "default", label: 'After adjusting the Temperature Report Interval, open the sensor and press the small white button'
        }
        
        valueTile("icon", "device.icon", inactiveLabel: false, decoration: "flat", width: 3, height: 1) {
            state "default", label: '', icon: "https://inovelli.com/wp-content/uploads/Device-Handler/Inovelli-Device-Handler-Logo.png"
        }
    }
}

def parse(String description) {
    def result = null
    if (description.startsWith("Err 106")) {
        if (state.sec) {
            log.debug description
        } else {
            result = createEvent(
                descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.",
                eventType: "ALERT",
                name: "secureInclusion",
                value: "failed",
                isStateChange: true,
            )
        }
    } else if (description != "updated") {
        def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1])
        if (cmd) {
            result = zwaveEvent(cmd)
        }
    }
    def now
    if(location.timeZone)
    now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
    else
    now = new Date().format("yyyy MMM dd EEE h:mm:ss a")
    sendEvent(name: "lastActivity", value: now, displayed:false)
    return result
}

def installed() {
    // Device-Watch simply pings if no device events received for 482min(checkInterval)
    sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "0"])
}

def updated() {
    // Device-Watch simply pings if no device events received for 482min(checkInterval)
    sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
    if (state.realTemperature != null) sendEvent(name:"temperature", value: getAdjustedTemp(state.realTemperature))
    def cmds = []
    if (!state.MSR) {
        cmds = [
            command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()),
            "delay 1200",
            zwave.wakeUpV1.wakeUpNoMoreInformation().format()
        ]
    } else if (!state.lastbat) {
        cmds = []
    } else {
        cmds = [zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
    }
    response(cmds)
}

private getAdjustedTemp(value) {
    value = Math.round((value as Double) * 100) / 100
    if (tempOffset) {
       return value =  value + Math.round(tempOffset * 100) /100
    } else {
       return value
    }
}

def configure() {
    commands([
        zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW),
        zwave.manufacturerSpecificV2.manufacturerSpecificGet()
    ], 1000)
}

def sensorValueEvent(value) {
    if (value) {
        createEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open")
    } else {
        createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed")
    }
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
{
    sensorValueEvent(cmd.value)
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd)
{
    sensorValueEvent(cmd.value)
}

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd)
{
    sensorValueEvent(cmd.sensorValue)
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpIntervalReport cmd)
{
    log.debug "WakeUpIntervalReport ${cmd.toString()}"
    state.wakeInterval = cmd.seconds
}

def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd)
{
    log.debug cmd
    def result = []
    if (cmd.notificationType == 0x06 && cmd.event == 0x16) {
        result << sensorValueEvent(1)
    } else if (cmd.notificationType == 0x06 && cmd.event == 0x17) {
        result << sensorValueEvent(0)
    } else if (cmd.notificationType == 0x07) {
        if (cmd.event == 0x00) {
            result << createEvent(descriptionText: "$device.displayName covering was restored", isStateChange: true)
            result << response(command(zwave.batteryV1.batteryGet()))
        } else if (cmd.event == 0x01 || cmd.event == 0x02) {
            result << sensorValueEvent(1)
        } else if (cmd.event == 0x03) {
            result << createEvent(descriptionText: "$device.displayName covering was removed", isStateChange: true)
            if(!state.MSR) result << response(command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()))
        }
    } else if (cmd.notificationType) {
        def text = "Notification $cmd.notificationType: event ${([cmd.event] + cmd.eventParameter).join(", ")}"
        result << createEvent(name: "notification$cmd.notificationType", value: "$cmd.event", descriptionText: text, displayed: false)
    } else {
        def value = cmd.v1AlarmLevel == 255 ? "active" : cmd.v1AlarmLevel ?: "inactive"
        result << createEvent(name: "alarm $cmd.v1AlarmType", value: value, displayed: false)
    }
    result
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
    def event = createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
    def cmds = []
    if (!state.MSR) {
        cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
        cmds << "delay 1200"
    }
    
    cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1).format()
    
    if(state.wakeInterval == null || state.wakeInterval != (tempReportInterval? tempReportInterval.toInteger()*60:10800)){
        log.debug "Setting Wake Interval to ${tempReportInterval? tempReportInterval.toInteger()*60:10800}"
        cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds: tempReportInterval? tempReportInterval.toInteger()*60:10800, nodeid:zwaveHubNodeId).format()
        cmds << zwave.wakeUpV1.wakeUpIntervalGet().format()
    }

    if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) {
        cmds << command(zwave.batteryV1.batteryGet())
    } else { // If we check the battery state we will send NoMoreInfo in the handler for BatteryReport so that we definitely get the report
        cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
    }

    [event, response(cmds)]
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd)
{
    log.debug "SensorMultilevelReport: $cmd"
    def map = [:]
    switch (cmd.sensorType) {
        case 1:
            map.name = "temperature"
            def cmdScale = cmd.scale == 1 ? "F" : "C"
            state.realTemperature = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
            map.value = getAdjustedTemp(state.realTemperature)
            map.unit = getTemperatureScale()
            log.debug "Temperature Report: $map.value"
            break;
        default:
            map.descriptionText = cmd.toString()
    }
    return createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
    def map = [ name: "battery", unit: "%" ]
    if (cmd.batteryLevel == 0xFF) {
        map.value = 1
        map.descriptionText = "${device.displayName} has a low battery"
        map.isStateChange = true
    } else {
        map.value = cmd.batteryLevel
    }
    state.lastbat = now()
    [createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
    def result = []

    def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
    log.debug "msr: $msr"
    updateDataValue("MSR", msr)

    result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
    result << response(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
    if (!device.currentState("battery")) {
        result << response(zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format())
    } else {
        result << response(command(zwave.batteryV1.batteryGet()))
    }

    result
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
    def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 1, 0x30: 1, 0x31: 5, 0x80: 1, 0x84: 1, 0x71: 3, 0x9C: 1])
    if (encapsulatedCommand) {
        state.sec = 1
        zwaveEvent(encapsulatedCommand)
    }
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
    createEvent(descriptionText: "$device.displayName: $cmd", displayed: false)
}

private command(physicalgraph.zwave.Command cmd) {
    if (state.sec) {
        zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
    } else {
        cmd.format()
    }
}

private commands(commands, delay=200) {
    delayBetween(commands.collect{ command(it) }, delay)
}
  • After the code is copied (above), paste it in the, “From Code” section (white space)
  • Then click, “Create”
  • Next click, “Publish”
  • Finally, click, “For Me”

To confirm you have the handler installed, please open your SmartThings app, locate your Inovelli switch and click on it. Your menu should look like this:

NZW1201 Device Handler

Note: Above screenshot is from an Android phone — it should look similar on iOS

-Step 4-
Run a Z-Wave Refresh to Update Your Mesh Network With Your New Sensor (OPTIONAL: But Recommended)

This step is highly recommended whenever a new Z-Wave device is added to your network. It tells your HUB to re-map the network which, ultimately, will make your network faster and more efficient.

Z-Wave Refresh Steps:

  • In the SmartThings app, click on the, “Menu” button
  • Then click, “Hub is Online”
  • Next click, “Z-Wave Utilities”
  • Next click, “Repair Z-Wave Network”
  • Finally, click, “Start Z-Wave Network Repair”
  • Wait 20 minutes for your SmartThings HUB to re-map (discover) the network
    NOTE: Do not touch anything on your network during this time

Congratulations, you now have a smart sensor!

-Device Removal-
Removing Your Smart Switch From SmartThings

Please follow the below directions to remove your smart switch from your SmartThings HUB.
(NOTE: this is the same process for SmartThings HUB’s 1.0 & 2.0)

Removal Steps:

  • From the, “My Home” screen (make sure you are on your, “Things” tab — located at the top) click on the device you’d like to remove
  • Click on the gear icon (top right of the screen)
  • Press the red, “Remove” button at the bottom
  • On the removal screen, you may receive a pop-up asking if you’re sure you want to remove this device
    • Press, “Remove Anyway”
  • Press the Top (UP) Button on your NZW30S six (6) times within 2 seconds
    • If successful, you will see a message saying that the device was successfully removed from SmartThings
    • If unsuccessful, you will see a message saying that the device failed to be removed from SmartThings — if this happens, please move the plug closer to the HUB and try again.

Your smart switch should now be removed from the SmartThings HUB.

Full Installation Videos

(Coming Soon)

SmartThings Light Schedule Setup