Smartthings Button Battery

Is this problem something new drivers could/will fix? :thinking:

Assuming that the battery information is not 100% reliable and that the duration also depends, among other factors, on the ambient temperature where the sensor is installed, colder = less duration.

With the driver edge tests, install, uninstall … several times, a battery that was at 60% has ended prematurely depleted, it measures 2.6v without load, but as soon as it has to transmit to hub it breaks down and the sensor turns off.

This problem remains the same with the edge drivers, since the default configuration is the same as the dth, minimum interval 30 sec, maximum 5 minutes and reportable change 0.1 °.

With the help of @nayelyz, I have implemented in the driver preference settings for report maximum interval between 5 and 240 minutes and reportable change between 0.1° and 6°.
It works very well, easier than with the DTH, since it is dynamic and instantaneous and there is no need to do the DTH version change maneuver after each value change.
I have it working on 3 multipurpose ST sensors (Batt CR2450)and 3 ST motion Sensors (Batt CR123A).

For the ST button, humidity sensor, and humidity and temperature sensor there is no edge drive yet.
I could do the drivers, but I don’t have those devices to do the tests.

I told to @nayelyz that she will transfer to smartthings the possibility of implementing the configuration of report settings in these devices in his edge drivers sock.

Everyone can choose which settings they need and save batteries. It is not a question of whether I can spend money for 6 batteries every 5 months, it is a question that there are hundreds of thousands of these sensors around the world and it is a waste that manufacturers should avoid.

For example I have a multipurpose sensor in a garage door, which on sunny days can have a dialy thermal amplitude of 15º and in summer much more.
What is the point of having a precision of 0.1º in this sensor? I have a configuration of 60 minutes maximum and 3º of temperature change and it sends between 20 and 30 daily events. With the default configuration it would send more than 150 temperature events.

Here I have some examples of 3 sensors with different battery models and their discharge curve with default and custom settings with the total number of events sent to hub.

2 Likes

Wow!! What a response, so thorough. Much appreciated. :pray:

But I agree with you completely. Users should have the last say when it comes to different variabilities. Everyone has their own and different need for their sensors.

1 Like

With DTH you have to follow the steps in the above post and publish a DTH for yourself in IDE. then follow the instructions to change the settings.

With edge driver, the driver would have to be done, but I don’t have an ST button at home to do the tests.

Do you want to try it?

If you some day want to make driver for Ikea buttons I’d be more than happy to try them.

Is it a single or multi-button ikea button?

Multi-component devices are still a bit raw.

But we can try, if you send me the model, manufacturer and number of buttons.

There have been a ton of complaints of the Ikea devices eating batteries. I don’t have any, but from my reading, it seems the issue goes far beyond simply modifying reporting times to extend battery life.

@Mariano_Colmenarejo Ikea has couple different remotes:

1 button - TRADFRI Shortcut button


SHORTCUT BUTTON FUNCTIONS
Single press. Activates the scene you link to this button through the IKEA Home smart app.

2 button - TRADFRI Wireless dimmer


ON - Dim UP
Press to turn your IKEA Home smart product on.
Press and hold to dim up.
OFF - Dim DOWN
Press to turn your IKEA Home smart product off.
Press and hold to dim down.

4 button - STYRBAR Remote Control


Short press to turn on.
To dim up, press and hold the button.
Short press to turn off.
To dim down, press and hold the button.
Change white spectrum or colours

5 button - TRADFRI Remote control


REMOTE CONTROL FUNCTIONS
ON/OFF: Press to turn your light source on and off. Press and hold for at least 3 seconds to synchronize your lights.
Dim up/down: Short presses will dim up/down in steps.
To dim up/down seamlessly, press and hold the button.
Change white spectrum, colours or scenes.

and

SYMFONISK Sound Remote


SOUND REMOTE FUNCTIONS
Play/Pause
Press once to start or stop the music
Press twice to skip to the next track
Press three times to jump back one song.
Volume up
Rotating the top right (clockwise) will increase volume up to max.
Volume down
Rotating the top left (counter-clockwise) will decrease volume to the lowest level, but NOT turn the music off.

They all have one thing in common, Battery drain

I’ll try to list all stock functions for each device

@Mariano_Colmenarejo currently i have only Dimmers in possession, but due battery drain issue they are all seating in a drawer, as usually battery drain within 24 hours.
Here is IDE device

Raw Description 01 0104 0820 01 07 0000 0001 0003 0009 0020 1000 FC7C 07 0003 0004 0006 0008 0019 0102 1000

Maybe others can add additional devices info
@Bry @Sakari

The ikea buttons battery drain is a different story!

The ST button has a temperature sensor, so I suggested that if he wanted to try to implement the temperature reports setting.

The ikea buttons thing is for trying different edge drives

Hello

Yes I have multiple custom DTH, if one exist for the button to avoid temp sensor, Im willing to try!

Also, not to feel rude but Sakari, maybe you can make a different thread for your ikea button?

thanks!

Thanks @milandjurovic71 for posting these. :blush:

What comes to battery drain I only have one remote that does it. Others have been working ok. Styrbar is latest dimmer and interesting because it uses AAA batteries. Rechargable batteries are quite cheap and easy to change. Also Styrbar costs only 8€ here where I live.

:thinking:

I found a custom dth online, and change the check interval, don’t know if it will help or not

/*

  • 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:
  •  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.
    */
    import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
    import physicalgraph.zigbee.zcl.DataType

metadata {
definition(name: “SmartSense Button Custom”, namespace: “smartthings”, author: “SmartThings”, runLocally: true, minHubCoreVersion: ‘000.022.0000’, executeCommandsLocally: false, mnmn: “SmartThings”, vid: “SmartThings-smartthings-SmartSense_Button”, ocfDeviceType: “x.com.st.d.remotecontroller”) {
capability “Configuration”
capability “Battery”
capability “Refresh”
capability “Temperature Measurement”
capability “Button”
capability “Holdable Button”
capability “Health Check”
capability “Sensor”

    fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "button", deviceJoinName: "Button"
}

simulator {
    status "button 1 pushed": "catchall: 0104 0500 01 01 0140 00 6C3F 00 00 0000 01 01 020000190100"
}

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 {
        input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false
    }
}

tiles(scale: 2) {
    multiAttributeTile(name: "button", type: "generic", width: 6, height: 4) {
        tileAttribute("device.button", key: "PRIMARY_CONTROL") {
            attributeState "pushed", label: "Pressed", icon:"st.Weather.weather14", backgroundColor:"#53a7c0"
            attributeState "double", label: "Pressed Twice", icon:"st.Weather.weather11", backgroundColor:"#53a7c0"
            attributeState "held", label: "Held", icon:"st.Weather.weather13", backgroundColor:"#53a7c0"
        }
    }
    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(["button", "temperature"])
    details(["button", "temperature", "battery", "refresh"])
}

}

def installed() {
sendEvent(name: “supportedButtonValues”, value: [“pushed”,“held”,“double”].encodeAsJSON(), displayed: false)
sendEvent(name: “numberOfButtons”, value: 1, displayed: false)
sendEvent(name: “button”, value: “pushed”, data: [buttonNumber: 1], displayed: false)
}

private List collectAttributes(Map descMap) {
List descMaps = new ArrayList()

descMaps.add(descMap)

if (descMap.additionalAttrs) {
    descMaps.addAll(descMap.additionalAttrs)
}

return  descMaps

}

def parse(String description) {
log.debug “description: $description”

// getEvent will handle temperature and humidity
Map map = zigbee.getEvent(description)
if (!map) {
    if (description?.startsWith('zone status')) {
        map = parseIasMessage(description)
    } else {
        Map descMap = zigbee.parseDescriptionAsMap(description)

        if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap.value) {
            List<Map> descMaps = collectAttributes(descMap)

            if (device.getDataValue("manufacturer") == "Samjin") {
                def battMap = descMaps.find { it.attrInt == 0x0021 }

                if (battMap) {
                    map = getBatteryPercentageResult(Integer.parseInt(battMap.value, 16))
                }
            } else {
                def battMap = descMaps.find { it.attrInt == 0x0020 }

                if (battMap) {
                    map = getBatteryResult(Integer.parseInt(battMap.value, 16))
                }
            }
        } else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002) {
            def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 16))
            map = translateZoneStatus(zs)
        } else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
            if (descMap.data[0] == "00") {
                log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
                sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
            } else {
                log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
            }
        } else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap?.value) {
            map = translateZoneStatus(new ZoneStatus(zigbee.convertToInt(descMap?.value)))
        }
    }
} else if (map.name == "temperature") {
    if (tempOffset) {
        map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP)
        map.unit = getTemperatureScale()
    }
    map.descriptionText = getTemperatureScale() == 'C' ? "${ device.displayName } was ${ map.value }°C" : "${ device.displayName } was ${ map.value }°F"
    map.translatable = true
}

log.debug "Parse returned $map"
def result = map ? createEvent(map) : [:]

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 Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)

translateZoneStatus(zs)

}

private Map translateZoneStatus(ZoneStatus zs) {
if (zs.isAlarm1Set() && zs.isAlarm2Set()) {
return getButtonResult(‘held’)
} else if (zs.isAlarm1Set()) {
return getButtonResult(‘pushed’)
} else if (zs.isAlarm2Set()) {
return getButtonResult(‘double’)
} else { }
}

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

def result = [:]

def volts = rawValue / 10

if (!(rawValue == 0 || rawValue == 255)) {
    result.name = '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 {
        def minVolts = 2.1
        def maxVolts = 3.0
        def pct = (volts - minVolts) / (maxVolts - minVolts)
        def roundedPct = Math.round(pct * 100)
        if (roundedPct <= 0)
            roundedPct = 1
        result.value = Math.min(100, roundedPct)
    }

}

return result

}

private Map getBatteryPercentageResult(rawValue) {
log.debug “Battery Percentage rawValue = ${rawValue} → ${rawValue / 2}%”
def result = [:]

if (0 <= rawValue && rawValue <= 200) {
    result.name = 'battery'
    result.translatable = true
    result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
    result.value = Math.round(rawValue / 2)
}

return result

}

private Map getButtonResult(value) {
def descriptionText
if (value == “pushed”)
descriptionText = “${ device.displayName } was pushed”
else if (value == “held”)
descriptionText = “${ device.displayName } was held”
else
descriptionText = “${ device.displayName } was pushed twice”
return [
name : ‘button’,
value : value,
descriptionText: descriptionText,
translatable : true,
isStateChange : true,
data : [buttonNumber: 1]
]
}

/**

  • PING is used by Device-Watch in attempt to reach the Device
  • */
    def ping() {
    zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS)
    }

def refresh() {
log.debug “Refreshing Values”
def refreshCmds =

if (device.getDataValue("manufacturer") == "Samjin") {
    refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021)
} else {
    refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
}
refreshCmds += zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
    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
// Sets up low battery threshold reporting
sendEvent(name: “DeviceWatch-Enroll”, displayed: false, value: [protocol: “zigbee”, hubHardwareId: device.hub.hardwareID, scheme: “TRACKED”, checkInterval: 2 * 60 * 60 + 1 * 60, lowBatteryThresholds: [15, 7, 3], offlinePingable: “1”].encodeAsJSON())

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

// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
if (device.getDataValue("manufacturer") == "Samjin") {
    configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 21600, 0x10)
} else {
    configCmds += zigbee.batteryConfig()
}
configCmds += zigbee.temperatureConfig(30, 300)

return refresh() + configCmds + refresh() // send refresh cmds as part of config

}

Sorry, I just assumed you knew the procedure.
In my first answer is the link to a post that explains how to do it and has at the end the link to the button code and four other devices.

Click on this post to open the whole conversation and access the link of the dth code in github and intructions.

1 Like

Sorry missed the thread, with all those replies haha

thanks a lot, just installed the dth and set the new parameters

will see if it help :slight_smile:
thanks a lot

1 Like

@Sakari, @milandjurovic71,

At the moment in this beta phase I do not see anything in the documentation that they have implemented something for the button capability or I cannot find it.
We will have to wait!

@Mariano_Colmenarejo I think that @iquix made edge driver for IKEA shortcut button. Maybe he can recommend how can be done

I’ve uploaded source code of some of my drivers.

Bunch of Zigbee dimmer switches has been added to the channel. I haven’t have any luck pairing my Ikea dimmer, which is listed as one of the fingerprints. Have anyone else tried this yet?

I’ve had a go at making a styrbar driver here Ikea Styrbar Remote