[Release] Z-Wave.me, Popp, & Devolo Wireless wall Controller & Key Fob (EU), with button controller dimming apps and CoRE integration

dth_wallswitch
dth_remotes
dth_lighting

(Adam V) #21

Thank you @Fuzzyligic!! it works!

Release: V1.4 See all details on first post

both Device Handler & Smartapp need to be updated for new features


(Stuart Buchanan) #22

cool glad it works. Just noticed you credited me in first post cheers


(Adam V) #23

no worries - I’ve just credited you now in the Device Handler as well


(Miles Frankland) #24

Hi,
I suppose the device handler I have cobbled together might go better on here.
I have a Z-Wave.Me secure keyfob Pert Number: ZME-KFOB-S
I have almost just done what you have just done with the help of @Fuzzyligic.
I used the config from his device handler as yours was knocking off the 4th button on my keyfob for some reason.
I then used the body from your device handler, modified the scene numbers, added some more scenes (Click then hold).
The click and hold function wont work until a smartapp will recognise it though.
This all seems to work.
Anyway here is the code, you may be able to add it to yours, or if not add it as an extra.

`
/**
* Copyright 2016 milesfrankland
* Originals from AdamV and Fuzzyligic
*
* 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.
*
* TODO:
* Get Double Click working
* Create Smartapp to handle dim events
*
*/

metadata {
    definition (name: "Secure Z-Wave.me Keyfob ZME-KFOB-S", author: "milesfrankland") {
        capability "Actuator"
        capability "Button"
        capability "Battery"
        capability "Configuration" 
        capability "Refresh"


        fingerprint deviceId: "0x1801", inClusters: "0x5E, 0x70, 0x85, 0x2D, 0x8E, 0x80, 0x84, 0x8F, 0x5A, 0x59, 0x5B, 0x73, 0x86, 0x72, 0xEF, 0x20, 0x5B, 0x26, 0x27, 0x2B, 0x60"

   }

    simulator {
        status "button 1 pushed":  "command: 9881, payload: 00 5B 03 DE 00 01"

        // need to redo simulator commands

    }
    tiles {
        standardTile("button", "device.button", width: 2, height: 2) {
            state "default", label: "", icon: "st.Home.home30", backgroundColor: "#ffffff"
            state "held", label: "holding", icon: "st.Home.home30", backgroundColor: "#C390D4"
        }
         valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
            tileAttribute ("device.battery", key: "PRIMARY_CONTROL"){
                        state "battery", label:'${currentValue}% battery', unit:""
            }
        }
        standardTile("configure", "device.button", width: 1, height: 1, decoration: "flat") {
            state "default", label: "configure", backgroundColor: "#ffffff", action: "configure"
        }

        main "button"
        details(["button", "battery", "configure"])
    }

}

def parse(String description) {
    def results = []
    log.debug("RAW command: $description")
    if (description.startsWith("Err")) {
        log.debug("An error has occurred")
        } 
    else {

        def cmd = zwave.parse(description.replace("98C1", "9881"), [0x98: 1, 0x20: 1, 0x84: 1, 0x80: 1, 0x60: 3, 0x2B: 1, 0x26: 1])
    //    log.debug "Parsed Command: $cmd"
        if (cmd) {
        results = zwaveEvent(cmd)

        }

    }

/* 
// OLD logic for default configuration:
    def BUTTON_IDs = [ 1, 2, 5, 6 ]

// Split string by comma xter, will return an array.
    String [] sections = description.split( "," )
//    log.debug("sections: $sections")
// Remove all whitespace from beginning and end of each section string.
    for (def i = 0; i < sections.length; i++) {
        sections[ i ] = sections[ i ].trim()
    }
//    log.debug("Trimmed sections: $sections")
// Fetch the command and payload strings from the sections array.
    String command = sections[ 1 ]
    String payload = sections[ 2 ]
//    log.debug( "Command: $command" )
//    log.debug( "Payload: $payload" )
// Get the command ID and payload ID from these strings.
    String commandID = command[-4..-1]
    String payloadID = payload[-2..-1]
//    log.debug( "CommandID: $commandID" )
//    log.debug( "PayloadID: $payloadID" )
// Coerce the payloadID to a Number from a string (using base 10 as radix)
    Integer payloadIDint = payloadID.toInteger()
//    log.debug(payloadIDint)
*/
/*
// Determine which button was pressed.
    if ( commandID == "9881" && payloadIDint == BUTTON_IDs[ 0 ]) {
            Integer button = 1
            results = createEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
    else if  ( commandID == "9881" && payloadIDint == BUTTON_IDs[ 1 ]) {
            Integer button = 2
            results = createEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
        else if  ( commandID == "9881" && payloadIDint == BUTTON_IDs[ 2 ]) {
            Integer button = 3
            results = createEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
        else if  ( commandID == "9881" && payloadIDint == BUTTON_IDs[ 3 ]) {
            Integer button = 4
            results = createEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
        else if  ( commandID == "98C1" && payloadIDint == BUTTON_IDs[ 0 ]) {
            Integer button = 1
            results = createEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was held", isStateChange: true)
            log.debug( "Button $button was held" )
            }
        else if  ( commandID == "98C1" && payloadIDint == BUTTON_IDs[ 1 ]) {
            Integer button = 2
            results = createEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was held" )
            }
        else if  ( commandID == "98C1" && payloadIDint == BUTTON_IDs[ 2 ]) {
            Integer button = 4
            results = createEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was held" ) 
            }
        else if  ( commandID == "98C1" && payloadIDint == BUTTON_IDs[ 3 ]) {
            Integer button = 4
            results = createEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was held" )
            }    
        else {
            log.debug( "Commands and Button ID combinations unaccounted for happened" )
            }

       return results
//        return commandID
 */   

    }


def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
        def encapsulatedCommand = cmd.encapsulatedCommand([0x98: 1, 0x20: 1])

        // can specify command class versions here like in zwave.parse
        if (encapsulatedCommand) {
                log.debug(encapsulatedCommand)
                return zwaveEvent(encapsulatedCommand)
        }
}

def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
        log.debug( "keyAttributes: $cmd.keyAttributes")
        log.debug( "sceneNumber: $cmd.sceneNumber")
        log.debug( "sequenceNumber: $cmd.sequenceNumber")
      //     log.debug( "payload: $cmd.payload")
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
    [ createEvent(descriptionText: "${device.displayName} woke up"),
      response(zwave.wakeUpV1.wakeUpNoMoreInformation()) ]
}

def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelGet cmd) {
    log.debug "Multilevel get: $cmd"
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) {
    log.debug "Multilevel report: $cmd"
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
        def map = [ name: "battery", unit: "%" ]
        if (cmd.batteryLevel == 0xFF) {  // Special value for low battery alert
                map.value = 1
                map.descriptionText = "${device.displayName} has a low battery"
                map.isStateChange = true
        } else {
                map.value = cmd.batteryLevel
                log.debug ("Battery: $cmd.batteryLevel")
        }
        // Store time of last battery update so we don't ask every wakeup, see WakeUpNotification handler
        state.lastbatt = new Date().time
        createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd){
        log.debug "basic event: $cmd.value"
}


def zwaveEvent(physicalgraph.zwave.commands.sceneactivationv1.SceneActivationSet cmd) {
    //log.debug( "Dimming Duration: $cmd.dimmingDuration")
    //log.debug( "Button code: $cmd.sceneId")


    if ( cmd.sceneId == 11 ) {
            Integer button = 1
            sendEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
    else if  ( cmd.sceneId == 12 ) {
            Integer button = 1
            sendEvent(name: "button", value: "doubleclick", data: [buttonNumber: button], descriptionText: "$device.displayName Button $button was Double Clicked", isStateChange: true)
            log.debug( "Button $button was Double Clicked" )
            }
    else if  ( cmd.sceneId == 13 ) {
            Integer button = 1
            sendEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "Button $button is closed", isStateChange: true)
            log.debug( "Button $button Hold start - held" )
            }
    else if  ( cmd.sceneId == 15 ) {
            Integer button = 1
            sendEvent(name: "button", value: "holdRelease", data: [buttonNumber: button], descriptionText: "Button $button is open")
            log.debug( "Button $button Hold stop" )
            }
    else if  ( cmd.sceneId == 14 ) {
            Integer button = 1
            sendEvent(name: "button", value: "clickheld", data: [buttonNumber: button], descriptionText: "Button $button is click-closed")
            log.debug( "Button $button Click-Hold start - held" )
            }
    else if  ( cmd.sceneId == 16 ) {
            Integer button = 1
            sendEvent(name: "button", value: "clickholdRelease", data: [buttonNumber: button], descriptionText: "Button $button is click-open")
            log.debug( "Button $button Click-Hold stop" )
            }
    else if  ( cmd.sceneId == 21 ) {
            Integer button = 2
            sendEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
    else if  ( cmd.sceneId == 22 ) {
            Integer button = 2
            sendEvent(name: "button", value: "doubleclick", data: [buttonNumber: button], descriptionText: "$device.displayName Button $button was Double Clicked", isStateChange: true)
            log.debug( "Button $button was Double Clicked" )
            }
    else if  ( cmd.sceneId == 23 ) {
            Integer button = 2
            sendEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "Button $button is closed")
            log.debug( "Button $button Hold start - held" )
            }
    else if  ( cmd.sceneId == 25 ) {
            Integer button = 2
            sendEvent(name: "button", value: "holdRelease", data: [buttonNumber: button], descriptionText: "Button $button is open")
            log.debug( "Button $button Hold stop" )
            }
    else if  ( cmd.sceneId == 24 ) {
            Integer button = 2
            sendEvent(name: "button", value: "clickheld", data: [buttonNumber: button], descriptionText: "Button $button is click-closed")
            log.debug( "Button $button Click-Hold start - held" )
            }
    else if  ( cmd.sceneId == 26 ) {
            Integer button = 2
            sendEvent(name: "button", value: "clickholdRelease", data: [buttonNumber: button], descriptionText: "Button $button is click-open")
            log.debug( "Button $button Click-Hold stop" )
            }
    else if  ( cmd.sceneId == 31 ) {
            Integer button = 3
            sendEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
    else if  ( cmd.sceneId == 32 ) {
            Integer button = 3
            sendEvent(name: "button", value: "doubleclick", data: [buttonNumber: button], descriptionText: "$device.displayName Button $button was Double Clicked", isStateChange: true)
            log.debug( "Button $button was Double Clicked" )
            }
    else if  ( cmd.sceneId == 33 ) {
            Integer button = 3
            sendEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "Button $button is closed")
            log.debug( "Button $button Hold start - held" )
            }
    else if  ( cmd.sceneId == 35 ) {
            Integer button = 3
            sendEvent(name: "button", value: "holdRelease", data: [buttonNumber: button], descriptionText: "Button $button is open")
            log.debug( "Button $button Hold stop" )
            }
    else if  ( cmd.sceneId == 34 ) {
            Integer button = 3
            sendEvent(name: "button", value: "clickheld", data: [buttonNumber: button], descriptionText: "Button $button is click-closed")
            log.debug( "Button $button Click-Hold start - held" )
            }
    else if  ( cmd.sceneId == 36 ) {
            Integer button = 3
            sendEvent(name: "button", value: "clickholdRelease", data: [buttonNumber: button], descriptionText: "Button $button is click-open")
            log.debug( "Button $button Click-Hold stop" )
            }
    else if ( cmd.sceneId == 41 ) {
            Integer button = 4
            sendEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
            log.debug( "Button $button was pushed" )
            }
    else if  ( cmd.sceneId == 42 ) {
            Integer button = 4
            sendEvent(name: "button", value: "doubleclick", data: [buttonNumber: button], descriptionText: "$device.displayName Button $button was Double Clicked", isStateChange: true)
            log.debug( "Button $button was Double Clicked" )
            }
    else if  ( cmd.sceneId == 43 ) {
            Integer button = 4
            sendEvent(name: "button", value: "held", data: [buttonNumber: button], descriptionText: "Button $button is closed")
            log.debug( "Button $button Hold start - held" )
            }
    else if  ( cmd.sceneId == 45 ) {
            Integer button = 4
            sendEvent(name: "button", value: "holdRelease", data: [buttonNumber: button], descriptionText: "Button $button is open")
            log.debug( "Button $button Hold stop" )
            }
    else if  ( cmd.sceneId == 44 ) {
            Integer button = 4
            sendEvent(name: "button", value: "clickheld", data: [buttonNumber: button], descriptionText: "Button $button is click-closed")
            log.debug( "Button $button Click-Hold start - held" )
            }
    else if  ( cmd.sceneId == 46 ) {
            Integer button = 4
            sendEvent(name: "button", value: "clickholdRelease", data: [buttonNumber: button], descriptionText: "Button $button is click-open")
            log.debug( "Button $button Click-Hold stop" )
            }
    else {
            log.debug( "Commands and Button ID combinations unaccounted for happened" )
            }
}


/*
def zwaveEvent(physicalgraph.zwave.Command cmd) {
    [ descriptionText: "$device.displayName: $cmd", linkText:device.displayName, displayed: false ]
    log.debug "command event: $cmd"
}
*/



  def configure() {
    def commands = [ ]

// Correct configure for dim events:

    for (def i = 11; i <= 12; i++) {
        commands << zwave.associationV1.associationSet(groupingIdentifier: 2, nodeId: zwaveHubNodeId).format()
   //     commands << zwave.sceneControllerConfV1.sceneControllerConfSet(groupId: 4, sceneId:i).format()
       commands << zwave.configurationV1.configurationSet(parameterNumber:i, size: 1, scaledConfigurationValue:4).format()
    }
        for (def i = 13; i <= 14; i++) {
        commands << zwave.associationV1.associationSet(groupingIdentifier: 3, nodeId: zwaveHubNodeId).format()
    //    commands << zwave.sceneControllerConfV1.sceneControllerConfSet(groupId: 5, sceneId:i).format()
       commands << zwave.configurationV1.configurationSet(parameterNumber:i, size: 1, scaledConfigurationValue:4).format()
    }

/*
    // Correct configure for default hold trigger:
    for (def i = 11; i <= 14; i++) {
    //      commands << zwave.associationV1.associationSet(groupingIdentifier: 2, nodeId: zwaveHubNodeId).format()
    //    commands << zwave.sceneControllerConfV1.sceneControllerConfSet(groupId:i, sceneId:i).format()
       commands << zwave.configurationV1.configurationSet(parameterNumber:i, size:1, scaledConfigurationValue:8).format()
    }
*/

    log.debug("Sending configuration")


    delayBetween(commands, 1250)
}

`


(Adam V) #25

@milesfrankland Thanks for this - I’ll check it out tonight.

TBH I have the same Key fob as you - and didn’t have any issues with the last two buttons - I’m definitely interested in this click hold business though… I don’t even know the controllers had another input method. Could you please explain the exact interaction here?


(Miles Frankland) #26

Hi,
What do you mean by the exact interaction?
On my keyfob it comes up with a different sceneID for all these click modes:
Single
Double
Hold
Click Hold


(Adam V) #27

I’ve ever come across click hold… what is it? as in you click, release and the click hold again for longer and its treated differently?


(Miles Frankland) #28

Yes exactly. Click once then click again and hold in quick succession. the remote recognises this as a different action.


(Adam V) #29

Thanks @milesfrankland - I checked out the action and it works! - I’ve updated the device handler code to take account of the extra actions - and updated the smartapp to let you take advantage of them with actions.

I do have one question for you - I tested my device type on the two types of wall controllers and my Key fob and all actions worked - but I can see from you and Stuart’s conversation that there is some other kind of Key fob that I clearly don’t have that seems to have an issue with some of the configuration - do you know what the difference is?


(Adam V) #30

**

Release: V1.5 See all details on first post

**
both Device Handler & Smartapp need to be updated for new features


(Stuart Buchanan) #31

AdamV, the only difference between them i believe is that the first once i had buttons 1 - 4 were assigned to Association Group 2 - 5 respectively, and association group 1 was only for messages such as the Battery report etc… which i didnt realise in the original device type i made. however on the newer fob i have button 1 - 4 are assigned to association group 1 - 4 respectively and Association group 5 is not used.

My newer device type just attempts to associate with groups 1 - 5 which works with both fobs. obvoiusly i wasnt aware of the click hold functionality which @milesfrankland discovered, but its pretty awesome that you can potentially have 16 actions assigned to a single switch. now only if i could think of 16 actions :slight_smile: most of my stuff is automated anyway so you don’t need to press buttons and switches, the only exception was the 3 locks i have, but thats only 3 actions out of 16 :slight_smile:


(Adam V) #32

I have to agree - 16 actions per controller is pretty awesome!

Now if only someone could find a good workaround for this 1s action firing whilst held (with no race conditions!) issue and these controllers are perfect


(Andrew Cole) #33

More than likely just me being stupid but im really struggling to get this to wor with a Zwave me wallc-s controller.

Ive tried to connect it by pressing down the 4 buttons then pushing one to enter inclusion mode. Smartthings then connects and adds it, i then change the device type to the custom one which seems to change ok.

I then cant get the “configure button” to work. Im assuming this is the configure button in the device bit of the smartthings app? When i push it nothing happens at all. Ive tried going back into inclusion mode again by pushing the 4 buttons together and pressing 1 but it still doesnt do anything?

Any help much appreciated


(Adam V) #34

@Andygosport Ye this bit is a bit fiddley - not much I can do because the device is a bit rubbish in this respect. Here is what you need to know:

  • You were on the right track re-entering inclusion mode to hit the configure button. The issue is that sometimes the device exits inclusion mode before the config command gets to it.
  • The only way around this is to press button 1 to enter inclusion mode and at the exact same time frantically start tapping away at the config button in the app. I know this sounds silly - but it’s what I have to do every time!
  • You’ll know when it works because the LED will start flashing crazy for about 20 seconds.

(Miles Frankland) #35

I use quite a few routines but only having the option to assign a routine to the click function I’ve quickly used all my routine slots.
Might be a good option to have routines be able to be fired when double clicked too.
Thanks


(Adam V) #36

Ok - good feature request - I’ll add this tonight


(Adam V) #37

Cool - that’s all taken care of

Smartapp Release 1.6 - details:

  • More actions that can trigger routines
  • set single increment dim up actions for buttons 1 & 2 and single increment dim down actions for buttons 3 & 4

(Miles Frankland) #38

Wow, quick work! Will test this out soon. Thanks! :smile:


(Adam V) #39

##Device Handler Release 1.6 - details:

  • Full button mapping for integration with Rule Machine (or other SmartApps)
  • Fixed a bug to do with the first attempt at mapping from V1.5

Mappings for other SmartApps work like this:

button pushed = button number pushed
button held = button number held
button double clicked = (real button number + 4) pushed
button hold stopped = (real button number + 8) pushed
button click-held start = (real button number + 4) held
button click-held stopped = (real button number + 8) held

This allows you to use this with Rule Machine properly (especially as Bruce just updated it to work with up to 20 buttons per device).

This is great because the only real advantage my Smartapp has is that it can do dimming and is neat for containing all the actions for a controller. However, it’s drawback is that it has no where near as many possible actions as rule machine has, or the versatility. With this new release you can use any type of action with any button of a controller using the mapping above.

As an example for button 1 from a controller, used in a different SmartApp e.g. Rule Machine:

button 1 pushed = button 1 pushed
button 1 held = button 1 held
button 1 double clicked = button 5 pushed
button 1 hold stopped = button 9 pushed
button 1 click-held start = button 5 held
button 1 click-held stopped = button 9 held

etc etc


(Miles Frankland) #40

Hey!
I still have a problem with my wall controller :frowning:
When I use your new code, and ‘configure’ the device using the app, my buttons 3 and 4 stop working.
Here is the device I have:


When I click button 3 I get button 1 double click in the logs.
When I click button 4 I get button 2 double click in the logs.
What do you think?..