Seeking clarification on preferences{} and actual device params

Hi. Please confirm if my understanding of this is correct:

Using preferences{} seems like the proper way to alter device configuration parameters. I’d like to clarify – preferences{} values are stored and populated independently of what the actual parameters are on the device. Let’s say, a user sets param 6 to [0] using preferences{} in the UI. Subsequently, param 6 is set to [1] without user intervention by either the DH or a smartapp. When the user goes into preferences{}, he will see [0] as the current value, even though the device now has [1] in param 6. Is this correct?

Could you point me to an example (if you’re aware of one) where configure() (I assume that’s the way it would be done, if there’s a different way, would very much appreciate the info) is used to retrieve current params from the device and to populate the settings.paramX so that preferences{} UI reflects the actual current device param configuration and not the last saved (by user) preferences{} values.

Thank you!

2 Likes

Unfortunately preferences, like your ir remote are a one way street, they can only be set via the Mobil app. So they won’t be synced from the device if they aren’t set via the device type preferences. Major bummer, I know.

2 Likes

Why is this marked as solved, when it clearly isn’t?!?

I’m updating a device driver for the Fibaro Dimmer 2, which has the capability to change it’s own parameters (via Auto-calibration feature). I want the settings shown in the SmartThings device to be able to updated with the real device parameters when this happens.

I have an event handler for receiving the configuration reports, but if I try the following code to update the device preferences, it fails with a groovy.lang.ReadOnlyPropertyException:

device.preferences.param19.value = 14

If device.preferences are currently read-only then we need to make a feature request to allow editing from code, as this would be a really useful feature.

@Aaron, can we get this as a feature request?

Device (and SmartApp) Preferences are Read-Only for security reasnons.

The customer sets Preferences (and authorizes devices, etc.), and code should not be allowed to change those preferences!!!

I’m not sure I agree with this. Regardless… @tgauchat how would you then suggest to solve the problem where device parameters (specified in the settings UI and sent to the device) subsequently become out-of-sync with the the physical device (e.g. the Fibaro Dimmer runs its auto-calibrate feature which changes various parameters)? At the moment, there appears to be no mechanism to show users the real parameter values in their devices via the UI.

1 Like

Yah… Hope you realize that I was being pedantic. The architecture makes sense, but that’s no reason for SmartThings not to come up with a flexible solution.

So…

  1. At the moment, the possibile option is to have use separate “Value Tiles” which you can update, rather than or in addition control tiles or input fields. It’s not uncommon to see up and down “^v” Tiles with the value in the middle. Yech. But it works.

  2. Wait for the release of “HTML” tiles/pages which will be integrated with SmartApps and DTHs. They were demonstrated months ago at the Samsung Developers Conference; but are being released on SmartThings’s timeline.

1 Like

Well finally, I can say Mike is wrong! :stuck_out_tongue: It appears we can now use:

app.updateSetting(inputName, [type: type, value: value]) 
app.updateSetting(inputName, value)
// or for DTHs:
device.updateSetting(inputName, [type: type, value: value]) 
device.updateSetting(inputName, value)
1 Like

updateSetting must be a new method, I’m seldom wrong, at least in my own mind…
where did you find this BTW?

github.

I’ve realised it’s not very consistent with the other methods for accessing settings, e.g.:

Reading settings values:

def p = setting.settingName
// Or:
def p = device.getPreferenceValue("settingName")

Updating settings values:

device.updateSetting(settingName, [type: type, value: value]) 

Reading settings meta-data via preferences:

preferences?.sections.each { section ->
    section.input.each { input ->
    	log.debug "$device.displayName: Found input: ${input.inspect()}"
    	log.debug "$device.displayName: Input value: ${input.value}" // Returns null.
        if (input.defaultValue != null) { // this returns true if default value is (bool)false.
        	log.debug "$device.displayName: Found defaultValue for: ${input.name}: ${input.defaultValue}"
        }
    }
}

All a bit of a mess really…

You would think we could have a standard name for these things too. I never know whether to use “preferences”, “settings”, or “inputs”!! :imp:

1 Like

I can confirm the short version works in a dth, however there’s quite a bit of funk to it
It will not update a setting unless it’s already been set (once), after that it’s fine.
The preferences settings in the UI aren’t updated to match those set in code…
The long version, just sets the pref to null, most awesomely, this is reflected in the ui…

/*
 
*/
metadata {
	
    definition (name: "updateSettingDTH", namespace: "mmaxwell", author: "mike maxwell") {
		capability "Switch"
 	}
    preferences {
       	input name: "enum1", type: "enum", title: "test enum 1", description: "enum1", required: true, options:["1","0"]
        input name: "bool1", type: "bool", title: "test bool 1", description: "bool1", required: true
    }
	tiles {
		standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
			state "off", label: '${currentValue}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
			state "on", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
		}

        main "switch"
		details(["switch"])
	}
}


def on() {
	sendEvent(name: "switch", value: "on")
    //device.updateSetting("enum1", [type: "enum", value: "1"]) //sets input to null
    //device.updateSetting("bool1", [type: "bool", value: true]) //sets input to null

	device.updateSetting("enum1","1")  //works
    device.updateSetting("bool1", true) //works
    
    log.debug "values after ON, enum1:${enum1}, bool1:${bool1}"
}

def off() {
	sendEvent(name: "switch", value: "off")
    //device.updateSetting("enum1", [type: "enum", value: "0"]) //sets input to null
    //device.updateSetting("bool1", [type: "bool", value: false]) //sets input to null
    
    
    device.updateSetting("enum1","0")  //works
    device.updateSetting("bool1", false)  //works
    
    log.debug "values after OFF, enum1:${enum1}, bool1:${bool1}"
}

def updated(){
	log.debug "values after pref set, enum1:${enum1}, bool1:${bool1}"
}

I had assumed that the long version was a map parameter element, maybe device.updateSetting(“bool1”, type: “bool”, value: true) would work, if someone else wants to test this…

This doesn’t match my quick testing today:

If a setting already has a non-null value then you can change it with device.updateSetting(inputName, value) and it will update in the UI (at least on iPhone it will). You can also set it to null.

However, if the setting is currently not set (i.e. settings.inputName == null) then you cannot give it a value using device.updateSetting(inputName, value).

However, I only tested with the short version and using a “number” type input.

Possibly the reason why this is not a documented/supported function yet is that it’s still a work in progress…?

right, no initial setting, and you can’t set it via code.
likely the android mobile app is at fault for not updating the setting when it does change…
In any event, broken as it is currently, it’s a step in the right direction and better than nothing…

Thanks for this info, it’s exactly what I was looking for. I’ve tried using this to update my settings.

private processParam1(cmd) {
def setValue
//log.trace “$cmd.scaledConfigurationValue”

	if (cmd.scaledConfigurationValue == 0) {
	setValue = "No"
	}
	if (cmd.scaledConfigurationValue == 1) {
	setValue = "Yes"
	}
log.info "LCDinvert: ${setValue}"
device.updateSetting(LCDinvert, setValue)

}

I’m getting this error though.

08:43:07: error org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: physicalgraph.device.Device.preferences, no session or session was closed @line 636 (processParam1)

If anyone can point me in the right direction, I’d be very grateful.

Thanks

Eventually found this to work

def paramValue

settings.$inputname = paramValue

This updates the mobile UI from an event change.

Hi,
I’m getting the same error as you when I tried to use the device.updateSetting method. I then tried your solution of settings.$inputname but can’t get it to work. No errors, but the value is not saving.

Here was my original statement:
device.updateSetting(“ledColor”, [value:colorValue.toInteger(), type:”enum”])

I then tried:
settings.$ledColor = colorValue.toInteger()

This is within a new method, not an event. Is that the issue?
Thank you.

Hi. Yes, upon further testing I realised this isn’t working for me. It was masked by something else I fixed which was settings sticking between apps.

I haven’t done any more since I noticed. I can’t seem to find any recent forum posts. The documentation says they’re read only but then, I’m not sure if that pre-dates the posts saying it’s possible.

I tried using device.updateSetting within the event directly and also within the configure and I got that error no matter where I used it.

Long story short, I’m not sure what to try next. I’ve used defaults and tested setting preferences to ensure I don’t end up with mismatching states.

I’m definitely interested to see if we can get to the bottom of it.

This code works for me. I go into settings. Slide doUpgrade to true, go back and go back to settings, it’s changed back to false.

if (doUpgrade=="true"){
	setOTAURL()
	doUpgrade()
	device.updateSetting("doUpgrade", false)
}

Unfortunately, still can’t get this to work. I haven’t tried with a boolean though. I’ll try that tomorrow.

Hi Davin,
I tried updating a boolean, still getting the same error.
What kind of method do you have this code in? I tried both an event to have this triggered directly from the device, and a regular method didn’t make a difference in my case.

Hi Davin,
As I’m re-reading your post, I’m wondering if it works for you because you’re in the Settings page to start with. Maybe they block changes when the user isn’t in Settings, and that’s what the error means when it says no session.