Issues with deselection of settings

No, just all of the button controller rules. I noticed when deleting my zigbee end devices that there were quite a few still associated with rules that they were completely removed from. I’m leaning towards this as being an issue. I also had to delete on of my light groups because I added a couple new lights to it, deleted a couple old lights from it, moved the old lights to my bedroom group, but the original group kept turning them on and off. I tried saving the group again, rebooting, but finally said wtf and deleted it. Thing that make you go :thinking:
Needless to say, I no longer edit groups; just delete and make new. After seeing this happen, I went through all of my groups, created new ones, and switched them out, deleting the old ones. This did speed some of them up quite a bit.

1 Like

I'd noticed with a scene I'd tried to remove a device from the was happening so ended up deleting and remaking.. mabey a bug in groups and scenes??

I think it goes deeper than that. I’ve had to do the same with RM and SL as well at one time or another in order to get the rule to work in a rule where I had changed devices. Rule doesn’t work, delete it, create the exact same rule, rule works perfect.

This is due to the way app inputs are handled in Hubitat. I just wrote my first couple apps and learned that if you have an input (setting) that is dynamic (removed / hidden or created / shown based on the value of other settings), and the setting gets removed / hidden when it still has a value (which could be a device), then that value (or device) will stay linked to that app. Even though from the user’s perspective the app is no longer configured to use a certain device, if you look at the app’s state, you will often see loads of orphaned settings / devices linked to it. Hubitat could fix this easily by removing input / settings values when an app no longer declares that input. As it is, the app itself doesn’t even have a way to clean up these orphaned inputs / settings. I just completely rewrote the UI code of one of my apps to prevent this issue, and the only way to do it is to force the user to unset a setting manually before you hide / remove it in your code.

2 Likes

This is not so easy to do. Apps don't actually "declare inputs", nor even know that you've changed or removed one. Given the dynamic nature of the UI framework, it is very difficult to determine that a given setting is no longer used, because in addition to the setting itself, the app would need to know the state of that setting from before any change -- essentially laboriously tracking every step that is taken in the UI. In most cases to do this would require a great deal of code devoted just to that purpose. For this reason, this has not been a priority to address, nor is it likely to become one. .

If you are writing your own app there is a fairly easy way to do this, assuming that you don't have a complex UI. For an app that has some UI complexity, it is not so easy. On the other hand, if you have a fairly simple UI, this is not as likely to be an issue in the first place.

When I say “declare input”, I’m talking about this, which is technically a method call, but essentially what it’s doing is declaring an input:

input “aSwitch”, “capability.switch”, title: “Switch”

And what do you mean apps don’t know if you’ve changed or removed one? You just add “submitOnChange: true” and then the app can know and deal with a user changing or removing an input value.

Finally, what makes it difficult for the app executor to determine if settings are used by the app or not? If an app has the following in its preferences code...

input “input1”, “number”
if (input1 == 2)
    input “input2”, “number”

... and the user enters 2 for input1 and then input2 shows up, a setting is created for input2, but if the user then changes input1 back to some other value and input2 is no longer “declared” / goes away, why is that so hard for Hubitat’s app executor to detect? The app is calling the input method to create inputs, and IMO, if there are keys in the settings that do not map to any inputs the app is currently declaring, they should be removed. At the very least, it would be nice to have a new option on the input method that is something like “removeIfUndeclared: true” or something. Or maybe the ability to call settings.remove(“input2”). It’s just an annoying thing to have to code around, and I’ve encountered bugs even in the built in Hubitat apps that were likely related to this.

I for one do not want to see any changes to app preferences.

You are approaching this issue in a linear fashion.. Not all apps declare variables within the preferences definition, in fact I bet a majority do not.

So what about the hundreds of apps that use dynamic pages? Apps that use dynamic pages can declare variables on multiple app pages, and yet there may not be any requirement for the user to actually visit all of those pages, hence the input statements never execute. How is the hub supposed to track declarations when they may not even executed each time the app is opened?

With that in mind, how does “garbage collection” work? What is the criteria by which the hub should declare a variable to be unused under these circumstances in which not every input statement is loaded each time the app runs?

I don’t think this is practical.

The answer, it can’t.

what confuses me is why the stock apps (simple lighting etc) hangs onto devices. why isnt the selection purged and repopulated upon clicking the update button.

Or does it and its user error, ie insted of clicking update clicking off to the side of the screen (in which case education is needed)?

Because, as @srwhite explains, the app doesn't know that the selection is gone. If you want to get rid of a selection, deselect it in the device selector. This is the only way. If you change a higher order selection, you just strand the original device selection. An app has no way to know this has happened short of Herculean efforts that we won't burden ourselves with.

If you want to cleanly puree an app, remove it and start over, making the correct selections at each step, on then don't change those selections.

You’re correct, garbage collection might not be perfect and might only work for pages that are actually loaded.

But what’s the problem with my other suggestion, to give developers the ability to call settings.remove() and manage our own settings if we choose?

I think this is basically the "Halting Problem", LOL. Interesting suggestion, but I don't think it can be accomplished.

1 Like

You can do this already.

1 Like

Man, you guys are so quick to give up and assume something is impossible. It may require some additional metadata from a developer, but it’s certainly not impossible. If each input passed a list of input names it was dependent on, then it could be garbage collected if one of its dependencies was removed, even if it was in a nested dynamic page that was never visited. For any page, the Hubitat app executor would just need to compare inputs displayed on a page before and after each change, and for any inputs on that page that were no longer displayed, iterate through all settings and remove those which declared that input as a dependency.

But again, since we’re apparently the lazy, negative type around here, I would be happy with just the ability to call settings.remove(). I’ve actually already coded my apps in a way that makes it impossible for settings to get orphaned (very possible to do, even with multiple dynamic pages), but I think my logic would be simplified by having settings.remove().

1 Like

Hm, I’m pretty sure I tried calling settings.remove from the code for one of my pages and got an error, but I’ll try it again.

I use it all over the latest HubConnect.. Works very well.

Not lazy and negative. At least, I don't think? :wink:

And yes, you are correct. If the dev provides extra metadata, that can get past the halting problem.

I'm just not sure what problem is solved by requiring a dev to put a bunch of dependency metadata on inputs, that couldn't be easier solved by them cleaning up settings explicitly if settings are a problem?

I don’t think it should be required, just optional. The root of the issue is that the current implementation makes it likely that the settings an app can see and the settings a user can see will differ, and if an app dev doesn’t consider this very carefully, they can easily make a mistake and use a setting in code that, from the user’s perspective, isn’t even configured. When I first bought my Hubitat, I experienced this very thing with either Motion Lighting or Rule Machine, I can’t remember which. It was controlling a light or performing some behavior that wasn’t even still configured in the app, and it was very confusing and made me scared to change any settings in apps. I ran into this multiple times and eventually, when I wanted to change a setting in an app, I would just recreate the app from scratch instead of modifying the existing one, to ensure there would be no orphaned settings or weird behavior. Also, even if it causes no adverse effects from a functionality point of view, if a user sees that a particular device is “being used” by some app, and then they check the app settings, and it’s not, this confuses the user and makes them distrust the app or platform. To your point about users clearing up settings explicitly, if the setting is hidden from them, they can’t, unless they reconfigure the app to how it was when they originally set the setting, which is a pain.

But that’s a common occurrence in a multi-dynamic page app. Say for example, your app has an Optional Settings page. The user may never actually open that page, yet there may be settings on that page that must be set to a value in order for the app to work. That’s the nature of dynamic page apps, and yes, there’s a responsibility on the developer to write good code. It shouldn’t be incumbent on the platform to clean up after a poorly written app.

Going back to my example, for instance, as a developer, I can call app.updateSettings() in the initialize() method to set the default values for those optional settings... By doing so, I have removed the dependency on forcing the user to open that page simply to initialize the default values.

And how would this work for dynamic preferences? It’s quite practical to dynamically define preferences for which the variable names, and even the quantity of preferences might possibly change each time the user opens the app. Since anything in the metadata section of an app is static the idea of using a manifest falls down here.

Of course it's the responsibility of the developer to write good code, but that doesn't mean the platform can't provide them with additional tools to help write good code. It's the purpose of the platform after all. When even the developers who are employed by Hubitat themselves are making this mistake sometimes, it might be time to think about changing something.

And with my suggested implementation, that would be fine! Those settings wouldn't be cleaned up.

Only inputs that are removed from the page a user is viewing would be cleaned up, OR any input (from any page) that explicitly listed one of those cleaned up inputs as a dependency.

Even if you do find some case that this doesn't work for, I'm suggesting making the clean up opt in, so behavior would not change if you didn't want it to.

I understand that preferences are dynamic... it's the entire reason they can get orphaned in the first place, and why we could use an additional tool to help us manage them. My suggested implemented accounts for that.

You keep on suggesting these "what if" cases, but all of them work perfectly fine with what I suggested. Maybe you just aren't fully understanding my suggestion.

I tried settings.remove() again, and it still didn't work, but I figured out that it's just the wrong method call. app.removeSetting() does work and does what I want, so thanks! In light of this, an automatic setting cleanup option is unnecessary.

2 Likes