I have a button device from LK (Danish manufacture under Schneider) with 4 buttons.
I've found some code which at first seemed to fit the bill, but needed some tweaking to get it to work.
The code is from a OSRAM 4 button switch which has 4 endpoints, like this button. But this button I have apparently only uses 1 endpoint, what I can tell at least. The weird thing is that I can't tell the difference between a button press/hold/release on button 1 and 3, or 2 and 4.
From the logs where I've pressed button 1 and 3:
[dev:776] 2021-07-13 19:09:45.712 [debug] Parse returned LK tryk button 1 was pushed
[dev:776] 2021-07-13 19:09:45.708 [debug] 6
[dev:776] 2021-07-13 19:09:45.704 [debug] parse description: catchall: 0104 0006 15 01 0040 00 40BE 01 00 0000 01 00
[dev:776] 2021-07-13 19:09:45.700 [debug] Parsing 'catchall: 0104 0006 15 01 0040 00 40BE 01 00 0000 01 00 '
[dev:776] 2021-07-13 19:09:44.267 [debug] Parse returned LK tryk button 1 was pushed
[dev:776] 2021-07-13 19:09:44.265 [debug] 6
[dev:776] 2021-07-13 19:09:44.261 [debug] parse description: catchall: 0104 0006 15 01 0040 00 40BE 01 00 0000 01 00
[dev:776] 2021-07-13 19:09:44.259 [debug] Parsing 'catchall: 0104 0006 15 01 0040 00 40BE 01 00 0000 01 00 '
Catchall is exactly the same.
Is there be some other way to detect the buttons? In the official gateway and software, it is totally possible, but how?
Show code
/**
* OSRAM 4 Button Switch Handler
*
* Copyright 2017 AnotherUser
*
* 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.
*
* Modified from code written by motley74 and sticks18.
* Original source: https://github.com/motley74/SmartThingsPublic/blob/master/devicetypes/motley74/osram-lightify-dimming-switch.src/osram-lightify-dimming-switch.groovy
*/
metadata {
definition (name: "DEV - OSRAM 4 Button Switch LK TEST", namespace: "AnotherUser", author: "AN") {
capability "Actuator"
capability "Battery"
capability "PushableButton"
capability "HoldableButton"
capability "Configuration"
capability "Refresh"
fingerprint profileId: "0104", deviceId: "0810", inClusters: "0000, 0001, 0003, 0020, FF17", outClusters: "0003, 0004, 0005, 0006, 0008, 0019, 0102", manufacturer: "OSRAM", model: "Switch 4x EU-LIGHTIFY", deviceJoinName: "OSRAM 4x Switch"
}
}
def installed() {
configure()
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'numberOfButtons' attribute
// Parse incoming device messages to generate events
Map map = [:]
log.debug "parse description: $description"
if (description?.startsWith('catchall:')) {
// call parseCatchAllMessage to parse the catchall message received
map = parseCatchAllMessage(description)
} else if (description?.startsWith('read')) {
// call parseReadMessage to parse the read message received
map = parseReadMessage(description)
} else {
log.debug "Unknown message received: $description"
}
//return event unless map is not set
return map ? createEvent(map) : null
}
def configure() {
log.debug "Confuguring Reporting and Bindings."
def configCmds = [
// Binding ON/OFF functions
"zdo bind 0x${device.deviceNetworkId} 21 1 6 {${device.zigbeeId}} {}",
"zdo bind 0x${device.deviceNetworkId} 22 1 6 {${device.zigbeeId}} {}",
"zdo bind 0x${device.deviceNetworkId} 23 1 6 {${device.zigbeeId}} {}",
"zdo bind 0x${device.deviceNetworkId} 24 1 6 {${device.zigbeeId}} {}",
// Binding dimmer functions
"zdo bind 0x${device.deviceNetworkId} 21 1 8 {${device.zigbeeId}} {}",
"zdo bind 0x${device.deviceNetworkId} 22 1 8 {${device.zigbeeId}} {}",
"zdo bind 0x${device.deviceNetworkId} 23 1 8 {${device.zigbeeId}} {}",
"zdo bind 0x${device.deviceNetworkId} 24 1 8 {${device.zigbeeId}} {}",
// Binding battery reporting
"zdo bind 0x${device.deviceNetworkId} 21 1 1 {${device.zigbeeId}} {}",
]
return configCmds
zigbee.configureReporting( 0x0001, 0x0021, DataType.UINT8, 1,86400, 1 )
refresh()
}
def refresh() {
//Straight copy. Need to check device and clusterID for battery.
def refreshCmds = [
zigbee.readAttribute(0x0001, 0x0021)
]
//when refresh button is pushed, read updated status
return refreshCmds
}
private Map parseReadMessage(String description) {
// Create a map from the message description to make parsing more intuitive
def msg = zigbee.parseDescriptionAsMap(description)
// def msg = zigbee.parse(description)
if (msg.clusterInt==1 && msg.attrInt==32) {
// call getBatteryResult method to parse battery message into event map
def result = getBatteryResult(Integer.parseInt(msg.value, 16))
} else {
log.debug "Unknown read message received, parsed message: $msg"
}
// return map used to create event
return result
}
private Map parseCatchAllMessage(String description) {
// Create a map from the raw zigbee message to make parsing more intuitive
def msg = zigbee.parse(description)
log.debug msg.clusterId
switch(msg.clusterId) {
case 1:
// call getBatteryResult method to parse battery message into event map
log.debug 'BATTERY MESSAGE'
def result = getBatteryResult(Integer.parseInt(msg.value, 16))
break
case 8:
switch(msg.command) {
case 1: // brightness decrease command
Map result = [:]
result = [
name: 'Held',
value: '2',
data: [buttonNumber: 2],
descriptionText: "$device.displayName button 2 was held",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
case 3: // brightness change stop command
def result = [
name: 'button',
value: 'released',
data: [buttonNumber: [1,2]],
descriptionText: "$device.displayName button was released",
isStateChange: true
]
log.debug "Recieved stop command"
//return result
break
case 5: // brightness increase command
Map result = [:]
result = [
name: 'Held',
value: '1',
data: [buttonNumber: 1],
descriptionText: "$device.displayName button 1 was held",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
}
case 6:
switch(msg.command) {
case 00: // brightness decrease command
Map result = [:]
result = [
name: 'Pushed',
value: '2',
data: [buttonNumber: 2],
descriptionText: "$device.displayName button 2 was pushed",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
case 02: /* brightness change stop command
def result = [
name: 'button',
value: 'pushed',
data: [buttonNumber: [1,2]],
descriptionText: "$device.displayName button was released",
isStateChange: true
]*/
log.debug "What's this?"
//return result
break
case 01: // brightness increase command
Map result = [:]
result = [
name: 'Pushed',
value: '1',
data: [buttonNumber: 1],
descriptionText: "$device.displayName button 1 was pushed",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
}
}
//New content follows
/* switch(msg.sourceEndpoint) {
//Endpoint numbering runs top left, top right, lower left, lower right.
case 15:
log.debug "physical button 1"
Map result = [:]
result = [
name: 'button',
value: 'pushed',
data: [buttonNumber: 1],
descriptionText: "$device.displayName button 1 was pushed",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
case 15: //physical button 3
Map result = [:]
result = [
name: 'button',
value: 'pushed',
data: [buttonNumber: 3],
descriptionText: "$device.displayName button 3 was pushed",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
case 15:
//physical button 2
Map result = [:]
result = [
name: 'button',
value: 'pushed',
data: [buttonNumber: 2],
descriptionText: "$device.displayName button 2 was pushed",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
case 15:
//physical button 4
Map result = [:]
result = [
name: 'button',
value: 'pushed',
data: [buttonNumber: 4],
descriptionText: "$device.displayName button 4 was pushed",
isStateChange: true
]
log.debug "Parse returned ${result?.descriptionText}"
return result
break
//ToDo: Look at how to capture hold down of buttons 3 & 4, it doesn't differentiate on cluster or command as per B1 and B2 .
} */
}
//Motley obtained from other examples, converts battery message into event map.
//AN: I don't think this is working yet.
private Map getBatteryResult(rawValue) {
def linkText = getLinkText(device)
def result = [
name: 'battery',
value: '--'
]
def volts = rawValue / 10
def descriptionText
if (rawValue == 0) {
} else {
if (volts > 3.5) {
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
} else if (volts > 0){
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}%"
}
}
log.debug "Parse returned ${result?.descriptionText}"
return result
}