Hue motion sensor does not detect motion

Hi all,
I have here a Philips Hue motion sensor that does pair with Hubitat but seems not to update info. And motion seems not to be detected.

Current States

  • battery : 100 I replaced the battery
  • illuminance : 58 this value changes when hitting refresh button on the device page.
  • motion : inactive never changes even if I wave like a monkey on crack in front of the sensor
  • temperature : 63.76 does change after refresh button

I only get that after hitting refresh. It worked fine with ST. I tried 10 seconds reset and the quick push to get the orange flashing light..But this thing is not functioning. What am I missing?
I appreciate the help. Many thanks in advance!
More info from Hubitat:

  • endpointId: 02
  • application: 02
  • model: SML001
  • manufacturer: Philips

Zigbee channel 12

Have yes pressed the CONFIGURE button on the device details page (after making sure the device is awake to receive a command.) This is just a guess as I do not have a Hue motion sensor. The CONFIGURE button sends configuration information to the device to tell it how to keep Hubitat up to date.

2 Likes

Assuming you had this paired with Hue bridge previously? Supported channels in on Hue Bridge are 11,15,20 and 25. If it was previously paired with the Hue Bridge, pair it again, and then reset it first.

Interesting...I saw that the smartthings hub is on channel 15 and the hubitat on 12...
It was paired with the Smartthings hub. And I have not been able to pair it with the Hue bridge anymore...but lets try the hubitat on 11 instead of 12. Thanks for the clues and advice...and the config button..I shall try that as well.

Keep in mind that if you change your Zigbee channel, you will need to wait up to 48 hours for the mesh to rebuild completely.

Thanks for the warning, luckily the motion sensor is the only zigbee device I was moving over.
But I am unable to pair that hue motion sensor with the hue bridge anymore.
I press reset 10+ seconds and then the orange led blinks..I run the add sensor on the hue app and then the led blinks green. But the hue app keeps searching and searching and searching even after an hour it does not detect.
Its almost like that the motion sensor does receive the sync command but the app does not receive the confirmation back.
It does get found by the ST hub and it works perfectly. But I want to migrate the hue motion sensor to Hubitat! And it looks like that something in the firmware of that motion sensor it is locked on the ST hub?

Try removing the battery for 30 seconds and then do the reset procedure that might help

There are still some Hue problems that they seem reluctant to fix.....has been going on for a month now....

@arnoud is unable to pair a Hue Motion Sensor with a Hue Bridge That says to me something is not right with the Motion Sensor.

1 Like

Related to the motion sensor directly attached to Hubitat via the OP? Or are you referring to something else?

I have been having problems with my hue motion sensor detecting motion from time to time as well. I just shrug and wait. Eventually it works again.

Im getting the same thing. It’s connected, yet not logging anything unless I Configure and refresh.

10:00:56.906:errorgroovy.lang.MissingMethodException: No signature of method: static com.hubitat.zigbee.message.ZigBeeMessageBuilder.getMsgType() is applicable for argument types: (java.util.ArrayList) values: [[zdo bind 0x3CE7 0x02 0x01 0x0001 {0017880102034ECD} {}, delay 2000, ...]] Possible solutions: getMsgType(java.lang.String) (configure)

dev:2572018-07-06 10:00:56.835:debugRefreshing Values

dev:2572018-07-06 10:00:56.831:debugConfuguring Reporting and Bindings.

dev:2572018-07-06 10:00:56.795:warnconfigure...

I’ve reset, readers etc to no avail.
Any ideas?

I updated the DTH I had in ST, and this seems to be working. Certainly no coder, but just minor changes. This does allow the "Configure" and also triggering lighting ok.

	/**
 *  Copyright 2015 SmartThings
 *
 *  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.
 *
 *  06/07/2018 Updated for use in Hubitat, from original by "digitalgecko".
 */

metadata {
	definition (name: "Hue Motion Sensor", 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
		}
			section {
			input title: "Luminance Offset", description: "This feature allows you to correct the luminance reading by selecting an offset. Enter a value such as 20 or -20 to adjust the luminance reading.", displayDuringSetup: false, type: "paragraph", element: "paragraph"
			input "luxOffset", "number", title: "Lux", description: "Adjust luminance by this amount", range: "*..*", displayDuringSetup: false
			input name: "debug", type: "bool", title: "Enable Debug?", defaultValue: false, displayDuringSetup: false, required: 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(60, 600) // Set temp reporting times // Confirmed
	
	configCmds += zigbee.configureReporting(0x406,0x0000, 0x18, 10, 600, null) // motion // confirmed
/* Default Orginal Code
	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}"

	if (luxOffset) {
		def offset = luxOffset as int
		def v = rawValue as int
		rawValue = v + offset
	}
	
	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 def logging(message) {
	if (settings.debug == "true") log.debug "$message"
}



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
}

Wow, I will try that. Thanks for posting your experience and the DTH. I am still recovering from surgery... so I am slow for a while yet.

1 Like

Indeed, I have 2 issues. One is getting it to work on the Hubitat and second is not being able to get a complete factory reset to pair the hue motion sensor back to the hue hub.
I know that hue bulbs are unable to be reconnected to the hue hub after connected to SmartThings and Hubitat due the change from ZLL to ZHA and there is no way to reset the bulbs back to ZLL.
The motion sensor should not have this issue.

This is the first I've head of this. Hubitat is using ZHA, so that wouldn't be a factor here anyway. My understanding is you can use either a Lutron Connected Bulb Remote (If you can get your hands on one) or a Hue Dimmer to reset them.

I don't know of a similar process for the motion sensor though. It should be able to reset and pair. Might be stuck on an incompatible channel with Hue. You may need to pair the motion sensor with ST, then change SmartThings to a channel that is compatible with Hue bridge (11,15,20 and 25). Of course this should not be one of the channels that Hue is currently using. Then, after ensuring that the motion sensor is working on the new channel with ST, try factory resetting it and see if Hue can pair with it.

I'm surprised that the Motion sensor wouldn't reset completely, without doing this, but it may be a scenario that was not anticipated by Philips engineers, so it cannot reset from an incompatible channel and then pair with one of the expected channels.

@arnoud wishing you a speedy recovery! :+1:

1 Like

I have tested the resetting with a new Philips Motoon sensor and that worked flawless.
The hubitat uses channel 11 which is supported by the Hue Bridge. I have sent the other Hue motion sensor for warranty, something has been corrupted in the resetting. Or it does not reset completely.

Now the second part. Hubitat does NOT work out of the box with the Hue motion sensor. There is some bug that hinders correct functioning. @Royski, the edited DHT from Smartthings works!
I hope that the Hubitat peeps will look at their native Hue driver and check with
digitalgecko's DHT modified by @Royski and fix the Hubitat native one.
Thanks!

2 Likes

Please let support know so that can look into the issue.

How do I contact support? Do I post that somewhere on this forum?