Zigbee pairing issues

Hi,
I have a mix of Hue and Xiaomi motion sensors as well as some Xiaomi buttons connected to Hubitat. The first ones paired just fine, but for some reason, one Hue motion sensor and one Xiaomi motion sensor just won't work.

The Hue motion sensor is actually found by Hubitat and the device is created, but for some reason, the status is "UNKNOWN" and it stays that way. The type is correctly pre-selected as "Hue Motion Sensor".

The Xiaomi motion sensor isn't even found during discovery, although I'm doing everything exactly like with the other sensors. Not 100 % sure if it could be broken, but it worked just fine with SmartThings a day ago.

What can I do?

Thanks,
Jan

On the motion sensor, you hit the Configure button?

Hi,
sure. I sucessfully paired both types - this is just about the last two sensors.

Doing the long reset and then hitting the reset every second or so on the Xiaomi.

Regarding the Hue, after I hit Configure all was good. Maybe open up a second page with the logging showing, see if you get responses?

Hi,

thanks for your hints - I know all about that weird paring behavior of Xiaomi's stuff. But I always got it working in the end - until now. Nothing showed up on the logs as far as I could see ...

Hmm. Think we’ve all been there with those.

Maybe try a new battery, being closer and maybe reboot of the hub? Clutching at straws here.

I have read others have solved some ZigBee pairing issues by turning off some HUE devices. Perhaps turning off some of the other ZigBee devices might help. Folks have also mentioned changing channel, especially if it's near a WiFi router.

Thanks for your hints ... Tried discovery next to the hub, turning off Hue devices, reboot - to no avail.

Hue motion sensor is being found, but never becomes active - stays "UNKNOWN".

Xiaomi motion sensor doesn't appear at all.

At the same time, I'm able to add all kinds of other devices - Xiaomi buttons, door/window sensors etc.

Could there be old data left in the Zigbee stick? I don't understand why just these two devices would make trouble while others work just fine. I'd like to avoid doing a full Zigbee reset after having added quite a few sensors.

Edit: This is what the ZigBee log looks like during and right after the non-functioning Hue motion sensor's join:

Wohnzimmer Motion 2018-09-04 00:55:19.560 profileId:0x104, clusterId:0x400, sourceEndpoint:2, destinationEndpoint:1 , groupId:0, lastHopLqi:255, lastHopRssi:-54
Hue Motion Sensor 2018-09-04 00:54:44.662 profileId:0x0, clusterId:0x8004, sourceEndpoint:0, destinationEndpoint:0 , groupId:0, lastHopLqi:255, lastHopRssi:-64
A4D2 2018-09-04 00:54:44.050 profileId:0x104, clusterId:0x0, sourceEndpoint:2, destinationEndpoint:1 , groupId:0, lastHopLqi:255, lastHopRssi:-63
A4D2 2018-09-04 00:54:43.542 profileId:0x104, clusterId:0x0, sourceEndpoint:2, destinationEndpoint:1 , groupId:0, lastHopLqi:255, lastHopRssi:-63
A4D2 2018-09-04 00:54:43.034 profileId:0x104, clusterId:0x0, sourceEndpoint:2, destinationEndpoint:1 , groupId:0, lastHopLqi:255, lastHopRssi:-63
A4D2 2018-09-04 00:54:42.529 profileId:0x0, clusterId:0x8004, sourceEndpoint:0, destinationEndpoint:0 , groupId:0, lastHopLqi:255, lastHopRssi:-64
A4D2 2018-09-04 00:54:42.021 profileId:0x0, clusterId:0x8005, sourceEndpoint:0, destinationEndpoint:0 , groupId:0, lastHopLqi:255, lastHopRssi:-64
A4D2 2018-09-04 00:54:39.301 profileId:0x0, clusterId:0x13, sourceEndpoint:0, destinationEndpoint:0 , groupId:0, lastHopLqi:255, lastHopRssi:-66
Wohnzimmer Motion 2018-09-04 00:54:28.531 profileId:0x104, clusterId:0x406, sourceEndpoint:2, destinationEndpoint:255 , groupId:0, lastHopLqi:255, lastHopRssi:-53
Wohnzimmer Motion 2018-09-04 00:54:26.916 profileId:0x104, clusterId:0x406, sourceEndpoint:2, destinationEndpoint:1 , groupId:0, lastHopLqi:255, lastHopRssi:-53

(A4D2 becomes "Hue Motion Sensor" which then remains in "UNKNOWN" state - removed and rejoined several times, always the same result)

Its not hue devices specifically, its zigbee bulbs in general that in some cases do not function properly as repeaters. If you have any zigbee bulbs paired directly to Hubitat it's recommended to unscrew them when joining other zigbee devices, after which you can power them up again.

Hi,

I don't have any bulbs nor any other device that might work as a repeater joined to Hubitat. My bulbs and ZigBee outlets are all connected to a Hue hub.
Any other ideas? Would it be possible for the Hubitat support team to take a look?

Thanks!

I’m having the exact same issue with a Hue Motion Sensor. It pairs, but remains UNKNOWN even after pressing Configure.

So I did some experimenting just now and got my Hue Motion Sensor working. Found the custom DTH that is being used by the SmartThings community and did a quick-and-dirty port to Hubitat. All credit goes to digitalgecko, I haven't done anything to the code other than to get it working with Hubitat. See below:

/**
 *  Port of digitalgecko's Hue Motion Sensor SmartThings DTH to Hubitat
 *  Original code licensed under Apache 2.0
 */

metadata {
    definition (name: "Hue Motion Sensor Custom Hubitat DH", namespace: "digitalgecko", author: "digitalgecko") {

		capability "Motion Sensor"
		capability "Configuration"
		capability "Battery"
		capability "Refresh"
        capability "Temperature Measurement"
        capability "Sensor"
        capability "Illuminance Measurement" //0x0400

        fingerprint profileId: "0104", inClusters: "0000,0001,0003,0406,0400,0402", outClusters: "0019", manufacturer: "Philips", model: "SML001", deviceJoinName: "Hue Motion Sensor"
    }

	preferences {
    		section {
			input title: "Temperature Offset", 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: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
		}
    }
}

// Parse incoming device messages to generate events
def parse(String description) {
    def msg = zigbee.parse(description)
    
    //log.warn "--"
    //log.trace description
    //log.debug msg
    //def x = zigbee.parseDescriptionAsMap( description )
    //log.error x
    
	Map map = [:]
    if (description?.startsWith('catchall:')) {
		map = parseCatchAllMessage(description)
	}
	else if (description?.startsWith('temperature: ')) {
		map = parseCustomMessage(description)
	}
    else if (description?.startsWith('illuminance: ')) {
		map = parseCustomMessage(description)
	}
//	else if (description?.startsWith('zone status')) {
//		//map = parseIasMessage(description)
//        log.trace "zone status"
//	}

	def result = map ? createEvent(map) : null

	if (description?.startsWith('enroll request')) {
		List cmds = enrollResponse()
		result = cmds?.collect { new hubitat.device.HubAction(it) }
	}
	else if (description?.startsWith('read attr -')) {
		result = parseReportAttributeMessage(description).each { createEvent(it) }
	}
	return result
}

/*
  Refresh Function
*/
def refresh() {
    log.debug "Refreshing Values"

    def refreshCmds = []
    refreshCmds += zigbee.readAttribute(0x0001, 0x0020) // Read battery?
    refreshCmds += zigbee.readAttribute(0x0402, 0x0000) // Read temp?
    refreshCmds += zigbee.readAttribute(0x0400, 0x0000) // Read luminance?
    refreshCmds += zigbee.readAttribute(0x0406, 0x0000) // Read motion?

    return refreshCmds + enrollResponse()

    }
/*
  Configure Function
*/
def configure() {

// TODO : device watch?

	String zigbeeId = swapEndianHex(device.hub.zigbeeId)
	log.debug "Confuguring Reporting and Bindings."
    
	def configCmds = []
    configCmds += zigbee.batteryConfig()
	configCmds += zigbee.temperatureConfig(30, 600) // Set temp reporting times // Confirmed
    configCmds += zigbee.configureReporting(0x406,0x0000, 0x18, 30, 600, null) // motion // confirmed
    
    // Data type is not 0x20 = 0x8D invalid data type Unsigned 8-bit integer
	configCmds += zigbee.configureReporting(0x400,0x0000, 0x21, 60, 600, 0x20) // Set luminance reporting times?? maybe    
    return refresh() + configCmds 
}


/*
	getMotionResult
 */

private Map getMotionResult(value) {
    //log.trace "Motion : " + value
	
    def descriptionText = value == "01" ? '{{ device.displayName }} detected motion':
			'{{ device.displayName }} stopped detecting motion'
    
    return [
		name: 'motion',
		value: value == "01" ? "active" : "inactive",
		descriptionText: descriptionText,
		translatable: true,
	]
}


/*
  getTemperatureResult
*/
private Map getTemperatureResult(value) {

	//log.trace "Temperature : " + value
	if (tempOffset) {
		def offset = tempOffset as int
		def v = value as int
		value = v + offset
	}
	def descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C':
			'{{ device.displayName }} was {{ value }}°F'

	return [
		name: 'temperature',
		value: value,
		descriptionText: descriptionText,
		translatable: true,
		unit: temperatureScale
	]
}

def getTemperature(value) {
	def celsius = Integer.parseInt(value, 16).shortValue() / 100
	if(getTemperatureScale() == "C"){
		return Math.round(celsius)
		} else {
			return Math.round(celsiusToFahrenheit(celsius))
		}
	}

private Map getLuminanceResult(rawValue) {
	log.debug "Luminance rawValue = ${rawValue}"

	def result = [
		name: 'illuminance',
		value: '--',
		translatable: true,
 		unit: 'lux'
	]
    
    result.value = rawValue as Integer
    return result
}

/*
	getBatteryResult
*/
//TODO: needs calibration
private Map getBatteryResult(rawValue) {
	//log.debug "Battery rawValue = ${rawValue}"

	def result = [
		name: 'battery',
		value: '--',
		translatable: true
	]

	def volts = rawValue / 10

	if (rawValue == 0 || rawValue == 255) {}
	else {
		if (volts > 3.5) {
			result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts."
		}
		else {
			if (device.getDataValue("manufacturer") == "SmartThings") {
				volts = rawValue // For the batteryMap to work the key needs to be an int
				def batteryMap = [28:100, 27:100, 26:100, 25:90, 24:90, 23:70,
								  22:70, 21:50, 20:50, 19:30, 18:30, 17:15, 16:1, 15:0]
				def minVolts = 15
				def maxVolts = 28

				if (volts < minVolts)
					volts = minVolts
				else if (volts > maxVolts)
					volts = maxVolts
				def pct = batteryMap[volts]
				if (pct != null) {
					result.value = pct
					result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
				}
			}
			else {
				def minVolts = 2.1
				def maxVolts = 3.0
				def pct = (volts - minVolts) / (maxVolts - minVolts)
				def roundedPct = Math.round(pct * 100)
				if (roundedPct <= 0)
					roundedPct = 1
				result.value = Math.min(100, roundedPct)
				result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
			}
		}
	}

	return result
}
/*
	parseCustomMessage
*/
private Map parseCustomMessage(String description) {
	Map resultMap = [:]
	if (description?.startsWith('temperature: ')) {
		def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
		resultMap = getTemperatureResult(value)
	}
    
    if (description?.startsWith('illuminance: ')) {
    log.warn "value: " + description.split(": ")[1]
            log.warn "proc: " + value

		def value = zigbee.lux( description.split(": ")[1] as Integer ) //zigbee.parseHAIlluminanceValue(description, "illuminance: ", getTemperatureScale())
		resultMap = getLuminanceResult(value)
	}
	return resultMap
}

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

	List result = []
    
    // Temperature
	if (descMap.cluster == "0402" && descMap.attrId == "0000") {
		def value = getTemperature(descMap.value)
		result << getTemperatureResult(value)
	}
    
    // Motion
   	else if (descMap.cluster == "0406" && descMap.attrId == "0000") {
    	result << getMotionResult(descMap.value)
	}
    
    // Battery
	else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
		result << getBatteryResult(Integer.parseInt(descMap.value, 16))
	}
    
    // Luminance
    else if (descMap.cluster == "0402" ) { //&& descMap.attrId == "0020") {
		log.error "Luminance Response " + description
        //result << getBatteryResult(Integer.parseInt(descMap.value, 16))
	}

	return result
}


/*
	parseCatchAllMessage
*/
private Map parseCatchAllMessage(String description) {
	Map resultMap = [:]
	def cluster = zigbee.parse(description)
//	log.debug cluster
	if (shouldProcessMessage(cluster)) {
		switch(cluster.clusterId) {
			case 0x0001:
				// 0x07 - configure reporting
				if (cluster.command != 0x07) {
					resultMap = getBatteryResult(cluster.data.last())
				}
			break

			case 0x0400:
            	if (cluster.command == 0x07) { // Ignore Configure Reporting Response
                	if(cluster.data[0] == 0x00) {
						log.trace "Luminance Reporting Configured"
						sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
					}
					else {
						log.warn "Luminance REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
					}
				}
				else {
            		log.debug "catchall : luminance" + cluster
                	resultMap = getLuminanceResult(cluster.data.last());
                }

			break
            
			
            
			case 0x0402:
				if (cluster.command == 0x07) {
					if(cluster.data[0] == 0x00) {
						log.trace "Temperature Reporting Configured"
						sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
					}
					else {
						log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
					}
				}
				else {
					// temp is last 2 data values. reverse to swap endian
					String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
					def value = getTemperature(temp)
					resultMap = getTemperatureResult(value)
				}
			break
		}
	}

	return resultMap
}

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


// This seems to be IAS Specific and not needed we are not really a motion sensor
def enrollResponse() {
//	log.debug "Sending enroll response"
//	String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
//	[
//		//Resending the CIE in case the enroll request is sent before CIE is written
//		"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
//		"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
//		//Enroll Response
//		"raw 0x500 {01 23 00 00 00}", "delay 200",
//		"send 0x${device.deviceNetworkId} 1 1", "delay 200"
//	]
}

def configureHealthCheck() {
    Integer hcIntervalMinutes = 12
    refresh()
    sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}

def updated() {
    log.debug "in updated()"
    configureHealthCheck()
}

def ping() {
    return zigbee.onOffRefresh()
}

private getEndpointId() {
	new BigInteger(device.endpointId, 16).toString()
}

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
}

After loading this code in Drivers Code, then switching the device type from the auto-detected Hue Motion Sensor to Hue Motion Sensor Custom Hubitat DH (under User at the bottom of the list), saving, then clicking configure, the states seemed to load properly, and the status of the device changed from UNKNOWN to ACTIVE.

Give it a try and see if it works for you. Seems like there may be an issue with the built-in Hubitat DH?

1 Like

Are you on the latest FW? There was a fix for Hue motion sensors not being configured when added. I was using a custom driver due to this, but now use the stock deiver.

Yes - 1.1.3.116.

1 Like

Ah sorry yours is now working @mtcoombes ? I should have replied to @janwerner
But you've done exactly what I did to get these working.

Yes, after switching between the custom DH and then back to the built-in DH, all seems working. Maybe there’s a bug in the configure() method in the built-in?

That may be given your expierence, and certainty something I can have a look at.

@mike.maxwell I believe this was already resolved in 1.1.2:

Bug Fixes

  • Fixed Hue motion refresh and config errors.
    Listed here

I only have the one which is connected and working fine,. I haven't had to pair any though.

1 Like

Or not, given what I’m seeing with the stock DH.

@mike.maxwell While you’re looking at the configure() method, any chance you could look at adding the ability to configure two additional parameters?

First, whether the red light comes on with motion or not (would be nice to be able to disable it).

Second, the time period before the sensor reports no motion (which, if I’m reading the ZCL right, is found in cluster 0x0406, attribute set 0x001, attribute 0x0010 - “PIROccupiedToUnoccupiedDelay” - which is a uint16 and the unit is seconds).

Thanks!

1 Like

Thanks for your hint. My hue motion sensor #5 that refused to become "ACTIVE" is working after switching to the custom device driver temporarily. Switched back to the stock driver and it's still all good.

Kind of strange that #1-4 worked out of the box and this one didn't ...

1 Like