Device handler preferences

Hi all,

I’ve spent quite a bit of time trying looking into the settings page of a device handler I’ve been working on, mainly trying to work out if I can get the settings to update based on configuration parameter values received from events.

I first noticed that, when editing the settings on the classic app, the settings did not update in the new app and I was trying to fix this. I now see that the new app is not actually making the setting change at all, even if set directly on the settings page.

So, two issues really.

  1. Mismatched settings between apps
  2. New app not sending correct parameter value

This is the code for one of the settings.

//Settings Page
preferences {
//parameter 1
input “LCDinvert”, “enum”, title: “Invert LCD”, options: [“No”, “Yes”], required: false, displayDuringSetup: true

//configure method
def configure() {
zwave.configurationV1.configurationSet(configurationValue: LCDinvert == “Yes” ? [0x01] : [0x00], parameterNumber:1, size:1, scaledConfigurationValue: LCDinvert == “Yes” ? 0x01 : 0x00)
}

//This is what the classic app sends when “Yes” is selected
14:54:21: debug [ConfigurationSet(parameterNumber: 1, scaledConfigurationValue: 1, reserved11: 0, defaultValue: false, size: 1, configurationValue: [1])

//This is what the new app sends
14:54:21: debug [ConfigurationSet(parameterNumber: 1, scaledConfigurationValue: 0, reserved11: 0, defaultValue: false, size: 1, configurationValue: [0])

If I debug the setting when setting from the classic app I see this

//debug classic
log.debug “$LCDinvert”

16:02:06: debug Yes

//debug from new app
log.debug “$LCDinvert”

16:05:50: debug 1

So I can see the parameter value is different depended on which app it was set in.

At this point I’m at a loss. Could this be the way that the parameter options are being handled? Do I need to use maps, i.e.

//suggested code?
def LCDinvertOptions = [:]
LCDinvertOptions << [“0” : “No”] // 0x00
LCDinvertOptions << [“1” : “Yes”] // 0x01

preferences {
//parameter 1
input “LCDinvert”, “enum”, title: “Invert LCD”, options: LCDinvertOptions, required: false, displayDuringSetup: true

I was trying to get this working
setting[LCDinvert] = “Yes”

as I’ve read in several posts that this should change the UI, unless I’ve misunderstood.

Any help, greatly appreciated.

For the benefit of anyone else, I’ve finally got to the bottom of the problem and managed to match the settings across the apps.

The new app sees the settings value as the option number, i.e. 0, 1 etc. If you don’t map the values to an option number, the classic app sees the options as the text values, i.e. “No”, “Yes”.

To manage that you need to map the values and then you can update the app setting. Works both ways now when changing the setting in either app.

Here’s the code I used:

//options for InvertLCD
def LCDinvertOptions = [:]
LCDinvertOptions << [“0” : “No”] // 0x00
LCDinvertOptions << [“1” : “Yes”] // 0x01

//Settings Page
preferences {
//parameter 1
input “LCDinvert”, “enum”, title: “Invert LCD”, options: LCDinvertOptions, required: false, displayDuringSetup: true
}

def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd ) {
	log.info "Report Received : $cmd"
	def events = []

	switch (cmd.parameterNumber) {

		case 1:
		events << processParam1(cmd)

		break

}

//LCDinvert
private processParam1(cmd) {
def setValue
if (cmd.scaledConfigurationValue == 0) {
setValue = “No”
}
if (cmd.scaledConfigurationValue == 1) {
setValue = “Yes”
}
settings.$LCDinvert = setValue //This updates the UI setting
}

Phew, got there in the end.

1 Like

This behavior in the new app is not intentional and the team is working on a fix. The workaround you found is a good one and should keep working once the fix is released.

2 Likes

That actually doesn’t work because the new app is returning the item index so if you added [“3”:“Maybe”] to that list it would save as 2 instead of 3 in the new mobile app…

Thank you for acknowledging the issue and working towards fixing it.

I’ve always used a list of maps in my DTHs, like shown above, but the previous update caused them to render as object in the new mobile app.

The last update fixed that issue, but caused them to save the index instead of key so once this bug is fixed will things be back the way they’ve always been or do I need to change my DTHs so that they just use a lists of strings?

I tested several variations and I can’t reproduce that error. I changed another setting to use a map, last night, with four options, and it saves correctly and maintains the correct setting across both apps. I have 0 in the index of the lists though.

def windowDetectOptions = [:]
windowDetectOptions << [“0” : “Disabled”] // 0x00
windowDetectOptions << [“1” : “Low”] // 0x01
windowDetectOptions << [“2” : “Medium”] // 0x02
windowDetectOptions << [“3” : “High”] // 0x03

My point was that unless the numbers are consecutive and start at 0 then that won’t work and there’s no point in including those numbers if they’re in order and start with 0 because that’s the index which is already built into all lists.

Example: You have a setting called someSetting with the options below and you select “Low” in the new mobile app then it will save 1 and you can get “Low” back from that list like options[1] because 1 is the index.

At the moment, you can easily make a simple string list work with both mobile apps like: (this works as long as the list items are NOT numbers)

def options = ["Disabled", "Low", "Medium", "High"]
def settingValue = "${someSettng}"
if (settingValue.isInteger()) {
    settingValue = options[settingValue.toInteger()]
}

Once they fix the new mobile app you’ll be able to map the options list directly to the configuration parameter values, like you currently can in the classic mobile app, and that makes working with the settings much easier.

Example: A setting with the options [[0:“Disabled”], [60: “1 Minute”], [180:“3 Minutes”]] will display the text list to the user in the app and display the selected text in the IDE, but when you get the setting value in the code it will return the number.

Until the new mobile app is fixed, selecting “3 Minutes” from the list above will return 2 when saved in the new app and 180 when saved in the classic app and that’s what broke the 40+ DTHs I’ve written…

Update:
The stuff I was saying was based off of users primarily using one app or the other to change a device’s settings and how you can easily change the code so that it works regardless of which mobile app was used to save the setting.

I just noticed that you were trying to make the setting selections stick so you can go back and forth between the mobile apps and see that the same setting is selected and you’re solution is probably the only workaround for that.

It’s a lot of extra work so fortunately this is just a bug which will hopefully be fixed soon and it’s not worth implementing a workaround at this point.

Ah, thanks. I understand now. I misunderstood your first example as it was next in the consecutive index.

Thanks for the example, as well. I can write code but, I’m ‘definitely’ not very experienced. That’s really useful.

Is this the type of example you refer to?

def tempReportRates = [:]
tempReportRates << [“0” : “Off - Default”] // 0x00
tempReportRates << [“1” : “Report 0.1 degree temperature change”] // 0x01
tempReportRates << [“2” : “Report 0.2 degree temperature change”] // 0x02
tempReportRates << [“5” : “Report 0.5 degree temperature change”] // 0x05
tempReportRates << [“8” : “Report 0.8 degree temperature change”] // 0x08
tempReportRates << [“10” : “Report 1.0 degree temperature change”] // 0x0A
tempReportRates << [“15” : “Report 1.5 degree temperature change”] // 0x0F
tempReportRates << [“20” : “Report 2.0 degree temperature change”] // 0x14
tempReportRates << [“30” : “Report 3.0 degree temperature change”] // 0x1E
tempReportRates << [“50” : “Report 5.0 degree temperature change”] // 0x32

I’ve just checked this one and these are the results:

def setValue
    log.debug "$cmd.scaledConfigurationValue"  // Result: 18:10:10: debug 50
    log.debug "$tempReport"                    // Result: 18:10:10: debug 50
    log.debug "Temp report: ${setValue}"       // Result: 18:10:10: debug Temp report: Report 5.0 degree temperature change

Not sure if that helps, at all.

Here are the different formats for options and the results of my testing:

1. Single map of key/value pairs

options: ["Option1Key":"Option 1 Value", "Option2Key":"Option 2 Value", "Option3Key":"Option 3 Value", "Option4Key":"Option 4 Value"]

Result: This works in both the Classic app and the new app

2. List of strings

options: ["Option 1 Value", "Option 2 Value", "Option 3 Value", "Option 4 Value"]

Result: This works in the Classic app but not the new app. This worked in the new app until early last week and this is the first thing we’re working on fixing.

3. List of maps of a single key/value pair each

options: [
							["Option 1 Value":"Option 1 Value"],
							["Option 2 Value":"Option 2 Value"],
							["Option 3 Value":"Option 3 Value"],
							["Option 4 Value":"Option 4 Value"]]

Result: This works in the Classic app but not the new app. I don’t believe it ever worked in the new app but I’ve requested that this format be supported.

Do you guys agree with this summary of the current state?

1 Like

Thanks for that @tpmanley.

I agree that example 2 doesn’t work with the new app.

I haven’t tried example 1. If example 3 is the same as my tempReportRates example above, that works for me.

Should that have read;

[“Option 1 Value”:“Option 1 key”],
[“Option 2 Value”:“Option 2 key”],
[“Option 3 Value”:“Option 3 key”],

Actually this is the same as option 1:

​def LCDinvertOptions = [:]
LCDinvertOptions << ["0" : "No"] // 0x00
LCDinvertOptions << ["1" : "Yes"] // 0x01​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

In which case, that works for me, in both apps, as well and it’s example 3 that I don’t fully understand.

Good thing I copied someone else who used this method when I designed my handlers.

2 or 3 years ago the single map didn’t work so since then I’ve always used a list of maps and that’s worked fine in both apps until a few weeks ago when it started displaying “object” instead of the items and once that was fixed the index issue started.

When you use a single map, does the key or value get returned when you use that setting in the code?

If a single map works in both apps then that will make things easier going forward, but I probably have at least 30 DTHs implemented with a list of maps and I’d rather not have to update them all so if you can put the new mobile app back the way it was, that would be great.

Please let me know if you don’t plan on fixing the list of maps soon because I have a couple of manufacturers that would like this fixed ASAP and I’ll have to update those handlers.

Thank you for keeping us updated on this.

The value. I’ve some debug earlier in the thread if that helps.

That’s what I expected, but I just wanted to make sure.

I’ve always defined my options as a single map and used a wrapper function that appends " [DEFAULT]" to the default option and converts it into a list of maps so changing 1 line of code in every handler will fix them, but I’d rather not waste time doing that unless I have to…

I’d love to see an example of what one will look like, if you don’t mind sharing.

My most recent is the Eva Logik in-wall Switch, but I wrote that last weekend, so I implemented the settings a different way.

I think the Zooz MultiRelay is the latest handler implemented the way I described.

I just realized you might have been asking about the 1 change I’d need to make in order for them to work in the new mobile app and that change in the Zooz MultiRelay handler is replacing"collect" with “collectEntries” on line 729.

1 Like

Wow. I see you’ve been busy. Thanks for that. It will take me a while to work out exactly what is happening there but I will persevere.

I’m getting further into this. I was reading a silabs standards document about the notification command class, yesterday, which has helped me write in some stuff that wasn’t being handled correctly. I really want to try and do things properly.

Thanks for taking the time to help @krlaframboise and @tpmanley

My handlers are very reliable and I always implement all the features the device supports, but I’m by no means an expert.

I’ve always had a hard time balancing the KISS and DRY principals and tend to lean towards not duplicating code which makes my DTHs a little more complex than they need to be.

On the other hand, if I hadn’t written all my handlers the way I did then in some of my DTHs I’d have to completely re-write the options list now instead of changing 1 line and some of them have 20+ settings.

I also have some weird things in my code that prevent issues I’ve run into in the past when ST made a breaking change or a SmartApp didn’t follow the capability specifications. Those things are no longer necessary, but they don’t hurt anything so I’ve included them going forward.

I’m 100% positive that a map didn’t work with enum setting when I tested it several years ago so I’ve used a list of maps ever since, but it’s possible there was a bug at the time I tested it and if I had tried a week later it would have worked.

Devices often implement things in slightly different ways and although they’re functional with the built-in DTHs they can be implemented in more efficient ways so I spend a lot of time testing the device and customizing the handler to fit the functionality of the device.

I also rarely comment my code because I feel that if you keep a function limited to doing one thing and name it accordingly then the code documents itself. If the code is doing that requires an explanation then I usually take a step back to see if there’s a cleaner way to implement it.

Long story short, my handlers are probably overkill and there are a lot of other handlers on the forum and in the SmartThingsPublic repository that are a better representation of what’s necessary to write a handler so I wouldn’t get hung up on trying to understand my code…

They have a 600+ page Application Command Class Specifications document that should include all the command classes you’ll be using.