Quirky Tripper Support?

I am tempted to try this code with the Securifi open/close sensor, which I have a couple laying around…Since both are zigbee I am hoping it will work out of the box, any reason why it wouldn’t?

It probably will work. You’d probably need to adjust the fingerprint info if you wanted it to automatically assign the device type. Battery min/max voltages might need tweaking.

Just picked some of these up today. thanks for the device type Mitch!

Having issue using new file to create smart app.

getting error

No signature of method: script14425138631181232252095.metadata() is applicable for argument types: (script14425138631181232252095$_run_closure1) values: [script14425138631181232252095$_run_closure1@4e1bda7b] Possible solutions: getMetadata(), getState(), setState(java.lang.Object), metaClass(groovy.lang.Closure)

Are you trying to install this as a device type or a smart app?

Sounds like you may have published a device type as a smartapp instead. See if this clears up any confusion:

hi, How to keep hub in join mode. i am trying to pair to v2 hub. i am new to smart things. i am was able to pair GE link bulbs with out any issue. i am having issue with tripper.

i copied the code and published it. and tried to pair. it is not doing anything.

If you start the Connect a New Device procedure through the app then take the battery out of the Tripper, hold the little black button on the Tripper, put the battery back in and release the button the Tripper should try to pair with the hub.

I tried that. no luck,

i don’t knoew if i did right.

Copied Code click on create
Click on Publish selected for me.

after that i rest the tripper as you send above and tried to connect. it is not connecting still

@anwesh, sounds like you may need to perform a general exclude on the device first since it won’t join to your hub, or did it join already and you see it in your device list and it’s not updating?

I did some progress now.

After Publish the code

I went into My Devices and Added the Device Manually and then connected device from app. it found the thing. but i am not getting any triggers now. i app it shows as open.

After Publish, i can get add the device manually by going to my device and them connect by app. is this right way?

Ok, that’s progress! Try opening/closing the contact sensor, as well as open the device to see the battery and cause a tamper alert. That may “wake up” the device and start communicating it status.

I need to understand 1 thing. You manually created the device in the IDE? You should only need to connect a new device from the app, and it should search and come back and say Found and then Identifying, or something to that effect.

Step i Did

1 - Added Code in My Device Types, clicked on create, clicked on save. After that i click on publish. it gave drop down for me. I clicked on it and Publish.
2. After publish i went in to the Android app and i clicked on connect new devices. it is say im looking for your new things and it is at that windows. after about 20 min i clicked on my devices from the web
3 there i click create new device. please find screen below.

in below screen name i gave as tripper
device network id as trip01
type quirky/wink tripper
version publish and my hub details for location and hub.

After then i tried to search the device from mobile app and it connected.

when i click on Tripper it say open. no activity is triggering.

Yeah you shouldn’t create the device in ide. Steps 1 and 2 are right but 3 may be screwing you up.

  1. I would remove all the devices you manually added, not the device type…keep that…that should be right.
    Check the app and Ide under My Devices to make sure you removed them all.

  2. Start the Connect Now (spinning circle).

  3. (On the Tripper) Take the battery out, press the button, put the battery back in, let go of the button. This should reset the Tripper and set it to pairing mode to look for the hub. I think it will start to blink a few times but won’t blink the whole time, it’s still trying to pair though.
    This device is Zigbee so there is no exclude, just a reset.
    It sounds like you have already done all of this but it never finds it. Can you move the Tripper closer to the hub? It may be too far from the hub, start with the closest device if possible then move out from there.
    I’m sure you have the right device type but I can send you mine if you want just to rule that out.

Do you have any other Zigbee devices connected to the hub now?

1 Like

Yeah, don’t do that.

Do this:

  1. Delete every device you created that way.
  2. Look at the device’s documentation on how to reset it, and redo the Connect New Device process from your SmartThings app.
  3. I recommend being as close to the hub as possible when trying to connect.
  4. Repeat as needed until the device connects. Since you have created your own custom device type, it should find it as the right type.
  5. If it’s found as a “Thing”, then go into the IDE and change Type to your device type. Based on the list you show above, you only have 1 custom device type to pick from.

I have a couple of these and they work very well.

1 Like

Great minds think alike :smile:

Also you can try to open the IDE and open the Live Logging tab to see if you see any problems there when it’s trying to pair.

1 Like

This is the device type i am using

Hope this is right one.

I was able to connect GE Link Bulbs with out any issues

Ok mine looks a little different and it could be that mine is older, I’m not sure but it works.

Here is mine and may be worth trying to overwrite yours, Save and Publish for Me. Then try to re-pair.

 *  Quirky Wink Tripper Contact Sensor
 *  Copyright 2015 Mitch Pond, 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.

metadata {
    definition (name: "Quirky/Wink Tripper", namespace: "mitchpond", author: "Mitch Pond") {
    capability "Contact Sensor"
    capability "Battery"
    capability "Configuration"
    attribute "tamper", "string"
    command "configure"
    command "resetTamper"
    fingerprint endpointId: "01", profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0020,0B05", outClusters: "0003,0019"

    // simulator metadata
    simulator {}

    // UI tile definitions
    tiles {
        standardTile("contact", "device.contact", width: 2, height: 2) {
            state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
            state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
        valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
            state "battery", label:'${currentValue}% battery', unit:""
        standardTile("tamper", "device.tamper", canChangeIcon: true, canChangeBackground: true) {
            state "OK", label: "Tamper OK", icon: "st.security.alarm.on", backgroundColor:"#79b821"
            state "tampered", label: "Tampered", action: "resetTamper", icon: "st.security.alarm.off", backgroundColor:"#ffa81e", nextState: "OK"
        main ("contact")

// Parse incoming device messages to generate events
def parse(String description) {
    //log.debug "description: $description"

    def results = []
    if (description?.startsWith('catchall:')) {
        results = parseCatchAllMessage(description)
    else if (description?.startsWith('read attr -')) {
        results = parseReportAttributeMessage(description)
    else if (description?.startsWith('zone status')) {
        results = parseIasMessage(description)

    log.debug "Parse returned $results"

    if (description?.startsWith('enroll request')) {
        List cmds = enrollResponse()
        log.debug "enroll response: ${cmds}"
        results = cmds?.collect { new physicalgraph.device.HubAction(it) }
    return results

def configure() {
    String zigbeeId = swapEndianHex(device.hub.zigbeeId)
    log.debug "Confuguring Reporting, IAS CIE, and Bindings."
    def cmd = [
        "zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
        "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
        "zcl global send-me-a-report 0x500 0x0012 0x19 0 0xFF {}", "delay 200", //get notified on tamper
        "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
        "zcl global send-me-a-report 1 0x20 0x20 5 3600 {}", "delay 200", //battery report request
        "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
        "zdo bind 0x${device.deviceNetworkId} 1 1 0x500 {${device.zigbeeId}} {}", "delay 500",
        "zdo bind 0x${device.deviceNetworkId} 1 1 0x0b05 {${device.zigbeeId}} {}", "delay 500",
        "zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 500",
        "st rattr 0x${device.deviceNetworkId} 1 1 0x20"

def enrollResponse() {
    log.debug "Sending enroll response"
    "raw 0x500 {01 23 00 00 00}", "delay 200",
    "send 0x${device.deviceNetworkId} 1 1"

private Map parseCatchAllMessage(String description) {
     def results = [:]
     def cluster = zigbee.parse(description)
     if (shouldProcessMessage(cluster)) {
        switch(cluster.clusterId) {
            case 0x0001:
                log.debug "Received a catchall message for battery status. This should not happen."
                results << createEvent(getBatteryResult(cluster.data.last()))

    return results

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

    def results = []
    if (descMap.cluster == "0001" && descMap.attrId == "0020") {
        log.debug "Received battery level report"
        results = createEvent(getBatteryResult(Integer.parseInt(descMap.value, 16)))

    return results

private parseIasMessage(String description) {
    List parsedMsg = description.split(' ')
    String msgCode = parsedMsg[2]
    int status = Integer.decode(msgCode)
    def linkText = getLinkText(device)

    def results = []
    if (status & 0b00000001) {results << createEvent(getContactResult('open'))}
    else if (~status & 0b00000001) results << createEvent(getContactResult('closed'))

    if (status & 0b00000100) {
            //log.debug "Tampered"
            results << createEvent([name: "tamper", value:"tampered"])
    else if (~status & 0b00000100) {
        //don't reset the status here as we want to force a manual reset
        //log.debug "Not tampered"
        //results = createEvent([name: "tamper", value:"OK"])
    if (status & 0b00001000) {
        //battery reporting seems unreliable with these devices. However, they do report when low.
        //Just in case the battery level reporting has stopped working, we'll at least catch the low battery warning.
        log.debug "${linkText} reports low battery!"
//        results << createEvent([name: "battery", value: 10])
    else if (~status & 0b00001000) {
        //log.debug "${linkText} battery OK"
    //log.debug results
    return results

private getBatteryResult(rawValue) {
    //log.debug 'Battery'
    def linkText = getLinkText(device)

    def result = [
        name: 'battery'

    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 = Math.min(100, (int) pct * 100)
        result.descriptionText = "${linkText} battery was ${result.value}%"

    return result

private Map getContactResult(value) {
    def linkText = getLinkText(device)
    def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
    return [
        name: 'contact',
        value: value,
        descriptionText: descriptionText

private resetTamper(){
    log.debug "Tamper alarm reset."
    sendEvent([name: "tamper", value:"OK"])

private hex(value) {
    new BigInteger(Math.round(value).toString()).toString(16)

private String swapEndianHex(String hex) {

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;
    return array

Thank you very much. you code is working. you rock my day

1 Like