[OBSOLETE] Osram Lightify 4 Button Switch DTH & Binder []

Warning: very draft work.
Great, fairly inexpensive 4 button zigbee battery powered switch. Magnetic back plate with either adhesive or screw fixings.

Code reworked from @Motley and @Sticks18 handlers and apps so a big thanks to them. Maybe one day I’ll attempt the ultra efficient version. Fastest responses are when sent directly to devices rather than proxying via virtual devices.

I’m purely a hobbyist when it comes to coding, so my github may not even be setup right but I bought a second switch today and the code tested fine. You’re probably safest just copy and pasting it into your IDE.

One thing I noticed is that my second switch joined as a generic Zigbee switch wher as my first, which had been on a lightify gateway first turned up as unknown. If I think the fingerprinting needs some work, but if it joins as a generic ZLL Switch then you’ll be fine to simply change it over to the Osram one. If it joins as Unknown you will need to rework it to get it to join as Osram otherwise the clusters don’t bind properly and you end up with broadcast on\off to all your devices.

Device Handler

Binder App

6 Likes

Amazing effort, will be testing tonight and will update here!

1 Like

Thanks Nate.

Questions for any audience: Can we query a basic ZLL light and ZLL RGBW for its current level from with a SmartApp, and if so how?
Can, how do we query a device for its capabilities\clusters from inside a SmartApp? Could help handling unknown events and tuning the interface.

Interestingly B3 and B4 send some different signals when they are pressed, held, and held long. Chances are that B1 and 2 will too but have yet to break it down. Have drafted some code this evening that allows B3 press = on, B3 hold up the level to x% B3 long hold up the level to y%. Similar to 4. Not yet published.

Eventually I’d like it to be a bit more dynamic, allow the SmartApp user to choose what kind of function the press and hold does based on the targeted device types. I’m thinking cycle color, volume, etc. Also I’d like to build some handling in so that it won’t try to send a command to an unsupported device - currently it can target any switch type device. So in theory it could try send 0x08 increase to a smart plug which wouldn’t action but would parse an error.

So upon testing, only buttons 1 & 2 work - and it randomly turns on and off lights that I haven’t chosen in the smart app :frowning:

What did the switch join as when it got added to the hub? The issue you are seeing there is that the clusters (buttons, essentially) have not bound to the DTH properly. The binding only happens on device join, if it origilly came in at ‘unknown’ or ‘thing’ it ends up multicasting to the whole world off of B1 and B2 which explains your issue.

Remove from the phone app. Press and hold lower left and upper right to reset device. Doing same puts it back in join mode (sometimes takes a few attempts). If it comes in as zigby switch you’re fine to change the DTH tomOsram one. If it comes in as Osram then you’re golden.

Work needed on finger printing…

There are apparently various model strings out there, which might explain why some are not joining with the custom device handler. Add this finger print string:

fingerprint profileId: “0104”, deviceId: “0810”, inClusters: “0000, 0001, 0020, 1000, FD00”, outClusters: “0003, 0004, 0005, 0006, 0008, 0019, 0300, 1000”, manufacturer: “OSRAM”, model: “Switch 4x-LIGHTIFY”, deviceJoinName: “OSRAM 4x Switch”

Still does not solve the issue of buttons 3 and 4 not working. I am working on trying to figure that one out. The Zigbee join string from mine shows:
zbjoin: {“dni”:“7D98”,“d”:“000D6F000C606F29”,“capabilities”:“80”,“endpoints”:[{“simple”:“01 0104 0810 02 05 0000 0001 0020 1000 FD00 08 0003 0004 0005 0006 0008 0019 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”},{“simple”:“02 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”},{“simple”:“03 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”},{“simple”:“04 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”}],“parent”:“FFFF”,“joinType”:255}

I have buttons 1 and 2 press and hold working perfectly (including hold), but I can’t for the life of me get buttons 3 and 4 to bind. I have cleared and rejoined many times. The correct DTH is associated no problem (with my additonal fingerprint line above).

Specifically, it seems this line:
// Bind Button 3 and 4. New cluster IDs.
“zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0x0300 {${device.zigbeeId}} {}”,

…either has no effect (?), or the endpoint is different than 0x01 for button 3/4, or the cluster is something other than 0x0300 for them.

AnotherUser, do you have these buttons (3&4) confirmed to be working with your DTH? If so, we may be looking at a variation.

Anyone have a Zigbee sniffer?

Hi Doctor,

Appologies but I missed your first reply. I have the following actions working:

B1 press\hold\stop hold
B2 press (I have misplaced hold somehow, its not even logging in catchalls)
B3 press\hold\long hold\stop hold
B4 press\hold\long hold\stop hold

B3 and B4 were working fine before, but the updated code should hopefully solve any potential variation by correctly resolving using source endpoint IDs rather than relying on the Cluster IDs and commands.

I have updated the binding to capture the devices, it should have been obvious at the start but each button has a different source endpoint ID (indeed I use it to detect the presses of 3 and 4).

Have some code, updated bindings, fingerprint and button actions. I’ve not tried your fingerprint yet but worked out that my own one was being interfered with by another test DTH I had setup. All seems to add nicely now. Name has been changed so I can revert quickly back to my old one.

/**
 *  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: "OSRAM 4 Button Switch Classic", namespace: "AnotherUser", author: "AN") {
	
    capability "Actuator"
    capability "Battery"
    capability "Button"
    capability "Configuration"
    capability "Refresh"
    capability "Sensor"
       
    attribute "zMessage", "String"
		fingerprint profileId: "0104", deviceId: "0810", inClusters: "0000, 0001, 0020, 1000, FD00", outClusters: "0003, 0004, 0005, 0006, 0008, 0019, 0300, 1000", manufacturer: "OSRAM", model: "Switch 4x EU-LIGHTIFY", deviceJoinName: "OSRAM 4x Switch"
	
    
    }


	simulator {
		// Nothing to see here
	}

	tiles(scale: 2) {
    	standardTile("button", "device.button", width: 6, height: 4) {
      	state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
    	}
    	valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
      	state "battery", label:'${currentValue}% battery'
    	}
    	standardTile("refresh", "device.button", decoration: "flat", width: 2, height: 2) {
      	state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
    	}
    main "button"
    details(["button", "battery", "refresh"])
  	}
	}


// 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 = [
    // Bind Button 1 and 2. No Change from source.
    "zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0x0006 {${device.zigbeeId}} {}",
    // Bind Button 3 and 4. New cluster IDs.
    "zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0x0300 {${device.zigbeeId}} {}",
    // Bind the outgoing level cluster from remote to hub, so the hub receives messages when Dim Up/Down buttons pushed
    "zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0x0008 {${device.zigbeeId}} {}",
   // Bind the incoming battery info cluster from remote to hub, so the hub receives battery updates
    "zdo bind 0x${device.deviceNetworkId} 0x01 0x01 0x0001 {${device.zigbeeId}} {}",
  //ToDO: Determine what other clusters are on there and how they can be used. What purpose do 0003, 0004, 0005, 0019, and 1000 have?
  "zdo bind 0x${device.deviceNetworkId} 0x02 0x01 0x0006 {${device.zigbeeId}} {}",
  "zdo bind 0x${device.deviceNetworkId} 0x03 0x01 0x0006 {${device.zigbeeId}} {}",
  "zdo bind 0x${device.deviceNetworkId} 0x04 0x01 0x0006 {${device.zigbeeId}} {}",
  "zdo bind 0x${device.deviceNetworkId} 0x02 0x01 0x0300 {${device.zigbeeId}} {}",
  "zdo bind 0x${device.deviceNetworkId} 0x03 0x01 0x0300 {${device.zigbeeId}} {}",
  "zdo bind 0x${device.deviceNetworkId} 0x04 0x01 0x0300 {${device.zigbeeId}} {}",
  ]
  return configCmds 
}
def refresh() {
  //Straight copy. Need to check device and clusterID for battery.
  def refreshCmds = [
    zigbee.readAttribute(0x0001, 0x0020)
  ]
  //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)
  def abc = "zdo active 0x${device.deviceNetworkId}"
  log.debug "cluster ID is $msg.clusterId"
  log.debug "message from source $msg.sourceEndpoint"
  //New content follows
  switch(msg.sourceEndpoint) {
    //Endpoint numbering runs top left, top right, lower left, lower right.
    case 1: //"physical button 1"
    Map result = [:]
    if (msg.command==01){
    	result = [
    	name: 'button',
    	value: 'pushed',
    	data: [buttonNumber: 1],
    	descriptionText: "$device.displayName button 1 was pushed",
        isStateChange: true
        ]
       }
       else if (msg.command==05) {
       	result = [
    	name: 'button',
    	value: 'held',
    	data: [buttonNumber: 1],
    	descriptionText: "$device.displayName button 1 was held",
        isStateChange: true
        ]
       }
       else if (msg.command==03) {
       	result = [
    	name: 'button',
    	value: 'stophold',
    	data: [buttonNumber: 1],
    	descriptionText: "$device.displayName button 1 stopped being held",
        isStateChange: true
        ]
    }
          
    log.debug  "Parse returned ${result?.descriptionText}"
    return result
    break
    case 2: //physical button 3    
    Map result = [:]
    if (msg.command==76){
    		result = [
    		name: 'button',
    		value: 'pushed',
    		data: [buttonNumber: 3],
    		descriptionText: "$device.displayName button 3 was pushed",
        	isStateChange: true
       		]
        }
     else if (msg.command==03){
		    result = [
    		name: 'button',
    		value: 'held',
    		data: [buttonNumber: 3],
    		descriptionText: "$device.displayName button 3 started to be held",
        	isStateChange: true
       		]
         }
     else if (msg.command==01){
     		if(msg.data[0]==1){
           		result = [
    			name: 'button',
	    		value: 'longhold',
    			data: [buttonNumber: 3],
    			descriptionText: "$device.displayName button 3 continued to be held",
        		isStateChange: true
       			]
         	}
            else if (msg.data[0]==0){
            	result = [
    			name: 'button',
	    		value: 'stophold',
    			data: [buttonNumber: 3],
    			descriptionText: "$device.displayName button 3 stopped being held",
        		isStateChange: true
       			]
         	}
            else{
            	result =[
                descriptionText: "$device.displayName button 3 unknown data in command 01",
            	]
			}
         }
      else{
      	result =[
                descriptionText: "$device.displayName button 3 unknown command",
            	]
        }
          
    log.debug "message data $msg.data[0]"
    log.debug "message command $msg.command"
    log.debug  "Parse returned ${result?.descriptionText}"
    return result
    break
    case 3:
    //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 4:
    //physical button 4
    Map result = [:]
    
    if (msg.command==76){
    		result = [
    		name: 'button',
    		value: 'pushed',
    		data: [buttonNumber: 4],
    		descriptionText: "$device.displayName button 4 was pushed",
        	isStateChange: true
       		]
        }
     else if (msg.command==03){
		    result = [
    		name: 'button',
    		value: 'held',
    		data: [buttonNumber: 4],
    		descriptionText: "$device.displayName button 4 started to be held",
        	isStateChange: true
       		]
         }
     else if (msg.command==01){
     		if(msg.data[0]==3){
           		result = [
    			name: 'button',
	    		value: 'longhold',
    			data: [buttonNumber: 4],
    			descriptionText: "$device.displayName button 4 continued to be held",
        		isStateChange: true
       			]
         	}
            else if (msg.data[0]==0){
            	result = [
    			name: 'button',
	    		value: 'stophold',
    			data: [buttonNumber: 3],
    			descriptionText: "$device.displayName button 4 stopped being held",
        		isStateChange: true
       			]
         	}
            else{
            	result =[
                descriptionText: "$device.displayName button 4 unknown data in command 01",
            	]
			}
         }
      else{
      	result =[
                descriptionText: "$device.displayName button 4 unknown command",
            	]
        }
    log.debug  "Parse returned ${result?.descriptionText}"
    log.debug "message data $msg.data[0]"
    log.debug "message command $msg.command"
    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
}

For sniffing the zigbee… try changing the DTH to ‘unknown’ or ‘Zigbee Switch’, then use Live Logging to look at all the catchalls generated. I’m off to do that with B2 now.

Thanks,

I tried your revised handler but there was no difference for me. Buttons 1 & 2 work great, but 3 & 4 don’t do anything. I took your advise and changed the device type to Zigbee Switch - I saw the raw data from buttons 1/2, but nothing when I tried buttons 3 or 4. Seems like the thing isn’t even transmitting for those buttons. The light does flash. Maybe I just got a defective one.

That is strange doc. I thought I had something but read my logs incorrectly.

Only two suggestions really, at the moment…

  1. Delete the new DTH (backup to txt first) and remove, reset, rejoin. If the fingerprint is missing from the DTHs it should come in as ‘unknown’. The behaviour at this point will be the usual mad broadcast on/off from b1/2 and nothing on 3 and 4. However you will see catchalls in the live logs for the action.

  2. Add the new DTH (ensure it is is the only one with the fingerprint) and again, remove, reset and rejoin.

I’ve not worked out the full reset process yet, aside from holding lower left and upper right buttons for 5 seconds. Sometimes the lights flash blue, others green, a few attempts seem to put it in join mode but I have no formal process for it yet.

Hi An,

Thanks again. I tried removing device handler and resetting the device itself. I use the upper-left/lower right for 10+ seconds to reset it. Then I alternate between holding UL/LR, and holding LL/UR until it shows up as a new device. Not sure which one actually does it. Interestingly, my device doesn’t ever seem to flash blue - only green or orange. I think we can confidently surmise that there are at least 2 different versions of this product.

Anyway, with the device in “broadcast mode” I still only see raw data from the left side buttons So I am still pretty convinced that the device I have isn’t sending anything from the right 2 buttons, at least that the hub can interpret. Again, I suppose it’s possible that my button is defective, or there is something amiss with my reset procedure. Maybe in a little while I’ll be motivated enough to pony up for another one, or someone else can chime in with what they observe with their device. Either way, I’ll be keeping an eye on this thread.

Cheers!

I can confirm that my hub only sees data from the left two buttons. Haven’t had any luck with the right two yet.

Did get the Fingerprint for mine figured out. Had to change the model from “Switch 4x EU-LIGHTIFY” to “Switch 4x-LIGHTIFY” and it worked fine in discovery.

Would love to know if anyone has any updates on why the right two buttons don’t seem to do anything.

It could be that there are some model variations out there?

I have two switches working with all four, and one currently boxed up. All bought from within the EU area.
Model is: AB371860155|x1117 found by removing the rear cover.

Can you post your ZBD join log entry? I’ll try compare to a new out of the box tonight.

I have one of the ones that doesn’t appear to transmit anything for buttons 3 & 4.

FCC ID/Model # as found under back cover:
2AJRH-LDV74099|x4516

Zigbee join log entry:

zbjoin: {“dni”:“7D98”,“d”:“000D6F000C606F29”,“capabilities”:“80”,“endpoints”:[{“simple”:“01 0104 0810 02 05 0000 0001 0020 1000 FD00 08 0003 0004 0005 0006 0008 0019 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”},{“simple”:“02 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”},{“simple”:“03 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”},{“simple”:“04 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000”,“application”:“01”,“manufacturer”:“OSRAM”,“model”:“Switch 4x-LIGHTIFY”}],“parent”:“FFFF”,“joinType”:255}

So from the EU model:

zbjoin: {"dni":"yyyy","d":"xxxxxxxxxxxxxxxx","capabilities":"80","endpoints":[{"simple":"01 0104 0810 02 05 0000 0001 0020 1000 FD00 08 0003 0004 0005 0006 0008 0019 0300 1000","application":"01","manufacturer":"OSRAM","model":"Switch 4x EU-LIGHTIFY"},{"simple":"02 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000","application":"01","manufacturer":"OSRAM","model":"Switch 4x EU-LIGHTIFY"},{"simple":"03 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000","application":"01","manufacturer":"OSRAM","model":"Switch 4x EU-LIGHTIFY"},{"simple":"04 0104 0810 02 03 0000 1000 FD00 07 0003 0004 0005 0006 0008 0300 1000","application":"01","manufacturer":"OSRAM","model":"Switch 4x EU-LIGHTIFY"}],"parent":"FFFF","joinType":255}

Endpoints and clusters appear the same, but it is quite possible that the devices made for each market ship with different firmware. I’ve had the EU ones on a gateway but worth someone checking out the US model to see if there is an update out there.

I just received one of these today (US - Amazon) and I can confirm that it behaves like “doctor567”'s does. Only 2 buttons recognized (regardless of whether I use the generic Zigbee Switch DTH or your OSRAM DTH. No blue lights when pairing, only green or amber lights. Interesting note, if you hold both lower buttons pressed for 10 seconds it goes into a different state where you see a longer amber followed by a red light as well. I’m guessing this might be “reset to factory settings”. It was very difficult to pair up to my hub. It would not appear at all on Add device screen, during many, many attempts at pairing (green light flashing). Not sure what finally made it show up. I am totally new to ST and Zigbee/ZWave but am willing to get my hands dirty as necessary. If I find anything useful, I will report here.

An update. I’ve been able to use the generic Zigbee Button handler for this device (per Amazon user Cooper’s instructions), and it works well for detecting buttons 1 and 2 (for both: press and hold actions). But even with the generic handler, I still get no reaction to buttons 3 and 4.

… Or it might be firmware download mode, which could be very interesting. I have read articles suggesting that Osram can change the firmware, perhaps even aftermarket. Imagine if we in the U.S. could figure out how to update to the European firmware, and then make use of all four buttons.

Still would like to hear from more Europeans (and/or someone with a real Zigbee sniffer).

I wouldn’t bother going to all this trouble, but there seems to be a lack of any decent 4 button, battery powered wall switches available for ST.

So here’s an odd thing. I have 3 of these. 1 works perfectly, 2 don’t respond to Button 4, but only Button 4.

Any ideas?