Tried it. Now I don’t get the battery response either.
Interesting. Can you try removing it and then add it back in? I know that this code is working with mine with both battery and water.
Ok, did that. Same result. When I add it, it first shows up as an unknown device. I go to the “my devices” on the smartthings developer site and associate it with your “Quirky Overflow” device type. When I show events the only thing I see is when I click “refresh” the “refresh command was sent” message.
When watching the live logging, if you touch the sensor with your thumb it should cause it to trigger. Watch the live logging and also the device log itself and see what shows up in there. I wonder if yours returns a different status than mine did.
Mainly this area in the code
case '0x0031': // Closed/No Motion/Wet
resultMap = getMoistureResult('wet')
break
case '0x0030': // Open/Motion/Dry
resultMap = getMoistureResult('dry')
break
That was what I had to watch for that finally lead me where to make the change to the code that @kevintierney provided me in the beginning.
Yeah, I’ve licked my thumb touched it to the sensor quite a few times, but the log shows nothing. I tried pairing it to my wink hub to make sure the device functions and it worked exactly as expected. I removed it from the wink hub and reconnected to the smart things hub and it still doesn’t want to talk.
Ok, I figured out what was wrong. The first time I set it up right and was only getting that battery response, but every subsequent time I tried to set it up with your new code I wasn’t associating that “my device type” properly with the unknown device. I was associating it by clicking on the device and choosing the device type from the drop down. For some reason that doesn’t work. Finally I tried associating it by opening device type, choosing the “home” location and then choosing the device to “test with”. Now it works properly. Thank you for your help!
No problem glad to hear that you got it to work. I hope that others use the code as well. I set it up with IFTTT to not only alert me if it detects water but to also call me. Mine are monitoring my 2 sump pumps I have in my house so I can know if something goes wrong before I get wet socks in the basement
I just got the V2 hub and I can only get it to be recognized as a device and then install the code as I did above with the V1 hub. But now I don’t get any messages from the device. It doesn’t detect battery or liquid.
You write nice code Jason. I am learning right now and I learned to appreciate it.
Thank you @Edward_Reese but actually the thanks goes to @kevintierney as he provided me with the template. I had to doctor some of it to work right. Thank you though very much.
Hello @TheFuzz4 and @kevintierney , is this still working for you? I just moved to ST from Wink and the device is found but only shows battery. not wet/dry.
I see this in the live logger…
bd07f872-d958-40c1-a756-5c67a282074a 7:29:40 PM: debug Desc Map: [raw:BF07010001082000201F, dni:BF07, endpoint:01, cluster:0001, size:08, attrId:0020, encoding:20, value:1f]
bd07f872-d958-40c1-a756-5c67a282074a 7:29:40 PM: debug description: read attr - raw: BF07010001082000201F, dni: BF07, endpoint: 01, cluster: 0001, size: 08, attrId: 0020, encoding: 20, value: 1f
@rpk113 I have one right now that I"ve removed from ST because I am getting the same response as you. I’m trying to figure out what its issue is but its not getting the same info from the device like it was when I first worked with @kevintierney on this. I haven’t messed with the device in a few weeks but if I get some time I’ll add it back in again and see what its doing.
I seem to be having the same problem as Brian Schwartz, i can add it but only reports on the battery and not wet or dry? I don’t understand what he says when he finally got it working by opening device type and choosing home location and then test with?
Sorry to revive this dinosaur of a thread but here is how I got this to work with my 2 Overflows. First, I added Kevin Tierny’s DH, then paired the overflow. After that, I overwrote Kevins DH with Hamiltons. After that, battery and status work.
Between these and my replacement of my 1 remaining Lutron with a Inovelli (non-neutral) dimmer, I can smash the sh** out my my Wink hub. It only existed to handle the Overflows and Lutron but now those issues are resolved. I moved over from Wink a few months ago but the subscription model will bring many others.
I have edited and fixed the handler, it now reports battery and status correctly.
/*
Quirky Moisture Sensor
*/
metadata {
definition (name: "Quirky Moisture Sensor",namespace: "tierneykev", author: "Kevin Tierney") {
capability "Configuration"
capability "Battery"
capability "Refresh"
capability "Water Sensor"
command "enrollResponse"
fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0020,0B05", outClusters: "0003,0019" }
simulator {
}
preferences {
}
tiles {
standardTile("water", "device.water", width: 2, height: 2) {
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
}
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
state "battery", label:'${currentValue}% battery'
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main "water"
details(["water", "battery", "refresh"])
}
}
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)) {
switch(cluster.clusterId) {
case 0x0001:
resultMap = getBatteryResult(cluster.data.last())
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
}
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 = [:]
if (descMap.cluster == "0001" && descMap.attrId == "0020") {
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
}
return resultMap
}
private Map parseIasMessage(String description) {
List parsedMsg = description.split(' ')
String msgCode = parsedMsg[2]
Map resultMap = [:]
switch(msgCode) {
case '0x0022': // Tamper Alarm
break
case '0x0023': // Battery Alarm
break
case '0x0024': // Supervision Report
log.debug 'dry with tamper alarm'
resultMap = getMoistureResult('dry')
break
case '0x0025': // Restore Report
log.debug 'water with tamper alarm'
resultMap = getMoistureResult('wet')
break
case '0x0026': // Trouble/Failure
break
case '0x0028': // Test Mode
break
case '0x0030': // Closed/No Motion/Dry
resultMap = getMoistureResult('dry')
break
case '0x0031': // Open/Motion/Wet
resultMap = getMoistureResult('wet')
break
}
return resultMap
}
private Map getBatteryResult(rawValue) {
log.debug 'Battery'
def linkText = getLinkText(device)
def result = [
name: 'battery', value: '100', descriptionText: 'text'
]
def volts = rawValue / 10
def descriptionText
if (volts > 3.5) {
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
}
else {
def minVolts = 2.1
def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts)
result.value = (int) (pct * 100)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
return result
}
private Map getMoistureResult(value) {
log.debug 'water'
String descriptionText = "${device.displayName} is ${value}"
return [
name: 'water',
value: value,
descriptionText: descriptionText
]
}
def refresh()
{
log.debug "Refreshing Battery"
[
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
]
}
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 1", "delay 1500",
"zcl global send-me-a-report 1 0x20 0x20 300 0600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x001 {${device.zigbeeId}} {}", "delay 1000",
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 1000",
]
return configCmds + refresh() // 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 1"
]
}
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
}
Thank you for your help with this. I appreciate it.
Thanks guys. I was just looking for this and noticed you had it already done! I have it working fine here although my battery is reading 122%. Any idea why that would be?
Are you using Nickel Zinck rechargeable batteries? The limits are set for regular Alkaline. If you infact have more than 3V set it to 3.2 Max there was logic to hard set this cases to 100% but I had to take it off.
I’m using regular alkaline. These here for reference:
Ok can you change this, the sensor reports battery every 10 mins so you should see 100% in 10 mins
private Map getBatteryResult(rawValue) {
log.debug 'Battery'
def linkText = getLinkText(device)
def result = [
name: 'battery', value: '100', descriptionText: 'text'
]
def volts = rawValue / 10
def descriptionText
if (volts > 3.5) {
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
}
else {
def minVolts = 2.1
def maxVolts = 3.0
def pct = (int) (((volts - minVolts) / (maxVolts - minVolts)) * 100)
result.value = Math.min(100, pct)
result.descriptionText = "${linkText} battery was ${result.value}%"
}
return result
}