Z-Wave Issues with Firmware Update 30.3

I wrote the following write up to help explain the situation to our users and provide potential workarounds to those are still experiencing issues post 0.30.4 release.

Background Info

Let’s talk a little Z-Wave, so we are all on the same page about this particular situation.

In Z-Wave, when a device is added to the network, it is assigned a Network ID (valid ranges 1-232), even when Multi Channel devices, for example a Z-Wave Power Strip or a Double Switch, joins the network, it gets assigned ONE number. In many protocols (i.e. Bluetooth Mesh), similar devices will have unique address for each endpoint/entity. So this means that addressing these entities must be done in the application layer instead of the transport/network layer.

The power strip that we are using in this scenario here has 4 outlets, and let’s say the different devices on the network want to control the individual outlets. This is where “Multi Channel Command Class” comes in play in Z-Wave Specification, which includes a simple command to allow the sender to specify the “destination endpoint” and the “source endpoint”

For a power strip of 4 outlets, you will have endpoint 0 (the root/main) device, and endpoints 1, 2, 3, 4 for the individual outlets here. Let’s you want to shut the whole thing off or read the manufacturer information about the device, you will use Root .

Let’s say the Hub wants to turn on the 2nd outlet, it will generate the following Z-Wave message.

Command Class: Multi Channel Command Class (0x60)
Command:  Multi Channel Command Encapsulation (0x0D)
Source Endpoint: 0 (for the Hub - Non multi channel devices)
Destination Endpoint: 2 (2nd outlet)
Encapsulated Command[] = {TURN ON COMMAND}

And when the 2nd outlet receives the command, performs the operation and wants to reply with a completion status It will generate the follow command

Command Class: Multi Channel Command Class (0x60)
Command:  Multi Channel Command Encapsulation (0x0D)
Source Endpoint: 2 (2nd outlet)
Destination Endpoint: 0 (for the Hub - Non multi channel devices)
Encapsulated Command[] = {ON STATUS}

Simple enough right? So how did the compatibility break with devices starting with 0.30.3 firmware release?

What prompted the incompatibility issues in 0.30.3?

Well, we recently went through a round of Z-Wave certification (Early 2020), and one of the things that we failed and later fixed was that whenever our hub received a Multi Channel Command Encapsulation from any device, we would essentially ignore Destination Endpoint and treat any message as if the destination endpoint was 0. In 0.30.X we landed a set of changes that fixed the Z-Wave compliancy issues in the previous firmwares, and one of the changes that was made was to drop any incoming messages from Destination Endpoints not 0.

0.30.3 was released and a lot of you were frustrated that previously working devices were broken, and the obvious and logical thinking here was that the firmware broke the integration. Unfortunately, that particular change highlighted the devices that were technically non-compliant, but had always worked because of the hub being non-compliant. So technically, when you have two devices being non-compliant, they are some what compliant :slight_smile: . Unfortunately, we cannot update the firmware on the devices to fix their wrong (different topic that I get very nice messages for on a regular basis).

TL;DR - SmartThings Hub was previously (Hub Firmware 0.29.X and older) ignoring the Destination Endpoint from Multi Channel devices,. Per Z-Wave Specification, the only valid Destination Endpoint for the hub or non Multi Channel device is 0 and any other message must be ignored. We rolled out a series of compliancy bug fixes in 0.30.3 which highlighted and broke integration with non-compliant devices that were sending unsolicited messages to Destination Endpoint that is not 0.

How I would explain it to my kids: We (SmartThings Hub) live on a street with only our house on it, anytime our friends (Z-Wave Devices like our old Fibaro friends) would send letters (Unsolicited Messages), we would open it up regardless of the House number (Destination endpoint), and the postman (Z-Wave Certification) got mad that we did that, so we now only open the letters assigned specifically to our house.

0.30.4 Release

In 0.30.4, We made a conscious change to allow incoming messages with Destination Endpoints of 1 to also propagate through the system, because the specification available at the time (3 years or older) may have confused some manufacturers on the proper addressing for Destination Endpoint, we also found that most of the “incorrect” messages were using Destination Endpoint of 1. We believe this change is a reasonable and compromise between supporting old/legacy Z-Wave devices and being Z-Wave Compliant.

0.30.5 Release

We now allow all endpoints.

Some devices are still not working?

Let us know.

Let’s start with, Why won’t you just return the same behavior as in 0.29.X and older?

05/11/2020 Update -
We made a modification to allow all endpoints.


Simple answer is that we must be Z-Wave compliant. This is where I ask that you can understand the predicament we are in. Before we can take this proposed change to Z-Wave certification, we need to understand the number of affected devices and users. I will provide updates as things progress.

Potential workarounds

So at this point, we made clear that the problem here is that there are devices generating unsolicited messages with invalid Destination Endpoints (not 0 or 1) and the hub is dropping them per Z-Wave specification.

So what are some potential work arounds?

Is the device “Works With SmartThings”?

If your affected device is having the exact or very similar issues as the problem statement above, and is a SmartThings compatible device (“Works With SmartThings”), then please do let us know immediately which device it is and what functionality is not working. We will work immediately to ensure the compatibility is what we had provided.

The list of SmartThings compatible devices are available in the following link: https://www.smartthings.com/products

Contact the Device Manufacturer

I understand this is not a pleasing solution, and can be time consuming and potentially not successful, but if your device is non-compliant, it most likely could end up having the same compatibility issues with other and future hubs. So it is best to get a replacement or a newer version of the same device.

Devices using Third Party/Custom Device Type Handlers

Please evaluate if you are having the same problem with SmartThings release Device Type Handlers

Polling your device instead of Unsolicited Messages from the device

Per Z-Wave Specification, a device returning a response to a Multi Channel encapsulated command MUST swap the Source and Destination End Point. This has always been a clear specification from Day 1, so I cannot imagine many or if any certified devices that violate this particular rule. This means, that if Device A with Source Endpoint of X, sends a message to Device B with Destination endpoint of Y, then Device B must respond to Destination endpoint of X in Device A.

This can be useful where instead of having the device send wrong unsolicited message, we can change the Device groovy DTH to poll the endpoints. For example, you can essentially set a timer in your groovy DTH and poll the different endpoints for the data that you are interested in. In the following example, The Hub is Polling the device’s endpoints (3, 4, 5, 6) every 90 seconds for their sensor reading (temperature in this case).

def tempReadRequest() {
    def cmds = []
    runIn(90, "tempReadRequest")
    log.debug "tempReadRequest"
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 3))
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 4))
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 5))
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 6))
	sendHubCommand(cmds,1000)
}
private encap(cmd, endpoint = null) {
	if (cmd) {
		if (endpoint) {
			cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd)
		}
		if (zwaveInfo.zw.contains("s")) {
			zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
		} else {
			cmd.format()
		}
	}
}

There are several downside to this workaround:

  • Extra traffic in the Z-Wave Network
  • Not scalable solution for the long term (I know it is because of our conscious decision to drop messages)
  • Custom DTH
  • Slow to catch the transitions

Given the situation we find ourselves in, I believe this is a reasonable compromise.

Last words

Sorry for a lot of words and grammar/spelling errors. I understand this has been frustrating, I only ask that you understand the reasoning behind the changes in 0.30.3/.4. We sincerely do care about all of users, and I am happy and proud to be in the company of my peers who have spent their days, nights and weekends working on this issue and many other issues that are now in our rear view. I also understand that it would have better to have caught this issue before 0.30.3 release, we certainly do have a lot to improve, I think this is where I ask you the brave ones, to join our Hub firmware beta program and yell at me earlier.

Thanks everyone!

17 Likes

I’ve received the new beta firmware last night (Australia). I’m using the built-in Fibaro DTH and I can confirm the Fibaro Dimmer 2 module is working properly now.

  • Can the built-in DTH be updated (I’ve seen couple in your repo with forced local execution) so that we won’t have to rely on cloud execution?
1 Like

I place my hub on a 25 foot cat 5 cable and extension cord so I can drag it around to repair devices… yes a pain, but I found it easier than to keep taking switches apart.

On the beta firmware 0.304 and my fibro Universal binary sensors are still not working. Is this the right place to reply as I am also new to the beta program.

In my setup Fibaro Double switch and fibaro
UBS(I use just contacts sensor) works again.
No issues until now!

Thanks

See the post above from Kianoosh. If you are using a custom DTH for your UBS, some modifications will need to be made for it to work. Hopefully the creator of this custom DTH can offer an update or someone else can fork and update the code.

2 Likes

I have the new beta firmware installed now, and both of my Fibaro FGS-223 modules are working great with the stock DTH. Thanks @jody.albritton and @Kianoosh_Karami for your help and hard work on this.

1 Like

Fair point… BUT:

When you run into such a major incompatibility for a critical system like ST what you do is rollback IMMEDIATELY and work with your beta team to find a suitable workaround. You prepare your customer base for the changes coming, informing them of the incompatibilities and when everyone is ready your roll out the new version. ST has been non-compliant for a while now, so a few more weeks wouldn’t change anything. But you would have avoided all the frustration that 0.30.3 caused.

My 2cents

4 Likes

Apparently they are not allowed to roll back because unfortunately the update is actually enforcing standards. If they rolled back, they’re technically not allowed to have the hub certified as zwave-stamped. At least that’s how I’ve picked things up.

I was (rather publicly) more frustrated that most due to the issues on my system … a matter of hours ago. Luckily after a massive amount of support it’s looking like my system is up and running properly again, I just need to add a few things back to verify.

I really do think that there should be an option for users to either block an update, or be able to upload an alternative firmware. If that’s possible. Surely that would take the onus off the company enabling you guys to “keep the badge” so to speak, without forcing users into a potentially unhappy position ?

1 Like

With a system that runs most parts from the cloud allowing multiple versions running simultaneously across the world would only complicate things. They force the update for everyone to make managing the cloud easier and this is an acceptable approach as long as there are no issues. But with an open platform (custom DTH etc) maintaining compatibility with every update can be really hard to ensure.

My only objection to the handling of this crisis was my previous point. They should have rolled back immediately, figure out the workaround and then proceed. Compliance is great to have but reliability is a must for systems like ST and I am afraid trust to ST has been severely compromised the last few days.

2 Likes

Hello, i’m trying to implement in FIbaro UBS what you shared with us with a “refresh” like capability to get endpoint status.

Fibaro UBS reply on temp changes or open/close sensor on:
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd)

I have tried your code but I get no answer from Fibaro UBS, so i have tried:
command(zwave.basicV1.basicGet())

and I get basic report that not include all the information related to destination endpoint.

Can you please help me?

Thanks
Marco

Fibaro ubs also is not working for me, i have no temperature reading at all, i have reset it, repaired it at least 5 times and nothing. Qubino flush 1 relay same as without beta, when i refresh it it shows me temperature change, if i dont refresh manualy no temperature change. Please help

For Fibaro UBS this DTH works for me:

/**
 *  Device Type Definition File
 *
 *  Device Type:		Fibaro UBS - Dual Contact and Temperature Sensor
 *  File Name:			Fibaro UBS - Dual Contact and Temperature Sensor.groovy
 *	Initial Release:	2017-11-07
 *	Author:				Chris Charles
 *
 *  Copyright 2017 Chris Charles, based on original code by carlos.ir33, modified
 *  by Stuart Buchanan and Paul Crookes. Testing thanks to borristhecat.
 *
 ***************************************************************************************
 */
 
metadata {
	definition (name: "Fibaro UBS", namespace: "cjcharles0", author: "Chris Charles") {
    
    capability "Contact Sensor"
 	capability "Motion Sensor"
    capability "Sensor"
	capability "Temperature Measurement"
    capability "Configuration"
    
    command "removeChildDevices"
    command "createChildDevices"
    command "createChildTempDevices"
    command "updateCurrentParams"
    command "listCurrentParams"
    command "open1"
    command "open2"
    command "close1"
    command "close2"
    
    attribute "contact1","enum",["open1","close1"]
    attribute "contact2","enum",["open2","close2"]
	
	fingerprint type: "2001", cc: "30 60 85 8E 72 70 86 7A", ccOut: "2B"
}

simulator {
}

tiles(scale: 2) {
	standardTile("contact1", "device.contact1", width: 3, height: 2) {
		state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13", action: "close1"
		state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc", action: "open1"
	}
	standardTile("contact2", "device.contact2", width: 3, height: 2) {
		state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13", action: "close2"
		state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc", action: "open2"
	}
	
	standardTile("temp1text", "temp1text", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Temp 1:', action:"", icon:""
	}
	standardTile("temp2text", "temp2text", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Temp 2:', action:"", icon:""
	}
	standardTile("temp3text", "temp3text", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Temp 3:', action:"", icon:""
	}
	standardTile("temp4text", "temp4text", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Temp 4:', action:"", icon:""
	}
	valueTile("temperature1", "temperature1", width:1, height:1, decoration: "flat") {
		state "default", label:'${currentValue}°', unit:"C", backgroundColor:"#fab907"//, icon:"st.Weather.weather2"
    }
	valueTile("temperature2", "temperature2", width:1, height:1, decoration: "flat") {
		state "default", label:'${currentValue}°', unit:"C", backgroundColor:"#fab907"//, icon:"st.Weather.weather2"
    }
	valueTile("temperature3", "temperature3", width:1, height:1, decoration: "flat") {
		state "default", label:'${currentValue}°', unit:"C", backgroundColor:"#fab907"//, icon:"st.Weather.weather2"
    }
    valueTile("temperature4", "temperature4", width:1, height:1, decoration: "flat") {
		state "default", label:'${currentValue}°', unit:"C", backgroundColor:"#fab907"//, icon:"st.Weather.weather2"
    }

	standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 3, height: 1) {
		state "default", label:'Send Config', action:"updateCurrentParams"//, icon:"st.secondary.configure"
	}
	standardTile("report", "device.report", inactiveLabel: false, decoration: "flat", width: 3, height: 1) {
		state "default", label:'List Config', action:"listCurrentParams"
	}
    
    standardTile("createchildren", "createchildren", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Create Contact Children', action:"createChildDevices"
	}
    standardTile("createtempchildren", "createtempchildren", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Create Temperature Children', action:"createChildTempDevices"
	}
    standardTile("removechildren", "removechildren", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Remove Child Devices', action:"removeChildDevices"
	}
}

main(["contact1"]) //, "temperature1"
details(["contact1","contact2",
		"temp1text", "temperature1", "temp2text", "temperature2",
        "temp3text", "temperature3", "temp4text", "temperature4",
        "configure", "report", "createchildren", "createtempchildren", "removechildren"])

preferences {
        input name: "Info", type: "paragraph", title:"Device Handler by @cjcharles", description: "Parameter Settings:", displayDuringSetup: false

        input name: "param1", type: "number", range: "0..65535", required: true, //defaultValue: "0",
            title: "Parameter No. 1 - Input 1 Alarm Cancellation Delay. \n" +
                   "Additional delay after an alarm from input 1 has ceased.\n" +
                   "Time in seconds to delay the ceasing event.\n" +
                   "Default value: 0."
       
        input name: "param2", type: "number", range: "0..65535", required: true, //defaultValue: "0",
            title: "Parameter No. 2 - Input 2 Alarm Cancellation Delay. \n" +
                   "Additional delay after an alarm from input 2 has ceased.\n" +
                   "Time in seconds to delay the ceasing event.\n" +
                   "Default value: 0."
       
        input name: "param3", type: "number", range: "0..3", required: true, //defaultValue: "1",
            title: "Parameter No. 3 - Type of Input No 1." +
                   "Available settings:\n" +
                   "0 – INPUT_NO (Normal Open)\n" +
				   "1 – INPUT_NC (Normal Close)\n" +
				   "2 – INPUT_MONOSTABLE\n" +
				   "3 – INPUT_BISTABLE\n" +
                   "Default value: 1."

		input name: "param4", type: "number", range: "0..3", required: true, //defaultValue: "1",
            title: "Parameter No. 4 - Type of Input No 2." +
                   "Available settings:\n" +
                   "0 – INPUT_NO (Normal Open)\n" +
				   "1 – INPUT_NC (Normal Close)\n" +
				   "2 – INPUT_MONOSTABLE\n" +
				   "3 – INPUT_BISTABLE\n" +
                   "Default value: 1."

		input name: "param5", type: "number", range: "0..255", required: true, //defaultValue: "255",
            title: "Parameter No. 5 - Type of transmitted control or alarm frame for association group 1." +
                   "Available settings:\n" +
				   "0 – Frame ALARM GENERIC\n" +
				   "1 – Frame ALARM SMOKE\n" +
				   "2 – Frame ALARM CO\n" +
				   "3 – Frame ALARM CO2\n" +
				   "4 – Frame ALARM HEAT\n" +
				   "5 – Frame ALARM WATER\n" +
				   "255 – Control frame BASIC_SET\n" +
                   "Default value: 255."

		input name: "param6", type: "number", range: "0..255", required: true, //defaultValue: "255",
            title: "Parameter No. 6 - Type of transmitted control or alarm frame for association group 2." +
                   "Available settings:\n" +
				   "0 – Frame ALARM GENERIC\n" +
				   "1 – Frame ALARM SMOKE\n" +
				   "2 – Frame ALARM CO\n" +
				   "3 – Frame ALARM CO2\n" +
				   "4 – Frame ALARM HEAT\n" +
				   "5 – Frame ALARM WATER\n" +
				   "255 – Control frame BASIC_SET\n" +
                   "Default value: 255."

		input name: "param7", type: "number", range: "0..255", required: true, //defaultValue: "255",
            title: "Parameter No. 7 - Value of the parameter specifying the forced level of dimming / opening sun blinds when " +
            	   "sent a “switch on” / ”open” command from association group no. 1.\n" +
                   "Available settings:\n" +
                   "0-99 - Dimming or Opening Percentage\n" +
                   "255 - Last set percentage\n" +
                   "Default value: 255."

		input name: "param8", type: "number", range: "0..255", required: true, //defaultValue: "255",
            title: "Parameter No. 8 - Value of the parameter specifying the forced level of dimming / opening sun blinds when " +
            	   "sent a “switch on” / ”open” command from association group no. 2.\n" +
                   "Available settings:\n" +
                   "0-99 - Dimming or Opening Percentage\n" +
                   "255 - Last set percentage\n" +
                   "Default value: 255."

		input name: "param9", type: "number", range: "0..3", required: true, //defaultValue: "0",
            title: "Parameter No. 9 - Deactivating transmission of the frame cancelling the alarm or the " +
				   "control frame deactivating the device (Basic). Disable the alarm cancellation function.\n" +
                   "Available settings:\n" +
                   "0 – Cancellation sent for association group 1 and 2\n" +
				   "1 – Cancellation sent for association group 1 only\n" +
				   "2 – Cancellation sent for association group 2 only\n" +
				   "3 - Not sent for association group 1 or 2\n" +
                   "Default value: 0."

		input name: "param10", type: "number", range: "1..255", required: true, //defaultValue: "20",
            title: "Parameter No. 10 - Interval between successive readings of temperature from all " +
				   "sensors connected to the device. (A reading does not result in sending to ST)\n" +
                   "Available settings:\n" +
                   "1-255 - Seconds between readings\n" +
                   "Default value: 20."

		input name: "param11", type: "number", range: "0..255", required: true, //defaultValue: "200",
            title: "Parameter No. 11 - Interval between forcing to send report of the temperature. " +
				   "The forced report is sent immediately after the next temperature reading, " +
				   "irrespective of parameter 12. Advised to be 200 unless rapid temperature changes are expected.\n" +
                   "Available settings:\n" +
                   "0 - Deactivate temperature sending\n" +
                   "1-255 - Seconds between sends\n" +
                   "Default value: 200."

		input name: "param12", type: "number", range: "0..255", required: true, //defaultValue: "8",
            title: "Parameter No. 12 - Insensitiveness to temperature changes. This is the maximum " +
				   "difference between the last reported temperature and the current temperature. " +
				   "If they differ by more than this then a report is sent.\n" +
                   "Available settings:\n" +
                   "0-255 - x/16 = temp diff in C\n" +
                   "x/80*9 = temp diff in F\n" +
                   "Default value: 8 (0.5oC)."

		input name: "param13", type: "number", range: "0..3", required: true, //defaultValue: "0",
            title: "Parameter No. 13 - Transmitting the alarm or control frame in “broadcast” mode (i.e. to " +
				   "all devices within range), this information is not repeated by the mesh network." +
                   "Available settings:\n" +
                   "0 - IN1 and IN2 broadcast inactive,\n" +
                   "1 - IN1 broadcast mode active only,\n" +
                   "2 - IN2 broadcast mode active only,\n" +
                   "3 - INI and IN2 broadcast mode active.\n" +
                   "Default value: 0."

		input name: "param14", type: "number", range: "0..1", required: true, //defaultValue: "0",
            title: "Parameter No. 14 - Scene activation functionality." +
                   "Available settings:\n" +
                   "0 - Deactivated functionality,\n" +
                   "1 - Activated functionality.\n" +
                   "Default value: 0."
	}
}

def installed() {
	log.debug "installed()"

}
def updated() {
	log.debug "updated()"
	log.debug "Dont forget to press the button to send config to the device"
    runIn(10, "tempReadRequest")
    //configure()
    //createChildDevices()
}
def uninstalled() {
    log.debug "uninstalled()"
    removeChildDevices()
}

def configure() {
	log.debug "configure()"
    updateCurrentParams()
}

def createChildDevices(){
	log.debug "Adding Child Devices if not already added"
    for (i in 1..2) {
    	try {
        	log.debug "Trying to create child switch if it doesn't already exist ${i}"
            def currentchild = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep${i}"}
            if (currentchild == null) {
            	log.debug "Creating child for ep${i}"
				addChildDevice("smartthings", "Open/Closed Sensor", "${device.deviceNetworkId}-ep${i}", device.hub.id,
                	[completedSetup: true, name: "${device.displayName} (Contact${i})", isComponent: false]) //, label: "${device.displayName} (Contact${i})"
                /*addChildDevice(deviceHandlerName, "${device.deviceNetworkId}-${deviceName}${deviceNumber}", null,
         			[completedSetup: true, label: "${device.displayName} (${deviceName}${deviceNumber})", 
                	isComponent: false, componentName: "${deviceName}${deviceNumber}", componentLabel: "${deviceName} ${deviceNumber}"])*/
            }
        } catch (e) {
            log.debug "Error adding child ${i}: ${e}"
        }
    }
}
def createChildTempDevices() {
    log.debug "Creating Temperature children"
    for (i in 1..4) {
    	try {
        	//If we have a temperature reading from this sensor (1 to 4) then try to create a child for it
        	if (device.currentValue("temperature${i}") != null) {
            	log.debug "Have received temperature readings for termperature${i} so creating a child for it if not already there"
                def currentchild = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-temperature${i}"}
                if (currentchild == null) {
                    addChildDevice("smartthings", "Temperature Sensor", "${device.deviceNetworkId}-temperature${i}", device.hub.id,
                        [completedSetup: true, name: "${device.displayName} (Temp${i})", isComponent: false]) //, label: "${device.displayName} (Temp${i})"
                }
            }
            else {
            	log.debug "No temperature received for temperature${i} so no child will be created" 
            }
        } catch (e) {
            log.debug "Error adding Temperature # ${i} child: ${e}"
        }
    }
}
private removeChildDevices() {
	log.debug "Removing Child Devices"
    try {
        getChildDevices()?.each {
        	try {
            	deleteChildDevice(it.deviceNetworkId)
            } catch (e) {
                log.debug "Error deleting ${it.deviceNetworkId}, probably locked into a SmartApp: ${e}"
            }
        }
    } catch (err) {
        log.debug "Either no children exist or error finding child devices for some reason: ${err}"
    }
}

def parse(String description) {
	def result = null
	def cmd = zwave.parse(description, [ 0x60: 3])
	if (cmd) {
		result = zwaveEvent(cmd)
	}
	log.debug "parsed '$description' to result: ${result}"
	return result
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv1.ManufacturerSpecificReport cmd) {
	log.debug("ManufacturerSpecificReport ${cmd.inspect()}")
}


def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
	log.debug("ConfigurationReport ${cmd.inspect()}")
}

def createEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, Map item1) { 
	log.debug "manufacturerId:   ${cmd.manufacturerId}"
    log.debug "manufacturerName: ${cmd.manufacturerName}"
    log.debug "productId:        ${cmd.productId}"
    log.debug "productTypeId:    ${cmd.productTypeId}"

}

def createEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd, Map item1) {	
    updateDataValue("applicationVersion", "${cmd.applicationVersion}")
    log.debug "applicationVersion:      ${cmd.applicationVersion}"
    log.debug "applicationSubVersion:   ${cmd.applicationSubVersion}"
    log.debug "zWaveLibraryType:        ${cmd.zWaveLibraryType}"
    log.debug "zWaveProtocolVersion:    ${cmd.zWaveProtocolVersion}"
    log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
	log.debug "BasicSet V1 ${cmd.inspect()}"
    def currentstate
	if (cmd.value) {
		currentstate = "open"
	} else {
    	currentstate = "closed"
	}
    createEvent(name: "contact1", value: currentstate, descriptionText: "${device.displayName} is ${currentstate}")
    try {
        def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep1"}
        if (childDevice)
        	def motionstate = (currentstate=="closed") ? "active" : "inactive"
        	childDevice.sendEvent(name: "motion", value: motionstate)
            childDevice.sendEvent(name: "contact", value: currentstate)
    } catch (e) {
        log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
    }
}

def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	log.debug "ZWaveEvent V3 ${cmd.inspect()}"
	def result
	if (cmd.commandClass == 32) {
        def currentstate
		if (cmd.parameter == [0]) {
        	currentstate = "closed"
		}
		if (cmd.parameter == [255]) {
        	currentstate = "open"
		}
        log.debug "ep${cmd.sourceEndPoint} is ${currentstate}"
        //First update tile on this device
        sendEvent(name: "contact${cmd.sourceEndPoint}", value: currentstate, descriptionText: "$device.displayName - ep${cmd.sourceEndPoint} is ${currentstate}")
		//If not null then we have found either ep1 or ep2, hence try to send to the child device aswell
        try {
            def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep${cmd.sourceEndPoint}"}
            if (childDevice)
                def motionstate = (currentstate=="closed") ? "active" : "inactive"
                childDevice.sendEvent(name: "motion", value: motionstate)
                childDevice.sendEvent(name: "contact", value: currentstate)
        } catch (e) {
            log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
        }
    }
	else if (cmd.commandClass == 49) {
		if ((cmd.sourceEndPoint >= 3) && (cmd.sourceEndPoint <= 6)) {
            
			def tempsensorid = cmd.sourceEndPoint - 2
			def tempendpoint = "temperature" + tempsensorid.toString()
			
            def tempval = ((cmd.parameter[4] * 256) + cmd.parameter[5])
            if (tempval > 32767) {
            	//Here we deal with negative values
            	tempval = tempval - 65536
            }
            //Finally round the temperature
            def tempprocessed = (tempval / 100).toDouble().round(1)
            
			//def cmdScale = cmd.scale == 1 ? "F" : "C"
			//def tempval = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision).toDouble().round(1)
            
            log.debug "${tempendpoint} has changed to ${tempprocessed}"
            
            sendEvent(name: tempendpoint, value: tempprocessed, displayed: true) //unit: getTemperatureScale()
            
			//If not null then we have found either contact1 or contact2, hence try to send to the child
            try {
                def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-${tempendpoint}"}
                if (childDevice)
                	//We found a child device that matches so send it the new temperature
                    childDevice.sendEvent(name: "temperature", value: tempprocessed)
            } catch (e) {
            	//Not an error message here as people may not want child temperature devices
                log.debug "Couldn't find child ${tempendpoint} device, probably doesn't exist...? Error: ${e}"
            }
        }
	}
	else {
		//Send them here just in case we want to do more complicated processing (not doing it as need to have endpoint passed and that makes it a bit messy)
		def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 2, 0x60: 3, 0x85: 2, 0x8E: 2, 0x72: 1, 0x70: 1, 0x86: 1, 0x7A: 1, 0xEF: 1, 0x2B: 1]) // can specify command class versions here like in zwave.parse
		log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
		if (encapsulatedCommand) {
			result = zwaveEvent(encapsulatedCommand)
		}
	}
    return result
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{
	//This is no longer used as caught in an earlier event, but kept here in case the code is useful
	log.debug "Sensor MultiLevel Report - Sensor Type = ${cmd.sensorType}"
	switch (cmd.sensorType) {
		case 1:
			// temperature
			def cmdScale = cmd.scale == 1 ? "F" : "C"
			def tempval = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision).toDouble().round(1)
            sendEvent(name: "temperature1", value: tempval, displayed: false) //unit: getTemperatureScale()
			break;
	}
    log.debug map
	createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv1.SensorMultilevelReport cmd) {
    log.debug "SensorMultilevelReport $cmd"
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
	// This will capture any commands not handled by other instances of zwaveEvent
	// and is recommended for development so you can see every command the device sends
	log.debug "Catchall reached for cmd: ${cmd.toString()}}"
	return createEvent(descriptionText: "${device.displayName}: ${cmd}")
}

def updateCurrentParams() {
	log.debug "Sending configuration parameters to device"
    def cmds = []
	cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
	cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
	cmds << zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 1, configurationValue:[param1.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 2, configurationValue:[param2.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 3, configurationValue:[param3.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 4, configurationValue:[param4.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 5, configurationValue:[param5.value]).format()
    cmds << zwave.configurationV1.configurationSet(parameterNumber: 6, configurationValue:[param6.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 7, configurationValue:[param7.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 8, configurationValue:[param8.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 9, configurationValue:[param9.value]).format()
    cmds << zwave.configurationV1.configurationSet(parameterNumber: 10, configurationValue:[param10.value]).format()
    cmds << zwave.configurationV1.configurationSet(parameterNumber: 11, configurationValue:[param11.value]).format()
    cmds << zwave.configurationV1.configurationSet(parameterNumber: 12, configurationValue:[param12.value]).format()
	cmds << zwave.configurationV1.configurationSet(parameterNumber: 13, configurationValue:[param13.value]).format()
    cmds << zwave.configurationV1.configurationSet(parameterNumber: 14, configurationValue:[param14.value]).format()
	delayBetween(cmds, 500)
}
def listCurrentParams() {
	log.debug "Listing of current parameter settings of ${device.displayName}"
    def cmds = []
	cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier:2).format()
	cmds << zwave.associationV2.associationGet(groupingIdentifier: 3).format()
	cmds << zwave.associationV1.associationGet(groupingIdentifier: 1).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
   	cmds << zwave.configurationV1.configurationGet(parameterNumber: 3).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 4).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 6).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 8).format()
   	cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 11).format()
   	cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
	cmds << zwave.configurationV1.configurationGet(parameterNumber: 14).format()
	delayBetween(cmds, 500)
}

def open1() {
    sendEvent(name: "contact1", value: "open", descriptionText: "$device.displayName (1) is opened manually")
    try {
        def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep1"}
        log.debug "Changing child ${childDevice} to open/inactive"
        if (childDevice)
        	childDevice.sendEvent(name: "motion", value: "inactive")
            childDevice.sendEvent(name: "contact", value: "open")
    } catch (e) {
        log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
    }
}

def close1() {
    sendEvent(name: "contact1", value: "closed", descriptionText: "$device.displayName (1) is closed manually")
    try {
        def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep1"}
        log.debug "Changing child ${childDevice} to closed/active"
        if (childDevice)
        	childDevice.sendEvent(name: "motion", value: "active")
            childDevice.sendEvent(name: "contact", value: "closed")
    } catch (e) {
        log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
    }
}

def open2() {
    sendEvent(name: "contact2", value: "open", descriptionText: "$device.displayName (2) is opened manually")
    try {
        def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep2"}
        log.debug "Changing child ${childDevice} to open/inactive"
        if (childDevice)
        	childDevice.sendEvent(name: "motion", value: "inactive")
            childDevice.sendEvent(name: "contact", value: "open")
    } catch (e) {
        log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
    }
}

def close2() {
    sendEvent(name: "contact2", value: "closed", descriptionText: "$device.displayName (2) is closed manually")
    try {
        def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-ep2"}
        log.debug "Changing child ${childDevice} to closed/active"
        if (childDevice)
        	childDevice.sendEvent(name: "motion", value: "active")
			childDevice.sendEvent(name: "contact", value: "closed")
    } catch (e) {
        log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
    }
}

def tempReadRequest() {
    def cmds = []
    runIn(60, "tempReadRequest")
    log.debug "Polling for temperature"
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 3))
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 4))
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 5))
	cmds << response(encap(zwave.sensorMultilevelV3.sensorMultilevelGet(), 6))
	sendHubCommand(cmds,1000)
}
private encap(cmd, endpoint = null) {
	if (cmd) {
		if (endpoint) {
			cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd)
		}
		if (zwaveInfo.zw.contains("s")) {
			zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
		} else {
			cmd.format()
		}
	}
}

I think there may also be an issue with the GE Motion Dimmer and Motion Switch as well. (Makes sense as this is likely a multi channel device) I’m noticing that device status isn’t propagating back to the hub properly. Just applied to the firmware beta

Also tagging @MichaelS (DTH Owner)

1 Like

9 posts were split to a new topic: Z-Wave Backwards Compatibilty

Thanks for the 30.4 update here in the UK. This is my status:

Double Switch 2 FGS-223 EU v3.3
Hub v 28 Fully functional
Hub v 30.3 Fully functional
Hub v 30.4 Fully functional

Single Switch 2 FGS-213 EU v3.3
Hub v 28 Functional apart from switch status not updating on Smartthings - e.g if ST showing switch as off using ST turns switch on but ST switch status unchanged (whirly symbol for 20 secs).
Hub v 30.3 Same as for v28
Hub v 30.4 Same as for v28

So I have had no problems with the Double Switch 2 on any ST hub version but I have had problems with both of my Single Switch 2s irrespective of the ST hub software version.
Just wondering if the Fibaro v3.3 might be the reason why my problems are the opposite of everyone else’s! All 3 devices were purchased late March

If not, any suggestions?

1 Like

My fibaro ubs is working now, but qubino temperature mesurements are only available with manual refresh, temperature not updating on change. Any sugestions ?

I am massively lacking sleep today. Partly due to troubleshooting this lot, and partly due to burning the candle at both ends getting our home in order for a new baby. Knackering! So maybe I have missed something and I have no issues admitting if that is the case.

Am I to understand that these fibaros essentially slipped through the net at the point of certification? And due to this, the fact they were passed when technically they should not have been, then the responsibility lies with the makers of the hub?

Or (more likely) is that that the cert process isn’t quite as stringent as it could be, so following this, everyone knows that hub makers just purely and simply need to ensure compatibility regardless of where the design faults are, provided that there was a cert awarded.

Just in case there’s any misunderstanding, I’m really not arguing. I’m asking. Ta. It may be helpful to understand moving forward. =)

2 Likes

Glad your setup is working again and congrats in advance on the baby, but there are those of use who haven’t received personal support from ST and still have a broken setup due to this firmware upgrade.

Like others, I don’t understand the rush to satisfy a standards body at the expense of existing customers. Those customers will certainly tell other prospective customers. Then who are you going to sell your ‘this time for real’ z-wave certified hub to?

ST staff has been responsive in acknowledging the problem and developing new beta firmware, but this recent angle to blame certification when you apparently weren’t certified to begin with at the expense of your customer base is concerning.

edit: wrong quote, I’m tired from troubleshooting this too and accidentally quoted a DHT in my clipboard

1 Like

2 posts were merged into an existing topic: Z-Wave Backwards Compatibilty