RELEASE: OSRAM Lightify Smart Dimmer Switch (button controller device handler and smart app)

Ok, so the latest version is up on the Github site, any input appreciated. I am guessing the events are being created as I see no errors and I see the log messages like below. I am not sure if I can pass an array of button numbers with the event like I am doing for the release event but it could be either button released so not sure how to handle that one, maybe it is good as is. I do think the conditionals could probably use some cleanup and I would not be surprised if there is some other changes needed but I see no errors so not sure what else would be needed.

68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:14:59 PM: debug Parse returned Dining Room Dimmer button 1 was pushed 68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:15:01 PM: debug Parse returned Dining Room Dimmer button 2 was pushed 68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:15:03 PM: debug Parse returned Dining Room Dimmer button 1 was held 68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:15:04 PM: debug Parse returned Dining Room Dimmer button 1 or 2 was released 68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:15:06 PM: debug Parse returned Dining Room Dimmer button 2 was held 68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:15:07 PM: debug Parse returned Dining Room Dimmer button 1 or 2 was released

Hmmm, very interesting. I just went back to look at the logs and saw the below, does this mean there is a temperature sensor? Would there be some conversion/calibration needed? I can assure you the temperature in my house is not 124.15 (F or C) :neutral_face:

If I keep this inbound cluster enabled I am guessing I would need to add code to handle that message to avoid the error reported.

68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:25:43 PM: error java.lang.NullPointerException: Cannot get property ‘command’ on null object @ line 52
68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:25:43 PM: debug null
68df2dc6-c59a-4c17-8a88-db44a3b1096e 9:25:43 PM: debug parse description: temperature: 124.15

That is interesting. You could try adding a refresh() command and use:
zigbee.readAttribute(0x0402, 0x0000)

That will read the temp value, so you can see if the 124.15 is definitely what the device is sending. That 124 is probably ST conversion from C to F. Not sure why the device would send something so high. Maybe Osram is using it for internal device temp?

I can’t read what you’re reading, but I bet 10 virtual bucks it’s Kelvin color temperature. That is, the color temperature of the light. Osram makes a huge deal out of the fact that their bulbs are color temperature adjustable and Hues are not. Maybe the switch has some way of adjusting it? Or a kind of scene setting?

I did a little bit more playing around with the device handler last night and could not quite figure out the refresh. I tried added a refresh method with the zigbee.readattribute command posted by @Sticks18 but it didn’t seem to do anything, even with a refresh tile pressing the tile did not trigger any log messages. It is very possible I did not get something right though.

EDIT: I actually appear to have gotten the refresh working, now when I click the refresh tile in the app I see the following message come into the hub. The message comes from the clusterId that @Sticks18 mentioned was for termperature (0x0402), my guess is this message contains the temperature information (in data?) but I still need to figure out how to parse that message which I will do as time permits.

56cf8297-b7a9-4e69-927e-1f054667902d 10:48:45 AM: debug SmartShield(clusterId: 0x0402, command: 0x01, data: [0x00, 0x00, 0x00, 0x29, 0x70, 0x30], destinationEndpoint: 0x01, direction: 0x01, isClusterSpecific: false, isManufacturerSpecific: false, manufacturerId: 0x0000, messageType: 0x00, number: null, options: 0x0140, profileId: 0x0104, senderShortId: 0x2a59, sourceEndpoint: 0x01, text: null) 56cf8297-b7a9-4e69-927e-1f054667902d 10:48:45 AM: debug parse description: catchall: 0104 0402 01 01 0140 00 2A59 00 00 0000 01 01 000000297030

I did notice that the “temperature” does not appear to be reported as part of a cluster message, at least not like other messages. The temperature is coming in without a clusterId and instead the description in these messages is starting with “temperature” (most messages I see come in with description starting with "catchall’). I also noticed that the temperature is not reported on any kind of interval so not sure what triggers it, there were times where I saw that message come in 10 minutes apart (at one point I got 3 messages within 30 minutes, each 9-12 minutes apart) but last night I left the live logging open to see what would be reported overnight and the “termperature” message never came in.

On another note I added the inbound cluster 0x0020 to the bindings since I think I read that cluster contains battery information. I was hoping to see battery levels reported but not sure that is really the case, the live logging picked up the following message being received once per hour. If this is useful information and can be used for something I will leave it but I don’t quite understand what this message is at the moment. Is this some polling message that helps keep the switch connected to the hub? By the way, so far I have had my dimmer switch connected for about 16 hours without re-pairing and left it unused overnight and it still seems to function, will report if I see any issues with it forgetting its network.

56cf8297-b7a9-4e69-927e-1f054667902d 9:32:03 AM: debug SmartShield(clusterId: 0x0020, command: 0x00, data: [], destinationEndpoint: 0x01, direction: 0x01, isClusterSpecific: true, isManufacturerSpecific: false, manufacturerId: 0x0000, messageType: 0x00, number: null, options: 0x0140, profileId: 0x0104, senderShortId: 0x2a59, sourceEndpoint: 0x01, text: null) 56cf8297-b7a9-4e69-927e-1f054667902d 9:32:03 AM: debug parse description: catchall: 0104 0020 01 01 0140 00 2A59 01 00 0000 00 01

For better or worse, ST automatically recognizes and re-formats temperature messages before they enter parse() as long as they’re in formats ST recognizes, which is why you just see “Temperature: xxx” for the regular checkpoints. It makes it easier to code for, but custom coders lose some info.

When you push refresh(), you’re sending a read attributes command. That temperature message you get back is the read attributes response, which is command 01 when “isClusterSpecific=false”. If you focus on the last 12 digit payload you get:

0000 00 29 7030

0000 is the attribute number, which we requested
00 means it was successfully read
29 is the data-type and stands for signed 16-bit integer
7030 is the attribute value and is a signed 16-bit integer in little endian format

7030 becomes 3070, which is 12400 in decimal and converts to 124 C. This appears to be an invalid number for this cluster. Based on the standard, the value should be between 954d and 7fff in hex format, but maybe I’m missing something in the conversion. Either way, I’m not sure what it’s supposed to mean, but it is in range of your other temp messages.


The other message from 0x0020 is actually the poll cluster checkin. 0x0020 is not for battery in zigbee HA profile. It’s a special poll cluster that controls how often the switch and the devices it’s paired to check-in and relay information to each depending on various modes. That message is the “Check in” command and its default is to send once per hour. It’s intended to ping devices to see if they want to change the polling parameters since this typically sleepy device is now awake.

Here’s a Github link for this version of the Hue Dimmer device handler and SmartApp I wrote. This allowed me to select zigbee bulb(s) directly and have the actual zigbee commands pass from the remote through a SmartApp and out to the device. It resulted in a more natural experience, but I only tested it with one bulb and there might be issues with the endpointId portion. In one iteration I had to ask the user to input the endpointId for their devices because it was null in the SmartApp.

I am considering removing the temperature cluster binding just because I cannot see any use for the seemingly invalid data being provided. Unless you think there is some use in keeping that coming in and displaying it. I can successfully parse the message and I have a temperature tile defined and displayed in the app but cannot for the life of me figure out what i am missing to get that temperature to display in that tile, I just get “–” and that is all. Below is the logging I have for temperature currently, this value is being set in a variable and returned by the parse method as well.

56cf8297-b7a9-4e69-927e-1f054667902d 5:26:51 PM: debug Calculated fahrenheit value is 255 56cf8297-b7a9-4e69-927e-1f054667902d 5:26:51 PM: debug TEMPERATURE 56cf8297-b7a9-4e69-927e-1f054667902d 5:26:51 PM: debug parse description: catchall: 0104 0402 01 01 0140 00 2A59 00 00 0000 01 01 000000297330

So does this mean I should remove the binding for 0020? Sounds like it doesn’t provide anything useful I should parse and display. One of the things I was hoping for is a battery status, is there some other cluster that I can read for that info that you are aware of?

I would remove temp too. The only thing I can think of is that Osram mixed up the Internal Temp cluster (0x0002) and Temp measurement (0x0402). Either way, it’s not really useful.

You can remove 0x0020 cluster too. Nothing to see there really.

For battery info you want cluster 0x0001 and attribute 0x0020. That has battery voltage. Usually device handlers will compare the battery voltage to the max and min required to create a battery percent. Any of the battery powered zigbee sensors (motion, temp, water, etc) will have this type of code if you’re looking for examples.

Sorry, I should have thought of this earlier. I actually mistook 0x0020 cluster for battery at one point too and has to correct my reply. Forgot that it’s in 0x0001, but attribute 0x0020. You could alter the temp read attribute to request this instead and work on getting the periodic reports.

Thanks, I will look into that. I already have the getBatteryResult code that I have seen in a few examples and that is what I was sending the 0020 output to but obviously that was not working well.

Do you have any tips for how to get the battery result to display on the tile? My latest code is on the Github site if you want to take a look at what may be missing. I am also not sure if I did the event creation properly, I have seen several different examples, some using a sendEvent and some using createEvent and not quite sure which to do and where to put it, right now I have the sendEvent being done in my custom method called lightEvent.

Looks to me like you would only get events for the actual button presses. Neither temp nor battery have either createEvent() or sendEvent() in their logic paths. For both of them it looks like parse() would just return a map. You want to use those maps as the parameter in a createEvent() and return that from parse(). I think if you removed the sendEvent stuff and just made those maps, then had “return createEvent(map)” at the end of parse, it would all work.

Sometimes I don’t fully understand it, but createEvent() is used as the result from parse(). It will only work if it is the last line or the result returned from parse(). The whole purpose of parse() is to “hear” the device and create events from what it says.

On the other hand, sendEvent() can be used anywhere including in parse(). It doesn’t have to be the result of parse(), it just fires when called. It has two primary uses: 1) Sometimes you want to trigger an event based on an action or you don’t want to wait for the device to respond. You can use sendEvent() in the command. Most actuator (switches, lights, locks, etc) will use sendEvent() in their commands. 2) For a complex device handler where a single device message in parse() necessitates more than one event. Parse() can only return one event, so you have to use sendEvent() for one of them. An example would be a color temp bulb where you want to provide a label like Soft White in addition to the actual Kelvin value.

Personally I pretty much just use sendEvent() because I don’t have to worry about it being the returned result of parse(). I don’t think there are any other differences.

Ok, latest code is on Github. I think it is time for me to update the OP and include a Github link there as well as I think this is pretty much ready, now to work on the SmartApp. The battery level is reporting and the tile is updating, I guess I didn’t think about the event creation to trigger the tile update but that makes sense now.

I have yet to have issues with the switch communicating to the hub so I suspect this switch doesn’t have the connectivity issues experienced with the Hue switch. I think this will work out well once I have the SmartApp portion done, I have already ordered 2 more of these switches. :grin:

1 Like

I bought the dimmer switch hoping I would find time to get the device created. Now I don’t have to. Thank you Motley and Sticks18 for all your work. I’ll test out the device sometime this week.

@Sticks18, I have an issue I am hoping you can help me with. I am trying to write the SmartApp for this device but am getting an error that I don’t understand. The error I am getting is below as well as the code that is generating the error and seems to indicate I am calling an invalid property but I am trying to get a specific value (buttonNumber) in the “data” field that is passed. All of the docs I have read say this is how to reference that data, any ideas?

log.debug “buttonPressedHandler invoked with ${evt.data.buttonNumber}”

29fa71cd-3218-4867-832a-c24b52211f49 4:34:16 PM: error groovy.lang.MissingPropertyException: No such property: buttonNumber for class: java.lang.String

That looks right to me. Was that a stop command by any chance? Looked like you gave buttonNumber 2 values for those. Not sure if that would cause an issue.

Actually The issue I am having right now is only with the on/off command (single button press). You can see the framework I have created for the SmartApp at the link below, all of the logic is working and if I only ask for $evt.data I get the data array returned but it seems I just cannot ask for only the buttonNumber element of the map. Below are some logs showing the logic working and returning the log entry but only if I reference just the entire $evt.data map. The logs are a full sequence of all button commands, first being the button 1 hold and release, then button 1 single press, then button 2 hold and release, and then button 2 single press.

29fa71cd-3218-4867-832a-c24b52211f49 7:42:34 PM: error groovy.lang.MissingPropertyException: No such property: buttonNumber for class: java.lang.String @ line 58 29fa71cd-3218-4867-832a-c24b52211f49 7:42:34 PM: debug buttonPressedHandler invoked with {"buttonNumber":2} 29fa71cd-3218-4867-832a-c24b52211f49 7:42:34 PM: debug buttonPressedHandler invoked with Dining Room Dimmer button 2 was pressed 29fa71cd-3218-4867-832a-c24b52211f49 7:42:32 PM: debug buttonReleasedHandler invoked with {"buttonNumber":[1,2]} 29fa71cd-3218-4867-832a-c24b52211f49 7:42:31 PM: debug buttonHeldHandler invoked with {"buttonNumber":2,"levelData":[0,50]} 29fa71cd-3218-4867-832a-c24b52211f49 7:42:27 PM: error groovy.lang.MissingPropertyException: No such property: buttonNumber for class: java.lang.String @ line 58 29fa71cd-3218-4867-832a-c24b52211f49 7:42:27 PM: debug buttonPressedHandler invoked with {"buttonNumber":1} 29fa71cd-3218-4867-832a-c24b52211f49 7:42:27 PM: debug buttonPressedHandler invoked with Dining Room Dimmer button 1 was pressed 29fa71cd-3218-4867-832a-c24b52211f49 7:42:23 PM: debug buttonReleasedHandler invoked with {"buttonNumber":[1,2]} 29fa71cd-3218-4867-832a-c24b52211f49 7:42:21 PM: debug buttonHeldHandler invoked with {"buttonNumber":1,"levelData":[1,50]}

Looks like the API doc to me, so I’m not sure what could be wrong. Only thing I can think of is that the evt.data becomes a string when it’s entered in the event map. What if you created a new map variable and loaded the evt.data into it first?

@Jim any thoughts on this?

I am guessing we will have to see if we get an answer, I have tried everything I can think of and I cannot seem to grab that element, I haven’t been able to even create a new map as you suggested because it kept causing errors. It seems odd to me that the keys have double-quotes around them and I wonder if that is an issue. No examples I look at show double-quotes on the key.

Looks like the evt.data is being returned as a JSON string, not an actual map that represents the JSON.

Try parsing it to json first with parseJson:

parseJson(evt.data)?.buttonNumber

@Jim, thanks that worked.

Do the docs need to be updated or am I possibly doing something not right in my device handler when creating the events? I was expecting to call the buttonNumber element as shown in the docs.

Hopefully I can get this SmartApp completed tonight now that I am past that issue.