Xiaomi AQara Smart Window Door Sensor are they working or not on Hubitat?

Xiaomi AQara Smart Window Door Sensor are they working or not, on Hubitat?
I didt find them listed on compatible devices but some say they work..
So can I get a clear answer to know if I should buy it or not? Maybe also update that list?
Thank you!

1 Like

If you are buying new devices, i would stick to the list of supported devices.

https://docs.hubitat.com/index.php?title=List_of_Compatible_Devices

1 Like

I have the older Xiaomi and the newer Aqara contact sensors and both are working ok for me. You will need to load a custom driver before you try and pair them with your hub so that they get allocated the correct device type when pairing.
Personally I like them as they are small, cheap and have a reasonable battery life.

Exactly, that's what I've heard!
But where do I get the custom driver? And how do I load it? :blush:

Working fine

you will want to read this as well

[quote="Huby, post:4, topic:24461"]
Exactly, that's what I've heard!
But where do I get the custom driver? And how do I load it? :blush:
[/quote]

Oh ok. I thought you were just querying if they worked or not.
Here is the driver code. 
In the menus pick Driver CODE and then New Driver at the top right.
Copy and paste the code in and save.
This process is in the documentation somewhere so it might be worth a read when you get time. 

/**
 *  Xiaomi "Original" Door/Window Sensor - model MCCGQ01LM
 *  & Aqara Door/Window Sensor - model MCCGQ11LM
 *  Device Driver for Hubitat Elevation hub
 *  Version 0.7.2
 *
 *
 *  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.
 *
 *  Based on SmartThings device handler code by a4refillpad
 *  With contributions by alecm, alixjg, bspranger, gn0st1c, foz333, jmagnuson, mike.maxwell, rinkek, ronvandegraaf, snalee, tmleafs, twonk, & veeceeoh
 *  Code reworked for use with Hubitat Elevation hub by veeceeoh
 *
 *  Known issues:
 *  + Xiaomi devices send reports based on changes, and a status report every 50-60 minutes. These settings cannot be adjusted.
 *  + The battery level / voltage is not reported at pairing. Wait for the first status report, 50-60 minutes after pairing.
 *    However, the Aqara Door/Window sensor battery level can be retrieved immediately with a short-press of the reset button.
 *  + Pairing Xiaomi devices can be difficult as they were not designed to use with a Hubitat hub.
 *    Holding the sensor's reset button until the LED blinks will start pairing mode.
 *    3 quick flashes indicates success, while one long flash means pairing has not started yet.
 *    In either case, keep the sensor "awake" by short-pressing the reset button repeatedly, until recognized by Hubitat.
 *  + The connection can be dropped without warning. To reconnect, put Hubitat in "Discover Devices" mode, and follow
 *    the same steps for pairing. As long as it has not been removed from the Hubitat's device list, when the LED
 *    flashes 3 times, the Aqara Motion Sensor should be reconnected and will resume reporting as normal
 *
 */

metadata {
	definition (name: "Xiaomi Door/Window Sensor", namespace: "veeceeoh", author: "veeceeoh") {
		capability "Contact Sensor"
		capability "Sensor"
		capability "Battery"

		attribute "lastCheckin", "String"
		attribute "lastOpened", "String"
		attribute "lastClosed", "String"
		attribute "batteryLastReplaced", "String"

		// fingerprint for Xiaomi "Original" Door/Window Sensor
		fingerprint endpointId: "01", profileId: "0104", deviceId: "0104", inClusters: "0000,0003,FFFF,0019", outClusters: "0000,0004,0003,0006,0008,0005,0019", manufacturer: "LUMI", model: "lumi.sensor_magnet"

		// fingerprint for Xiaomi Aqara Door/Window Sensor
		fingerprint endpointId: "01", profileId: "0104", deviceId: "5F01", inClusters: "0000,0003,FFFF,0006", outClusters: "0000,0004,FFFF", manufacturer: "LUMI", model: "lumi.sensor_magnet.aq2"

		command "resetBatteryReplacedDate"
		command "resetToClosed"
		command "resetToOpen"
	}

	preferences {
		//Battery Voltage Range
 		input name: "voltsmin", title: "Min Volts (0% battery = ___ volts, range 2.9). Default = 2.9 Volts", description: "", type: "decimal", range: "2..2.9"
 		input name: "voltsmax", title: "Max Volts (100% battery = ___ volts, range 3.055). Default = 3.055 Volts", description: "", type: "decimal", range: "2.9..3.1"
 		//Logging Message Config
		input name: "infoLogging", type: "bool", title: "Enable info message logging", description: ""
		input name: "debugLogging", type: "bool", title: "Enable debug message logging", description: ""
		//Firmware 2.0.5 Compatibility Fix Config
		input name: "oldFirmware", type: "bool", title: "DISABLE 2.0.5 firmware compatibility fix (for users of 2.0.4 or earlier)", description: ""
	}
}

// Parse incoming device messages to generate events
def parse(String description) {
	def cluster = description.split(",").find {it.split(":")[0].trim() == "cluster"}?.split(":")[1].trim()
	def attrId = description.split(",").find {it.split(":")[0].trim() == "attrId"}?.split(":")[1].trim()
	def encoding = Integer.parseInt(description.split(",").find {it.split(":")[0].trim() == "encoding"}?.split(":")[1].trim(), 16)
	def valueHex = description.split(",").find {it.split(":")[0].trim() == "value"}?.split(":")[1].trim()
	Map map = [:]

	if (!oldFirmware & valueHex != null & encoding > 0x18 & encoding < 0x3e) {
		displayDebugLog("Data type of payload is little-endian; reversing byte order")
		// Reverse order of bytes in description's payload for LE data types - required for Hubitat firmware 2.0.5 or newer
		valueHex = reverseHexString(valueHex)
	}

	displayDebugLog("Parsing message: ${description}")
	displayDebugLog("Message payload: ${valueHex}")

	// lastCheckin can be used with Hubitat
	sendEvent(name: "lastCheckin", value: new Date().toLocaleString())

	// Send message data to appropriate parsing function based on the type of report
	if (cluster == "0006") {
		// Parse open / closed status report
		map = parseContact(Integer.parseInt(valueHex))
	} else if (attrId == "0005") {
		displayDebugLog("Reset button was short-pressed")
		// Parse battery level from longer type of announcement message
		map = (valueHex.size() > 60) ? parseBattery(valueHex.split('FF42')[1]) : [:]
	} else if (attrId == "FF01" || attrId == "FF02") {
		// Parse battery level from hourly announcement message
		map = (valueHex.size() > 30) ? parseBattery(valueHex) : [:]
	} else {
		displayDebugLog("Unable to parse message")
	}

	if (map != [:]) {
		displayInfoLog(map.descriptionText)
		displayDebugLog("Creating event $map")
		return createEvent(map)
	} else
		return [:]
}

// Reverses order of bytes in hex string
def reverseHexString(hexString) {
	def reversed = ""
	for (int i = hexString.length(); i > 0; i -= 2) {
		reversed += hexString.substring(i - 2, i )
	}
	return reversed
}

// Parse open/close report
private parseContact(closedOpen) {
	def value = ["closed", "open"]
	def desc = ["closed", "opened"]
	def coreEvent = ["lastClosed", "lastOpened"]
	displayDebugLog("Setting ${coreEvent[closedOpen]} to current date/time for Hubitat")
	sendEvent(name: coreEvent[closedOpen], value: new Date().toLocaleString(), descriptionText: "Updated ${coreEvent[closedOpen]} (Hubitat)")
	return [
		name: 'contact',
		value: value[closedOpen],
		isStateChange: true,
		descriptionText: "Contact was ${desc[closedOpen]}"
	]
}

// Convert raw 4 digit integer voltage value into percentage based on minVolts/maxVolts range
private parseBattery(description) {
	displayDebugLog("Battery parse string = ${description}")
	def MsgLength = description.size()
	def rawValue
	for (int i = 4; i < (MsgLength-3); i+=2) {
		if (description[i..(i+1)] == "21") { // Search for byte preceeding battery voltage bytes
			rawValue = Integer.parseInt((description[(i+4)..(i+5)] + description[(i+2)..(i+3)]),16)
			break
		}
	}
	def rawVolts = rawValue / 1000
	def minVolts = voltsmin ? voltsmin : 2.8
	def maxVolts = voltsmax ? voltsmax : 3.055
	def pct = (rawVolts - minVolts) / (maxVolts - minVolts)
	def roundedPct = Math.min(100, Math.round(pct * 100))
	def descText = "Battery level is ${roundedPct}% (${rawVolts} Volts)"
	displayInfoLog(descText)
	def result = [
		name: 'battery',
		value: roundedPct,
		unit: "%",
		isStateChange: true,
		descriptionText: descText
	]
	return result
}

// Manually override contact state to closed
def resetToClosed() {
	if (device.currentState('contact')?.value == "open") {
		displayInfoLog("Manually reset to closed")
		sendEvent(parseContact(0))
	}
}

// Manually override contact state to open
def resetToOpen() {
	if (device.currentState('contact')?.value == "closed") {
		displayInfoLog("Manually reset to open")
		sendEvent(parseContact(1))
	}
}

private def displayDebugLog(message) {
	if (debugLogging)
		log.debug "${device.displayName}: ${message}"
}

private def displayInfoLog(message) {
	if (infoLogging || state.prefsSetCount != 1)
		log.info "${device.displayName}: ${message}"
}

//Reset the batteryLastReplaced date to current date
def resetBatteryReplacedDate(paired) {
	def newlyPaired = paired ? " for newly paired sensor" : ""
	sendEvent(name: "batteryLastReplaced", value: new Date())
	displayInfoLog("Setting Battery Last Replaced to current date${newlyPaired}")
}

// installed() runs just after a sensor is paired
def installed() {
	displayInfoLog("Installing")
	state.prefsSetCount = 0
}

// configure() runs after installed() when a sensor is paired or reconnected
def configure() {
	displayInfoLog("Configuring")
	init()
	state.prefsSetCount = 1
	return
}

// updated() will run every time user saves preferences
def updated() {
	displayInfoLog("Updating preference settings")
	init()
	displayInfoLog("Info message logging enabled")
	displayDebugLog("Debug message logging enabled")
}

def init() {
	if (!device.currentState('batteryLastReplaced')?.value)
		resetBatteryReplacedDate(true)
}
1 Like

Thank YOU so much for the help, and everyone who took of their time to help!
As soon as I get the sensor I will do as instructed.
I may ask you more then since I'm not so good with this..:slight_smile:

BTW. do you have a roller shutter home? What device do you use for it?
I bought Fibaro Roller Shutter 3, Unfortunately it's not on the supported list, but Aeotec nano shatter is , thow I read some posts from february where ppl. where not happy.
Maybe I should make a new thread about this..

I've got around 20 different Xiaomi and Aqara zigbee devices (contact sensors, outlets, wireless buttons, even a curtain motor) paired to my Hubitat and they work extremely well, specially after adding a XBee router, as noted in this YouTube video (its in Spanish, but should be pretty easy to follow):

Witch one? Is it working on a roller shatter too?
Thank you!

I don't have shutters so cannot advise on that I'm afraid.

I'm sure I've seen a post about these but it might be worth raising a new post about these if you cannot find anything.

I meant the Aqara Curtain motor with a DT-82 rail, using the SmartThings device driver on my Hubitat Elevation hub.

There is also a new Aqara Rolling Shutter Motor, but no Hubitat / ST device driver available as of now (although based on past experiences, I assume that it may work with a standard switch device driver).
https://www.aliexpress.com/i/33009670676.html

Hope this helps!

The power monitoring function does not work with the generic driver.

Using Xiaomi door/window DH for the battery?
Works fine

Mine worked for the first 2 weeks then stopped. I know this won't help the original poster but maybe somebody else. I'm not sure what is wrong either. No other devices have this issue.