LeakSmart Sensors

Currently migrating from Wink and I've gotten a ton of devices happily and successfully working with Hubitat. Still trying to figure out my 10 LeakSmart water sensors (not the valve).

When I pair using the generic zigbee moisture sensor, I get temperature + battery level reports that look correct, but the state doesn't change from "dry" when I test the sensor with some water.

When I try using the custom driver I get wonky temperature and battery readings (598F temperature, 120% battery) and the water test still fails to trigger a state change. (Tried with and without compatibility mode turned on)

Sensors are using firmware .0b34 which is AFAIK the most current. Any ideas? If these sensors are known to be flaky, is there a good "bulletproof" water sensor that works out of the box? Leak sensors aren't something I want to worry about!

Edit: Removed the sensor, rebooted hub, and tried again. Now things look better, using the community driver they are reporting water immediately, though battery and temperature are still wonked.

1 Like

I hear you! My parents had $10k worth of water damage because of a HVAC issue and that prompted me to buy water sensors for every sink, toilet, and my attic HVAC drip pan plus a water shutoff valve.

I have been using the ST branded water sensors which were made by Centralite - the Iris ones are the same and you can likely buy from ebay. They have worked flawlessly, report temperature, and have had a super long battery life. I installed them in January 2018 and I have yet to replace any of the batteries. The newer ST version has sensors on top as well and have read positive reviews of those as well.

Months ago my son was supposedly cleaning his shoes in our laundry room while I was on business travel. I got a SMS from my hub that water was detected under the sink and that my valve was shutting off. After immediately calling my wife I realized it was a false alarm but it was refreshing to both of us to know that the system was working. My son had somehow unscrewed the water line a little from the pull out nozzle and water was running down the hose into the cabinet below, thus setting off the water sensor.

I have two of these sensors. The community driver is giving weird temp readings, but ithwise working fine.

The new ST one is nice, I have one of those that I picked up on a sale - the only thing I don't like is that it doesn't include an audible alarm.

1 Like

I have the old Aeotec ones (DSB45). I have 8 of them that I converted to be line-powered using a plug-in transformer. They've been fine, and I don't need to worry about changing batteries.

Is this the driver code you are using (see below)? Mine works like I said, but yes the temp is funky for some reason. Both are the v34 firmware. One is newer and shipped with v34, the other was upgraded while still attached to Wink.

The newer one I have to compensate the temp by 447˚ F, and the older version that was upgraded to v34 I have to compensate the temp by -39˚ F. It honestly doesn't matter to me that much. If those areas of my basement are freezing, I've got much bigger problems. Besides I have an Iris water sensor in front of my water heater, just a few feet from where the two leaksmart sensors are, so I can always get the temp reading from that.

/*
 * leakSmart Sensor
 *
 * Version 1.2.4 - Various improvements, details below. (08/13/2018)
 *   Fixed battery percentage rounding error that caused the battery to read 0% on occasion.
 *   Updated logging prefixes.
 *   Made the "wet" state blue.
 * Version 1.2.3 - Added capability "Sensor". (04/20/2017)
 * Version 1.2.2 - Added second fingerprint. (01/29/2017)
 * Version 1.2.1 - Fixed case where some new sensors can be stuck "wet". (10/26/2016)
 * Version 1.2.0 - Various improvements, details below. (09/15/2016)
 *  New configuration options for setting the upper and lower limit of your battery
 *   life which will allow users to better tune the battery reporting against the
 *   actual voltage output profiles for their particular batteries. For example,
 *   rechargeable batteries have a different voltage profile than regular batteries.
 *  Resolved a defect in device configuration that was causing the devices to report
 *   temperature too frequently leading to a reduced battery life.
 *  Added a flag so I could force a device reconfiguration without having to reset or
 *   use the simulator.
 * Version 1.1.0 - Increased time between reports to increase battery life. Also
 *  adjusted the battery calculation. 4.5 max, 3.6 min.
 * Version 1.0.9 - Cleaned up some logging, providing proper logs at the INFO level.
 *  Set the default log level to INFO. Updated the poll method for proper poll 
 *  handling.
 * Version 1.0.8 - Added a label to display the last activity date/time of the device.
 * Version 1.0.7 - Updated to add a compatibility mode for sensors that are not sending 
 *   data as expected, could be related to V1 of the hub.
 * Version 1.0.6 - Decreased frequency of battery reporting from 5 minutes to 4 hours. 
 *	 Increased the wet/dry window from 30 seconds to 1 second. This is just a guess at 
 *   at fix. Decreased frequency of temperature reporting from 30 seconds to 5 minutes. 
 *   (07/28/2016)
 * Version 1.0.5 - Changed the default log level to "INFO" versus "DEBUG" (07/25/2016)
 * Version 1.0.4 - Updated initialziation code which allows the device to pair and 
 *   configure without additional setup, thanks again @krlaframboise (07/24/2016)
 * Version 1.0.3 - Prevented duplicate refresh / configure calls, thanks @krlaframboise
 * Version 1.0.2 - Cleaned up the code by removing un-needed lines of code (07/15/2016)
 * Version 1.0.1 - Added these version numbers (07/15/2016)
 * Version 1.0.0 - Initial Release (07/14/2016)
 * 
 * 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.
 *
 * This code is by no means 100% all my work. This device handler is the work of SmartThings, @dhelm2, @John_Luikart, & @krlaframboise.
 *
 * You can find this device handler @ https://github.com/ericvitale/ST-leakSmart-Sensor/
 * You can find my other device handlers & SmartApps @ https://github.com/ericvitale
 *
 */

public static String version() { return "v1.2.4.20180813" }

metadata {
    definition (name: "leakSmart Sensor", namespace: "ericvitale", author: "ericvitale@gmail.com", category: "C2") {
        capability "Configuration"
        capability "Battery"
        capability "Refresh"
        capability "Temperature Measurement"
        capability "Water Sensor"
        capability "Polling"
        capability "Sensor"
        
        attribute "lastActivity", "string"

        fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0402,0B02,FC02", outClusters: "0003,0019"
		fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0B02,FC02", outClusters: "0003,0019"
	}

    simulator {
    }

    preferences {
        section {
            image(name: 'educationalcontent', multiple: true, images: [
                "http://cdn.device-gse.smartthings.com/Moisture/Moisture1.png",
                "http://cdn.device-gse.smartthings.com/Moisture/Moisture2.png",
                "http://cdn.device-gse.smartthings.com/Moisture/Moisture3.png"
            ])
        }
        
        section("Temperature Configuration") {
            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("Battery Configuration") {
        	input "fullVolts", "decimal", title: "Max Voltage", defaultValue: getDefaultTop()
            input "emptyVolts", "decimal", title: "Min Voltage", defaultValue: getDefaultBottom()
        }
        
        section("Settings") {
        	input "logging", "enum", title: "Log Level", required: false, defaultValue: "INFO", options: ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]
            input "v1", "bool", title: "Compatibility Mode?", required: true, defaultValue: false
        }
    }

    tiles(scale: 2) {

        multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
            tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
                attributeState "dry", label: "Dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
                attributeState "wet", label: "Wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc"
            }
            
            tileAttribute ("device.lastActivity", key: "SECONDARY_CONTROL") {
				attributeState "default", label:'Last activity: ${currentValue}', action: "refresh.refresh"
			}
        }

        valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
            state "temperature", label:'${currentValue}°',
            backgroundColors:[
                [value: 31, color: "#153591"],
                [value: 44, color: "#1e9cbb"],
                [value: 59, color: "#90d2a7"],
                [value: 74, color: "#44b621"],
                [value: 84, color: "#f1d801"],
                [value: 95, color: "#d04e00"],
                [value: 96, color: "#bc2323"]
            ]
        }

        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"
        }
        
        

        main (["water", "temperature"])
        details(["water", "temperature", "battery", "refresh"])
    }
}

private getLogPrefix() {
	return "leakSmart.${version()}.${device.label}>>>"
}

private determineLogLevel(data) {
    switch (data?.toUpperCase()) {
        case "TRACE":
            return 0
            break
        case "DEBUG":
            return 1
            break
        case "INFO":
            return 2
            break
        case "WARN":
            return 3
            break
        case "ERROR":
        	return 4
            break
        default:
            return 1
    }
}

def log(data, type) {
    data = "${getLogPrefix()} ${data ?: ''}"
        
    if (determineLogLevel(type) >= determineLogLevel(settings?.logging ?: "INFO")) {
        switch (type?.toUpperCase()) {
            case "TRACE":
                log.trace "${data}"
                break
            case "DEBUG":
                log.debug "${data}"
                break
            case "INFO":
                log.info "${data}"
                break
            case "WARN":
                log.warn "${data}"
                break
            case "ERROR":
                log.error "${data}"
                break
            default:
                log.error "${getLogPrefix()} Invalid Log Setting"
        }
    }
}

def getLastMessageDateTimeStamp() {
	return state.updateTimeStamp
}

def updated() {
    log("Update started.", "DEBUG")
    
    setTopVolts(fullVolts)
    setBottomVolts(emptyVolts)
    
    sendEvent(name: "water", value: "dry")
    
    log("Top End Voltage = ${getTopVolts()}.", "INFO")
    log("Bottom End Voltage = ${getBottomVolts()}.", "INFO")
    
	if (!isDuplicateCommand(state.lastUpdated, 5000)) {
        state.lastUpdated = new Date().time
        
        if(shouldReconfigure()) {
        	state.configured = false
            setStateVersion(getNewStateVersion())
            log("Initializing a reconfigure.", "INFO")
        }

        if (state.configured) {
        	log("Device already configured.", "TRACE")
            return response(refresh())
        }
        else {
        	log("Device being reconfigured.", "INFO")
            return response(configure())
        }
    }
}

def canPoll() {
	def theCurrentTime = new Date().time
	if(state.lastPoll == null) {
    	state.lastPoll = new Date().time
        log("Never polled before, ok to poll.", "INFO")
        return true
    } else if((theCurrentTime - state.lastPoll) >= (1000*60*60*4)) {
    	state.lastPoll = new Date().time
        log("Minimum poll time elapsed. Ok to poll.", "INFO")
        return true
    } else {
    	log("Minimum poll time not elapsed.", "INFO")
        return false
    }
}

def poll() {
	if(canPoll()) {
		def retVal = zigbee.readAttribute(0x0402, 0x0000)    
    	return retVal
    }
}

def parse(String description) {
    log("parse(${description}.", "DEBUG")

    Map map = [:]
    
    if (description?.startsWith('catchall:')) {
        map = parseCatchAllMessage(description)
    }
    else if (description?.startsWith('read attr -')) {
        map = parseReportAttributeMessage(description)
    }
    else if (description?.startsWith('temperature: ')) {
        map = parseCustomMessage(description)
	}

    log("map = ${map}.", "DEBUG")

	def result = map ? createEvent(map) : null
    
    updateDeviceLastActivity(new Date())

    return result
}

private Map parseCatchAllMessage(String description) {
    Map resultMap = [:]
    def cluster = zigbee.parse(description)
    if (shouldProcessMessage(cluster)) {
		switch(cluster.clusterId) {
            case 0x0001:
                log("001 Cluster Data: ${cluster.data}.", "DEBUG")
                resultMap = getBatteryResult(cluster.data.last())
                break

            case 0x0402:
               	//temp is last 2 data values. reverse to swap endian
                log("402 Cluster Data: ${cluster.data}.", "DEBUG")
                String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
               	def value = getTemperature(temp)
                resultMap = getTemperatureResult(value)
                break
                
            case 0x0B02:
                log("B02 Cluster Data: ${cluster.data}.", "DEBUG")
                String temp = cluster.data[2];
                log.debug "B02 temp data ${temp}"
                resultMap = parseAlarmCode(temp)
                break
                
            default:
            	log("Unhandled Cluster Data: ${cluster.data}.", "WARN")
                break
		}
    } else {
    	log("Did not process message ${cluster}.", "DEBUG")
    }
    
    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("Desc Map: $descMap.", "DEBUG")

    Map resultMap = [:]

	log("map = ${map}", "DEBUG")
    
    if (descMap.cluster.toLowerCase() == "0402" && descMap.attrId.toLowerCase() == "0000") {
        def value = getTemperature(descMap.value)
        resultMap = getTemperatureResult(value)
    } else if (descMap.cluster.toLowerCase() == "0001" && descMap.attrId.toLowerCase() == "0020") {
    	resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
    } else if (descMap.cluster.toLowerCase() == "0b02" && descMap.attrId.toLowerCase() == "0000") {
        log("Parsing cluster B02 data.", "DEBUG")
    } else if (descMap.cluster.toLowerCase() == "0b02" && descMap.attrId.toLowerCase() == "8101") {
        if(v1) {
        	log("In compatibility mode!", "DEBUG")
            if(descMap.encoding.trim() == "11") {
            	resultMap =  parseAlarmCode("17")
            } else if(descMap.encoding.trim() == "01") {
                resultMap = parseAlarmCode("1")
            }
    	}
    }

    return resultMap
}

private Map parseCustomMessage(String description) {
    Map resultMap = [:]
    
    if (description?.startsWith('temperature: ')) {
    	def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
    	resultMap = getTemperatureResult(value)
    }
    
    return resultMap
}

def getTemperature(value) {
    def celsius = Integer.parseInt(value, 16).shortValue() / 100
    
    log("${getVersionStatementString()}", "INFO")
    
    if(shouldReconfigure()) {
        	state.configured = false
            setStateVersion(getNewStateVersion())
            log("Initializing a reconfigure.", "INFO")
            log("Device being reconfigured.", "INFO")
            return response(configure())
    }
    
    if(getTemperatureScale() == "C") {
    	log("Temperature Reported: ${celsius}C.", "INFO")
    	return celsius
    } else {
    	log("Temperature Reported: ${celsiusToFahrenheit(celsius)}F.", "INFO")
    	return celsiusToFahrenheit(celsius) as Integer
    }
}

private Map getBatteryResult(rawValue) {
    log("Battery rawValue = ${rawValue}.", "DEBUG")
	
    def linkText = getLinkText(device)

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

	def volts = rawValue / 10

    if (rawValue == 0 || rawValue == 255) {
    	 //Nothing
    } else {
        if (volts > (getTopVolts() + 0.3)) {
            result.value = 100
            result.descriptionText = "${device.displayName} battery has too much power."
        } else {
            def minVolts = getBottomVolts()
            def maxVolts = getTopVolts()
            def pct = (volts - minVolts) / (maxVolts - minVolts)
	    result.value = (int)Math.round(pct * 100)
            result.descriptionText = "${device.displayName} battery was ${result.value}%."
        }
    }
    
    log("Battery Value Reported: ${result.value}%.", "INFO")
    log("${getVersionStatementString()}", "INFO")
    if(shouldReconfigure()) {
    	state.configured = false
        setStateVersion(getNewStateVersion())
        log("Initializing a reconfigure.", "INFO")
        log("Device being reconfigured.", "INFO")
        return response(configure())
    }

    return result
}

private Map getTemperatureResult(value) {
    log("Begin getTemperatureResult(${value}).", "DEBUG")
    
    if (tempOffset) {
        def offset = tempOffset as int
        def v = value as int
        value = v + offset
    }
    
    def descriptionText
    if ( temperatureScale == 'C' )
    	descriptionText = "${device.displayName} was ${value}°C"
    else
    	descriptionText = "${device.displayName} was ${value}°F"

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

private Map getMoistureResult(value) {
    log("Begin getMoistureResult(${value}).", "DEBUG")
    
    def descriptionText
    
    if ( value == "wet" )
    	descriptionText = "${device.displayName} is wet"
    else
    	descriptionText = "${device.displayName} is dry"
    
    return [
        name: 'water',
        value: value,
        descriptionText: descriptionText,
        translatable: true
    ]
}

private Map parseAlarmCode(value) {

	log("Parse alarm code ${value}.", "DEBUG")

    Map resultMap = [:]

    switch(value) {
        case "1":
            log("Sensor is dry.", "INFO")
            resultMap = getMoistureResult('dry')
            break

        case "17":
            log("Sensor is wet!", "INFO")
            resultMap = getMoistureResult('wet')
            break
	}

    return resultMap
}

def updateDeviceLastActivity(lastActivity) {
	def finalString = lastActivity?.format('MM/d/yyyy hh:mm a',location.timeZone)    
	sendEvent(name: "lastActivity", value: finalString, display: false , displayed: false)
}

def refresh() {
    log("Refreshing...", "INFO")
    
    log("${getVersionStatementString()}", "INFO")
    
    def retVal = zigbee.readAttribute(0x0402, 0x0000) +
    	zigbee.readAttribute(0x0001, 0x0020)
        
    return retVal
}

/* 0000
   0001 - Battery
   0003 - 
   0020
   0402 - Temp
   0B02 - Wet / Dry
   FC02
*/

def configure() {
    log("Configuring Reporting, IAS CIE, and Bindings.", "INFO")
    
    try {
            def retVal = 
            zigbee.configureReporting(0x0001, 0x0020, 0x20, 1440, 84600, 0x01) +
            zigbee.configureReporting(0x0402, 0x0000, 0x29, 1800, 14400, 0x0064) +
            zigbee.configureReporting(0x0b02, 0x0000, 0x00, 5, 14400, null) +
            zigbee.readAttribute(0x0402, 0x0000) +
            zigbee.readAttribute(0x0001, 0x0020)

            log("Ending configure(), returning retVal = ${retVal}.", "INFO")
            
            state.configured = true
            
			return retVal	
            
    } catch(e) {
            log("ERROR -- ${e}", "ERROR")
    } 
}

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

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
}

def isConfigured() {
	if (state.configured == null || state.configured == false) {
    	return false
	} else {
    	return true
    }
}

private isDuplicateCommand(lastExecuted, allowedMil) {
	!lastExecuted ? false : (lastExecuted + allowedMil > new Date().time)
}

def getTopVolts() {
	if(state.topVolts == null) {
    	state.topVolts = getDefaultTop()
    }
	
    return state.topVolts
}

def setTopVolts(volts) {
	state.topVolts = volts
}

def getBottomVolts() {
	if(state.bottomVolts == null) {
    	state.bottomVolts = getDefaultBottom()
    }

	return state.bottomVolts
}

def setBottomVolts(volts) {
	state.bottomVolts = volts
}

def getStateVersion() {
	if(state.version != null) {
		return state.version
    } else {
    	return 0
    }
}

def setStateVersion(val) {
	state.version = val
}

def getNewStateVersion() {
	return 7
}

def getVersionStatementString() {
	return "Current state version is ${getStateVersion()} and new state version is ${getNewStateVersion()}."
}

def shouldReconfigure() {
	if(getNewStateVersion() > getStateVersion()) {
    	return true
    } else {
    	return false
    }
}

def getDefaultTop() {
	return 4.5
}

def getDefaultBottom() {
	return 3.0
}

Did you ever get your Leaksmart sensors working? I have 3 of them and have only attempted to pair one. Using the community Leaksmart driver, I can pair it successfully, but when I test its operation (using the notifier app to send a notification when wet)- Im not getting anything. I tried switching to "generic zigbee moisture" driver and i get nothing as well. I've reset the sensor, rebooted the hub, and attempted another re-pairing and still no dice.

The LeakSmart sensors work with the built-in "generic zigbee moisture sensor" driver. They have to be paired very close to the HE and do not report (or work well) unless the zigbee mesh is strong.

1 Like

Thanks for your immediate reply. Does this mean I can delete the community driver altogether? I tried pairing it directly next to the hub and it paired as a Leaksmart. I will try again after deleting the community driver.

I have tried several times within 5 feet from the hub. I get a successful pairing each time, but automations don't seem to work. The sensor itself will beep when moisture is detected, but it will not serve as a trigger to any automations (Notifications app or HSM, etc). I have 2 more sensors that I haven't tried yet which I will check out tomorrow.

Factory reset the sensor before re-pairing it. Here's how you reset the sensor:

  1. Remove the battery door, install batteries, press and hold the black button for 15 seconds, then let go.
  2. Power cycle the sensor by removing and reinstalling a battery.

If the reset is successful, the sensor should chirp and the blue LEDwill flash 5 times every second.

I have had no luck with the LeakSmart sensor on HE using the generic Zigbee moisture sensor driver. I have 3 of them on ST working fine; however I can only been able to get them to function on HE using a modified version of the ST community driver-- they pair and report wet/dry/battery normally with the modified driver, but temperature reporting is seemingly random (-466, 78, 511, etc). When I use the same sensor with the generic Zigbee driver, temperature and battery reporting works but wet/dry sensing does not. I wonder if it is related to the firmware level of this sensor; mine were updated to 34 level (according to ST; it isn't reported on HE) when I sent them to LeakSmart a couple of years ago.

Unfortunately, I have tried the above steps (factory reset and power cycle) , paired the sensor to Hubitat (as a Generic Zigbee Moisture sensor) - then used it as a HSM trigger for water leak.. the sensor itself will detect moisture and will start beeping.. however the device "current states" will never show as having detected moisture and will not thereby trigger my HSM rule. The same goes for if I use the community Leaksmart driver. I have previously paired these to Wink 2 and have verified they have the latest firmware (updated via the Wink 2 hub). This has been attempted with fresh batteries and within a few feet from the hub.

How robust is your zigbee mesh? What repeaters are you using?

Aaiyar- thanks for staying with me thru this issue. I have 3 Tradfri zigbee repeaters purchased from IKEA, 1 of which is less than 3 feet from the Hub (plugged into the same power strip as the hub). I'm also pairing the Leaksmart sensor approx 3 feet from the hub and water testing it in the same location.

Aaiyar,

 Thank you for following up with me and making sure to provide the best support possible.   I was able to make it work properly using the community provided Leaksmart driver.   I have since moved all 3 of my sensors to Hubitat.   Appreciate you !   Happy holidays!

J

I have observed the same as above. With the Generic Zigbee Moisture Sensor driver I get accurate temperatures and battery level, but the leakSMART sensor never reports moisture correctly to the device page. If I switch to the community driver moisture sensing works every time, but temperatures (and sometimes battery level) are random. Using the temp offset doesn't work because the temp value is so random.

With the Generic driver I think it is actually reporting the moisture, but the driver is not processing correctly. In the text logs when you get it wet there are a number of repeated temperature reports much more frequent than the normal interval. I have pasted a debug log of this below. The sensor was wetted at 7:44 in the log.

Any ideas on how the temperature could be fixed in the community leakSMART driver or could the Generic Zigbee Moisture Sensor (@mike.maxwell) driver be updated to fix moisture sensing??

Thanks

dev:1142020-05-08 07:44:52.590 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:52.582 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:52.578 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:47.587 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:47.585 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:47.577 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:47.573 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:42.558 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:42.557 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:42.549 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:42.545 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:37.564 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:37.563 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:37.557 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:catchall: 0104 0B02 01 01 0040 00 518D 01 00 0000 01 01 01810100, profileId:0104, clusterId:0B02, clusterInt:2818, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:518D, isClusterSpecific:true, isManufacturerSpecific:false, manufacturerId:0000, command:01, direction:01, data:[01, 81, 01, 00]]

dev:1142020-05-08 07:44:37.556 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:37.555 pm debugparse: catchall: 0104 0B02 01 01 0040 00 518D 01 00 0000 01 01 01810100

dev:1142020-05-08 07:44:37.553 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:32.579 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:32.577 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:32.569 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:32.565 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:27.553 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:27.551 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:27.544 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:27.540 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:22.571 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:22.569 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:22.561 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:22.558 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:17.564 pm debugparseReportAttributeMessage: Temp resultMap: [name:temperature, value:53.19, descriptionText:Guest Bath Sensor temperature is 53.19°F, unit:°F]

dev:1142020-05-08 07:44:17.563 pm infoGuest Bath Sensor temperature is 53.19°F

dev:1142020-05-08 07:44:17.556 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0104020A0000299904, dni:518D, endpoint:01, cluster:0402, size:0A, attrId:0000, encoding:29, command:0A, value:0499, clusterInt:1026, attrInt:0]

dev:1142020-05-08 07:44:17.552 pm debugparse: read attr - raw: 518D0104020A0000299904, dni: 518D, endpoint: 01, cluster: 0402, size: 0A, attrId: 0000, encoding: 29, command: 0A, value: 9904

dev:1142020-05-08 07:44:17.550 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:catchall: 0104 0B02 01 01 0040 00 518D 01 00 0000 01 01 01811100, profileId:0104, clusterId:0B02, clusterInt:2818, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:518D, isClusterSpecific:true, isManufacturerSpecific:false, manufacturerId:0000, command:01, direction:01, data:[01, 81, 11, 00]]

dev:1142020-05-08 07:44:17.547 pm debugparse: catchall: 0104 0B02 01 01 0040 00 518D 01 00 0000 01 01 01811100

dev:1142020-05-08 07:43:57.523 pm infoGuest Bath Sensor battery is 100%

dev:1142020-05-08 07:43:57.520 pm debugzigbee.parseDescriptionAsMap-read attr: [raw:518D0100010A20002028, dni:518D, endpoint:01, cluster:0001, size:0A, attrId:0020, encoding:20, command:01, value:28, clusterInt:1, attrInt:32]

Possibly, would need a device in hand to try out.

I do have a (currently) unused spare. I could loan one out (or would you need it permanently?).

On loan is fine...