Dynamic state options not showing up

Several people on the forum have reported that their squeezebox favorites sometimes are not showing up in the UI. The squeezebox binding uses dynamic state options on a channel named playFavorite. When using a Selection widget in Basic UI and HABpanel, the list of favorites is not showing up on an item linked to the playFavorite channel.

I’ve also observed that the state options list is empty when using this in a rule:

    PlayFavorite.getStateDescription.getOptions.forEach[option |
        logInfo("test", "Option " + option.getValue + ": " + option.getLabel)
    ]

In fact, PlayFavorite.getStateDescription.getOptions.size returns 0.

Link to forum post describing the problem.

Sometimes a restart of openHAB will resolve the issue. Some people have reported that clearing tmp and cache resolves the issue.

Based on what I’ve found so far, I’ve observed the following:

  • I can see everything working all the way up to the call to stateDescriptionProvider.setStateOptions in the SqueezeBoxPlayerHandler. setStateOptions is being called with a valid channel and a list of state options for the playFavorite channel.

  • In a test version of the binding, I’ve demonstrated that a call to stateDescriptionProvider.getStateDescription(channel, null, null).getOptions() immediately following the above call successfully returns a list containing the state options.

  • However, when using an item linked to that channel , there are no state options.

I’m not sure what to do next. @cweitkamp @wborn @J-N-K any suggestions?

One other observation I can add…

I added a couple static state options to the binding’s thing.xml. Those show up just fine, so it appears to be something with how dynamic state options are accessed through the item.

Hi Mark,

I might have an idea what could be wrong. I am not sure if it is caused by the squeezebox binding itself. Here is a path to follow:

tl;dr The ChannelStateDescriptionProvider iterates all known DynamicStateDescriptionProvider to find a custom state description for a channel. This seems very inefficient and also error prone. If a DynamicStateDescriptionProvider does not return null when it is not for that specific channel. If that provider is called before the actual provider it will not even show the expected states.

That might be the culprit. And it can be located in every binding installed in a user setup.

Hmm. Interesting. I do recall seeing that issue. But I’m a bit confused. That issue was fixed back in September. The problem I described is happening on current builds that have the 2.5 core. Are you saying there may be another issue related to the iteration through the dynamic state description providers?

Yes, exactly. It is kind of complex and could be explained at best with an example. I will provide you some code later. Currently I have a blueprint for some improvements in my mind. Probably not for OH2.5.x anymore - but for OH3.

Ok, so I was seeing the issue on two openHAB installations - a test system and my main production system.

Earlier this morning, on the test system, I removed all the bindings except the squeezebox binding, and that system started to work. One of the bindings I removed was the sony binding.

Just a minute ago, I removed the sony binding from my production system. That system started to work immediately.

I removed that one first because it was the most recently added binding, and it showed up when I looked at all the installed DynamicStateDescriptionProvider services running on my system.

bundle:services | grep DynamicStateDescriptionProvider

Off to look at what that binding is doing…

Is it possible that there are cases where getStateDescription won’t return null when it’s called for a channel not associated with the sony binding? It would seem that it will return the originalStateDescription that was passed in, and if that is non-null, then it could be a problem. Am I understanding this correctly?

Sure enough. I put the sony binding back in, and the squeezebox state options broke.

[org.eclipse.smarthome.core.thing.type.DynamicStateDescriptionProvider, org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkStateDescriptionOptionsProvider]
[org.eclipse.smarthome.core.thing.type.DynamicStateDescriptionProvider, org.openhab.binding.squeezebox.internal.SqueezeBoxStateDescriptionOptionsProvider]
[org.eclipse.smarthome.core.thing.type.DynamicStateDescriptionProvider, org.openhab.binding.sony.internal.providers.SonyDynamicStateProvider, org.openhab.binding.sony.internal.providers.SonyDefinitionProvider, org.eclipse.smarthome.core.thing.binding.ThingTypeProvider, org.eclipse.smarthome.core.thing.type.ChannelGroupTypeProvider, org.openhab.binding.sony.internal.providers.SonyModelProvider]

So, I guess it depends on the order that the state description providers appear in the List<DynamicStateDescriptionProvider> list. That’s why it can work sometimes and not work other times. If you happen to hit a provider that returns non-null when it shouldn’t, then you’re out of luck.

And that’s why the call to getStateDescription worked when I called it from inside the binding – because it’s only using that binding’s DynamicStateDescriptionProvider.

As a final test, I rebuilt the sony binding, but replaced the return originalStateDescription with return null. I’m not sure if that’s the correct fix for this binding, but when running the modified version of the binding, the squeezebox binding’s state options work fine. When putting in the original version of the sony binding, the squeezebox binding’s state options don’t work.

Interesting - didn’t really think about returning null because if we have an original - I figured I should return it. I don’t see any reason I can’t change it to return null however…

:+1:

You nailed it. But the root cause is not the Sony binding. The problem is the design of the feature inside OHC. It is a mess that one wrong implementation stops a whole part of it from working properly.

You raised my interest in this and I will try to find a general solution for it.

Since the sony one is waiting to be merged - let me know if you want me to return null for that case rather than the original. No problems to change it…

Thanks for jumping in @tmrobert8. I was waiting to hear back on my analysis before pulling you in.

I’m unclear about returning null because I don’t have a very deep grasp of this area, and I wasn’t sure what effect it would have on the functionality of the binding. @cweitkamp what would you recommend? Is returning null the correct fix until this can be fixed in core?

Agreed, and thanks!

@tmrobert8 I left a comment in your PR. And of course thanks for all the great work. As I said: Not your fault.

@mhilbush Yes, returning null is the correct way for all implementations. At least in the short run. The JavaDoc tells you about that. But I think it is not clear enough. We should mention to never return the original state description.

1 Like

My first draft for a solution:

hello all,
since i updated openhabian (rpi 4b, 4gb) to 3.2.0m3 (from 3.2.0.m2) it seems the dynamic state description again does not work. anybody else who can confirm this?

this was my jython-rule that worked earlier:

    for option in ir.getItem("iSbPlayer_Favorit").getStateDescription().getOptions():
        LogAction.logInfo(u"test", u"### Station {} bei nr {} gefunden".format(option, int(option.getValue())))

and this i tried in dsl, also without success:

        iSbPlayer_Favorit.getStateDescription.getOptions.forEach[option |
                logInfo("test", "Option " + option.getValue + ": " + option.getLabel)
            ]

in mainui the playFavorite looks like:

not 100% but rahter certain that it happened with the update. would be glad if somebody could help.