Xiaomi released a new sensor with light intensity detection:
It works great except I cannot make the intensity to be detected by ST.
Anyone has a custom DH out there?
Xiaomi released a new sensor with light intensity detection:
It works great except I cannot make the intensity to be detected by ST.
Anyone has a custom DH out there?
Would be also interested in this!
Ive orderd two of them, hope someone makes a DH. god i love the xiaomi products, dirt cheap and good products.
I have this exact one and cannot add it to my ST hub. Is there a Device Handler for this one?
Are u adding it correctly? Mine is working except the luminosity part
Yes, I am adding it correctlyâŠI think. I am not sure how I could add it incorrectly? I âAdd a Thingâ and it never shows up. I am assuming I need a DH. I tried the DH for the original Xiaomi human body sensor, but still nothing. Do you have a DH for the Aqara Human Body Sensor?
Have u clicked several times in the device button to put it in pair mode?
Have you found an answer to this?
My Aqara sensors were able to be added much easier than the older non-aqara Xiaomi sensors. With the add thing function on, hold the button for 5 seconds, wait 5, then press the button for 2 seconds. Might take a few goes but it does work. If it fails, the âcatchallâ method will work.
I am using the aqara motion sensor DTH by bspranger/Xiaomi on Github - the light intensity is reported in percentage. I Havenât got it working with the light controller app as it expects a lux readingâŠ
I have just got 2 of these as I was interested in using the lux capability as well.
I have them paired and can see the light intensity being shown as a percentage.
Also when trying to add them to webCoRE they do not show up in the illumination sensor category.
Iâve also noticed in the bspranger DH that there is no capability for illumination so this is probably why.
Has anybody got these working as a lux sensor?
If so, how are they performing and what did you do to get them working.
Additional note. I see that light % only reports when there is motion. Is this correct?
TIA.
Correct. Only when motion triggers we get an updated lux value.
I have it working in WebCoreâŠ
When you say you have it working in webCoRE, is this for light measurement or motion?
light measurementâŠ
I manage to add it as an illuminance sensorâŠ
I am using this DH:
/**
http://www.apache.org/licenses/LICENSE-2.0
*/
metadata {
definition (name: âXiaomi Aqara Motion Sensor Luxâ, namespace: âinpierâ, author: âa4refillpadâ) {
capability "Motion Sensor"
capability "Configuration"
capability "Battery"
capability "Sensor"
capability "Refresh"
capability "Health Check"
capability âIlluminance Measurementâ
attribute "lastCheckin", "String"
attribute "lastMotion", "String"
//attribute "illuminance", "String"
fingerprint profileId: "0104", deviceId: "0104", inClusters: "0000, 0003, 0001, 0400, FFFF, 0019", outClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0019", manufacturer: "LUMI", model: "lumi.sensor_motion.aq2", deviceJoinName: "Xiaomi Aqara Motion"
//fingerprint profield: "0104", inClusters: "0000, 0400, 0406, FFFF", outClusters: "0000, 0019", manufacturer: "LUMI", model: "lumi.sensor_motion.aq2", deviceJoinName: "Xiaomi Aquara Motion"
command "reset"
command "Refresh"
}
simulator {
}
preferences {
input "motionReset", "number", title: "Number of seconds after the last reported activity to report that motion is inactive (in seconds). \n\n(The device will always remain blind to motion for 60seconds following first detected motion. This value just clears the 'active' status after the number of seconds you set here but the device will still remain blind for 60seconds in normal operation.)", description: "", value:120, displayDuringSetup: false
}
tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
tileAttribute("device.lastCheckin", key: "SECONDARY_CONTROL") {
attributeState("default", label:'Last Update: ${currentValue}',icon: "st.Health & Wellness.health9")
}
}
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
standardTile("configure", "device.configure", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", action:"reset", label: "Reset Motion"
}
standardTile("icon", "device.refresh", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
state "default", label:'Last Motion:', icon:"st.Entertainment.entertainment15"
}
valueTile("lastmotion", "device.lastMotion", decoration: "flat", inactiveLabel: false, width: 4, height: 1) {
state "default", label:'${currentValue}'
}
standardTile("refresh", "command.refresh", inactiveLabel: false) {
state "default", label:'refresh', action:"refresh.refresh", icon:"st.secondary.refresh-icon"
}
valueTile("illuminance", "device.illuminance", width: 2, height: 2) {
state "illuminance", label:'${currentValue}\nlux', unit:"lux"
}
main(["motion"])
details(["motion", "battery", "illuminance", "icon", "lastmotion", "reset", "refresh"])
}
}
def parse(String description) {
def linkText = getLinkText(device)
log.debug â${linkText} Parsing: $descriptionâ
Map map = [:]
if (description?.startsWith('catchall:')) {
map = parseCatchAllMessage(description)
}
else if (description?.startsWith('read attr -')) {
map = parseReportAttributeMessage(description)
}
else if (description?.startsWith('illuminance')) {
//getLumminanceResult(description)
map = parseCustomMessage(description)
}
log.debug "${linkText} Parse returned: $map"
def result = map ? createEvent(map) : null
// send event for heartbeat
def now = new Date().format(âyyyy MMM dd EEE h:mm:ss aâ, location.timeZone)
sendEvent(name: âlastCheckinâ, value: now)
if (description?.startsWith('enroll request')) {
List cmds = enrollResponse()
log.debug "${linkText} enroll response: ${cmds}"
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
}
log.debug "Parse returned $map"
return result
}
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
}
/* Old method
private getLumminanceResult(String luxLevel) {
//log.debug luxLevel.substring(12)
def lux = luxLevel.substring(12)
def linkText = getLinkText(device)
log.debug "${linkText} Illuminance is ${lux} lux"
sendEvent(name: "illuminance", value: "$lux")
//sendEvent(name: "Illuminance Measurement", value: "$lux")
return
}
*/
private Map getBatteryResult(rawValue) {
//log.debug 'Batteryâ
def linkText = getLinkText(device)
//log.debug rawValue
def result = [
name: 'battery',
value: '--'
]
def volts = rawValue / 1
def maxVolts = 100
if (volts > maxVolts) {
volts = maxVolts
}
result.value = volts
result.descriptionText = "${linkText} battery was ${result.value}%"
return result
}
private Map parseCatchAllMessage(String description) {
def linkText = getLinkText(device)
Map resultMap = [:]
def cluster = zigbee.parse(description)
log.debug cluster
if (shouldProcessMessage(cluster)) {
switch(cluster.clusterId) {
case 0x0000:
resultMap = getBatteryResult(cluster.data.get(30))
break
//#############################################################
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 0xFC02:
log.debug '${linkText}: ACCELERATIONâ
break
case 0x0402:
log.debug '${linkText}: TEMP'
// 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
// 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
}
def configure() {
// TODO : device watch?
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
log.debug "Confuguring Reporting and Bindings."
def configCmds = []
configCmds += zigbee.batteryConfig()
//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, 0, 600, 0x20) // Set luminance reporting times?? maybe Not working
return refresh() + configCmds
}
def enrollResponse() {
def linkText = getLinkText(device)
log.debug â${linkText}: Enrolling device into the IAS Zoneâ
[
// Enrolling device into the IAS Zone
"raw 0x500 {01 23 00 00 00}", âdelay 200â,
âsend 0x${device.deviceNetworkId} 1 1â
]
}
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?
//log.debug refreshCmds
return refreshCmds + enrollResponse()
}
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â
Map resultMap = [:]
def now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
if (descMap.cluster == â0000â && descMap.attrId == â0005â) {
log.info âCluster 0000 and AttrID 0005â
}
if (descMap.cluster == â0001â && descMap.attrId == â0020â) {
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
}
// Luminance
else if (descMap.cluster == â0400â ) { //&& descMap.attrId == â0020â) {
log.error "Luminance Response " + description
//result << getBatteryResult(Integer.parseInt(descMap.value, 16))
}
else if (descMap.cluster == "0406" && descMap.attrId == "0000") {
def value = descMap.value.endsWith("01") ? "active" : "inactive"
sendEvent(name: "lastMotion", value: now)
if (settings.motionReset == null || settings.motionReset == "" ) settings.motionReset = 120
if (value == "active") runIn(settings.motionReset, stopMotion)
resultMap = getMotionResult(value)
}
return resultMap
}
private Map parseCustomMessage(String description) {
Map resultMap = [:]
//###############################################################################################
if (description?.startsWith('illuminance: ')) {
// log.info âvalue: " + description.split(â: ")[1]
//log.warn "proc: " + value
//def value = zigbee.lux( description.split(": ")[1] as Integer ) //zigbee.parseHAIlluminanceValue(description, "illuminance: ", getTemperatureScale())
def value = description.split(": ")[1]
resultMap = getLuminanceResult(value)
}
//###############################################################################################
return resultMap
}
private Map parseIasMessage(String description) {
def linkText = getLinkText(device)
List parsedMsg = description.split(â ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0020': // Closed/No Motion/Dry
resultMap = getMotionResult('inactive')
break
case '0x0021': // Open/Motion/Wet
resultMap = getMotionResult('active')
break
case '0x0022': // Tamper Alarm
log.debug '${linkText}: motion with tamper alarm'
resultMap = getMotionResult('active')
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
log.debug '${linkText}: no motion with tamper alarm'
resultMap = getMotionResult('inactive')
break
case '0x0025': // Restore Report
break
case '0x0026': // Trouble/Failure
log.debug '${linkText}: motion with failure alarm'
resultMap = getMotionResult('active')
break
case '0x0028': // Test Mode
break
}
return resultMap
}
private Map getMotionResult(value) {
def linkText = getLinkText(device)
//log.debug "${linkText}: motion"
String descriptionText = value == âactiveâ ? â${linkText} detected motionâ : "${linkText} motion has stopped"
def commands = [
name: âmotionâ,
value: value,
descriptionText: descriptionText
]
return commands
}
private byte[] reverseArray(byte[] array) {
byte tmp;
tmp = array[1];
array[1] = array[0];
array[0] = tmp;
return array
}
private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}
def stopMotion() {
sendEvent(name:âmotionâ, value:âinactiveâ)
}
def reset() {
sendEvent(name:âmotionâ, value:âinactiveâ)
}
def installed() {
// Device wakes up every 1 hour, this interval allows us to miss one wakeup notification before marking offline
def linkText = getLinkText(device)
log.debug "${linkText}: Configured health checkInterval when installed()"
sendEvent(name: âcheckIntervalâ, value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: âzigbeeâ, hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device wakes up every 1 hours, this interval allows us to miss one wakeup notification before marking offline
def linkText = getLinkText(device)
log.debug "${linkText}: Configured health checkInterval when updated()"
sendEvent(name: âcheckIntervalâ, value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: âzigbeeâ, hubHardwareId: device.hub.hardwareID])
}
Thanks for this but do you have the link where you got it from as it would be easier to copy in in.
Sorry but donâtâŠ
Looks like this code from @ArstenA:
https://github.com/bspranger/Xiaomi/blob/master/devicetypes/a4refillpad/xiaomi-aqara-motion-sensor.src/xiaomi-aqara-motion-sensor.groovy
This is the one that i already have.
There is no illuminence capability in this one. That I can see anyway.
Hi @Sergio_Ferreira
Is there anyway you can post the cost in the same way that @jymbob posted his?
While I really appreciate your help, Iâm afraid I cannot copy and paste the code with the way you have posted it.
Thanks.
are you sure youâve got the latest version? Iâve got illuminance here, and Iâm pretty sure thatâs the DTH Iâm usingâŠ
If you look at the code you have posted, there is no capability for Illuminance. (Under line 37).
If you look at the code that @Sergio_Ferreira posted you will see that there is and also there are additional fingerprint profileIdâs in lines 43,44.
I can copy those in to the existing code easy enough but it is going through all the code to find the differences that is the problem.
Someone obviously wrote the code for the new DH but I just need to know who so that I can hopefully find it on github.