[BUG] device.clearSetting not working

I've been playing with more driver development and trying to figure out things like if new inputs have defaults set automatically.

To debug more I put together a driver that just interacts with the settings object and see how things behave. What I've observed is:

  • When a device is first added the defaultValues for all inputs are populated into the settings Map
  • Adding a new input to an existing device driver does not modify the settings Map
  • device.updateSetting doesn't appear to do anything. If you try to update a setting that is not a real input you do get a NullPointerException but updating a real setting doesn't actually persist.
  • device.clearSetting sets the target setting's value to null, not the default value from the input.

I'm basing my attempted use of these APIs on these pages:

Here is the device code I'm using to do all this testing: hubitat/basic-settings-tool.groovy at master · edalquist/hubitat · GitHub

@bravenel for visibility.

EDIT. Thanks to @stephack I figured out how to get updateSetting working by passing a Map in for the second argument: comment #10

Did you review this?

state.clear()
state.remove("version")

Both of those work, for example.

I'm referring to settings not state.

settings.clear
settings.remove("logDebug")

1 Like

I'm reporting that these two methods do not work as documented, not looking for a work-around. For my original post I can just do the logic in removeAllSettings() and then reload the device page and then click Save to get back to the default settings.

  • device.removeSettings DOES work.
  • settings.clear() clears the settings map for that execution but the change does not persist. My guess is the settings map is created on each execution such that changes to it don't reflect in the actual settings.

If you look at the code I posted the one reliable way to delete all settings I've found is:

def removeAllSettings() {
    log.debug "before: " + settings
    // Copy keys set first to avoid any chance of concurrent modification
    def keys = new HashSet(settings.keySet())
    keys.each{ key -> device.removeSetting(key) }
    log.debug " after: " + settings
}

That does result in an empty settings Map until the Save Preferences button is pressed again.

I don't get what you posted here when you said updating a real setting does not persist. I've used this a few times and here what I noticed.

You cannot update a setting that hasn't been assigned a value. Once the input has been manually assigned a value from the device page, device.updateSetting() works fine. This was mentioned in a post a while back and we have asked @chuck.schwer if we could get the device settings to behave like the app settings ie allow modifications without having to manually set a value in the device page first. I recently asked fort an update on this because I could really use this functionality on a driver I'm building.

That isn't the behavior I'm seeing. Using the sample device I posted I uncommented the testSetting_2 string input and then did the following:

  1. Run removeAllSettings()
    • settings: [:]
  2. Click Save Preferences
    • settings: [testSetting_1:1, testSetting_2:foo]
  3. Change testSetting_2 in the Preferences UI to a new value of foo2 and click Save Preferences
    • settings: [testSetting_1:1, testSetting_2:foo2]
  4. Run updateSetting(testSetting_2, foo3) command
    • settings: [testSetting_1:1, testSetting_2:foo2]

So even with saving a non-default value to testSetting_2 before calling updateSetting I'm not seeing the change persist.

Your command would need to be
device.updateSetting("testSetting_2", [value: "foo3", type: "text"]

I was following the method signatures from here: Device Object - Hubitat Documentation

Sadly giving that a try still doesn't work for me :frowning:

def updateSetting(settingName = null, settingValue = null, settingType = null) {
    log.debug "Replacing ${settingName}: '${settings[settingName]}' with '${settingValue}' of type ${settingType}"
    try {
        device.updateSetting(settingName, [value: settingValue, type: settingType])
    } catch (NullPointerException e) {
        log.error "Setting ${settingName} is not a valid setting: " + e
    }
    log.debug "Updated Settings: " + settings
}

Running that command results in:

dev:289 2019-06-13 03:07:13.812 pm debug settings: [testSetting_1:1, testSetting_2:foo2]
dev:289 2019-06-13 03:07:08.378 pm debug Updated Settings: [testSetting_1:1, testSetting_2:foo2]
dev:289 2019-06-13 03:07:08.363 pm debug Replacing testSetting_2: 'foo2' with 'foo4' of type text

I dont understand what you are trying to do in the code above but I have used the format above many times and can tell you. It definitely works.

I know this because I was testing it just this morning to assist me with an update to my driver. The change necessitated that I switch from an enum list to plain text and had to update the input's value to avoid having the user to manually make changes, See below

def cleanUp() {
    if(deviceNames.contains("[")){ //if string version of enum list..then remove brackets and quotes
        def newVal = deviceNames.replace("[", "").replace("]", "").replace("\"","")
        device.updateSetting("deviceNames",[value:newVal,type:"text"])
    }
	device.removeSetting("deviceName")
	device.removeSetting("myImage")
	device.removeSetting("myTitle")
	device.removeSetting("apiKey")
	device.removeSetting("myPackage")
	device.removeSetting("action")
    state.remove("devices")
}
1 Like

That is essentially what got me down this rabbit hole, doing driver development and wanting to add/remove/change inputs without having to completely remove/reinstall the device.

At this point I just created that demo device that just manipulates the settings object to try and see what does work and what does.

What version are you on? I'm running into this behavior on 2.1.1.119 Also just so we are on the same page, is that cleanUp method in your device code or in app code?

Device code.

This is all being done on my Dev hub that is part of the Beta program.
I was testing this morning on the latest release at the time. I am now on the release that was posted today.

So I just tried again and I blindly copied "text" as the type even though my input is a "string" setting a matching type works! I'll update the original post to clarify the correct usage of updateSetting.

Have you ever had any luck using clearSetting

1 Like

Nope. I only used it once when trying to "reset" an input in hopes that it would allow updateSetting() to apply. Nogo on that unfortunately.

which should you use?

state.remove("temperature")
state.clear("temperature")

I think it's either state.clear() to remove everything or state.remove("temperature"), for example, to remove a specific variable.

Another note: because you said "temperature," which is most commonly seen as an attribute/event under "Current States" (perhaps an unfortunate partial overlap in name), your question and my answer are about the state or atomicState object, "State Variables" on the device page or app status page. There is no way to clear/remove an attribute, short of re-pairing or using a driver that doesn't implement it, nor do I believe is it recommended that have missing attributes when your driver claims to the implement them.

Thanks, I was using state. for doing a comparison but it was a needless write to the dB, so I null'ed it thinking it would go away after a cleanup or boot but it didn't.

Just for other ppl reading I tried both but one threw an error but can't remember which, it probably didn't like the 'temperature' bit if it was intended to all

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.