Zigbee gas detector for kitchen

everything from the live log (binding process when I re-joined the device to the hub, and then triggering the alarm.-
but the app itself on the phone did not change states or indicate alarm status.

fba61a72-8eeb-438f-b0b7-9366859f098a ‎6‎:‎19‎:‎58‎ ‎PM: debug Parse returned [:]
fba61a72-8eeb-438f-b0b7-9366859f098a ‎6‎:‎19‎:‎58‎ ‎PM: debug description: zone status 0x0003 – extended status 0x00
fba61a72-8eeb-438f-b0b7-9366859f098a ‎6‎:‎19‎:‎40‎ ‎PM: debug configure: Write IAS CIE
fba61a72-8eeb-438f-b0b7-9366859f098a ‎6‎:‎19‎:‎40‎ ‎PM: debug Confuguring Reporting, IAS CIE, and Bindings.

I’m surprised that we didn’t see a message about sending enroll response. I’ve added a ‘Refresh’ button that will query the detector for both its enrollment status and the “zone type” (which I expect to be Gas Sensor 0x002b) just to make sure it’s joined properly. No need to reset and re-join. You can just update the device code, re-publish it and the refresh button should show up.

Post the live logs after pressing the refresh button. Should get a few messages back. Once we know it’s properly paired, we can start to properly debug how it’s sending the alarm messages. The 0x0003 was not what I was expecting for the alarm going off. I would have expected 0x0021 based on other IAS devices in ST.

/**
 *  WZB 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.
 *
 */
 
metadata {
	definition (name: "WZB Natural Gas", namespace: "smartthings", author: "SmartThings") {
		
        capability "Configuration"
        capability "Smoke Detector"
        capability "Sensor"
        capability "Refresh"
        
        command "enrollResponse"
 
 
		fingerprint profileID: "0104", deviceID: "0402", inClusters: "0000,0500", outClusters: "0500,0001"
        
}
 
	simulator {
 
	}

	preferences {
		input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
		input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
	}
 
	tiles {
    	standardTile("smoke", "device.smoke", width: 2, height: 2) {
			state("clear", label:"clear", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff")
			state("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13")
		}
        
        standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
			state "default", action:"configuration.configure", icon:"st.secondary.configure"
		}
 		
        standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
			state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
		}
        
		main (["smoke"])
		details(["smoke","refresh","configure"])
	}
}
 
def parse(String description) {
	log.debug "description: $description"
    
	Map map = [:]
	if (description?.startsWith('catchall:')) {
		map = parseCatchAllMessage(description)
	}
	else if (description?.startsWith('read attr -')) {
		map = parseReportAttributeMessage(description)
	}
    else if (description?.startsWith('zone status')) {
    	map = parseIasMessage(description)
    }
 
	log.debug "Parse returned $map"
	def result = map ? createEvent(map) : null
    
    if (description?.startsWith('enroll request')) {
    	List cmds = enrollResponse()
        log.debug "enroll response: ${cmds}"
        result = cmds?.collect { new physicalgraph.device.HubAction(it) }
    }
    return result
}
 
private Map parseCatchAllMessage(String description) {
    Map resultMap = [:]
    def cluster = zigbee.parse(description)
    if (shouldProcessMessage(cluster)) {
        log.debug "Parse $cluster"
    }

    return resultMap
}

private boolean shouldProcessMessage(cluster) {
    // 0x0B is default response indicating message got through
    // 0x07 is bind message
    boolean ignoredMessage = cluster.profileId != 0x0104 || 
        cluster.command == 0x0B ||
        cluster.command == 0x07 ||
        (cluster.data.size() > 0 && cluster.data.first() == 0x3e)
    return !ignoredMessage
}

 
private Map parseReportAttributeMessage(String description) {
	Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
		def nameAndValue = param.split(":")
		map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
	}
	log.debug "Desc Map: $descMap"
 
}
 


private Map parseIasMessage(String description) {
    List parsedMsg = description.split(' ')
    String msgCode = parsedMsg[2]
    
    Map resultMap = [:]
    switch(msgCode) {
        case '0x0020': // Clear
        	resultMap = getSmokeResult('clear')
            break

        case '0x0021': // Smoke
        	resultMap = getSmokeResult('detected')
            break

        case '0x0022': // Tamper Alarm
            break

        case '0x0023': // Battery Alarm
            break

        case '0x0024': // Supervision Report
        	resultMap = getSmokeResult('clear')
            break

        case '0x0025': // Restore Report
        	resultMap = getSmokeResult('detected')
            break

        case '0x0026': // Trouble/Failure
            break

        case '0x0028': // Test Mode
            break
    }
    return resultMap
}


private Map getSmokeResult(value) {
	log.debug 'Gas Status'
	def linkText = getLinkText(device)
	def descriptionText = "${linkText} is ${value == 'detected' ? 'detected' : 'clear'}"
	return [
		name: 'smoke',
		value: value,
		descriptionText: descriptionText
	]
}

def refresh() {		//read enrolled state and zone type from IAS cluster
	[
	"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0500 0", "delay 500",
    "st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0500 1"
	]
}	

def configure() {

	String zigbeeId = swapEndianHex(device.hub.zigbeeId)
	log.debug "Confuguring Reporting, IAS CIE, and Bindings."
	def configCmds = [
		"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
		"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500",
        
        //"raw 0x500 {01 23 00 00 00}", "delay 200",
        //"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
        
	]
    log.debug "configure: Write IAS CIE"
    return configCmds // send refresh cmds as part of config
}

def enrollResponse() {
	log.debug "Sending enroll response"
    [	
    	
	"raw 0x500 {01 23 00 00 00}", "delay 200",
    "send 0x${device.deviceNetworkId} 1 ${endpointId}"
        
    ]
}
private hex(value) {
	new BigInteger(Math.round(value).toString()).toString(16)
}

private String swapEndianHex(String hex) {
    reverseArray(hex.decodeHex()).encodeHex()
}

private byte[] reverseArray(byte[] array) {
    int i = 0;
    int j = array.length - 1;
    byte tmp;
    while (j > i) {
        tmp = array[j];
        array[j] = array[i];
        array[i] = tmp;
        j--;
        i++;
    }
    return array
}
1 Like

Pressing the config button now:

fba61a72-8eeb-438f-b0b7-9366859f098a ‎7‎:‎21‎:‎34‎ ‎PM: debug configure: Write IAS CIE
fba61a72-8eeb-438f-b0b7-9366859f098a ‎7‎:‎21‎:‎34‎ ‎PM: debug Confuguring Reporting, IAS CIE, and Bindings.

Live logging still seems to be having some intermittent delay/lag, but a short time after dismissing the alarm on the device, it does send what would then appear to be clear signal -

fba61a72-8eeb-438f-b0b7-9366859f098a ‎7‎:‎34‎:‎13‎ ‎PM: debug Parse returned [:]
fba61a72-8eeb-438f-b0b7-9366859f098a ‎7‎:‎34‎:‎13‎ ‎PM: debug description: zone status 0x0000 – extended status 0x00

That ‘All Clear’ is really good to see. That is definitely what that message is. So the easy fix is to change the 0x0020 in the switch statement to 0x0000 and the 0x0021 to 0x0003. That should correctly identify the alarm and all clear messages.

Took a little digging, but the 0x0003 converts to 1 in the first 2 digit places, so when you triggered the alarm, it announces that both alarm1 and alarm2 are going off.

Is there a ‘test’ button? That might send a unique message too, so we can tell it apart.

1 Like

Yep, changing out the values in the switch statement does make it work as expected, as far as the app and SHM is concerned.

There is a test button, but it doesn’t seem to trigger any zigbee messages. I think what it is doing for it’s test is simply checking for the alarm state (0x0003) and not finding it set, the unit declares operation normal. (this thing is odd… part of the alarm is spoken voice of “Operation: normal” when the alarm state clears (or using test button) and “Danger, evacuate!” when alarm state is triggered.) Worst part is that the voice is not a native english speaking voice, lol.

Any updates here? Is this a device you think is worth buying and going through the hurdles to get it shipped?

The device type is working fine. I am working on a battery solution, as these are designed for a 12v DC power source (Plugin) The housing has a spot for a battery, so I have a 12v 123A battery and holder and just today got the connectors to hook it up. The battery won’t be monitored, as the circuitry wasn’t designed for that, but I can just replace it when it stops reporting. Outside of testing with a butane lighter, the only other way to test would be to actually flood the kitchen with combustible gas… I don’t think I want to test that. - given proper placement, I expect it will work fine.

1 Like

ugh. product not found :frowning:

They’ve updated to the latest model, that I actually got instead of the old one:

http://www.shop-wifi.com/wireless-sensors/wireless-safety-and-security-solution/sg-02-gs-zigbee-residential-combustible-gas-detector

It seems to work just fine, but my attempts to power by battery failed, it must be plugged in :frowning:

2 Likes

@Toasty how have your detectors been working for you? How has battery life been? My lines to my furnace sprung a leak and now I am concerned so I would like to install a few in my crawl space and island now. Would rather be notified sooner versus me having to smell it in the house.

Kiddie and Safe Alert now make a 3 in 1 detector that includes gas, smoke and carbon monoxide. I will be upgrading my old detectors to those as well.

1 Like

The battery thing didn’t work out, I had to plug them in.

I am also in the process of looking for a gas detector of my UK ST. I have seen this one from Homi Security that might be a cheaper alternative to the one in this thread?

https://www.aliexpress.com/item/Wireless-Zigbee-smart-natural-gas-coal-gas-LPG-combustible-gas-leakage-sensor/32730735040.html

It seems to be HA 1.2 compliant so I was wondering if someone already managed to connect it before trying for myself.

1 Like

Dunno. Worth a shot.

The gas detector finally arrived. I will try to create a device handler for it, first time doing it so I might need a lot of help :sweat_smile:

Will report my findings here. I have started from the device handler code posted by @Sticks18 in post #22. After pairing it with ST the RAW description for the device is:

01 0104 0402 00 04 0000 0003 0500 0009 01 0019

so I have modified the line in the handler to be:

fingerprint profileID: "0104", deviceID: "0402", inClusters: "0000,0003,0500,0009", outClusters: "0019"

After that, pairing again the device with ST does recognise the device type correctly (yeah! :slight_smile:)

Need to figure out if I need to change the configure and refresh commands…

1 Like

It should be easily testable using a butane type lighter (hold open trigger, but unlit)

OK, it was pretty simple with the help of the lighter :slight_smile: Also there is a button in the gas detector that triggers an alarm to test.

It seems as if the detector sends a “0x0020” in the clear state and a “0x0022” when smoke/gas is detected. I have modified the handler accordingly and everything seems to work fine. My only doubt if what to do with the configure and refresh methods in the handler. Should I leave them like there were? Should I change any code?

In any case, here is the final code, as I said it seems to be working fine here…

https://github.com/jrhbcn/smartthings/blob/master/device_handlers/homi_gas_detector.src/homi_gas_detector.groovy

2 Likes

Thanks I need one for my camper so looks like I order the one from Alie.

Just to throw this out there, I just purchased a Heiman HS1CG from here: http://store.cutedigi.com/smart-combustible-gas-sensor/

I used jrhbcn’s device handler from here https://github.com/jrhbcn/smartthings/blob/master/device_handlers/homi_gas_detector.src/homi_gas_detector.groovy

I modified it to say gas instead of smoke.

Works great! Only issue is I cant get it to send push alerts or trigger an alarm when the security is set to “away”. Working on that now.

Glad to hear it is working for others @wildio. I have updated the device handler to say “GAS” thanks.

1 Like