Post Requests for Zwave Edge Drivers Here (community-created)

Hi @Jake_Mohl

I have added it as the same profile of the Aeotec nano. Let’s see if it works, I don’t understand the buttons very well

Z-Wave Button Mc

  • id: 0208/0201/000B
    deviceLabel: Hank Four-Key Scene
    manufacturerId: 0x0208
    productType: 0x0201
    productId: 0x000B
    deviceProfileName: multi-button-4
1 Like

Hi everyone,
I have two requests for (I suppose) re-branded Z-Wave Radiator Thermostats based on the Danfoss LC-13.
The first one is a “devolo Home Control”, which is actually working fine with the modified DTH below, where I replaced the correct fingerprint.

The fingerprint of the devolo is:
zw:S type:0804 mfr:0002 prod:0005 model:0175 ver:1.00 zwv:3.67 lib:06 cc:80,46,81,72,8F,75,31,43,86,84 ccOut:46,81,8F

The second TRV is a “Donexon varmo TZ pro” which I purchased just a week ago, but is not working with the DTH below, even if I change the fingerprint.

The fingerprint of the Donexon TRV is:
zw:S type:0804 mfr:0002 prod:5FFF model:A010 ver:0.00 zwv:0.00 lib:00 cc:80,46,81,72,8F,75,31,43,86,84 ccOut:46,81,8F

Additionally, I added a two pictures the manuals below the DTH.

I’m looking forward to your replies, thanks a lot.
Best redgards,

08/11/18 code coddensed and private change to def - It’s syntactically allowed, but actually isn’t respected by Groovy (gasp!). And in SmartThings, this really isn’t necessary since we are not creating our own classes or object models. So, we typically just omit any visibility modifier for simplicity.
07/11/18 Added function to update 1)wake interval 2)set clock - during wake periods
21/10/18 Updated from SmartThingsPublic/POPP TRV at 1630d63192f0349b26f64deaa10403ba958a8003 · edshaken/SmartThingsPublic · GitHub

  • This started off originally from the work Tom Philip did and the submission here:
  • SmartThingsPublic/danfoss-living-connect-radiator-thermostat.groovy at master · tommysqueak/SmartThingsPublic · GitHub
  • This was originally for Danfoss Living Connect Radiator Thermostat LC-13, but I want it to work with POPP POPE010101 Z-Wave Radiator Thermostat (TRV)
  • Main difference is POPP can report back actual temperature rather than just set point
  • Original
  • Copyright 2016 Tom Philip
  • 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:
  • 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.
  • To Do
  • Sort out Heating / Idle / Auto states and their impact on the TRV.
  • Perhaps writing a smartapp that does scheduling.
  • Sort out first time device is installed 0 values screws up the device in the app.
  • Temperature offset

metadata {
definition (name: “Devolo-TRV”, namespace: “Matthias Hierweck”, author: “Matthias Hierweck”, ocfDeviceType: “oic.d.thermostat”) {
capability “Actuator”
capability “Sensor”
capability “Thermostat”
capability “Battery”
capability “Configuration”
capability “Switch”
capability “Temperature Measurement”
capability “Thermostat Cooling Setpoint” //attribute- coolingSetpoint command - setCoolingSetpoint - having both alows extra settings in routines
capability “Thermostat Heating Setpoint”

	command "temperatureUp"
	command "temperatureDown"
	command "summer" //summer mode to lock out temp changes in summer time
	attribute "nextHeatingSetpoint", "number"
	attribute "temperature", "number"
    attribute "battery", "string"
    attribute "minHeatingSetpoint", "number" //google alex compatability // shuld be part of heating setpoint to test without//	
	attribute "maxHeatingSetpoint", "number" //google alex compatability // shuld be part of heating setpoint to test without//	
	attribute "summer", "String" //for feed
    attribute "thermostatTemperatureSetpoint", "String"						//need for google
fingerprint type: "0804", mfr: "0002", prod: "0005", model: "0175", cc: "80,46,81,72,8F,75,31,43,86,84", ccOut:"46,81,8F" //8f last
	// 0x80 = Battery v1 //tets
	// 0x46 = Climate Control Schedule v1
	// 0x81 = Clock v1
	// 0x72 = Manufacturer Specific v1
	// 0x8F = Multi Cmd v1 (Multi Command Encapsulated)
	// 0x75 = Protection v2
	// 0x31 V2 0x31 Sensor Multilevel
	// 0x43 = Thermostat Setpoint v2
	// 0x86 = Version v1
	// 0x84 = Wake Up v2

simulator {

tiles(scale: 2) {
	multiAttributeTile(name:"temperature", type:"thermostat", width:6, height:4, canChangeIcon: true) {
		tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
			attributeState("temperature", label:'${currentValue}°',defaultState: true, backgroundColors:[
					// Celsius Color Range
					[value: 0, color: "#153591"],
					[value: 10, color: "#1e9cbb"],
					[value: 13, color: "#90d2a7"],
					[value: 17, color: "#44b621"],
					[value: 20, color: "#f1d801"],
					[value: 25, color: "#d04e00"],
					[value: 29, color: "#bc2323"],
					// Fahrenheit Color Range
					[value: 40, color: "#153591"],
					[value: 44, color: "#1e9cbb"],
					[value: 59, color: "#90d2a7"],
					[value: 74, color: "#44b621"],
					[value: 84, color: "#f1d801"],
					[value: 92, color: "#d04e00"],
					[value: 96, color: "#bc2323"]
		tileAttribute("device.nextHeatingSetpoint", key: "VALUE_CONTROL") {
			attributeState("VALUE_UP", action: "temperatureUp")
			attributeState("VALUE_DOWN", action: "temperatureDown")
		tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
			attributeState("default", label:'${currentValue}')
			attributeState("heating", label:"heating", backgroundColor:"#ffa81e", icon:"st.thermostat.heat")
			attributeState("idle", label:"idle", backgroundColor:"#1e9cbb", icon:"st.thermostat.heating-cooling-off")
		tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") {
			attributeState("default", label:'${currentValue}')
			attributeState("heat", label:"heat",  icon:"st.thermostat.heat") //backgroundColor:"#ffa81e",
			attributeState("off", label:"off",  icon:"st.thermostat.heating-cooling-off") //backgroundColor:"#1e9cbb",
		tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { // //nextHeatingSetpoint //setpoint as last reported by device
			attributeState("heatingSetpoint", label:'${currentValue}', unit:"°C", defaultState: true, backgroundColors:[
			// Celsius 
			[value: 0, color: "#b8c2de"],
			[value: 10, color: "#bbe1ea"],
			[value: 13, color: "#ddf1e4"],
			[value: 17, color: "#c6e9bc"],
			[value: 20, color: "#faf3b2"],
			[value: 25, color: "#f0c9b2"],
			[value: 29, color: "#eabdbd"],
			// Fahrenheit
			[value: 40, color: "#b8c2de"],
			[value: 44, color: "#bbe1ea"],
			[value: 59, color: "#ddf1e4"],
			[value: 74, color: "#c6e9bc"],
			[value: 84, color: "#faf3b2"],
			[value: 95, color: "#f0c9b2"],
			[value: 96, color: "#eabdbd"]

valueTile("battery", "device.battery", inactiveLabel: true, height: 2, width: 2, decoration: "flat") {
	state ("battery", label:'${currentValue}%', icon:"", defaultState: true, backgroundColors:[
		[value: 100, color: "#44b621"],
		[value: 50, color: "#f1d801"],
		[value: 0, color: "#bc2323"],
standardTile("switcher", "device.switch", height: 2, width: 2, decoration: "flat") {
	state("off", action:"on", label: "off", icon: "st.thermostat.heating-cooling-off", backgroundColor:"#ffffff")
	state("on", action:"off", label: "on", icon: "st.thermostat.heat", backgroundColor:"#ffa81e")
standardTile("thermostatMode", "device.thermostatMode", height: 2, width: 2, decoration: "flat") {
			state("heat", label:"press for off", action:"off", icon:"st.thermostat.heat") //backgroundColor:"#ffa81e",
			state("off", label:"Press for On", action:"on", icon:"st.thermostat.heating-cooling-off") //backgroundColor:"#1e9cbb",
valueTile("temp", "device.temperature", width: 2, height: 2, inactiveLabel: true) { // hear to enable it to show in activity feed
	state ("temp", label:'${currentValue}°', defaultState: true, backgroundColors:[
		[value: 0, color: "#153591"],
		[value: 10, color: "#1e9cbb"],
		[value: 13, color: "#90d2a7"],
		[value: 17, color: "#44b621"],
		[value: 20, color: "#f1d801"],
		[value: 25, color: "#d04e00"],
		[value: 29, color: "#bc2323"],
valueTile("nextHeatingSetpoint", "device.nextHeatingSetpoint", width: 2, height: 2, inactiveLabel: true) { // hear to enable it to show in activity feed
	state ("nextHeatingSetpoint", label:'${currentValue}°', defaultState: true)
standardTile("summer", "device.summer", height: 2, width: 2, decoration: "flat") {
		state "off", 	label: "Press for \nSummer", 		action:"summer", 	icon: "", backgroundColor:"#d3d3d3"
		state "on", 	label: "Press to turn\n off summer", action:"summer", 	icon: "st.custom.wuk.clear"
    valueTile("lastseen", "device.lastseen", width: 6, height: 2, inactiveLabel: true) {
	state ("default", label:'Last seen ${currentValue}', defaultState: true)
    main "temperature"
	details(["temperature", "battery", "switcher","summer", "lastseen"]) //"thermostatMode"

preferences {
	input "wakeUpIntervalInMins", "number", title: "Wake Up Interval (min). Default 5mins.", description: "Wakes up and send\receives new temperature setting", range: "1..30", displayDuringSetup: true
	input "quickOnTemperature", "number", title: "Quick On Temperature. Default 21°C.", description: "Quickly turn on the radiator to this temperature", range: "5..82", displayDuringSetup: false
	input "quickOffTemperature", "number", title: "Quick Off Temperature. Default 4°C.", description: "Quickly turn off the radiator to this temperature", range: "4..68", displayDuringSetup: false

/* Event order
Scenario - temp is changed via the app
* BatteryReport (seem to get one of these everytime it wakes up! This is ood, as we don’t ask for it)
* WakeUpNotification (the new temperature, set by the app is sent)
* ScheduleOverrideReport (we don’t handle it)
* ThermostatSetpointReport (we receivce the new temp we sent when it woke up. We also set the heatingSetpoint and next one, all is aligned :))
Scenario - temp is changed via the app - alternative (this sometimes happens instead)
* ThermostatSetpointReport - resets the next temp back to the current temp. Not what we want :frowning:
* BatteryReport
* WakeUpNotification
* ScheduleOverrideReport
Scenario - temp is changed on the radiator thermostat
* BatteryReport (seem to get one of these everytime it wakes up! This is ood, as we don’t ask for it)
* ThermostatSetpointReport (we receive the temp set on the thermostat. We also set the heatingSetpoint and next one. If we set a next one, it’s overwritten.)
* ScheduleOverrideReport (we don’t handle it)
* WakeUpNotification (no temp is sent, as they’re both the same coz of ThermostatSetpointReport)
Scenario - wakes up
* BatteryReport
* WakeUpNotification
WakeUpINterval 300 (5mins) to 1800 (30 mins)
* Installed WakeUpIntervalSeconds: 300, minimumWakeUpIntervalSeconds: 60, wakeUpIntervalStepSeconds: 60

// All messages from the device are passed to the parse method. It is responsible for turning those messages into something the SmartThings platform can understand.
def parse(String description) {
//log.debug “RAW - $description”
def result = null
// The commands in the array are to map to versions of the command class. eg physicalgraph.zwave.commands.wakeupv1 vs physicalgraph.zwave.commands.wakeupv2
// If none specified, it’ll use the latest version of that command class.
def cmd = zwave.parse(description)
if (cmd) {
result = zwaveEvent(cmd) “Parsed ‘${cmd}’” // to ${result.inspect()}" //result.inspect shows all the decoded details removed to keep debugin tidye
else {
log.warn “Non-parsed event: ${description} — cmd = ‘${cmd}’”

def zwaveEvent(physicalgraph.zwave.Command cmd) { // catch all unhandled events
log.warn “Uncaptured/unhandled event for ${device.displayName}: ${cmd} to ${result.inspect()} and ${cmd.toString()}”
return createEvent(descriptionText: “Uncaptured event for ${device.displayName}: ${cmd}”)
def zwaveEvent(physicalgraph.zwave.commands.climatecontrolschedulev1.ScheduleOverrideReport cmd) { // dont actualy do anything with this message and messages are autmoticly retunred
//log.debug “Schedule Override Report ${device.displayName} ${cmd} key = OVERRIDE_STATE_NO_OVERRIDE = 0”
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) { // dont actualy do anything with this message
//log.debug “Wake Up Interval Report recived: ${cmd.toString()}”
def zwaveEvent(physicalgraph.zwave.commands.protectionv2.ProtectionReport cmd) { // dont actualy do anything with this message
//log.debug “Protection Report recived: ${cmd.toString()}”
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { // dont actualy do anything with this message
//log.debug “Version Command Class Report recived: ${cmd.toString()}”
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { // dont actualy do anything with this message
//log.debug “manufacturer specific Report recived: ${cmd.toString()}”
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalCapabilitiesReport cmd) { // dont actualy do anything with this message
//log.debug “Wake Up Interval Capabilities Report recived: ${cmd.toString()}”

def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { // example message – Parsed ThermostatSetpointReport(precision: 2, reserved01: 0, scale: 0, scaledValue: 21.00, setpointType: 1, size: 2, value: [8, 52])
state.scale = cmd.scale // So we can respond with same format later, see setHeatingSetpoint()
state.precision = cmd.precision

def eventList = []
def cmdScale = cmd.scale == 1 ? "F" : "C"
def radiatorTemperature = Double.parseDouble(convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision)).round(1) //reported setpoint
def currentTemperature = currentDouble("heatingSetpoint")	//current app setpoint
def nextTemperature = currentDouble("nextHeatingSetpoint")	// app next setpoint
def discText = ""
if(radiatorTemperature != currentTemperature){
	log.debug "ThermostatSetpointReport detected change, AppCurrent:${currentTemperature} AppNext:${nextTemperature} DeviceCurrent:${radiatorTemperature}"
    if(state.lastSentTemperature == radiatorTemperature) {
		discText = "Temperature changed by app to ${radiatorTemperature}°" + getTemperatureScale() + "."
    	log.debug "ThermostatSetpointReport - '${discText}'"
	else {
    	discText = "Temperature changed manually to ${radiatorTemperature}°" + getTemperatureScale() + "."
		log.debug "ThermostatSetpointReport -'${discText}'"
		state.lastSentTemperature = radiatorTemperature
		buildNextState(radiatorTemperature).each { eventList << it }

eventList << createEvent(name: "heatingSetpoint", value: radiatorTemperature, unit: getTemperatureScale(), displayed: false, descriptionText:discText)
eventList << createEvent(name: "coolingSetpoint", value: radiatorTemperature, unit: getTemperatureScale(), displayed: false, descriptionText:discText)
//eventList << createEvent(name: "thermostatSetpoint", value: radiatorTemperature, unit: getTemperatureScale(), descriptionText:discText)
def switchState = onOffEvent(radiatorTemperature).value
eventList << createEvent(name: "thermostatMode", value: (switchState == "on") ? "heat" : "off") //displayed: false
eventList << createEvent(name: "thermostatOperatingState", value: (switchState == "on") ? "heating" : "idle")
//eventList << createEvent(name: "thermostatTemperatureSetpoint", value: radiatorTemperature, unit: "C", displayed: false)

if (state.productId != "4") {
eventList << createEvent(name: "thermostatSetpoint", value: radiatorTemperature, unit: getTemperatureScale(), descriptionText:discText)
eventList << createEvent(name: "thermostatTemperatureSetpoint", value: radiatorTemperature, unit: "C", displayed: false)

if(nextTemperature == 0) { //	initialise the nextHeatingSetpoint, on the very first time we install and get the devices temp
	buildNextState(radiatorTemperature).each { eventList << it }
	state.lastSentTemperature = radiatorTemperature
return eventList


//Recives the actual temperature from the TRV.
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
//log.debug “Recive temparture value from device zwaveEvent $cmd)” //(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport
def events =
if (cmd.sensorType == 0x01) {
def reportedTemperatureValue = cmd.scaledSensorValue
def reportedTemperatureUnit = cmd.scale == 1 ? “F” : “C”
def convertedTemperatureValue = convertTemperatureIfNeeded(reportedTemperatureValue, reportedTemperatureUnit, 2)
def descriptionText = “temperature was $convertedTemperatureValue °” + getTemperatureScale() + “.”
state.temperature = convertedTemperatureValue
events << createEvent(name: “temperature”, value: convertedTemperatureValue, descriptionText: “$descriptionText”)
return events

def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
//log.debug “Wakey wakey zwaveEvent ${cmd}”

def nowtime = now()
def nowtimeplus = nowtime + (settings.wakeUpIntervalInMins * 60 * 1000)
def nowtimeplusdate = new Date(nowtimeplus)

// log.debug “now = $nowtime, plus = $nowtimeplus, ${nowtimeplusdate.format(‘HH:mm’)}” //,location.timeZone

state.ComCount = 0
def event = createEvent(name: "wake up", value: "${new Date().time}", descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
def encap = []
sendEvent(name: "lastseen" , value: "${new Date().format("dd-MM-yy HH:mm")} Next Expected ${nowtimeplusdate.format('HH:mm')}", displayed: false) //${settings.wakeUpIntervalInMins}

if (!state.lastBatteryReportReceivedAt || (new Date().time) - state.lastBatteryReportReceivedAt > daysToTime(7)) {
log.trace “WakeUp - Asking for battery report as over 7 days since”
state.ComCount = state.ComCount + 1
state.ComBat = true
//cmds << zwave.batteryV1.batteryGet().format()
if (!state.lastClockSet || (new Date().time) - state.lastClockSet > daysToTime(7)) {
log.trace “WakeUp - Updating Clock as 7 days since - clock details state = ‘${state.lastClockSet}’ and new date ${new Date().time}”
state.ComCount = state.ComCount + 1
state.ComClock = true
//cmds << currentTimeCommand()
// wake up intval
if (state.configrq == true) {
log.trace “WakeUp - Sending - wakeUpIntervalSet='${state.wakeUpEvery}'s or '${state.wakeUpEvery/60}'min, this normally takes a full cycle to come into effect”
state.ComCount = state.ComCount + 6
state.ComWake = true
//cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds:state.wakeUpEvery, nodeid:zwaveHubNodeId).format()
state.configrq = false
// temp setpoint
def nextHeatingSetpoint = currentDouble(“nextHeatingSetpoint”)
def heatingSetpoint = currentDouble(“heatingSetpoint”)

if (nextHeatingSetpoint != 0 && nextHeatingSetpoint != heatingSetpoint) {
	log.trace "WakeUp - Sending new temperature ${nextHeatingSetpoint}, curent heating setpoint ${heatingSetpoint}"
	state.lastSentTemperature = nextHeatingSetpoint
    state.ComSetTemp = true
	//cmds << setHeatingSetpointCommand(nextHeatingSetpoint).format()
    //cmds << "delay 2000"
	//cmds << zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
    state.ComCount =  state.ComCount + 2
// no more - go back to sleep

state.ComCount =  state.ComCount + 1 // for no more info

encap << zwave.multiCmdV1.multiCmdEncap(numberOfCommands: state.ComCount).format() //implmented 10/12/18 this 68% other 73% dif 5%
if (state.ComBat == true){
	cmds << zwave.batteryV1.batteryGet().format()
	state.ComBat = false
if (state.ComClock == true){
	cmds << currentTimeCommand()
    state.ComClock = false
if (state.ComWake == true){
	cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()
    cmds << zwave.versionV1.versionGet().format()
	cmds << zwave.protectionV1.protectionGet().format()
    cmds << zwave.wakeUpV2.wakeUpIntervalCapabilitiesGet().format()
	cmds << zwave.wakeUpV1.wakeUpIntervalSet(seconds:state.wakeUpEvery, nodeid:zwaveHubNodeId).format()
    cmds << "delay 1900"
    cmds << zwave.wakeUpV1.wakeUpIntervalGet().format()
    state.ComWake = false
if (state.ComSetTemp == true){
	cmds << setHeatingSetpointCommand(nextHeatingSetpoint).format()
    cmds << "delay 1900"
	cmds << zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
    state.ComSetTemp = false

cmds << zwave.wakeUpV2.wakeUpNoMoreInformation().format()

encap << cmds.collect{ (it instanceof physicalgraph.zwave.Command ) ? response(encapCommand(it)) : response(it) }
log.trace "WakeUp - commands are ${cmds}, command count is $state.ComCount, encap is ${encap} - product id - ${state.productId}"
state.ComCount = 0

return [event, response(delayBetween(encap, 10))]
//[event, response(delayBetween(cmds, 50))]

def zwaveEvent(physicalgraph.zwave.commands.multicmdv1.MultiCmdEncap cmd) { //this should be used to save battery but how!
log.debug “MultiCmd with $numberOfCommands inner commands”
cmd.encapsulatedCommands(commandClassVersions).collect { encapsulatedCommand →

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: “battery”, unit: “%” ]
if (cmd.batteryLevel == 0xFF) { // Special value for low battery alert
map.value = 1
map.descriptionText = “Low Battery”
else {
map.value = cmd.batteryLevel
state.lastBatteryReportReceivedAt = new Date().time // Store time of last battery update so we don’t ask every wakeup, see WakeUpNotification handler

def currentTimeCommand() {
def nowCalendar = Calendar.getInstance(location.timeZone)
def weekday = nowCalendar.get(Calendar.DAY_OF_WEEK) - 1
if (weekday == 0) {
weekday = 7
log.debug “currentTimeCommand Setting clock to hour=‘${nowCalendar.get(Calendar.HOUR_OF_DAY)}’, minute=‘${nowCalendar.get(Calendar.MINUTE)}’, DayNum=‘${weekday}’”
state.lastClockSet = new Date().time // Store time of last time update so we only send once a week, see WakeUpNotification handler
return zwave.clockV1.clockSet(hour: nowCalendar.get(Calendar.HOUR_OF_DAY), minute: nowCalendar.get(Calendar.MINUTE), weekday: weekday).format()

// commands (that it can handle, must implement those that match it’s capabilities, so SmartApps can call these methods)
// TODO: review the commands, do they have the right interface/params

def temperatureUp() {
def nextTemp = currentDouble(“nextHeatingSetpoint”) + 0.5d
// TODO: deal with Farenheit?
if(nextTemp > fromCelsiusToLocal(28)) { // It can’t handle above 28, so don’t allow it go above
nextTemp = fromCelsiusToLocal(28)

def temperatureDown() {
def nextTemp = currentDouble(“nextHeatingSetpoint”) - 0.5d
if(nextTemp < fromCelsiusToLocal(4)) { // It can’t go below 4, so don’t allow it
nextTemp = fromCelsiusToLocal(4)

// this enables a cooling temparture to be in Apps but sends to setThermostat Heating Setpoint
def setCoolingSetpoint(temp){
log.debug “setCoolingSetpoint - temp of ‘${temp}’, sending temp value to setHeatingSetpoint”
def setHeatingSetpoint(degrees) {
log.debug “setHeatingSetpoint(just degrees) - Storing temperature for next wake ${degrees}”
def setHeatingSetpoint(Double degrees) {
log.debug “setHeatingSetpoint(Double deg) - Storing temperature for next wake ${degrees}”
if (state.summer == “on” && degrees != 28){
degrees = 28.0
log.warn “temp changed to ${degrees} as in summer mode”
sendEvent(name:“nextHeatingSetpoint”, value: degrees.round(1), unit: getTemperatureScale())
def setHeatingSetpointCommand(Double degrees) {
log.trace “setHeatingSetpointCOMMAND(DD) setting to ‘${degrees}’”
if (state.summer == “on” && degrees != 28){
degrees = 28.0
log.warn “temp changed to ${degrees} as in summer mode”
def deviceScale = state.scale ?: 0
def deviceScaleString = deviceScale == 1 ? “F” : “C”
def locationScale = getTemperatureScale()
def precision = state.precision ?: 2
def convertedDegrees
if (locationScale == “C” && deviceScaleString == “F”) {
convertedDegrees = celsiusToFahrenheit(degrees)
else if (locationScale == “F” && deviceScaleString == “C”) {
convertedDegrees = fahrenheitToCelsius(degrees)
else {
convertedDegrees = degrees
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: precision, scaledValue: convertedDegrees)

def on() {
//def nexttemp = currentDouble(“nextHeatingSetpoint”)
//sendEvent(name: “thermostatMode”, value: “heat”, descriptionText: “turned on”, displayed: true)
setHeatingSetpoint(quickOnTemperature ?: fromCelsiusToLocal(21))

def off() {
setHeatingSetpoint(quickOffTemperature ?: fromCelsiusToLocal(4))
//sendEvent(name: “thermostatMode”, value: “off”, descriptionText: “turned off”, displayed: true)

def installed() {
log.debug “installed”
state.configrq = false
state.lastClockSet = “”
state.lastBatteryReportReceivedAt = “”
zwave.configurationV1.configurationSet(parameterNumber:1, size:2, scaledConfigurationValue:100).format(), // not sure if needed
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(), // Get it’s configured info, like it’s scale (Celsius, Farenheit) Precicsion // 1 = SETPOINT_TYPE_HEATING_1
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(),
currentTimeCommand(), // Set it’s time/clock. Do we need to do this periodically, like the battery check?
zwave.wakeUpV1.wakeUpIntervalSet(seconds:300, nodeid:zwaveHubNodeId).format() // Make sure sleepy battery-powered sensor sends its UpNotifications to the hub every 5 mins intially
], 1000)
log.debug “installed finished - wakeUpIntervalSet to 300”

def updated() {
log.debug “updated”

def configure() {
def wakeUpEvery = (wakeUpIntervalInMins ?: 5) * 60
log.debug “prodID - ${state.productId}”
if (state.productId == “4”) {
//device.temperature = " "
sendEvent(name: “temperature”, value: null , unit: null, descriptionText: “device does not report temparture”)
sendEvent(name: “thermostatSetpoint”, value: null, unit: null, descriptionText:“device does not report temparture”)
sendEvent(name: “thermostatTemperatureSetpoint”, value: null, unit: null, descriptionText:“device does not report temparture”)
log.trace “device dose not report temp”

state.supportedModes = [off,heat] // basic modes prior to detailes from device
state.minHeatingSetpoint = 4
state.maxHeatingSetpoint = 28
sendEvent(name:"minHeatingSetpoint", value: state.minHeatingSetpoint, unit: "°C", displayed: false)
sendEvent(name:"maxHeatingSetpoint", value: state.maxHeatingSetpoint, unit: "°C", displayed: false)
log.trace "setDeviceLimits - device max/min set"
state.configrq = true
state.lastClockSet = ""
state.wakeUpEvery = wakeUpEvery
log.debug "Configure - storing wakeUpInterval for next wake '$state.wakeUpEvery'seconds AND configuration flag is $state.configrq"


def buildNextState(Double degrees) {
def nextStateList =

nextStateList << createEvent(name:"nextHeatingSetpoint", value: degrees, unit: getTemperatureScale(), displayed: false)
nextStateList << createEvent(onOffEvent(degrees))


def onOffEvent(Double degrees) {
if(degrees > (quickOffTemperature ?: fromCelsiusToLocal(4))) {
[name:“switch”, value: “on”, displayed: false]

else {
	[name:"switch", value: "off", displayed: false]


def daysToTime(days) { // used during wake up to calculate ‘7’ day to time

def fromCelsiusToLocal(Double degrees) {
if(getTemperatureScale() == “F”) {
return celsiusToFahrenheit(degrees)
else {
return degrees

def currentDouble(attributeName) {
if(device.currentValue(attributeName)) {
return device.currentValue(attributeName).doubleValue()
else {
return 0d
/// misc stuff
def heat() {
def cool() {
def emergencyHeat() {
def setThermostatMode(mode){
if (mode == “on” || mode == “heat” || mode == “auto”) { heat() }
if (mode == “off”) { off()}
//if (mode == “cool” || mode == “eco”) { ecoheat() }
if (mode == “emergency heat”) {emergencyHeat()}
//“rush hour” ??
log.debug “set mode $mode”
def fanOn() {
def fanAuto() {
def fanCirculate() {
def setThermostatFanMode(mode) {
def auto() {
def summer() {
def discText = " "
def temp = 0
def cmds =
if (state.summer == “on” || state.summer == null){ “summer is on so turn off”
temp = 20
discText = “summer mode off, temp change commands will processed as normall”
state.summer = “off”
else if (state.summer == “off”){ “summer is off, turning on”
temp = 28
discText = “summer mode activated, all temp change commands will be blocked and the trv will stay fully open. Mannual adjustment will turn this off”
state.summer = “on”
else {
log.warn “shouldnt go here”
temp = 20
state.summer = “off”
discText = “some thing went wroung in summer mode”
cmds << sendEvent(name: “summer”, value: state.summer, descriptionText: discText)
cmds << setHeatingSetpoint(temp)

Does anyone know if there’s an edge driver for this Iris plug that monitors the power and energy as well as allows the repeater capability?


The Z-Wave standard classifies devices and provides a “basic command set” for each device. It’s reasonable to assume that SmartThings will first assign a driver that matches the exact fingerprint; if there is none, it will assign the generic driver for the device type. If you use only basic functions of your Z-Wave device (turn a switch on or off, test if a sensor is open or closed, set a thermostat temperature) then this will almost surely be supported by a generic driver.

Custom drivers are helpful only if you use non-generic features - detect double- or triple tap of a switch; set minimum level or ramp rate of a dimmer; trigger on a metering switch level; adjust motion sensor sensitivity; etc. Indeed, the finite memory in SmartThings hubs may force you to use generic drivers if you don’t use non-generic features.

anyone know of an edge driver for this or the zwave alternative? or could create one?

Nice looking device. The product description says it’s “guaranteed to work with smartthings“, have you asked them if it will have an edge driver?

As far as possible alternatives, There’s an eight button device available on both the US and UK zwave frequencies which does have an edge driver, but it’s not really intended as a handheld remote, more as a wall controller.


Here’s the community-created edge driver for the Remotec device:

1 Like

Yes contacted them and explained that they do not have an edge driver, just older drivers that do not work or will not in short future. They have no plans to create an edge driver at present but continue to advertise it is compatable . . so after 4 emails gave up trying to explain the problem. so any TV lookalike remote e.g. handhld that would work . looked at the scene Master and its not exactly a handheld . . thanks for your reply

1 Like

If you can wait a few months once Matter is more widely deployed we should see a lot more devices available to use with SmartThings from many different companies, all usable without custom code. :tada:

The SmartThings V3 hub was the very first device certified for Matter this week, although the integration is not live yet. So it’s definitely coming.

That won’t help with zwave devices, but there may well be a Thread alternative soon.

No promises, but I personally am delaying most new device purchases for a few months just to see what’s available once Matter is an option. 🕵🏽‍♂️

1 Like

Any luck finding something for this? I have a feeling my basement bar is going to be in the dark tomorrow.

Tomorrow is just the start of the migration. If there isn’t an appropriate Edge driver for the device it shouldn’t just stop working (yet).

FortrezZ MIMOlite
Qubino Flush 1 Relay
Qubino Flush 2 Relays
Qubino Temperature Sensor
Fibaro Flood Sensor



Hey all, just wanted to post an update on the Qubino devices. I reached out to Qubino and they indicated that they are actively working on Edge Drivers for their devices and will have them done before Groovy is shut down. I use a ton of them, so hopefully this will help comfort anyone else who was as nervous as I was about loosing the use of these amazing devices.


Qubino Flush relays appear to be fully supported by “Z-Wave Switch” in the community-created Edge drivers. The channel is here. (I have two Flush 2.)

The only trick is that to access the second relay in the Flush 2 by name (i.e. with Google Assistant) you need to create a virtual switch and synchronize it with the Flush 2 “Switch2” using four routines, or a virtual switch mirror device driver. This may change before general release…

I It looks like Temperature Sensor support is in process - see e.g. this pull request.


Edge Driver for Ring Alarm Motion Sensor & Ring Alarm Contact Sensor

I searched the ST Community forum and I have not been able to find any Edge Driver support for Ring Alarm Sensor. The Motion sensor is currently installed with the ‘Z-Wave Motion Sensor’ DTH. The contact sensor is currently installed with the ‘Z-Wave Plus Door/Window Sensor’ DTH. Will the devices using the stock DTH automatically be migrated over?

I have provided additional information assuming data is needed for these devices.

Data and RAW description for Motion Sensor:

Data * MSR: 0346-0301-0301

  • networkSecurityLevel: ZWAVE_S2_AUTHENTICATED
    Raw Description zw:Fs2a type:0701 mfr:0346 prod:0301 model:0301 ver:1.09 zwv:7.12 lib:03 cc:5E,9F,6C,55 sec:59,85,80,70,5A,7A,87,72,8E,71,73,86

Data and RAW description for Contact Sensor:

Data * networkSecurityLevel: ZWAVE_S2_AUTHENTICATED
Raw Description zw:Ss2a type:0701 mfr:0346 prod:0201 model:0301 ver:1.15 zwv:7.12 lib:03 cc:5E,9F,6C,55 sec:59,85,80,70,5A,7A,87,72,8E,71,73,86,84

What happened with this option?

Edge Driver needed for the Ring Alarm Contact Sensor Using the 'Z-Wave Plus Door/Window Sensor' DTH

As far as what will happen, it all depends on the fingerprint. If the fingerprint is in one of the new stock drivers, it will be migrated over if it is currently using a groovy DTH and there is no custom edge driver with a matching fingerprint.

If you manually changed it to a stock DTH, that won’t cause it to be automatically migrated to the stock edge driver.

1 Like

To my knowledge still works, as all my windows and doors are equipped wirh Ring Contact Sensors


Milan: About your comment, “To my knowledge still works, as all my windows and doors are equipped with Ring Contact Sensors”, my sensor is not showing “driver” in the setting menu. Did you uninstall and reinstall the device to pickup an edge driver or did you download a driver and change it manually?


Disregard my follow-up question. I was able to get the contact sensor connected to ST. To accomplish this, I deleted and excluded the contact sensor. Exclusion is done by entering the Z-wave Exclusion utility and then holding the reset button inside the battery compartment for about 10 seconds until the ring light on the front of the sensor turns a steady red. (Note: It was difficult to exclude and I finally need to force delete the device.)
For inclusion, I just selected scan for nearby devices and then held the front button for 3 seconds and then released. This puts the device in “Classic Inclusion Mode”. During Classic Inclusion mode, the green LED will blink three times followed by a brief pause, and it does this sequence repeatedly. I was unable to get ST to discover the contact sensor in this mode. While the the device was still flashing, I again tried to scan for nearby devices and this time I held the front button down for at least 10 seconds and released. This caused the device to rapid flash green and the device was discovered. I then enabled S2 Security by scanning my QR code and the device was successfully setup. It is now displaying “Driver” in the settings menu and it is installed with the ‘Z-Wave Sensor Ring’ Driver. It is also showing ‘placeholder’ in for the device type.

NOTE: I was not successful with paring the Ring Alarm Motion Sensor with ST using the above references driver. The motion sensor pairs as a “Z-Wave Device” DTH.

Here are a couple of screen shots of the Ring Alarm Contact Sensor:


Yes, i removed all sensors and added them back again