Fibaro binary input (Dual contact and temperature sensor)

I could do we some help finishing a device handler I have tweaked. What I want to be able to do is have 2 seperate Contact sensers, which I have but I want to declare them as two separate “enums” so that I can use them seperatly in webCoRE. At the moment I have it working, but only if I then create 2 seperate virtual contact sensers and link them to the device.

Credit to @fuzzysb Stuart Buchanan for creating the original DH, thanks

If anyone know how to do this and could give me some help, would really appreciate it :).

/**
 *  Device Type Definition File
 *
 *  Device Type:		Fibaro Universal Sensor - Dual Contact + Temp
 *  File Name:			Fibaro Universal Sensor - Dual Contact + Temp.groovy
 *	Initial Release:	2016-01-17
 *	Author:				Stuart Buchanan
 *  Modified:   Steven Stroud 10-06-2017
 *  
 *  Copyright 2017 Steven S, based on original code by Stuart Buchanan with thanks
 *
 *  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: "Fibaro Universal Sensor - Dual Contact + Temp test", namespace: "Borristhecat", author: "Steven Stroud") {
    capability 	"Contact Sensor"
    capability 	"Contact Sensor" 
	capability 	"Temperature Measurement"
	capability 	"Configuration"
	capability 	"Sensor"
   
    
    command "updateCurrentParams"
    command "listCurrentParams"

        /* Capability notes
        0x30 Sensor Binary V1 V2
        0x60 Multi Channel V3
        0x85 Association V1 V2
        0x8E Multi Instance Association V1
        0x72 Manufacturer Specific V1 V2
        0x70 Configuration V1 V2
        0x86 Version V1
        0x7A Firmware Update Md V1 V2
        0xEF Mark V1
        0x2B Scene Activation V1
        */
	
	fingerprint deviceId: "0x2001", inClusters: "0x20 0x30 0x31 0x60 0x85 0x8E 0x72 0x70 0x86 0x7A 0xEF 0x2B"
	}

	simulator {
	}

	tiles(scale: 2) {
      	multiAttributeTile(name: "thermostat", type:"thermostat", width:6, height:4) {
			tileAttribute("device.temperature", key:"PRIMARY_CONTROL", canChangeIcon: true, canChangeBackground: true){
            	attributeState "default", label:'${currentValue}°', unit:"C", backgroundColor:"#fab907", icon:"st.Weather.weather2"
            }
			tileAttribute ("device.contact1", key: "SECONDARY_CONTROL") {
            	attributeState "open", label: '${name}'
				attributeState "closed", label: '${name}'
	}
			tileAttribute ("device.contact2", key: "TERTIARY_CONTROL") {
            	attributeState "open", label: '${name}'
				attributeState "closed", label: '${name}'
			}
    	}
       standardTile("contact1", "device.contact1", width: 2, height: 2) {
			state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
			state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
		}
        standardTile("contact2", "device.contact2", width: 2, height: 2) {
    		state "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
			state "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
		}
		standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2 ) {
			state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
		}

	main(["thermostat"])
	details(["thermostat", "contact1" ,"contact2", "configure"])
	}
}

def parse(String description) {
	def result = null
	def cmd = zwave.parse(description, [ 0x20: 1, 0x30: 1, 0x31: 2, 0x60: 3, 0x85: 2, 0x8E: 2, 0x72: 1, 0x70: 1, 0x86: 1, 0x7A: 1, 0xEF: 1, 0x2B: 1 ])
	if (cmd) {
		result = zwaveEvent(cmd)
	}
	log.debug "parsed '$description' to result: ${result}"
	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 configure() {
	log.debug "Updating Configuration of ${device.displayName}"
    def cmds = []
    cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
    cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
    cmds << zwave.associationV2.associationRemove(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()   
    cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 4, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [20], parameterNumber: 10, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [60], parameterNumber: 11, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [8], parameterNumber: 12, size: 1).format()
   
	delayBetween(cmds, 500)
}

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()}"
	if (cmd.value) {
	createEvent(name: "contact1", value: "open", descriptionText: "$device.displayName is open")
	} else {
	createEvent(name: "contact1", value: "closed", descriptionText: "$device.displayName is closed")
	}
}

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd) {
    log.debug "Sensor Binary report"
	def map = [:]
	map.value = cmd.sensorValue ? "active" : "inactive"
	map.name = "motion"
	if (map.value == "active") {
		map.descriptionText = "$device.displayName detected motion"
	}
	else {
		map.descriptionText = "$device.displayName motion has stopped"
	}
	map
}


def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{
	log.debug "Sensor MultiLevel Report"
	def map = [:]
	switch (cmd.sensorType) {
		case 1:
			// temperature
			def cmdScale = cmd.scale == 1 ? "F" : "C"
			map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision).toDouble().round(1)
            log.debug("tempvalue: " + map.value)
			map.unit = getTemperatureScale()
            log.debug("tempunit: " + map.unit)
			map.name = "temperature"
			break;
	}
	createEvent(map)
}

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


def createEvent(physicalgraph.zwave.commands.firmwareupdatemdv1.FirmwareMdReport cmd, Map item1) { 
    log.debug "checksum:       ${cmd.checksum}"
    log.debug "firmwareId:     ${cmd.firmwareId}"
    log.debug "manufacturerId: ${cmd.manufacturerId}"
}
 
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
    	log.debug "ZWaveEvent V3 ${cmd.inspect()}"
	if (cmd.commandClass == 32) {
		if (cmd.parameter == [0]) {
			if (cmd.sourceEndPoint == 1) {
				return createEvent(name: "contact1", value: "closed", descriptionText: "$device.displayName is closed", isStateChange: true)
				log.debug "Contact1 is closed"
			}
			else
			if (cmd.sourceEndPoint == 2) {
				return createEvent(name: "contact2", value: "closed", descriptionText: "$device.displayName is closed", isStateChange: true)
				log.debug "Contact2 is closed"
			}
		}
		if (cmd.parameter == [255]) {
			if (cmd.sourceEndPoint == 1) {
				return createEvent(name: "contact1", value: "open", descriptionText: "$device.displayName is open", isStateChange: true)
				log.debug "Contact1 is open"
			}
			else
			if (cmd.sourceEndPoint == 2) {
				return createEvent(name: "contact2", value: "open", descriptionText: "$device.displayName is open", isStateChange: true)
				log.debug "Contact2 is open"
			}
		}
    } else {
		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) {
			return zwaveEvent(encapsulatedCommand)
		}
	}
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
	log.debug "Catchall reached for cmd: ${cmd.toString()}}"
	[:]
}


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 updateCurrentParams() {
	log.debug "Updating current parameter settings of ${device.displayName}"
    def cmds = []
    cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
    cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
    cmds << zwave.associationV2.associationRemove(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()   
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0, 0], parameterNumber: 1, size: 2).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0, 0], parameterNumber: 2, size: 2).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 4, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 6, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 8, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 9, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [120], parameterNumber: 10, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [200], parameterNumber: 11, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [8], parameterNumber: 12, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 14, size: 1).format()
   
	delayBetween(cmds, 500)
}

@anon36505037 Is this something that you might be able to me help with?

@borristhecat
Is there a particular reason you dont want child devices? It would be easy to create child devices automatically (single click with no smartapp linking them) and solve the problem. Or you could even have a secondary value on the main DTH and then have a single child which has the secondary value as its main (and only) value.

The problem with trying to keep multiple values in a single DTH is that SmartThings is not built to handle it very well, and hence changes can easily break it. My experience is that if they are the same type you might get away with it, but if they are different (and youre trying to temperatures aswell) it is better to have some parts split out (also you can then do far more with them, from logging to a multitude of SmartApps that are built for single sensor devices.

I am not entirely sure what you have changed from the standard FUS DTH (which I am actually using). Can you paste it as code and then I can do a quick comparison since then formatting and everything is maintained.

Yeah can do just don’t know how :frowning: :slight_smile: if you could let me know how to do it that would help, been trying to work it out for ages :joy:

I think the original DH was contact and PIR and I wanted two contacts, may have changed somthing on the temperature aswell but can’t remember now :thinking: .

The only reason was because I’m using them as simple latching switches then using webCoRE to decide what they do, I wanted to alow webCoRE to see both contacts in its attributes list. With the idea of then making the dash board neater.

Where as before when I was using it in ST standard apps you have to have separate devices. But didn’t realize this may cause issues. At the moment I’m using the same DH if I’m just using 2 contacts aswell as if I’m used temp and 2 contacts. So is it worth trying to do two separate ones?

Have this as the standard one with temp and contacts, then a dual contact one only?

If you upload the code again in your first post (by editing it), just ensure that you use the ‘pre-formatted text’ button in the edit window. That will ensure that all the spacing and stuff is correctly preserved for me to check it.

I actually have a few temperature sensors which should turn up in the next couple of days, as soon as they arrive then I will give it a proper test with the DTH.

You’re right, the FUS sensors are a bit unreliable… they do sometimes miss an event, but because of how I use them it doesnt cause me any problems. I keep meaning to check a firmware update for them, as Im sure they must be aware of a problem and it is so easy to fix in their firmware…

Remember @anon36505037 saying he had issues with then but touch wood mine haven’t missed a beat but like you said that may because of how I’m using them. Don’t think they would work well with a retractive switch :thinking: , but turning on and off osram ZigBee lamps and RGBW strip via webCoRE they have been great!

BOOM thanks @cjcharles for that been trying to work that out for ages!

Thanks. Just done a comparison and it seems there are some strange sections of code in the DTH above that are either duplicated or not used, plus some bits where I will need to understand what certain parameters do!

If I have time over the weekend I’ll add temperature to my DTH and then split it out with child devices. You would then need to modify it a bit if you want something other than open/closed for each of the child devices.

As a side point, you say you are using it to control other lights, are you doing that with the relay outputs? Can they be zwave/ST/web controlled? I thought they were just a mirror of the input wires which need grounding to show closed…

1 Like

No I wish they were as I could control my LCM in my bathroom even better and have my DALI lights come on at different levels depending on conditions :slight_smile:. They are just a mirror of the input wires

No, I have pistons set up to turn on/ off the lights using the open/ closed trigger changing.

how do you update the firmware on them? i thought it was only the z wave+ that you could do it on?

I didn’t mean doing the update necessarily, I thought I would try and see whether the update existed. After that I’d need to try and do it, probably involving moving the FUS to a separate Fibaro hub and then running the update there.

1 Like

Thought that needing a fibaro hub might be the case, if it was updatable :frowning:

If you ever find out if it’s possible let me know then will have to invest in one :slight_smile:

@cjcharles tried to incorporate your Fibaro FGS-222 Double Relay DH to @Fuzzyligic Fibaro Universal Sensor- Contact/Motion so that it spits out the child devices, but i’m way out of my depth. Im able to tweak things, but I have no idea what’s going on in that DH :sweat_smile:

Did you get any chance to look at this @cjcharles?

Sorry, had family around this weekend so didnt get a chance. Will do in the next couple of days.

Temperature sensors have just arrived aswell, so I can finally test with them added too.

1 Like

Brilliant :slight_smile: as I understand it they should work with multiple temperature sensors but I only use one per unit. Then using them for switches and door reed switches aswell as the temperature of every room :slight_smile:

Hi @cjcharles any updates on this? did you get it working?

Hi,

Any updates on this ? I do not get it to work.

Thanks!

What can’t you get working? If your trying to do the temperature have you installed it in the correct order?

You need to exclude the binary device then install the temperature sensors, then add the device too ST. Once you done that you can then install the DH and then click configure and it should work.

Hi @borristhecat I have finally had the time to test my coding. Have made quite a lot of changes tbh so while I have done some testing it would be great if you could have a quick test too and let me know feedback before I release a version 1 of it. After adding the child devices (by ticking the flag in configuration menu), it should create the child devices, and you can then rename them as you wish.

Sadly as I have used ST’s default simulated devices I dont have control of the colours or styling, and I think they are out of sync with what ST now recommend as the official ST style, but not by much.

/**
 *  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
 *
 ***************************************************************************************
 */
 
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 "updateCurrentParams"
    command "listCurrentParams"
    command "open1"
    command "open2"
    command "close1"
    command "close2"
	
	fingerprint deviceId: "0x2001", inClusters: "0x30 0x60 0x85 0x8E 0x72 0x70 0x86 0x7A 0xEF"
}

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: 2, height: 1) {
		state "configure", label:'Send Config', action:"configuration.configure", icon:"st.secondary.configure"
	}

	standardTile("report", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "report", label:'List Config', action:"listCurrentParams"
	}
    
    standardTile("removechildren", "removechildren", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
		state "default", label:'Remove Child Devices', action:"removeChildDevices"
	}
}

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

preferences {
        def paragraph = "Device Handler by @cjcharles \n\n"
        input("childcontact1", "bool", title: paragraph + "Create Child Contact1 Device?", required:false, displayDuringSetup: true)
        input("childcontact2", "bool", title:"Create Child Contact2 Device?", required:false, displayDuringSetup: true)

		paragraph = "Parameter Settings:\n\n"
        input name: "param1", type: "number", range: "0..65535", required: false, //defaultValue: "0",
            title: paragraph + "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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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: false, //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()"
	createChildDevices()
}
def uninstalled() {
    log.debug "uninstalled()"
    removeChildDevices()
}

def configure() {
	log.debug "configure"
    delayBetween([
	zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format(),
	zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format(),
	zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 1, configurationValue:[param1.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 2, configurationValue:[param2.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 3, configurationValue:[param3.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 4, configurationValue:[param4.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 5, configurationValue:[param5.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 6, configurationValue:[param6.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 7, configurationValue:[param7.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 8, configurationValue:[param8.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 9, configurationValue:[param9.value]).format(),
    zwave.configurationV1.configurationSet(parameterNumber: 10, configurationValue:[param10.value]).format(),
    zwave.configurationV1.configurationSet(parameterNumber: 11, configurationValue:[param11.value]).format(),
    zwave.configurationV1.configurationSet(parameterNumber: 12, configurationValue:[param12.value]).format(),
	zwave.configurationV1.configurationSet(parameterNumber: 13, configurationValue:[param13.value]).format(),
    zwave.configurationV1.configurationSet(parameterNumber: 14, configurationValue:[param14.value]).format(),
    ], 500)
}

private void createChildDevices(){
	log.debug "Adding Child Devices if they are configured"
    if (childcontact1) {
    	log.debug "Creating Contact1 child"
        try {
        	def currentchild = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact1"}
            if (currentchild == null) {
            	addChildDevice("smartthings/testing", "Simulated Contact Sensor", "${device.deviceNetworkId}-contact1", device.hub.id, //cjcharles0 Visonic Contact Zone
                  [completedSetup: true, name: "${device.displayName} (Contact1)", label: "${device.displayName} (Contact1)", isComponent: false])
            }
        } catch (e) {
			log.debug "Error adding Contact1 child: ${e}"
        }
    }
    if (childcontact2) {
    	log.debug "Creating Contact2 child"
        try {
        	def currentchild = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact2"}
            if (currentchild == null) {
            	addChildDevice("smartthings/testing", "Simulated Contact Sensor", "${device.deviceNetworkId}-contact2", device.hub.id, //cjcharles0 - Visonic Contact Zone
                  [completedSetup: true, name: "${device.displayName} (Contact2)", label: "${device.displayName} (Contact2)", isComponent: false])
            }
        } catch (e) {
			log.debug "Error adding Contact2 child: ${e}"
        }
    }
}
private removeChildDevices(){
	log.debug "Removing Child Devices"
    try {
        getChildDevices()?.each {
            deleteChildDevice(it.deviceNetworkId)
        }
    } catch (e) {
        log.debug "Error deleting ${it}, either it didn't exist or probably locked into a SmartApps: ${e}"
    }
}

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}")
    if (childcontact1) {
        try {
            def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact1"}
            if (childDevice)
                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 currentcontact
        def currentstate
		if (cmd.parameter == [0]) {
        	currentstate = "closed"
			if (cmd.sourceEndPoint == 1) {
            	currentcontact = "contact1"
				//result = createEvent(name: "contact1", value: "closed", descriptionText: "$device.displayName is closed")
				//log.debug "Contact1 is closed"
			}
			else
			if (cmd.sourceEndPoint == 2) {
            	currentcontact = "contact2"
				//result = createEvent(name: "contact2", value: "closed", descriptionText: "$device.displayName is closed")
				//log.debug "Contact2 is closed"
			}
		}
		if (cmd.parameter == [255]) {
        	currentstate = "open"
			if (cmd.sourceEndPoint == 1) {
				currentcontact = "contact1"
                //result = createEvent(name: "contact1", value: "open", descriptionText: "$device.displayName is open")
				//log.debug "Contact1 is open"
			}
			else
			if (cmd.sourceEndPoint == 2) {
				currentcontact = "contact2"
                //result = createEvent(name: "contact2", value: "open", descriptionText: "$device.displayName is open")
				//log.debug "Contact2 is open"
			}
		}
        log.debug "${currentcontact} is ${currentstate}"
        sendEvent(name: currentcontact, value: currentstate, descriptionText: "$device.displayName - ${currentcontact} is ${currentstate}")
        if (childcontact1 && (currentcontact == "contact1")) {
            try {
                def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-${currentcontact}"}
                if (childDevice)
                    childDevice.sendEvent(name: "contact", value: currentstate)
            } catch (e) {
                log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
            }
    	}
        if (childcontact2 && (currentcontact == "contact2")) {
            try {
                def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-${currentcontact}"}
                if (childDevice)
                    childDevice.sendEvent(name: "contact", value: currentstate)
            } catch (e) {
                log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
            }
    	}
    } else {
		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)
{
	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 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")
    if (childcontact1) {
        try {
            def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact1"}
            if (childDevice)
                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")
    if (childcontact1) {
        try {
            def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact1"}
            if (childDevice)
                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")
    if (childcontact2) {
        try {
            def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact2"}
            if (childDevice)
                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")
    if (childcontact2) {
        try {
            def childDevice = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-contact2"}
            if (childDevice)
                childDevice.sendEvent(name: "contact", value: "closed")
        } catch (e) {
            log.error "Couldn't find child device, probably doesn't exist...? Error: ${e}"
        }
	}
}
1 Like