ST Multi-Sensor battery reporting issues

Is anyone else having issues with ST multi-sensors battery reading stuck at 100% since the last Hub updates when they change the battery reporting and/or the firmware update for the multi-sensors?

Background: I had a multi-sensor stop reporting open/close but stating it was 100%. I check my others and they were all still 100% and all have been in use for a while. The “dead” multi-sensor was still reporting temperature, just not open/close. The same symptoms as when they use to get to around 67% before the last update, just that the app and IDE stated it was 100%. I replaced the battery and the sensor started working (Open/Close). No load voltage on the battery removed was 2.528 volts. They all have current firmware (as I had OTA updates enabled). Support changed the DH on all of my multi-sensors from their side and the batteries did drop to the low 90’s after a day. The DH messed the temperature reporting up. The ones I had I have on my doors read over 400 degrees and the one in my freezer read almost -400 degrees. The temperature offsets did not work and the option to use on a garage door was broken in the setup. After another round of emails support determined all my multi-sensors were somehow defective. I changed the DH’s back to the stock and the temperatures began reporting correctly, but the voltages jumped back up to 100%. The multi-sensors are fine; the DH and/or battery calculation system and/or firmware is bad. That is where they sit, at 100% until they drop off the system reading correct temperatures. I will have to watch them closely since all my tools to throw a warning flag that the battery is getting low will no longer work since they are always 100% and Device Health has its own problems. I guess when I have some time next week, I will delete one from the system and all the associated automation and pair back to the hub to see if it gets fixed.

I’ve had multiple SmartSense leak sensors die at 100% since the last firmware update. If I bring them down near the hub, pull the battery, put it back in, an press the button they go back to 100% battery and work. Never had this issue until the last firmware update.

There are a couple other threads about it also:

I think what has likely happened is that with the newer firmware (which changes the battery curve some to, in theory, allow somewhate more correct battery reporting) the curve changed but the publlshed DTH in the cloud doesn’t have a different curve encoded for older centralite firmware and newer centralite firmware devices.

Relevant changes:

@rhoffer @vseven Can you confirm the model and firmware version of these devices. You should be able to see this information in the IDE.

CC @Zach_Varberg @tpmanley

@posborne, Thank you for looking at this.

My 6 are all CentraLite, Model 3321-S with Current and Target Firmware versions: 0x1F015310

I also have a Motion Detector, CerntaLite 3325-S, Firmware 0x1F015310 that is reporting 100%. The batteries have been in there since February 2017.

The leak detectors seem to be reporting battery fine, my CentraLite 3315-S, Firmware 0x10025100 is reporting 67%.

If there is anything else you need, let me know.

Edit: 412456 was the support ticket number

My multi sensors haven’t gone offline but they all show 100% battery even though some have been in for a year now. They are all SmartSense Multi Sensor, same as @rhoffer, model 3321-S also running 0x1F015310.

My one motion sensor also shows 100% battery and I put in a new battery about 5 or 6 months ago. It’s in my kitchen and gets almost constant activity so I know that can’t be right. It’s also the same one as above, model 3325-S running 0x1F015310.

Just a FYI if it helps my SmartSense Humidity/Temp Sensor, model 3310-S, also running firmware 0x1F075310, do not have this issue. They are all reporting different battery statuses including one in my refrigerator at 44% which is the lowest (and with the cold that makes sense).

Also not sure if this is related but I’ve been having issues with some of my leak sensors lately (about the last month). All are SmartSense Moisture Sensor M/N: STS-WTR-250, Model moisturev4, current and target firmware are both 0x00000019. The will be marked offline and but at 100% battery. Here is on doing it right now:


So I pull the cover, press the button, it starts a couple blue/green blinks, click the X in the app and hit refresh. Magically its back online and still shows 100% battery. It’s been in for at least 4 months now. This is the second one to do this and same thing on the other…100% battery. The other after doing this has stayed online so far (about a week) so IDK. Just hitting X and refresh doesn’t fix it…have to press the button inside.


I’ve replaced several batteries that were still reporting 100%. I knew they were nearly dead because they kept going online/offline several times a day, each time triggering a false event.

I just had another muilti drop from my system this morning. The battery was showing 100% but read 2.532 volts. I will be contacting support again tomorrow.

I have been trouble shooting since support was of no help. I have 3 test case DTHs reporting percentages, each differently. The least modified version has me scratcbing my head. Can anybody tell me it this line is correct.

def curValVolts = Integer.parseInt(device.currentState(“battery”)?.value ?: “100”) / 100.0

This is line 278 of the DTH for the Smartsense Multi Sensor. If I remove the ?: “100” to where it looks like this:

def curValVolts = Integer.parseInt(device.currentState(“battery”)?.value ) / 100.0

The Centralite sensor begins to report what looks to be correct values in the app instead of 100% all the time. I also played with the min and max voltage. Original max was 2.7 volts. Min voltage was 2.1. I changed this to 2.5 because i know at 2.5 volts the device no longer reports open/close.

I know they will all run in the cloud now, just trying to get a battery percentage to keep from having the device drop from the system without any warning.

If anyone could help explain if that original line is correct I would be greatful.

So this is still a issue here too but I’ve found some differences in exactly what devices have the issue. Example - I have 6 leak sensors. 5 are reporting 100% battery and one is reporting 78%. So I looked into it further:

5x manufacturer: SmartThings model: moisturev4 - All Show 100% (firmware 0x00000019)
1x manufacturer: CentraLite model: 3315-S - Shows 78% (firmware 0x10015100)

So same with the SmartSense Multi Sensor but the opposite of above:

5x manufacturer: CentraLite model: 3321-S - All Show 100% (firmware 0x1F015310)
1x manufacturer: SmartThings model: multiv4 - Shows 90% (firmware 0x00000019)

@posborne - You CC’d @Zach_Varberg and @tpmanley before. Has any progress been made on this to fix it? My motion sensor also is showing 100% and not changing and its been in for 8 months with daily use…I know its not 100%. Its listed as manufacturer: CentraLite model: 3325-S.

Should there be a different device type for the different manufactures? They are the “same” device but obviously they are not being treated as such.


In the DTH, there is a split when it comes to battery reporting for the Multi Sensors (IF SmartThings then X else Y). ST manuractured ones have one way of calculating and the CentraLites have another. I haven’t looked at the leak or motion detectors to see if they different methods of calculating/reporting for each manufacturer.

I started post in the developer device handler section to see if anyone of the pros could answer the question above about the parseInt format. No takers/replys yet.

So far the modified version is holding.

Update: My scheduled daily 10 am battery check correctly reported that 2 multis were below the old magic threshold of 68% battery.

Whats weird is the fact that I have “SmartThings” listed devices that only show 100% while the CentraLite ones show correct then for other devices it’s the opposite.

Either way the devs need to look at this and fix it in the DTH’s especially since their changes seemed to break things.

I looked at the moister sensor DTH. For the SmartSense Moisture Sensor DTH, the ST section is calculated the same as the ST in the multi. The Max Volt on it is 2.8 volts (100%)

For the CentraLite section they did not add in any of the curValVolts calculations/formulas. That is why it is working for the CentraLite moisture sensors. The max volt for these is set at 3.0 volts.

If the ST batteries in the moisture sensor are 2.8 or over then they are reported at 100%. That same battery, if it fit in a CentraLite would be less than 100 of the voltave was under 3.0 volts

1 Like

Any update to this issue? I’m having the same problem

No change as far as word/fix from support other than working on it emails. The five I have on a modified DTH are going fine. I have two @ 60% and One @ 80%. The other ones had recent battery changes, one 21 days and the other 5 days ago. They are both @ 100%. Temperature and all other sensor functions are reporting fine also. The sixth one in a freezer has the temp not working properly on the modified DTH. I haven’t sorted through the code to see if I can find out why. This one has been modified with external batteries because The tab broke off during a battery change. The temp is fine with the stock DTH, just not battery % other than 100%.

Yes I notified support about this and they confirmed it is an issue. Their suggestions was to change the battery 2-3 times a year.

Thats BS. I would reply and tell them thats not a answer and ask when it will be fixed. They made a change that broke it, they can figure out how to fix it.

Here is the modified DTH I am using on my CentraLite 3321-S sensors. Battery reporting seems to be working correctly. I added remarks to explain the changes made. It will not run locally, but it fixed the battery reporting for my 6 sensors. All other senor abilities are also working except for temperature for the one I have in a freezer.

The changes include addition of remarks and the follow:
1 - Name change to keep track of test version
2 - Changed minVolt from 2.1 to 2.5, as my sensors no longer report open/close when batteries get close to 2.5 volts.
3 - Changed maxVolt from 2.7 to 3 to get a more realistic battery percentage an to gain more steps in the battery reporting percentages.
4 - Changed defining line for curValVolt to correctly follow the parseInt(string, radix) by changing the “?:100” to “, 10” for the proper radix for decimal numeral


  • Copyright 2016 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:
  • 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.
    // Rhoffer - Edited version to original SmartSense Multi Senesor. See comments at lines 22, 279-281, 283-284, 286-287 for the remarks on the changes made

import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
import physicalgraph.zigbee.zcl.DataType

metadata {
//Rhoffer - Changed Name to reflect Test Version on Line 23
definition(name: “SmartSense Multi Sensor test3”, namespace: “smartthings”, author: “SmartThings”) {

	capability "Three Axis"
	capability "Battery"
	capability "Configuration"
	capability "Sensor"
	capability "Contact Sensor"
	capability "Acceleration Sensor"
	capability "Refresh"
	capability "Temperature Measurement"
	capability "Health Check"

	command "enrollResponse"
	fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
	fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
	fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor"
	fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor"

	attribute "status", "string"

simulator {
	status "open": "zone report :: type: 19 value: 0031"
	status "closed": "zone report :: type: 19 value: 0030"

	status "acceleration": "acceleration: 1"
	status "no acceleration": "acceleration: 0"

	for (int i = 10; i <= 50; i += 10) {
		status "temp ${i}C": "contactState: 0, accelerationState: 0, temp: $i C, battery: 100"

	// kinda hacky because it depends on how it is installed
	status "x,y,z: 0,0,0": "x: 0, y: 0, z: 0"
	status "x,y,z: 1000,0,0": "x: 1000, y: 0, z: 0"
	status "x,y,z: 0,1000,0": "x: 0, y: 1000, z: 0"
	status "x,y,z: 0,0,1000": "x: 0, y: 0, z: 1000"
preferences {
	section {
		image(name: 'educationalcontent', multiple: true, images: [
	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("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", description: "Tap to set", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false)

tiles(scale: 2) {
	multiAttributeTile(name: "status", type: "generic", width: 6, height: 4) {
		tileAttribute("device.status", key: "PRIMARY_CONTROL") {
			attributeState "open", label: 'Open', icon: "", backgroundColor: "#e86d13"
			attributeState "closed", label: 'Closed', icon: "", backgroundColor: "#00a0dc"
			attributeState "garage-open", label: 'Open', icon: "st.doors.garage.garage-open", backgroundColor: "#e86d13"
			attributeState "garage-closed", label: 'Closed', icon: "st.doors.garage.garage-closed", backgroundColor: "#00a0dc"
	standardTile("contact", "", width: 2, height: 2) {
		state("open", label: 'Open', icon: "", backgroundColor: "#e86d13")
		state("closed", label: 'Closed', icon: "", backgroundColor: "#00a0dc")
	standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
		state("active", label: 'Active', icon: "", backgroundColor: "#00a0dc")
		state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#cccccc")
	valueTile("temperature", "device.temperature", 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(["status", "acceleration", "temperature"])
	details(["status", "acceleration", "temperature", "battery", "refresh"])


def parse(String description) {
def maps = []
maps << zigbee.getEvent(description)
if (!maps[0]) {
maps = []
if (description?.startsWith(‘zone status’)) {
maps += parseIasMessage(description)
} else {
Map descMap = zigbee.parseDescriptionAsMap(description)
if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
maps << getBatteryResult(Integer.parseInt(descMap.value, 16))
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
if ([0] == “00”) {
sendEvent(name: “checkInterval”, value: 60 * 12, displayed: false, data: [protocol: “zigbee”, hubHardwareId: device.hub.hardwareID])
} else {
log.warn “TEMP REPORTING CONFIG FAILED- error code: ${[0]}”
} else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap?.value) {
maps += translateZoneStatus(new ZoneStatus(zigbee.convertToInt(descMap?.value)))
} else {
maps += handleAcceleration(descMap)
} else if (maps[0].name == “temperature”) {
def map = maps[0]
if (tempOffset) {
map.value = (int) map.value + (int) tempOffset
map.descriptionText = temperatureScale == ‘C’ ? ‘{{ device.displayName }} was {{ value }}°C’ : '{{ device.displayName }} was {{ value }}°F’
map.translatable = true

def result = maps.inject([]) {acc, it ->
	if (it) {
		acc << createEvent(it)
if (description?.startsWith('enroll request')) {
	List cmds = zigbee.enrollResponse()
	log.debug "enroll response: ${cmds}"
	result = cmds?.collect { new physicalgraph.device.HubAction(it) }
return result


private List handleAcceleration(descMap) {
def result = []
if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0010) {
def value = descMap.value == “01” ? “active” : "inactive"
log.debug "Acceleration $value"
result << [
name : “acceleration”,
value : value,
descriptionText: “{{ device.displayName }} was $value”,
isStateChange : isStateChange(device, “acceleration”, value),
translatable : true

	if (descMap.additionalAttrs) {
		result += parseAxis(descMap.additionalAttrs)
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
	def addAttrs = descMap.additionalAttrs ?: []
	addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
	result += parseAxis(addAttrs)
return result


private List parseAxis(List attrData) {
def results = []
def x = hexToSignedInt(attrData.find { it.attrInt == 0x0012 }?.value)
def y = hexToSignedInt(attrData.find { it.attrInt == 0x0013 }?.value)
def z = hexToSignedInt(attrData.find { it.attrInt == 0x0014 }?.value)

if ([x, y ,z].any { it == null }) {
	return []

def xyzResults = [:]
if (device.getDataValue("manufacturer") == "SmartThings") {
	// This mapping matches the current behavior of the Device Handler for the Centralite sensors
	xyzResults.x = z
	xyzResults.y = y
	xyzResults.z = -x
} else {
	// The axises reported by the Device Handler differ from the axises reported by the sensor
	// This may change in the future
	xyzResults.x = z
	xyzResults.y = x
	xyzResults.z = y

log.debug "parseAxis -- ${xyzResults}"

if (garageSensor == "Yes")
	results += garageEvent(xyzResults.z)

def value = "${xyzResults.x},${xyzResults.y},${xyzResults.z}"
results << [
		name           : "threeAxis",
		value          : value,
		linkText       : getLinkText(device),
		descriptionText: "${getLinkText(device)} was ${value}",
		handlerName    : name,
		isStateChange  : isStateChange(device, "threeAxis", value),
		displayed      : false


private List parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)



private List translateZoneStatus(ZoneStatus zs) {
List results = []

if (garageSensor != "Yes") {
	def value = zs.isAlarm1Set() ? 'open' : 'closed'
	log.debug "Contact: ${device.displayName} value = ${value}"
	def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
	results << [name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true]
	results << [name: 'status', value: value, descriptionText: descriptionText, translatable: true]

return results


private Map getBatteryResult(rawValue) {
log.debug “Battery rawValue = ${rawValue}”

def result = [:]

def volts = rawValue / 10

if (!(rawValue == 0 || rawValue == 255)) { = 'battery'
	result.translatable = true
	result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
	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]
		result.value = pct
	} else {
		// Rhoffer - Changed minVolts from 2.1 to 2.5 because my Multi sensors (3321-S Centralite) 
        // Rhoffer - would no longer report open/close around 2.5 but would still report temperature
        // Rhoffer - 2.5 volts = 0%
        def minVolts = 2.5
		// Rhoffer - Changed maxVolts from 2.7 to 3 because CR-2450 is a 3V battery. This gives a better
        // Rhoffer - scale of true percentage of batter.  3V =100%
        def maxVolts = 3.0
        // Rhoffer - Changed fomula to remove non-standard ?:"100" and replaced with 10, which is for decimal numeral system
        // Rhoffer - The original formula did not follow the parseInt(String, radix) standard where radix is an integer between 2 and 36
        // Get the current battery percentage as a multiplier 0 - 1
		def curValVolts = Integer.parseInt(device.currentState("battery")?.value, 10 ) / 100.0
		// Find the corresponding voltage from our range
		curValVolts = curValVolts * (maxVolts - minVolts) + minVolts
		// Round to the nearest 10th of a volt
		curValVolts = Math.round(10 * curValVolts) / 10.0
		// Only update the battery reading if we don't have a last reading,
		// OR we have received the same reading twice in a row
		// OR we don't currently have a battery reading
		// OR the value we just received is at least 2 steps off from the last reported value
		if(state?.lastVolts == null || state?.lastVolts == volts || device.currentState("battery")?.value == null || Math.abs(curValVolts - volts) > 0.1) {
			def pct = (volts - minVolts) / (maxVolts - minVolts)
			def roundedPct = Math.round(pct * 100)
			if (roundedPct <= 0)
				roundedPct = 1
			result.value = Math.min(100, roundedPct)
		} else {
			// Don't update as we want to smooth the battery values
			result = null
		state.lastVolts = volts

return result


List garageEvent(zValue) {
List results = []
def absValue = zValue.abs()
def contactValue = null
def garageValue = null
if (absValue > 900) {
contactValue = 'closed’
garageValue = ‘garage-closed’
} else if (absValue < 100) {
contactValue = 'open’
garageValue = ‘garage-open’
if (contactValue != null) {
def descriptionText = contactValue == ‘open’ ? ‘{{ device.displayName }} was opened’ : '{{ device.displayName }} was closed’
results << [name: ‘contact’, value: contactValue, descriptionText: descriptionText, displayed: false, translatable: true]
results << [name: ‘status’, value: garageValue, descriptionText: descriptionText, translatable: true]


  • PING is used by Device-Watch in attempt to reach the Device
  • */
    def ping() {
    return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level

def refresh() {
log.debug "Refreshing Values "

def refreshCmds = zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
		zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) +
		zigbee.readAttribute(0xFC02, 0x0010, [mfgCode: manufacturerCode]) +
		zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) + zigbee.enrollResponse()

return refreshCmds


def configure() {
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: “checkInterval”, value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: “zigbee”, hubHardwareId: device.hub.hardwareID])

log.debug "Configuring Reporting"
def configCmds = []

if (device.getDataValue("manufacturer") == "SmartThings") {
	log.debug "Refreshing Values for manufacturer: SmartThings "
	/* These values of Motion Threshold Multiplier(0x01) and Motion Threshold (0x0276)
        seem to be giving pretty accurate results for the XYZ co-ordinates for this manufacturer.
        Separating these out in a separate if-else because I do not want to touch Centralite part
        as of now.
	configCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x01, [mfgCode: manufacturerCode])
	configCmds += zigbee.writeAttribute(0xFC02, 0x0002, 0x21, 0x0276, [mfgCode: manufacturerCode])
} else {
	// Write a motion threshold of 2 * .063g = .126g
	// Currently due to a Centralite firmware issue, this will cause a read attribute response that
	// indicates acceleration even when there isn't.
	configCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x02, [mfgCode: manufacturerCode])

// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
configCmds += zigbee.batteryConfig() +
		zigbee.temperatureConfig(30, 300) +
		zigbee.configureReporting(0xFC02, 0x0010, DataType.BITMAP8, 10, 3600, 0x01, [mfgCode: manufacturerCode]) +
		zigbee.configureReporting(0xFC02, 0x0012, DataType.INT16, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
		zigbee.configureReporting(0xFC02, 0x0013, DataType.INT16, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
		zigbee.configureReporting(0xFC02, 0x0014, DataType.INT16, 1, 3600, 0x0001, [mfgCode: manufacturerCode])

return refresh() + configCmds


def updated() {
log.debug "updated called" "garage value : $garageSensor"
if (garageSensor == “Yes”) {
def descriptionText = "Updating device to garage sensor"
if (device.latestValue(“status”) == “open”) {
sendEvent(name: ‘status’, value: ‘garage-open’, descriptionText: descriptionText, translatable: true)
} else if (device.latestValue(“status”) == “closed”) {
sendEvent(name: ‘status’, value: ‘garage-closed’, descriptionText: descriptionText, translatable: true)
} else {
def descriptionText = "Updating device to open/close sensor"
if (device.latestValue(“status”) == “garage-open”) {
sendEvent(name: ‘status’, value: ‘open’, descriptionText: descriptionText, translatable: true)
} else if (device.latestValue(“status”) == “garage-closed”) {
sendEvent(name: ‘status’, value: ‘closed’, descriptionText: descriptionText, translatable: true)

private hexToSignedInt(hexVal) {
if (!hexVal) {
return null

def unsignedVal = hexToInt(hexVal)
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal


private getManufacturerCode() {
if (device.getDataValue(“manufacturer”) == “SmartThings”) {
return “0x110A”
} else {
return “0x104E”

private hexToInt(value) {
new BigInteger(value, 16)

You should put in a Pull Request against the DTh in the smartthings repo. Maybe they can just use your changes or at the very least use it as a base for modifying theirs.

Still not sure why they would change something in firmware and not change the DTH to match. This seems like a wide spread issue…maybe most people arn’t noticing.

I will give it a try. I guess it is time to learn a little more on the Github side of things!

I’ve put in 25+ PRs on their repo, majority got committed. If you don’t have a GitHub account create one. Then go to and navigate to devicetypes -> smartthings and find the device. Click the sub directory, click the groovy file, click the Edit button. Make your changes, give a good description of why (I would also link back to this thread), and hit Propose File Change. On the next screen click Create Pull Request and submit it.

You can also open a new issue by starting at the root of the repo (link above) then clicking Issues and New Issue and listing what the problem seems to be and link your PR on how you think it should be fixed and ask for a review.