Driver for Gas Sensor

I have one going. Seems to be working for me so far. Haven't test with actual gas yet. I am sure the driver could use some work.

Updated 7/21: Changed smoke status from "cleared" to "clear".

/**
 *  Heiman Natural Gas Sensor
 *
 *  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.
 *
 */


import hubitat.zigbee.clusters.iaszone.ZoneStatus
 
metadata {
	definition (name: "Heiman Gas Detector", namespace: "hubitat", author: "cuboy29") {
		
        capability "Configuration"
        capability "SmokeDetector"
        capability "Sensor"
        capability "Refresh"
              
        attribute "smoke", "string"
        
		fingerprint profileID: "0104", deviceID: "12", inClusters: "0000,0003,0500,0009", outClusters: "0003,0019"      
    }
}
 
def parse(String description) {
    
	//log.debug "description: $description"
    def descMap = [:]
    
	if (description?.startsWith('zone status')) {
			descMap = parseIasMessage(description)
    }else if (description?.startsWith('enroll request')) {
		    List cmds = zigbee.enrollResponse()
		    descMap = cmds?.collect { new hubitat.device.HubAction(it) }
	}else if (description?.startsWith('catchall')) {
            descMap = parseCatchAllMessage(description)
    }else if (description?.startsWith('read attr'))  {  
            descMap = zigbee.parseDescriptionAsMap(description)
       
            if ((descMap?.cluster == "0500" && descMap.attrInt == 0x0001) && (descMap.value == '002B')){  //Zone Type
                log.debug "Zone Type is Carbon Monoxide (CO) Sensor"
			}else if ((descMap?.cluster == "0500" && descMap.attrInt == 0x0000) && (descMap.value == '01')){  //Zone State
                log.debug "Zone State is enrolled"
			}else if ((descMap?.cluster == "0500" && descMap.attrInt == 0x0002) && ((descMap.value == '0030') || (descMap.value == '0020'))){  //Zone Status
                log.debug "${device.displayName} is cleared"
            }else if (descMap?.cluster == "0000" && descMap.attrInt == 0x0004){  //Manufacture
                sendEvent(name: "manufacture", value: descMap.value)
            }else if (descMap?.cluster == "0000" && descMap.attrInt == 0x0005){  //Model 
                sendEvent(name: "model", value: descMap.value)
            }
	}

	//def result = descMap ? createEvent(descMap) : [:]	
	return descMap   
}    


private Map translateZoneStatus(ZoneStatus zs) {
	// Some sensor models that use this DTH use alarm1 and some use alarm2 to signify motion       
	return getGasResult(zs.isAlarm1Set() || zs.isAlarm2Set())
}

private Map getGasResult(value) {

    def descriptionText = value ? "${device.displayName} has detected GAS!" : "${device.displayName} is clear!"
    log.debug descriptionText
	return [
			name			: 'smoke',
			value			: value ? 'detected' : 'clear',
            isStateChange: true,
			descriptionText : descriptionText
	]
}

private parseCatchAllMessage(String description) {
    
    Map resultMap = [:]
    def descMap = zigbee.parse(description)  
    //log.debug descMap.inspect()
    return resultMap
}

private Map parseIasMessage(String description) {
    
    ZoneStatus zs = zigbee.parseZoneStatus(description)    
    translateZoneStatus(zs)    
}

def refresh() {
    
	log.debug "Refreshing..."
	def refreshCmds = []
    
    refreshCmds +=
	zigbee.readAttribute(0x0500, 1) +	// IAS ZoneType
    zigbee.readAttribute(0x0500, 0) +	// IAS ZoneState
    zigbee.readAttribute(0x0500, 2) +	// IAS ZoneStatus
    zigbee.readAttribute(0x0000, 7) +	// power source
    //zigbee.readAttribute(0x0009, 7) +	// not sure what this cluster do yet
    zigbee.readAttribute(0x0000, 4) +	// manufacture
    zigbee.readAttribute(0x0000, 5) +	// model indentification
        zigbee.enrollResponse()
    
	return refreshCmds
}

def configure() {
    
    log.debug "Configuring..."
    
    def cmds = [
            //bindings
            "zdo bind 0x${device.deviceNetworkId} 1 1 0x0500 {${device.zigbeeId}} {}", "delay 200",
        ] +  zigbee.enrollResponse(1200) + refresh()
    
    return cmds
}
3 Likes